git subrepo commit mailcow/src/mailcow-dockerized
subrepo: subdir: "mailcow/src/mailcow-dockerized"
merged: "308860af"
upstream: origin: "https://github.com/mailcow/mailcow-dockerized.git"
branch: "master"
commit: "3f1a5af8"
git-subrepo: version: "0.4.5"
origin: "???"
commit: "???"
Change-Id: I5d51c14b45db54fe706be40a591ddbfcea50d4b0
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery-3.6.0.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery-3.6.0.min.js
new file mode 100644
index 0000000..c4c6022
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery-3.6.0.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}S.fn=S.prototype={jquery:f,constructor:S,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=S.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return S.each(this,e)},map:function(n){return this.pushStack(S.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(S.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(S.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},S.extend=S.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(S.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||S.isPlainObject(n)?n:{},i=!1,a[t]=S.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},S.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){b(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(p(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},makeArray:function(e,t){var n=t||[];return null!=e&&(p(Object(e))?S.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(p(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g(a)},guid:1,support:y}),"function"==typeof Symbol&&(S.fn[Symbol.iterator]=t[Symbol.iterator]),S.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var d=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,S="sizzle"+1*new Date,p=n.document,k=0,r=0,m=ue(),x=ue(),A=ue(),N=ue(),j=function(e,t){return e===t&&(l=!0),0},D={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",F=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",B=new RegExp(M+"+","g"),$=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="<a id='"+S+"'></a><select id='"+S+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!=C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!=C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&D.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(j),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(B," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[k,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===k&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[S]||(a[S]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[k,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace($,"$1"));return s[S]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[k,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[S]||(e[S]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===k&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[S]&&(v=Ce(v)),y&&!y[S]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[S]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace($,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace($," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=A[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[S]?i.push(a):o.push(a);(a=A(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=k+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(k=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(k=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=S.split("").sort(j).join("")===S,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);S.find=d,S.expr=d.selectors,S.expr[":"]=S.expr.pseudos,S.uniqueSort=S.unique=d.uniqueSort,S.text=d.getText,S.isXMLDoc=d.isXML,S.contains=d.contains,S.escapeSelector=d.escape;var h=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&S(e).is(n))break;r.push(e)}return r},T=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},k=S.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var N=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1<i.call(n,e)!==r}):S.filter(n,e,r)}S.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?S.find.matchesSelector(r,e)?[r]:[]:S.find.matches(e,S.grep(t,function(e){return 1===e.nodeType}))},S.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(S(e).filter(function(){for(t=0;t<r;t++)if(S.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)S.find(e,i[t],n);return 1<r?S.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&k.test(e)?S(e):e||[],!1).length}});var D,q=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(S.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&S(e);if(!k.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&S.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?S.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(S(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(S.uniqueSort(S.merge(this.get(),S(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),S.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return h(e,"parentNode")},parentsUntil:function(e,t,n){return h(e,"parentNode",n)},next:function(e){return O(e,"nextSibling")},prev:function(e){return O(e,"previousSibling")},nextAll:function(e){return h(e,"nextSibling")},prevAll:function(e){return h(e,"previousSibling")},nextUntil:function(e,t,n){return h(e,"nextSibling",n)},prevUntil:function(e,t,n){return h(e,"previousSibling",n)},siblings:function(e){return T((e.parentNode||{}).firstChild,e)},children:function(e){return T(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(A(e,"template")&&(e=e.content||e),S.merge([],e.childNodes))}},function(r,i){S.fn[r]=function(e,t){var n=S.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=S.filter(t,n)),1<this.length&&(H[r]||S.uniqueSort(n),L.test(r)&&n.reverse()),this.pushStack(n)}});var P=/[^\x20\t\r\n\f]+/g;function R(e){return e}function M(e){throw e}function I(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}S.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},S.each(e.match(P)||[],function(e,t){n[t]=!0}),n):S.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){S.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return S.each(arguments,function(e,t){var n;while(-1<(n=S.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<S.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},S.extend({Deferred:function(e){var o=[["notify","progress",S.Callbacks("memory"),S.Callbacks("memory"),2],["resolve","done",S.Callbacks("once memory"),S.Callbacks("once memory"),0,"resolved"],["reject","fail",S.Callbacks("once memory"),S.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return S.Deferred(function(r){S.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,R,s),l(u,o,M,s)):(u++,t.call(e,l(u,o,R,s),l(u,o,M,s),l(u,o,R,o.notifyWith))):(a!==R&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){S.Deferred.exceptionHook&&S.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==M&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(S.Deferred.getStackHook&&(t.stackTrace=S.Deferred.getStackHook()),C.setTimeout(t))}}return S.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:R,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:R)),o[2][3].add(l(0,e,m(n)?n:M))}).promise()},promise:function(e){return null!=e?S.extend(e,a):a}},s={};return S.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=S.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(I(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)I(i[t],a(t),o.reject);return o.promise()}});var W=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;S.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&W.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},S.readyException=function(e){C.setTimeout(function(){throw e})};var F=S.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),S.ready()}S.fn.ready=function(e){return F.then(e)["catch"](function(e){S.readyException(e)}),this},S.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--S.readyWait:S.isReady)||(S.isReady=!0)!==e&&0<--S.readyWait||F.resolveWith(E,[S])}}),S.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(S.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var $=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)$(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(S(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},_=/^-ms-/,z=/-([a-z])/g;function U(e,t){return t.toUpperCase()}function X(e){return e.replace(_,"ms-").replace(z,U)}var V=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function G(){this.expando=S.expando+G.uid++}G.uid=1,G.prototype={cache:function(e){var t=e[this.expando];return t||(t={},V(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[X(t)]=n;else for(r in t)i[X(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][X(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(X):(t=X(t))in r?[t]:t.match(P)||[]).length;while(n--)delete r[t[n]]}(void 0===t||S.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!S.isEmptyObject(t)}};var Y=new G,Q=new G,J=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,K=/[A-Z]/g;function Z(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(K,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:J.test(i)?JSON.parse(i):i)}catch(e){}Q.set(e,t,n)}else n=void 0;return n}S.extend({hasData:function(e){return Q.hasData(e)||Y.hasData(e)},data:function(e,t,n){return Q.access(e,t,n)},removeData:function(e,t){Q.remove(e,t)},_data:function(e,t,n){return Y.access(e,t,n)},_removeData:function(e,t){Y.remove(e,t)}}),S.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=Q.get(o),1===o.nodeType&&!Y.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=X(r.slice(5)),Z(o,r,i[r]));Y.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){Q.set(this,n)}):$(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=Q.get(o,n))?t:void 0!==(t=Z(o,n))?t:void 0;this.each(function(){Q.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){Q.remove(this,e)})}}),S.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Y.get(e,t),n&&(!r||Array.isArray(n)?r=Y.access(e,t,S.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=S.queue(e,t),r=n.length,i=n.shift(),o=S._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){S.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Y.get(e,n)||Y.access(e,n,{empty:S.Callbacks("once memory").add(function(){Y.remove(e,[t+"queue",n])})})}}),S.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?S.queue(this[0],t):void 0===n?this:this.each(function(){var e=S.queue(this,t,n);S._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&S.dequeue(this,t)})},dequeue:function(e){return this.each(function(){S.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=S.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Y.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var ee=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,te=new RegExp("^(?:([+-])=|)("+ee+")([a-z%]*)$","i"),ne=["Top","Right","Bottom","Left"],re=E.documentElement,ie=function(e){return S.contains(e.ownerDocument,e)},oe={composed:!0};re.getRootNode&&(ie=function(e){return S.contains(e.ownerDocument,e)||e.getRootNode(oe)===e.ownerDocument});var ae=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&ie(e)&&"none"===S.css(e,"display")};function se(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return S.css(e,t,"")},u=s(),l=n&&n[3]||(S.cssNumber[t]?"":"px"),c=e.nodeType&&(S.cssNumber[t]||"px"!==l&&+u)&&te.exec(S.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)S.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,S.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ue={};function le(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Y.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ae(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ue[s])||(o=a.body.appendChild(a.createElement(s)),u=S.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ue[s]=u)))):"none"!==n&&(l[c]="none",Y.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}S.fn.extend({show:function(){return le(this,!0)},hide:function(){return le(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ae(this)?S(this).show():S(this).hide()})}});var ce,fe,pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="<option></option>",y.option=!!ce.lastChild;var ge={thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Y.set(e[n],"globalEval",!t||Y.get(t[n],"globalEval"))}ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td,y.option||(ge.optgroup=ge.option=[1,"<select multiple='multiple'>","</select>"]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))S.merge(p,o.nodeType?[o]:o);else if(me.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+S.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;S.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<S.inArray(o,r))i&&i.push(o);else if(l=ie(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}var be=/^([^.]*)(?:\.(.+)|)/;function we(){return!0}function Te(){return!1}function Ce(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ee(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ee(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Te;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return S().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=S.guid++)),e.each(function(){S.event.add(this,t,i,r,n)})}function Se(e,i,o){o?(Y.set(e,i,!1),S.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Y.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(S.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Y.set(this,i,r),t=o(this,i),this[i](),r!==(n=Y.get(this,i))||t?Y.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n&&n.value}else r.length&&(Y.set(this,i,{value:S.event.trigger(S.extend(r[0],S.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Y.get(e,i)&&S.event.add(e,i,we)}S.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.get(t);if(V(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&S.find.matchesSelector(re,i),n.guid||(n.guid=S.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof S&&S.event.triggered!==e.type?S.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(P)||[""]).length;while(l--)d=g=(s=be.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=S.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=S.event.special[d]||{},c=S.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&S.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),S.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Y.hasData(e)&&Y.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(P)||[""]).length;while(l--)if(d=g=(s=be.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=S.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||S.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)S.event.remove(e,d+t[l],n,r,!0);S.isEmptyObject(u)&&Y.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=S.event.fix(e),l=(Y.get(this,"events")||Object.create(null))[u.type]||[],c=S.event.special[u.type]||{};for(s[0]=u,t=1;t<arguments.length;t++)s[t]=arguments[t];if(u.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,u)){a=S.event.handlers.call(this,u,l),t=0;while((i=a[t++])&&!u.isPropagationStopped()){u.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!u.isImmediatePropagationStopped())u.rnamespace&&!1!==o.namespace&&!u.rnamespace.test(o.namespace)||(u.handleObj=o,u.data=o.data,void 0!==(r=((S.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s))&&!1===(u.result=r)&&(u.preventDefault(),u.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,u),u.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<S(i,this).index(l):S.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(S.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[S.expando]?e:new S.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click",we),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&Se(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Y.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},S.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},S.Event=function(e,t){if(!(this instanceof S.Event))return new S.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?we:Te,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&S.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[S.expando]=!0},S.Event.prototype={constructor:S.Event,isDefaultPrevented:Te,isPropagationStopped:Te,isImmediatePropagationStopped:Te,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=we,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=we,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=we,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},S.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:!0},S.event.addProp),S.each({focus:"focusin",blur:"focusout"},function(e,t){S.event.special[e]={setup:function(){return Se(this,e,Ce),!1},trigger:function(){return Se(this,e),!0},_default:function(){return!0},delegateType:t}}),S.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){S.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||S.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),S.fn.extend({on:function(e,t,n,r){return Ee(this,e,t,n,r)},one:function(e,t,n,r){return Ee(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,S(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Te),this.each(function(){S.event.remove(this,e,n,t)})}});var ke=/<script|<style|<link/i,Ae=/checked\s*(?:[^=]|=\s*.checked.)/i,Ne=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)S.event.add(t,i,s[i][n]);Q.hasData(e)&&(o=Q.access(e),a=S.extend({},o),Q.set(t,a))}}function He(n,r,i,o){r=g(r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Ae.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),He(t,r,i,o)});if(f&&(t=(e=xe(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=S.map(ve(e,"script"),De)).length;c<f;c++)u=e,c!==p&&(u=S.clone(u,!0,!0),s&&S.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,S.map(a,qe),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Y.access(u,"globalEval")&&S.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?S._evalUrl&&!u.noModule&&S._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):b(u.textContent.replace(Ne,""),u,l))}return n}function Oe(e,t,n){for(var r,i=t?S.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||S.cleanData(ve(r)),r.parentNode&&(n&&ie(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}S.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=ie(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||S.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Le(o[r],a[r]);else Le(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=S.event.special,o=0;void 0!==(n=e[o]);o++)if(V(n)){if(t=n[Y.expando]){if(t.events)for(r in t.events)i[r]?S.event.remove(n,r):S.removeEvent(n,r,t.handle);n[Y.expando]=void 0}n[Q.expando]&&(n[Q.expando]=void 0)}}}),S.fn.extend({detach:function(e){return Oe(this,e,!0)},remove:function(e){return Oe(this,e)},text:function(e){return $(this,function(e){return void 0===e?S.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return He(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return He(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return He(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(S.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return S.clone(this,e,t)})},html:function(e){return $(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!ke.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=S.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(S.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return He(this,arguments,function(e){var t=this.parentNode;S.inArray(this,n)<0&&(S.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),S.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){S.fn[e]=function(e){for(var t,n=[],r=S(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),S(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var Pe=new RegExp("^("+ee+")(?!px)[a-z%]+$","i"),Re=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Me=function(e,t,n){var r,i,o={};for(i in t)o[i]=e.style[i],e.style[i]=t[i];for(i in r=n.call(e),t)e.style[i]=o[i];return r},Ie=new RegExp(ne.join("|"),"i");function We(e,t,n){var r,i,o,a,s=e.style;return(n=n||Re(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||ie(e)||(a=S.style(e,t)),!y.pixelBoxStyles()&&Pe.test(a)&&Ie.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function Fe(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(l){u.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",l.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",re.appendChild(u).appendChild(l);var e=C.getComputedStyle(l);n="1%"!==e.top,s=12===t(e.marginLeft),l.style.right="60%",o=36===t(e.right),r=36===t(e.width),l.style.position="absolute",i=12===t(l.offsetWidth/3),re.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=E.createElement("div"),l=E.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===l.style.backgroundClip,S.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),s},scrollboxSize:function(){return e(),i},reliableTrDimensions:function(){var e,t,n,r;return null==a&&(e=E.createElement("table"),t=E.createElement("tr"),n=E.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",re.appendChild(e).appendChild(t).appendChild(n),r=C.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,re.removeChild(e)),a}}))}();var Be=["Webkit","Moz","ms"],$e=E.createElement("div").style,_e={};function ze(e){var t=S.cssProps[e]||_e[e];return t||(e in $e?e:_e[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Be.length;while(n--)if((e=Be[n]+t)in $e)return e}(e)||e)}var Ue=/^(none|table(?!-c[ea]).+)/,Xe=/^--/,Ve={position:"absolute",visibility:"hidden",display:"block"},Ge={letterSpacing:"0",fontWeight:"400"};function Ye(e,t,n){var r=te.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function Qe(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=S.css(e,n+ne[a],!0,i)),r?("content"===n&&(u-=S.css(e,"padding"+ne[a],!0,i)),"margin"!==n&&(u-=S.css(e,"border"+ne[a]+"Width",!0,i))):(u+=S.css(e,"padding"+ne[a],!0,i),"padding"!==n?u+=S.css(e,"border"+ne[a]+"Width",!0,i):s+=S.css(e,"border"+ne[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function Je(e,t,n){var r=Re(e),i=(!y.boxSizingReliable()||n)&&"border-box"===S.css(e,"boxSizing",!1,r),o=i,a=We(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(Pe.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||!y.reliableTrDimensions()&&A(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===S.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===S.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+Qe(e,t,n||(i?"border":"content"),o,r,a)+"px"}function Ke(e,t,n,r,i){return new Ke.prototype.init(e,t,n,r,i)}S.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=We(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=X(t),u=Xe.test(t),l=e.style;if(u||(t=ze(s)),a=S.cssHooks[t]||S.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=te.exec(n))&&i[1]&&(n=se(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(S.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=X(t);return Xe.test(t)||(t=ze(s)),(a=S.cssHooks[t]||S.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=We(e,t,r)),"normal"===i&&t in Ge&&(i=Ge[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),S.each(["height","width"],function(e,u){S.cssHooks[u]={get:function(e,t,n){if(t)return!Ue.test(S.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?Je(e,u,n):Me(e,Ve,function(){return Je(e,u,n)})},set:function(e,t,n){var r,i=Re(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===S.css(e,"boxSizing",!1,i),s=n?Qe(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-Qe(e,u,"border",!1,i)-.5)),s&&(r=te.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=S.css(e,u)),Ye(0,t,s)}}}),S.cssHooks.marginLeft=Fe(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(We(e,"marginLeft"))||e.getBoundingClientRect().left-Me(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),S.each({margin:"",padding:"",border:"Width"},function(i,o){S.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+ne[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(S.cssHooks[i+o].set=Ye)}),S.fn.extend({css:function(e,t){return $(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Re(e),i=t.length;a<i;a++)o[t[a]]=S.css(e,t[a],!1,r);return o}return void 0!==n?S.style(e,t,n):S.css(e,t)},e,t,1<arguments.length)}}),((S.Tween=Ke).prototype={constructor:Ke,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||S.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(S.cssNumber[n]?"":"px")},cur:function(){var e=Ke.propHooks[this.prop];return e&&e.get?e.get(this):Ke.propHooks._default.get(this)},run:function(e){var t,n=Ke.propHooks[this.prop];return this.options.duration?this.pos=t=S.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ke.propHooks._default.set(this),this}}).init.prototype=Ke.prototype,(Ke.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=S.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){S.fx.step[e.prop]?S.fx.step[e.prop](e):1!==e.elem.nodeType||!S.cssHooks[e.prop]&&null==e.elem.style[ze(e.prop)]?e.elem[e.prop]=e.now:S.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=Ke.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},S.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},S.fx=Ke.prototype.init,S.fx.step={};var Ze,et,tt,nt,rt=/^(?:toggle|show|hide)$/,it=/queueHooks$/;function ot(){et&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(ot):C.setTimeout(ot,S.fx.interval),S.fx.tick())}function at(){return C.setTimeout(function(){Ze=void 0}),Ze=Date.now()}function st(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=ne[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function ut(e,t,n){for(var r,i=(lt.tweeners[t]||[]).concat(lt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function lt(o,e,t){var n,a,r=0,i=lt.prefilters.length,s=S.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=Ze||at(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:S.extend({},e),opts:S.extend(!0,{specialEasing:{},easing:S.easing._default},t),originalProperties:e,originalOptions:t,startTime:Ze||at(),duration:t.duration,tweens:[],createTween:function(e,t){var n=S.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=X(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=S.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=lt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(S._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return S.map(c,ut,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),S.fx.timer(S.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}S.Animation=S.extend(lt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return se(n.elem,e,te.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(P);for(var n,r=0,i=e.length;r<i;r++)n=e[r],lt.tweeners[n]=lt.tweeners[n]||[],lt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&ae(e),v=Y.get(e,"fxshow");for(r in n.queue||(null==(a=S._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,S.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],rt.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||S.style(e,r)}if((u=!S.isEmptyObject(t))||!S.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Y.get(e,"display")),"none"===(c=S.css(e,"display"))&&(l?c=l:(le([e],!0),l=e.style.display||l,c=S.css(e,"display"),le([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===S.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Y.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&le([e],!0),p.done(function(){for(r in g||le([e]),Y.remove(e,"fxshow"),d)S.style(e,r,d[r])})),u=ut(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?lt.prefilters.unshift(e):lt.prefilters.push(e)}}),S.speed=function(e,t,n){var r=e&&"object"==typeof e?S.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return S.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in S.fx.speeds?r.duration=S.fx.speeds[r.duration]:r.duration=S.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&S.dequeue(this,r.queue)},r},S.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ae).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=S.isEmptyObject(t),o=S.speed(e,n,r),a=function(){var e=lt(this,S.extend({},t),o);(i||Y.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=S.timers,r=Y.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&it.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||S.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Y.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=S.timers,o=n?n.length:0;for(t.finish=!0,S.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),S.each(["toggle","show","hide"],function(e,r){var i=S.fn[r];S.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(st(r,!0),e,t,n)}}),S.each({slideDown:st("show"),slideUp:st("hide"),slideToggle:st("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){S.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),S.timers=[],S.fx.tick=function(){var e,t=0,n=S.timers;for(Ze=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||S.fx.stop(),Ze=void 0},S.fx.timer=function(e){S.timers.push(e),S.fx.start()},S.fx.interval=13,S.fx.start=function(){et||(et=!0,ot())},S.fx.stop=function(){et=null},S.fx.speeds={slow:600,fast:200,_default:400},S.fn.delay=function(r,e){return r=S.fx&&S.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},tt=E.createElement("input"),nt=E.createElement("select").appendChild(E.createElement("option")),tt.type="checkbox",y.checkOn=""!==tt.value,y.optSelected=nt.selected,(tt=E.createElement("input")).value="t",tt.type="radio",y.radioValue="t"===tt.value;var ct,ft=S.expr.attrHandle;S.fn.extend({attr:function(e,t){return $(this,S.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){S.removeAttr(this,e)})}}),S.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?S.prop(e,t,n):(1===o&&S.isXMLDoc(e)||(i=S.attrHooks[t.toLowerCase()]||(S.expr.match.bool.test(t)?ct:void 0)),void 0!==n?null===n?void S.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=S.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(P);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ct={set:function(e,t,n){return!1===t?S.removeAttr(e,n):e.setAttribute(n,n),n}},S.each(S.expr.match.bool.source.match(/\w+/g),function(e,t){var a=ft[t]||S.find.attr;ft[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=ft[o],ft[o]=r,r=null!=a(e,t,n)?o:null,ft[o]=i),r}});var pt=/^(?:input|select|textarea|button)$/i,dt=/^(?:a|area)$/i;function ht(e){return(e.match(P)||[]).join(" ")}function gt(e){return e.getAttribute&&e.getAttribute("class")||""}function vt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(P)||[]}S.fn.extend({prop:function(e,t){return $(this,S.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[S.propFix[e]||e]})}}),S.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&S.isXMLDoc(e)||(t=S.propFix[t]||t,i=S.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=S.find.attr(e,"tabindex");return t?parseInt(t,10):pt.test(e.nodeName)||dt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(S.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),S.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){S.propFix[this.toLowerCase()]=this}),S.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).addClass(t.call(this,e,gt(this)))});if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){S(this).removeClass(t.call(this,e,gt(this)))});if(!arguments.length)return this.attr("class","");if((e=vt(t)).length)while(n=this[u++])if(i=gt(n),r=1===n.nodeType&&" "+ht(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=ht(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){S(this).toggleClass(i.call(this,e,gt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=S(this),r=vt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=gt(this))&&Y.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Y.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+ht(gt(n))+" ").indexOf(t))return!0;return!1}});var yt=/\r/g;S.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,S(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=S.map(t,function(e){return null==e?"":e+""})),(r=S.valHooks[this.type]||S.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=S.valHooks[t.type]||S.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(yt,""):null==e?"":e:void 0}}),S.extend({valHooks:{option:{get:function(e){var t=S.find.attr(e,"value");return null!=t?t:ht(S.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=S(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=S.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<S.inArray(S.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),S.each(["radio","checkbox"],function(){S.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<S.inArray(S(e).val(),t)}},y.checkOn||(S.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var mt=/^(?:focusinfocus|focusoutblur)$/,xt=function(e){e.stopPropagation()};S.extend(S.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!mt.test(d+S.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[S.expando]?e:new S.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:S.makeArray(t,[e]),c=S.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,mt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Y.get(o,"events")||Object.create(null))[e.type]&&Y.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&V(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!V(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),S.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,xt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,xt),S.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=S.extend(new S.Event,n,{type:e,isSimulated:!0});S.event.trigger(r,null,t)}}),S.fn.extend({trigger:function(e,t){return this.each(function(){S.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return S.event.trigger(e,t,n,!0)}}),y.focusin||S.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){S.event.simulate(r,e.target,S.event.fix(e))};S.event.special[r]={setup:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r);t||e.addEventListener(n,i,!0),Y.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=Y.access(e,r)-1;t?Y.access(e,r,t):(e.removeEventListener(n,i,!0),Y.remove(e,r))}}});var bt=C.location,wt={guid:Date.now()},Tt=/\?/;S.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||S.error("Invalid XML: "+(n?S.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Ct=/\[\]$/,Et=/\r?\n/g,St=/^(?:submit|button|image|reset|file)$/i,kt=/^(?:input|select|textarea|keygen)/i;function At(n,e,r,i){var t;if(Array.isArray(e))S.each(e,function(e,t){r||Ct.test(n)?i(n,t):At(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)At(n+"["+t+"]",e[t],r,i)}S.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!S.isPlainObject(e))S.each(e,function(){i(this.name,this.value)});else for(n in e)At(n,e[n],t,i);return r.join("&")},S.fn.extend({serialize:function(){return S.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=S.prop(this,"elements");return e?S.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!S(this).is(":disabled")&&kt.test(this.nodeName)&&!St.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=S(this).val();return null==n?null:Array.isArray(n)?S.map(n,function(e){return{name:t.name,value:e.replace(Et,"\r\n")}}):{name:t.name,value:n.replace(Et,"\r\n")}}).get()}});var Nt=/%20/g,jt=/#.*$/,Dt=/([?&])_=[^&]*/,qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Lt=/^(?:GET|HEAD)$/,Ht=/^\/\//,Ot={},Pt={},Rt="*/".concat("*"),Mt=E.createElement("a");function It(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(P)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Wt(t,i,o,a){var s={},u=t===Pt;function l(e){var r;return s[e]=!0,S.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function Ft(e,t){var n,r,i=S.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&S.extend(!0,e,r),e}Mt.href=bt.href,S.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:bt.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(bt.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Rt,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":S.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Ft(Ft(e,S.ajaxSettings),t):Ft(S.ajaxSettings,e)},ajaxPrefilter:It(Ot),ajaxTransport:It(Pt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=S.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?S(y):S.event,x=S.Deferred(),b=S.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=qt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||bt.href)+"").replace(Ht,bt.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(P)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Mt.protocol+"//"+Mt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=S.param(v.data,v.traditional)),Wt(Ot,v,t,T),h)return T;for(i in(g=S.event&&v.global)&&0==S.active++&&S.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Lt.test(v.type),f=v.url.replace(jt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Nt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(Tt.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Dt,"$1"),o=(Tt.test(f)?"&":"?")+"_="+wt.guid+++o),v.url=f+o),v.ifModified&&(S.lastModified[f]&&T.setRequestHeader("If-Modified-Since",S.lastModified[f]),S.etag[f]&&T.setRequestHeader("If-None-Match",S.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+Rt+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=Wt(Pt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),!i&&-1<S.inArray("script",v.dataTypes)&&S.inArray("json",v.dataTypes)<0&&(v.converters["text script"]=function(){}),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(S.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(S.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--S.active||S.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return S.get(e,t,n,"json")},getScript:function(e,t){return S.get(e,void 0,t,"script")}}),S.each(["get","post"],function(e,i){S[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),S.ajax(S.extend({url:e,type:i,dataType:r,data:t,success:n},S.isPlainObject(e)&&e))}}),S.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),S._evalUrl=function(e,t,n){return S.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){S.globalEval(e,t,n)}})},S.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=S(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){S(this).wrapInner(n.call(this,e))}):this.each(function(){var e=S(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){S(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){S(this).replaceWith(this.childNodes)}),this}}),S.expr.pseudos.hidden=function(e){return!S.expr.pseudos.visible(e)},S.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},S.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Bt={0:200,1223:204},$t=S.ajaxSettings.xhr();y.cors=!!$t&&"withCredentials"in $t,y.ajax=$t=!!$t,S.ajaxTransport(function(i){var o,a;if(y.cors||$t&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Bt[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),S.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),S.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return S.globalEval(e),e}}}),S.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),S.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=S("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=ht(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&S.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?S("<div>").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var Xt=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;S.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||S.guid++,i},S.holdReady=function(e){e?S.readyWait++:S.ready(!0)},S.isArray=Array.isArray,S.parseJSON=JSON.parse,S.nodeName=A,S.isFunction=m,S.isWindow=x,S.camelCase=X,S.type=w,S.now=Date.now,S.isNumeric=function(e){var t=S.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},S.trim=function(e){return null==e?"":(e+"").replace(Xt,"")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return S});var Vt=C.jQuery,Gt=C.$;return S.noConflict=function(e){return C.$===S&&(C.$=Gt),e&&C.jQuery===S&&(C.jQuery=Vt),S},"undefined"==typeof e&&(C.jQuery=C.$=S),S});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery.min.js
deleted file mode 100644
index d788cb4..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/000-jquery.min.js
+++ /dev/null
@@ -1,4 +0,0 @@
-/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
-!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}k.fn=k.prototype={jquery:f,constructor:k,length:0,toArray:function(){return s.call(this)},get:function(e){return null==e?s.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=k.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return k.each(this,e)},map:function(n){return this.pushStack(k.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(s.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(0<=n&&n<t?[this[n]]:[])},end:function(){return this.prevObject||this.constructor()},push:u,sort:t.sort,splice:t.splice},k.extend=k.fn.extend=function(){var e,t,n,r,i,o,a=arguments[0]||{},s=1,u=arguments.length,l=!1;for("boolean"==typeof a&&(l=a,a=arguments[s]||{},s++),"object"==typeof a||m(a)||(a={}),s===u&&(a=this,s--);s<u;s++)if(null!=(e=arguments[s]))for(t in e)r=e[t],"__proto__"!==t&&a!==r&&(l&&r&&(k.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||k.isPlainObject(n)?n:{},i=!1,a[t]=k.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},k.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),isReady:!0,error:function(e){throw new Error(e)},noop:function(){},isPlainObject:function(e){var t,n;return!(!e||"[object Object]"!==o.call(e))&&(!(t=r(e))||"function"==typeof(n=v.call(t,"constructor")&&t.constructor)&&a.call(n)===l)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t){b(e,{nonce:t&&t.nonce})},each:function(e,t){var n,r=0;if(d(e)){for(n=e.length;r<n;r++)if(!1===t.call(e[r],r,e[r]))break}else for(r in e)if(!1===t.call(e[r],r,e[r]))break;return e},trim:function(e){return null==e?"":(e+"").replace(p,"")},makeArray:function(e,t){var n=t||[];return null!=e&&(d(Object(e))?k.merge(n,"string"==typeof e?[e]:e):u.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:i.call(t,e,n)},merge:function(e,t){for(var n=+t.length,r=0,i=e.length;r<n;r++)e[i++]=t[r];return e.length=i,e},grep:function(e,t,n){for(var r=[],i=0,o=e.length,a=!n;i<o;i++)!t(e[i],i)!==a&&r.push(e[i]);return r},map:function(e,t,n){var r,i,o=0,a=[];if(d(e))for(r=e.length;o<r;o++)null!=(i=t(e[o],o,n))&&a.push(i);else for(o in e)null!=(i=t(e[o],o,n))&&a.push(i);return g.apply([],a)},guid:1,support:y}),"function"==typeof Symbol&&(k.fn[Symbol.iterator]=t[Symbol.iterator]),k.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var h=function(n){var e,d,b,o,i,h,f,g,w,u,l,T,C,a,E,v,s,c,y,k="sizzle"+1*new Date,m=n.document,S=0,r=0,p=ue(),x=ue(),N=ue(),A=ue(),D=function(e,t){return e===t&&(l=!0),0},j={}.hasOwnProperty,t=[],q=t.pop,L=t.push,H=t.push,O=t.slice,P=function(e,t){for(var n=0,r=e.length;n<r;n++)if(e[n]===t)return n;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",I="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",W="\\["+M+"*("+I+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+I+"))|)"+M+"*\\]",$=":("+I+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+W+")*)|.*)\\)|)",F=new RegExp(M+"+","g"),B=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=new RegExp("^"+M+"*,"+M+"*"),z=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="<a id='"+k+"'></a><select id='"+k+"-\r\\' msallowcapture=''><option selected=''></option></select>",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0<se(t,C,null,[e]).length},se.contains=function(e,t){return(e.ownerDocument||e)!==C&&T(e),y(e,t)},se.attr=function(e,t){(e.ownerDocument||e)!==C&&T(e);var n=b.attrHandle[t.toLowerCase()],r=n&&j.call(b.attrHandle,t.toLowerCase())?n(e,t,!E):void 0;return void 0!==r?r:d.attributes||!E?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},se.escape=function(e){return(e+"").replace(re,ie)},se.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},se.uniqueSort=function(e){var t,n=[],r=0,i=0;if(l=!d.detectDuplicates,u=!d.sortStable&&e.slice(0),e.sort(D),l){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return u=null,e},o=se.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else while(t=e[r++])n+=o(t);return n},(b=se.selectors={cacheLength:50,createPseudo:le,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1<t.indexOf(i):"$="===r?i&&t.slice(-i.length)===i:"~="===r?-1<(" "+t.replace(F," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(h,e,t,g,v){var y="nth"!==h.slice(0,3),m="last"!==h.slice(-4),x="of-type"===e;return 1===g&&0===v?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u,l=y!==m?"nextSibling":"previousSibling",c=e.parentNode,f=x&&e.nodeName.toLowerCase(),p=!n&&!x,d=!1;if(c){if(y){while(l){a=e;while(a=a[l])if(x?a.nodeName.toLowerCase()===f:1===a.nodeType)return!1;u=l="only"===h&&!u&&"nextSibling"}return!0}if(u=[m?c.firstChild:c.lastChild],m&&p){d=(s=(r=(i=(o=(a=c)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1])&&r[2],a=s&&c.childNodes[s];while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if(1===a.nodeType&&++d&&a===e){i[h]=[S,s,d];break}}else if(p&&(d=s=(r=(i=(o=(a=e)[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]||[])[0]===S&&r[1]),!1===d)while(a=++s&&a&&a[l]||(d=s=0)||u.pop())if((x?a.nodeName.toLowerCase()===f:1===a.nodeType)&&++d&&(p&&((i=(o=a[k]||(a[k]={}))[a.uniqueID]||(o[a.uniqueID]={}))[h]=[S,d]),a===e))break;return(d-=v)===g||d%g==0&&0<=d/g}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||se.error("unsupported pseudo: "+e);return a[k]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?le(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=P(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:le(function(e){var r=[],i=[],s=f(e.replace(B,"$1"));return s[k]?le(function(e,t,n,r){var i,o=s(e,null,r,[]),a=e.length;while(a--)(i=o[a])&&(e[a]=!(t[a]=i))}):function(e,t,n){return r[0]=e,s(r,null,n,i),r[0]=null,!i.pop()}}),has:le(function(t){return function(e){return 0<se(t,e).length}}),contains:le(function(t){return t=t.replace(te,ne),function(e){return-1<(e.textContent||o(e)).indexOf(t)}}),lang:le(function(n){return V.test(n||"")||se.error("unsupported lang: "+n),n=n.replace(te,ne).toLowerCase(),function(e){var t;do{if(t=E?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return(t=t.toLowerCase())===n||0===t.indexOf(n+"-")}while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var t=n.location&&n.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===a},focus:function(e){return e===C.activeElement&&(!C.hasFocus||C.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:ge(!1),disabled:ge(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!b.pseudos.empty(e)},header:function(e){return J.test(e.nodeName)},input:function(e){return Q.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:ve(function(){return[0]}),last:ve(function(e,t){return[t-1]}),eq:ve(function(e,t,n){return[n<0?n+t:n]}),even:ve(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:ve(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:ve(function(e,t,n){for(var r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:ve(function(e,t,n){for(var r=n<0?n+t:n;++r<t;)e.push(r);return e})}}).pseudos.nth=b.pseudos.eq,{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})b.pseudos[e]=de(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=he(e);function me(){}function xe(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function be(s,e,t){var u=e.dir,l=e.next,c=l||u,f=t&&"parentNode"===c,p=r++;return e.first?function(e,t,n){while(e=e[u])if(1===e.nodeType||f)return s(e,t,n);return!1}:function(e,t,n){var r,i,o,a=[S,p];if(n){while(e=e[u])if((1===e.nodeType||f)&&s(e,t,n))return!0}else while(e=e[u])if(1===e.nodeType||f)if(i=(o=e[k]||(e[k]={}))[e.uniqueID]||(o[e.uniqueID]={}),l&&l===e.nodeName.toLowerCase())e=e[u]||e;else{if((r=i[c])&&r[0]===S&&r[1]===p)return a[2]=r[2];if((i[c]=a)[2]=s(e,t,n))return!0}return!1}}function we(i){return 1<i.length?function(e,t,n){var r=i.length;while(r--)if(!i[r](e,t,n))return!1;return!0}:i[0]}function Te(e,t,n,r,i){for(var o,a=[],s=0,u=e.length,l=null!=t;s<u;s++)(o=e[s])&&(n&&!n(o,r,i)||(a.push(o),l&&t.push(s)));return a}function Ce(d,h,g,v,y,e){return v&&!v[k]&&(v=Ce(v)),y&&!y[k]&&(y=Ce(y,e)),le(function(e,t,n,r){var i,o,a,s=[],u=[],l=t.length,c=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)se(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),f=!d||!e&&h?c:Te(c,s,d,n,r),p=g?y||(e?d:l||v)?[]:t:f;if(g&&g(f,p,n,r),v){i=Te(p,u),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(p[u[o]]=!(f[u[o]]=a))}if(e){if(y||d){if(y){i=[],o=p.length;while(o--)(a=p[o])&&i.push(f[o]=a);y(null,p=[],i,r)}o=p.length;while(o--)(a=p[o])&&-1<(i=y?P(e,a):s[o])&&(e[i]=!(t[i]=a))}}else p=Te(p===t?p.splice(l,p.length):p),y?y(null,t,p,r):H.apply(t,p)})}function Ee(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=be(function(e){return e===i},a,!0),l=be(function(e){return-1<P(i,e)},a,!0),c=[function(e,t,n){var r=!o&&(n||t!==w)||((i=t).nodeType?u(e,t,n):l(e,t,n));return i=null,r}];s<r;s++)if(t=b.relative[e[s].type])c=[be(we(c),t)];else{if((t=b.filter[e[s].type].apply(null,e[s].matches))[k]){for(n=++s;n<r;n++)if(b.relative[e[n].type])break;return Ce(1<s&&we(c),1<s&&xe(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(B,"$1"),t,s<n&&Ee(e.slice(s,n)),n<r&&Ee(e=e.slice(n)),n<r&&xe(e))}c.push(t)}return we(c)}return me.prototype=b.filters=b.pseudos,b.setFilters=new me,h=se.tokenize=function(e,t){var n,r,i,o,a,s,u,l=x[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=_.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=z.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(B," ")}),a=a.slice(n.length)),b.filter)!(r=G[o].exec(a))||u[o]&&!(r=u[o](r))||(n=r.shift(),i.push({value:n,type:o,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?se.error(e):x(e,s).slice(0)},f=se.compile=function(e,t){var n,v,y,m,x,r,i=[],o=[],a=N[e+" "];if(!a){t||(t=h(e)),n=t.length;while(n--)(a=Ee(t[n]))[k]?i.push(a):o.push(a);(a=N(e,(v=o,m=0<(y=i).length,x=0<v.length,r=function(e,t,n,r,i){var o,a,s,u=0,l="0",c=e&&[],f=[],p=w,d=e||x&&b.find.TAG("*",i),h=S+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t===C||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument===C||(T(o),n=!E);while(s=v[a++])if(s(o,t||C,n)){r.push(o);break}i&&(S=h)}m&&((o=!s&&o)&&u--,e&&c.push(o))}if(u+=l,m&&l!==u){a=0;while(s=y[a++])s(c,f,t,n);if(e){if(0<u)while(l--)c[l]||f[l]||(f[l]=q.call(r));f=Te(f)}H.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&se.uniqueSort(r)}return i&&(S=h,w=p),c},m?le(r):r))).selector=e}return a},g=se.select=function(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&h(e=l.selector||e);if(n=n||[],1===c.length){if(2<(o=c[0]=c[0].slice(0)).length&&"ID"===(a=o[0]).type&&9===t.nodeType&&E&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(te,ne),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=G.needsContext.test(e)?0:o.length;while(i--){if(a=o[i],b.relative[s=a.type])break;if((u=b.find[s])&&(r=u(a.matches[0].replace(te,ne),ee.test(o[0].type)&&ye(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&xe(o)))return H.apply(n,r),n;break}}}return(l||f(e,c))(r,t,!E,n,!t||ee.test(e)&&ye(t.parentNode)||t),n},d.sortStable=k.split("").sort(D).join("")===k,d.detectDuplicates=!!l,T(),d.sortDetached=ce(function(e){return 1&e.compareDocumentPosition(C.createElement("fieldset"))}),ce(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||fe("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),d.attributes&&ce(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||fe("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ce(function(e){return null==e.getAttribute("disabled")})||fe(R,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),se}(C);k.find=h,k.expr=h.selectors,k.expr[":"]=k.expr.pseudos,k.uniqueSort=k.unique=h.uniqueSort,k.text=h.getText,k.isXMLDoc=h.isXML,k.contains=h.contains,k.escapeSelector=h.escape;var T=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&k(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},N=k.expr.match.needsContext;function A(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var D=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1<i.call(n,e)!==r}):k.filter(n,e,r)}k.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?k.find.matchesSelector(r,e)?[r]:[]:k.find.matches(e,k.grep(t,function(e){return 1===e.nodeType}))},k.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(k(e).filter(function(){for(t=0;t<r;t++)if(k.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)k.find(e,i[t],n);return 1<r?k.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&N.test(e)?k(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(k.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&k(e);if(!N.test(e))for(;r<i;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(n.nodeType<11&&(a?-1<a.index(n):1===n.nodeType&&k.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?k.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?i.call(k(e),this[0]):i.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(k.uniqueSort(k.merge(this.get(),k(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),k.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return T(e,"parentNode")},parentsUntil:function(e,t,n){return T(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return T(e,"nextSibling")},prevAll:function(e){return T(e,"previousSibling")},nextUntil:function(e,t,n){return T(e,"nextSibling",n)},prevUntil:function(e,t,n){return T(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return"undefined"!=typeof e.contentDocument?e.contentDocument:(A(e,"template")&&(e=e.content||e),k.merge([],e.childNodes))}},function(r,i){k.fn[r]=function(e,t){var n=k.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=k.filter(t,n)),1<this.length&&(O[r]||k.uniqueSort(n),H.test(r)&&n.reverse()),this.pushStack(n)}});var R=/[^\x20\t\r\n\f]+/g;function M(e){return e}function I(e){throw e}function W(e,t,n,r){var i;try{e&&m(i=e.promise)?i.call(e).done(t).fail(n):e&&m(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}k.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},k.each(e.match(R)||[],function(e,t){n[t]=!0}),n):k.extend({},r);var i,t,o,a,s=[],u=[],l=-1,c=function(){for(a=a||r.once,o=i=!0;u.length;l=-1){t=u.shift();while(++l<s.length)!1===s[l].apply(t[0],t[1])&&r.stopOnFalse&&(l=s.length,t=!1)}r.memory||(t=!1),i=!1,a&&(s=t?[]:"")},f={add:function(){return s&&(t&&!i&&(l=s.length-1,u.push(t)),function n(e){k.each(e,function(e,t){m(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==w(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return k.each(arguments,function(e,t){var n;while(-1<(n=k.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<k.inArray(e,s):0<s.length},empty:function(){return s&&(s=[]),this},disable:function(){return a=u=[],s=t="",this},disabled:function(){return!s},lock:function(){return a=u=[],t||i||(s=t=""),this},locked:function(){return!!a},fireWith:function(e,t){return a||(t=[e,(t=t||[]).slice?t.slice():t],u.push(t),i||c()),this},fire:function(){return f.fireWith(this,arguments),this},fired:function(){return!!o}};return f},k.extend({Deferred:function(e){var o=[["notify","progress",k.Callbacks("memory"),k.Callbacks("memory"),2],["resolve","done",k.Callbacks("once memory"),k.Callbacks("once memory"),0,"resolved"],["reject","fail",k.Callbacks("once memory"),k.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return s.done(arguments).fail(arguments),this},"catch":function(e){return a.then(null,e)},pipe:function(){var i=arguments;return k.Deferred(function(r){k.each(o,function(e,t){var n=m(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&m(e.promise)?e.promise().progress(r.notify).done(r.resolve).fail(r.reject):r[t[0]+"With"](this,n?[e]:arguments)})}),i=null}).promise()},then:function(t,n,r){var u=0;function l(i,o,a,s){return function(){var n=this,r=arguments,e=function(){var e,t;if(!(i<u)){if((e=a.apply(n,r))===o.promise())throw new TypeError("Thenable self-resolution");t=e&&("object"==typeof e||"function"==typeof e)&&e.then,m(t)?s?t.call(e,l(u,o,M,s),l(u,o,I,s)):(u++,t.call(e,l(u,o,M,s),l(u,o,I,s),l(u,o,M,o.notifyWith))):(a!==M&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){k.Deferred.exceptionHook&&k.Deferred.exceptionHook(e,t.stackTrace),u<=i+1&&(a!==I&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(k.Deferred.getStackHook&&(t.stackTrace=k.Deferred.getStackHook()),C.setTimeout(t))}}return k.Deferred(function(e){o[0][3].add(l(0,e,m(r)?r:M,e.notifyWith)),o[1][3].add(l(0,e,m(t)?t:M)),o[2][3].add(l(0,e,m(n)?n:I))}).promise()},promise:function(e){return null!=e?k.extend(e,a):a}},s={};return k.each(o,function(e,t){var n=t[2],r=t[5];a[t[1]]=n.add,r&&n.add(function(){i=r},o[3-e][2].disable,o[3-e][3].disable,o[0][2].lock,o[0][3].lock),n.add(t[3].fire),s[t[0]]=function(){return s[t[0]+"With"](this===s?void 0:this,arguments),this},s[t[0]+"With"]=n.fireWith}),a.promise(s),e&&e.call(s,s),s},when:function(e){var n=arguments.length,t=n,r=Array(t),i=s.call(arguments),o=k.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?s.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(W(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||m(i[t]&&i[t].then)))return o.then();while(t--)W(i[t],a(t),o.reject);return o.promise()}});var $=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;k.Deferred.exceptionHook=function(e,t){C.console&&C.console.warn&&e&&$.test(e.name)&&C.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},k.readyException=function(e){C.setTimeout(function(){throw e})};var F=k.Deferred();function B(){E.removeEventListener("DOMContentLoaded",B),C.removeEventListener("load",B),k.ready()}k.fn.ready=function(e){return F.then(e)["catch"](function(e){k.readyException(e)}),this},k.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--k.readyWait:k.isReady)||(k.isReady=!0)!==e&&0<--k.readyWait||F.resolveWith(E,[k])}}),k.ready.then=F.then,"complete"===E.readyState||"loading"!==E.readyState&&!E.documentElement.doScroll?C.setTimeout(k.ready):(E.addEventListener("DOMContentLoaded",B),C.addEventListener("load",B));var _=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===w(n))for(s in i=!0,n)_(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,m(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(k(e),n)})),t))for(;s<u;s++)t(e[s],n,a?r:r.call(e[s],s,t(e[s],n)));return i?e:l?t.call(e):u?t(e[0],n):o},z=/^-ms-/,U=/-([a-z])/g;function X(e,t){return t.toUpperCase()}function V(e){return e.replace(z,"ms-").replace(U,X)}var G=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function Y(){this.expando=k.expando+Y.uid++}Y.uid=1,Y.prototype={cache:function(e){var t=e[this.expando];return t||(t={},G(e)&&(e.nodeType?e[this.expando]=t:Object.defineProperty(e,this.expando,{value:t,configurable:!0}))),t},set:function(e,t,n){var r,i=this.cache(e);if("string"==typeof t)i[V(t)]=n;else for(r in t)i[V(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][V(t)]},access:function(e,t,n){return void 0===t||t&&"string"==typeof t&&void 0===n?this.get(e,t):(this.set(e,t,n),void 0!==n?n:t)},remove:function(e,t){var n,r=e[this.expando];if(void 0!==r){if(void 0!==t){n=(t=Array.isArray(t)?t.map(V):(t=V(t))in r?[t]:t.match(R)||[]).length;while(n--)delete r[t[n]]}(void 0===t||k.isEmptyObject(r))&&(e.nodeType?e[this.expando]=void 0:delete e[this.expando])}},hasData:function(e){var t=e[this.expando];return void 0!==t&&!k.isEmptyObject(t)}};var Q=new Y,J=new Y,K=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function ee(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(Z,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:K.test(i)?JSON.parse(i):i)}catch(e){}J.set(e,t,n)}else n=void 0;return n}k.extend({hasData:function(e){return J.hasData(e)||Q.hasData(e)},data:function(e,t,n){return J.access(e,t,n)},removeData:function(e,t){J.remove(e,t)},_data:function(e,t,n){return Q.access(e,t,n)},_removeData:function(e,t){Q.remove(e,t)}}),k.fn.extend({data:function(n,e){var t,r,i,o=this[0],a=o&&o.attributes;if(void 0===n){if(this.length&&(i=J.get(o),1===o.nodeType&&!Q.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=V(r.slice(5)),ee(o,r,i[r]));Q.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){J.set(this,n)}):_(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=J.get(o,n))?t:void 0!==(t=ee(o,n))?t:void 0;this.each(function(){J.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){J.remove(this,e)})}}),k.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=Q.get(e,t),n&&(!r||Array.isArray(n)?r=Q.access(e,t,k.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=k.queue(e,t),r=n.length,i=n.shift(),o=k._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){k.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return Q.get(e,n)||Q.access(e,n,{empty:k.Callbacks("once memory").add(function(){Q.remove(e,[t+"queue",n])})})}}),k.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?k.queue(this[0],t):void 0===n?this:this.each(function(){var e=k.queue(this,t,n);k._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&k.dequeue(this,t)})},dequeue:function(e){return this.each(function(){k.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=k.Deferred(),o=this,a=this.length,s=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=void 0),e=e||"fx";while(a--)(n=Q.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var te=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ne=new RegExp("^(?:([+-])=|)("+te+")([a-z%]*)$","i"),re=["Top","Right","Bottom","Left"],ie=E.documentElement,oe=function(e){return k.contains(e.ownerDocument,e)},ae={composed:!0};ie.getRootNode&&(oe=function(e){return k.contains(e.ownerDocument,e)||e.getRootNode(ae)===e.ownerDocument});var se=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&oe(e)&&"none"===k.css(e,"display")},ue=function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];for(o in i=n.apply(e,r||[]),t)e.style[o]=a[o];return i};function le(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return k.css(e,t,"")},u=s(),l=n&&n[3]||(k.cssNumber[t]?"":"px"),c=e.nodeType&&(k.cssNumber[t]||"px"!==l&&+u)&&ne.exec(k.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)k.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,k.style(e,t,c+l),n=n||[]}return n&&(c=+c||+u||0,i=n[1]?c+(n[1]+1)*n[2]:+n[2],r&&(r.unit=l,r.start=c,r.end=i)),i}var ce={};function fe(e,t){for(var n,r,i,o,a,s,u,l=[],c=0,f=e.length;c<f;c++)(r=e[c]).style&&(n=r.style.display,t?("none"===n&&(l[c]=Q.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&se(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ce[s])||(o=a.body.appendChild(a.createElement(s)),u=k.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ce[s]=u)))):"none"!==n&&(l[c]="none",Q.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}k.fn.extend({show:function(){return fe(this,!0)},hide:function(){return fe(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){se(this)?k(this).show():k(this).hide()})}});var pe=/^(?:checkbox|radio)$/i,de=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n<r;n++)Q.set(e[n],"globalEval",!t||Q.get(t[n],"globalEval"))}ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;var me,xe,be=/<|&#?\w+;/;function we(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d<h;d++)if((o=e[d])||0===o)if("object"===w(o))k.merge(p,o.nodeType?[o]:o);else if(be.test(o)){a=a||f.appendChild(t.createElement("div")),s=(de.exec(o)||["",""])[1].toLowerCase(),u=ge[s]||ge._default,a.innerHTML=u[1]+k.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;k.merge(p,a.childNodes),(a=f.firstChild).textContent=""}else p.push(t.createTextNode(o));f.textContent="",d=0;while(o=p[d++])if(r&&-1<k.inArray(o,r))i&&i.push(o);else if(l=oe(o),a=ve(f.appendChild(o),"script"),l&&ye(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}me=E.createDocumentFragment().appendChild(E.createElement("div")),(xe=E.createElement("input")).setAttribute("type","radio"),xe.setAttribute("checked","checked"),xe.setAttribute("name","t"),me.appendChild(xe),y.checkClone=me.cloneNode(!0).cloneNode(!0).lastChild.checked,me.innerHTML="<textarea>x</textarea>",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t<arguments.length;t++)u[t]=arguments[t];if(s.delegateTarget=this,!c.preDispatch||!1!==c.preDispatch.call(this,s)){a=k.event.handlers.call(this,s,l),t=0;while((i=a[t++])&&!s.isPropagationStopped()){s.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!s.isImmediatePropagationStopped())s.rnamespace&&!1!==o.namespace&&!s.rnamespace.test(o.namespace)||(s.handleObj=o,s.data=o.data,void 0!==(r=((k.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,u))&&!1===(s.result=r)&&(s.preventDefault(),s.stopPropagation()))}return c.postDispatch&&c.postDispatch.call(this,s),s.result}},handlers:function(e,t){var n,r,i,o,a,s=[],u=t.delegateCount,l=e.target;if(u&&l.nodeType&&!("click"===e.type&&1<=e.button))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n<u;n++)void 0===a[i=(r=t[n]).selector+" "]&&(a[i]=r.needsContext?-1<k(i,this).index(l):k.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u<t.length&&s.push({elem:l,handlers:t.slice(u)}),s},addProp:function(t,e){Object.defineProperty(k.Event.prototype,t,{enumerable:!0,configurable:!0,get:m(e)?function(){if(this.originalEvent)return e(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[t]},set:function(e){Object.defineProperty(this,t,{enumerable:!0,configurable:!0,writable:!0,value:e})}})},fix:function(e){return e[k.expando]?e:new k.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click",ke),!1},trigger:function(e){var t=this||e;return pe.test(t.type)&&t.click&&A(t,"input")&&De(t,"click"),!0},_default:function(e){var t=e.target;return pe.test(t.type)&&t.click&&A(t,"input")&&Q.get(t,"click")||A(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},k.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},k.Event=function(e,t){if(!(this instanceof k.Event))return new k.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?ke:Se,this.target=e.target&&3===e.target.nodeType?e.target.parentNode:e.target,this.currentTarget=e.currentTarget,this.relatedTarget=e.relatedTarget):this.type=e,t&&k.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[k.expando]=!0},k.Event.prototype={constructor:k.Event,isDefaultPrevented:Se,isPropagationStopped:Se,isImmediatePropagationStopped:Se,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=ke,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=ke,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=ke,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},k.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,code:!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(e){var t=e.button;return null==e.which&&Te.test(e.type)?null!=e.charCode?e.charCode:e.keyCode:!e.which&&void 0!==t&&Ce.test(e.type)?1&t?1:2&t?3:4&t?2:0:e.which}},k.event.addProp),k.each({focus:"focusin",blur:"focusout"},function(e,t){k.event.special[e]={setup:function(){return De(this,e,Ne),!1},trigger:function(){return De(this,e),!0},delegateType:t}}),k.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){k.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||k.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),k.fn.extend({on:function(e,t,n,r){return Ae(this,e,t,n,r)},one:function(e,t,n,r){return Ae(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,k(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return!1!==t&&"function"!=typeof t||(n=t,t=void 0),!1===n&&(n=Se),this.each(function(){k.event.remove(this,e,n,t)})}});var je=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/<script|<style|<link/i,Le=/checked\s*(?:[^=]|=\s*.checked.)/i,He=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n<r;n++)k.event.add(t,i,l[i][n]);J.hasData(e)&&(s=J.access(e),u=k.extend({},s),J.set(t,u))}}function Ie(n,r,i,o){r=g.apply([],r);var e,t,a,s,u,l,c=0,f=n.length,p=f-1,d=r[0],h=m(d);if(h||1<f&&"string"==typeof d&&!y.checkClone&&Le.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),Ie(t,r,i,o)});if(f&&(t=(e=we(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=k.map(ve(e,"script"),Pe)).length;c<f;c++)u=e,c!==p&&(u=k.clone(u,!0,!0),s&&k.merge(a,ve(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,k.map(a,Re),c=0;c<s;c++)u=a[c],he.test(u.type||"")&&!Q.access(u,"globalEval")&&k.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?k._evalUrl&&!u.noModule&&k._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")}):b(u.textContent.replace(He,""),u,l))}return n}function We(e,t,n){for(var r,i=t?k.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||k.cleanData(ve(r)),r.parentNode&&(n&&oe(r)&&ye(ve(r,"script")),r.parentNode.removeChild(r));return e}k.extend({htmlPrefilter:function(e){return e.replace(je,"<$1></$2>")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&pe.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||ve(e),a=a||ve(c),r=0,i=o.length;r<i;r++)Me(o[r],a[r]);else Me(e,c);return 0<(a=ve(c,"script")).length&&ye(a,!f&&ve(e,"script")),c},cleanData:function(e){for(var t,n,r,i=k.event.special,o=0;void 0!==(n=e[o]);o++)if(G(n)){if(t=n[Q.expando]){if(t.events)for(r in t.events)i[r]?k.event.remove(n,r):k.removeEvent(n,r,t.handle);n[Q.expando]=void 0}n[J.expando]&&(n[J.expando]=void 0)}}}),k.fn.extend({detach:function(e){return We(this,e,!0)},remove:function(e){return We(this,e)},text:function(e){return _(this,function(e){return void 0===e?k.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Ie(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Oe(this,e).appendChild(e)})},prepend:function(){return Ie(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Oe(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Ie(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(k.cleanData(ve(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return k.clone(this,e,t)})},html:function(e){return _(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!qe.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=k.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(k.cleanData(ve(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return Ie(this,arguments,function(e){var t=this.parentNode;k.inArray(this,n)<0&&(k.cleanData(ve(this)),t&&t.replaceChild(e,this))},n)}}),k.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){k.fn[e]=function(e){for(var t,n=[],r=k(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),k(r[o])[a](t),u.apply(n,t.get());return this.pushStack(n)}});var $e=new RegExp("^("+te+")(?!px)[a-z%]+$","i"),Fe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=C),t.getComputedStyle(e)},Be=new RegExp(re.join("|"),"i");function _e(e,t,n){var r,i,o,a,s=e.style;return(n=n||Fe(e))&&(""!==(a=n.getPropertyValue(t)||n[t])||oe(e)||(a=k.style(e,t)),!y.pixelBoxStyles()&&$e.test(a)&&Be.test(t)&&(r=s.width,i=s.minWidth,o=s.maxWidth,s.minWidth=s.maxWidth=s.width=a,a=n.width,s.width=r,s.minWidth=i,s.maxWidth=o)),void 0!==a?a+"":a}function ze(e,t){return{get:function(){if(!e())return(this.get=t).apply(this,arguments);delete this.get}}}!function(){function e(){if(u){s.style.cssText="position:absolute;left:-11111px;width:60px;margin-top:1px;padding:0;border:0",u.style.cssText="position:relative;display:block;box-sizing:border-box;overflow:scroll;margin:auto;border:1px;padding:1px;width:60%;top:1%",ie.appendChild(s).appendChild(u);var e=C.getComputedStyle(u);n="1%"!==e.top,a=12===t(e.marginLeft),u.style.right="60%",o=36===t(e.right),r=36===t(e.width),u.style.position="absolute",i=12===t(u.offsetWidth/3),ie.removeChild(s),u=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s=E.createElement("div"),u=E.createElement("div");u.style&&(u.style.backgroundClip="content-box",u.cloneNode(!0).style.backgroundClip="",y.clearCloneStyle="content-box"===u.style.backgroundClip,k.extend(y,{boxSizingReliable:function(){return e(),r},pixelBoxStyles:function(){return e(),o},pixelPosition:function(){return e(),n},reliableMarginLeft:function(){return e(),a},scrollboxSize:function(){return e(),i}}))}();var Ue=["Webkit","Moz","ms"],Xe=E.createElement("div").style,Ve={};function Ge(e){var t=k.cssProps[e]||Ve[e];return t||(e in Xe?e:Ve[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Ue.length;while(n--)if((e=Ue[n]+t)in Xe)return e}(e)||e)}var Ye=/^(none|table(?!-c[ea]).+)/,Qe=/^--/,Je={position:"absolute",visibility:"hidden",display:"block"},Ke={letterSpacing:"0",fontWeight:"400"};function Ze(e,t,n){var r=ne.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function et(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(u+=k.css(e,n+re[a],!0,i)),r?("content"===n&&(u-=k.css(e,"padding"+re[a],!0,i)),"margin"!==n&&(u-=k.css(e,"border"+re[a]+"Width",!0,i))):(u+=k.css(e,"padding"+re[a],!0,i),"padding"!==n?u+=k.css(e,"border"+re[a]+"Width",!0,i):s+=k.css(e,"border"+re[a]+"Width",!0,i));return!r&&0<=o&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))||0),u}function tt(e,t,n){var r=Fe(e),i=(!y.boxSizingReliable()||n)&&"border-box"===k.css(e,"boxSizing",!1,r),o=i,a=_e(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if($e.test(a)){if(!n)return a;a="auto"}return(!y.boxSizingReliable()&&i||"auto"===a||!parseFloat(a)&&"inline"===k.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===k.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+et(e,t,n||(i?"border":"content"),o,r,a)+"px"}function nt(e,t,n,r,i){return new nt.prototype.init(e,t,n,r,i)}k.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=_e(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,gridArea:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnStart:!0,gridRow:!0,gridRowEnd:!0,gridRowStart:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=V(t),u=Qe.test(t),l=e.style;if(u||(t=Ge(s)),a=k.cssHooks[t]||k.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"===(o=typeof n)&&(i=ne.exec(n))&&i[1]&&(n=le(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(k.cssNumber[s]?"":"px")),y.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=V(t);return Qe.test(t)||(t=Ge(s)),(a=k.cssHooks[t]||k.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=_e(e,t,r)),"normal"===i&&t in Ke&&(i=Ke[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),k.each(["height","width"],function(e,u){k.cssHooks[u]={get:function(e,t,n){if(t)return!Ye.test(k.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?tt(e,u,n):ue(e,Je,function(){return tt(e,u,n)})},set:function(e,t,n){var r,i=Fe(e),o=!y.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===k.css(e,"boxSizing",!1,i),s=n?et(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-et(e,u,"border",!1,i)-.5)),s&&(r=ne.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=k.css(e,u)),Ze(0,t,s)}}}),k.cssHooks.marginLeft=ze(y.reliableMarginLeft,function(e,t){if(t)return(parseFloat(_e(e,"marginLeft"))||e.getBoundingClientRect().left-ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),k.each({margin:"",padding:"",border:"Width"},function(i,o){k.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+re[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(k.cssHooks[i+o].set=Ze)}),k.fn.extend({css:function(e,t){return _(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Fe(e),i=t.length;a<i;a++)o[t[a]]=k.css(e,t[a],!1,r);return o}return void 0!==n?k.style(e,t,n):k.css(e,t)},e,t,1<arguments.length)}}),((k.Tween=nt).prototype={constructor:nt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||k.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(k.cssNumber[n]?"":"px")},cur:function(){var e=nt.propHooks[this.prop];return e&&e.get?e.get(this):nt.propHooks._default.get(this)},run:function(e){var t,n=nt.propHooks[this.prop];return this.options.duration?this.pos=t=k.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):nt.propHooks._default.set(this),this}}).init.prototype=nt.prototype,(nt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=k.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){k.fx.step[e.prop]?k.fx.step[e.prop](e):1!==e.elem.nodeType||!k.cssHooks[e.prop]&&null==e.elem.style[Ge(e.prop)]?e.elem[e.prop]=e.now:k.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=nt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},k.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},k.fx=nt.prototype.init,k.fx.step={};var rt,it,ot,at,st=/^(?:toggle|show|hide)$/,ut=/queueHooks$/;function lt(){it&&(!1===E.hidden&&C.requestAnimationFrame?C.requestAnimationFrame(lt):C.setTimeout(lt,k.fx.interval),k.fx.tick())}function ct(){return C.setTimeout(function(){rt=void 0}),rt=Date.now()}function ft(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=re[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function pt(e,t,n){for(var r,i=(dt.tweeners[t]||[]).concat(dt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function dt(o,e,t){var n,a,r=0,i=dt.prefilters.length,s=k.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=rt||ct(),t=Math.max(0,l.startTime+l.duration-e),n=1-(t/l.duration||0),r=0,i=l.tweens.length;r<i;r++)l.tweens[r].run(n);return s.notifyWith(o,[l,n,t]),n<1&&i?t:(i||s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l]),!1)},l=s.promise({elem:o,props:k.extend({},e),opts:k.extend(!0,{specialEasing:{},easing:k.easing._default},t),originalProperties:e,originalOptions:t,startTime:rt||ct(),duration:t.duration,tweens:[],createTween:function(e,t){var n=k.Tween(o,l.opts,e,t,l.opts.specialEasing[e]||l.opts.easing);return l.tweens.push(n),n},stop:function(e){var t=0,n=e?l.tweens.length:0;if(a)return this;for(a=!0;t<n;t++)l.tweens[t].run(1);return e?(s.notifyWith(o,[l,1,0]),s.resolveWith(o,[l,e])):s.rejectWith(o,[l,e]),this}}),c=l.props;for(!function(e,t){var n,r,i,o,a;for(n in e)if(i=t[r=V(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=k.cssHooks[r])&&"expand"in a)for(n in o=a.expand(o),delete e[r],o)n in e||(e[n]=o[n],t[n]=i);else t[r]=i}(c,l.opts.specialEasing);r<i;r++)if(n=dt.prefilters[r].call(l,o,c,l.opts))return m(n.stop)&&(k._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return k.map(c,pt,l),m(l.opts.start)&&l.opts.start.call(o,l),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always),k.fx.timer(k.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}k.Animation=k.extend(dt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return le(n.elem,e,ne.exec(t),n),n}]},tweener:function(e,t){m(e)?(t=e,e=["*"]):e=e.match(R);for(var n,r=0,i=e.length;r<i;r++)n=e[r],dt.tweeners[n]=dt.tweeners[n]||[],dt.tweeners[n].unshift(t)},prefilters:[function(e,t,n){var r,i,o,a,s,u,l,c,f="width"in t||"height"in t,p=this,d={},h=e.style,g=e.nodeType&&se(e),v=Q.get(e,"fxshow");for(r in n.queue||(null==(a=k._queueHooks(e,"fx")).unqueued&&(a.unqueued=0,s=a.empty.fire,a.empty.fire=function(){a.unqueued||s()}),a.unqueued++,p.always(function(){p.always(function(){a.unqueued--,k.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],st.test(i)){if(delete t[r],o=o||"toggle"===i,i===(g?"hide":"show")){if("show"!==i||!v||void 0===v[r])continue;g=!0}d[r]=v&&v[r]||k.style(e,r)}if((u=!k.isEmptyObject(t))||!k.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=Q.get(e,"display")),"none"===(c=k.css(e,"display"))&&(l?c=l:(fe([e],!0),l=e.style.display||l,c=k.css(e,"display"),fe([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===k.css(e,"float")&&(u||(p.done(function(){h.display=l}),null==l&&(c=h.display,l="none"===c?"":c)),h.display="inline-block")),n.overflow&&(h.overflow="hidden",p.always(function(){h.overflow=n.overflow[0],h.overflowX=n.overflow[1],h.overflowY=n.overflow[2]})),u=!1,d)u||(v?"hidden"in v&&(g=v.hidden):v=Q.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&fe([e],!0),p.done(function(){for(r in g||fe([e]),Q.remove(e,"fxshow"),d)k.style(e,r,d[r])})),u=pt(g?v[r]:0,r,p),r in v||(v[r]=u.start,g&&(u.end=u.start,u.start=0))}],prefilter:function(e,t){t?dt.prefilters.unshift(e):dt.prefilters.push(e)}}),k.speed=function(e,t,n){var r=e&&"object"==typeof e?k.extend({},e):{complete:n||!n&&t||m(e)&&e,duration:e,easing:n&&t||t&&!m(t)&&t};return k.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in k.fx.speeds?r.duration=k.fx.speeds[r.duration]:r.duration=k.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){m(r.old)&&r.old.call(this),r.queue&&k.dequeue(this,r.queue)},r},k.fn.extend({fadeTo:function(e,t,n,r){return this.filter(se).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=k.isEmptyObject(t),o=k.speed(e,n,r),a=function(){var e=dt(this,k.extend({},t),o);(i||Q.get(this,"finish"))&&e.stop(!0)};return a.finish=a,i||!1===o.queue?this.each(a):this.queue(o.queue,a)},stop:function(i,e,o){var a=function(e){var t=e.stop;delete e.stop,t(o)};return"string"!=typeof i&&(o=e,e=i,i=void 0),e&&!1!==i&&this.queue(i||"fx",[]),this.each(function(){var e=!0,t=null!=i&&i+"queueHooks",n=k.timers,r=Q.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&ut.test(t)&&a(r[t]);for(t=n.length;t--;)n[t].elem!==this||null!=i&&n[t].queue!==i||(n[t].anim.stop(o),e=!1,n.splice(t,1));!e&&o||k.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=Q.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=k.timers,o=n?n.length:0;for(t.finish=!0,k.queue(this,a,[]),r&&r.stop&&r.stop.call(this,!0),e=i.length;e--;)i[e].elem===this&&i[e].queue===a&&(i[e].anim.stop(!0),i.splice(e,1));for(e=0;e<o;e++)n[e]&&n[e].finish&&n[e].finish.call(this);delete t.finish})}}),k.each(["toggle","show","hide"],function(e,r){var i=k.fn[r];k.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(ft(r,!0),e,t,n)}}),k.each({slideDown:ft("show"),slideUp:ft("hide"),slideToggle:ft("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){k.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),k.timers=[],k.fx.tick=function(){var e,t=0,n=k.timers;for(rt=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||k.fx.stop(),rt=void 0},k.fx.timer=function(e){k.timers.push(e),k.fx.start()},k.fx.interval=13,k.fx.start=function(){it||(it=!0,lt())},k.fx.stop=function(){it=null},k.fx.speeds={slow:600,fast:200,_default:400},k.fn.delay=function(r,e){return r=k.fx&&k.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=C.setTimeout(e,r);t.stop=function(){C.clearTimeout(n)}})},ot=E.createElement("input"),at=E.createElement("select").appendChild(E.createElement("option")),ot.type="checkbox",y.checkOn=""!==ot.value,y.optSelected=at.selected,(ot=E.createElement("input")).value="t",ot.type="radio",y.radioValue="t"===ot.value;var ht,gt=k.expr.attrHandle;k.fn.extend({attr:function(e,t){return _(this,k.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){k.removeAttr(this,e)})}}),k.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?k.prop(e,t,n):(1===o&&k.isXMLDoc(e)||(i=k.attrHooks[t.toLowerCase()]||(k.expr.match.bool.test(t)?ht:void 0)),void 0!==n?null===n?void k.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=k.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!y.radioValue&&"radio"===t&&A(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(R);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),ht={set:function(e,t,n){return!1===t?k.removeAttr(e,n):e.setAttribute(n,n),n}},k.each(k.expr.match.bool.source.match(/\w+/g),function(e,t){var a=gt[t]||k.find.attr;gt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=gt[o],gt[o]=r,r=null!=a(e,t,n)?o:null,gt[o]=i),r}});var vt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;function mt(e){return(e.match(R)||[]).join(" ")}function xt(e){return e.getAttribute&&e.getAttribute("class")||""}function bt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(R)||[]}k.fn.extend({prop:function(e,t){return _(this,k.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[k.propFix[e]||e]})}}),k.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&k.isXMLDoc(e)||(t=k.propFix[t]||t,i=k.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=k.find.attr(e,"tabindex");return t?parseInt(t,10):vt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),y.optSelected||(k.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),k.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){k.propFix[this.toLowerCase()]=this}),k.fn.extend({addClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).addClass(t.call(this,e,xt(this)))});if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},removeClass:function(t){var e,n,r,i,o,a,s,u=0;if(m(t))return this.each(function(e){k(this).removeClass(t.call(this,e,xt(this)))});if(!arguments.length)return this.attr("class","");if((e=bt(t)).length)while(n=this[u++])if(i=xt(n),r=1===n.nodeType&&" "+mt(i)+" "){a=0;while(o=e[a++])while(-1<r.indexOf(" "+o+" "))r=r.replace(" "+o+" "," ");i!==(s=mt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(i,t){var o=typeof i,a="string"===o||Array.isArray(i);return"boolean"==typeof t&&a?t?this.addClass(i):this.removeClass(i):m(i)?this.each(function(e){k(this).toggleClass(i.call(this,e,xt(this),t),t)}):this.each(function(){var e,t,n,r;if(a){t=0,n=k(this),r=bt(i);while(e=r[t++])n.hasClass(e)?n.removeClass(e):n.addClass(e)}else void 0!==i&&"boolean"!==o||((e=xt(this))&&Q.set(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===i?"":Q.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+mt(xt(n))+" ").indexOf(t))return!0;return!1}});var wt=/\r/g;k.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=m(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,k(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=k.map(t,function(e){return null==e?"":e+""})),(r=k.valHooks[this.type]||k.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=k.valHooks[t.type]||k.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(wt,""):null==e?"":e:void 0}}),k.extend({valHooks:{option:{get:function(e){var t=k.find.attr(e,"value");return null!=t?t:mt(k.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r<u;r++)if(((n=i[r]).selected||r===o)&&!n.disabled&&(!n.parentNode.disabled||!A(n.parentNode,"optgroup"))){if(t=k(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=k.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<k.inArray(k.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),k.each(["radio","checkbox"],function(){k.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<k.inArray(k(e).val(),t)}},y.checkOn||(k.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),y.focusin="onfocusin"in C;var Tt=/^(?:focusinfocus|focusoutblur)$/,Ct=function(e){e.stopPropagation()};k.extend(k.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||E],d=v.call(e,"type")?e.type:e,h=v.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||E,3!==n.nodeType&&8!==n.nodeType&&!Tt.test(d+k.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[k.expando]?e:new k.Event(d,"object"==typeof e&&e)).isTrigger=r?2:3,e.namespace=h.join("."),e.rnamespace=e.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,e.result=void 0,e.target||(e.target=n),t=null==t?[e]:k.makeArray(t,[e]),c=k.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!x(n)){for(s=c.delegateType||d,Tt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||E)&&p.push(a.defaultView||a.parentWindow||C)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(Q.get(o,"events")||{})[e.type]&&Q.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&G(o)&&(e.result=l.apply(o,t),!1===e.result&&e.preventDefault());return e.type=d,r||e.isDefaultPrevented()||c._default&&!1!==c._default.apply(p.pop(),t)||!G(n)||u&&m(n[d])&&!x(n)&&((a=n[u])&&(n[u]=null),k.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Ct),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Ct),k.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=k.extend(new k.Event,n,{type:e,isSimulated:!0});k.event.trigger(r,null,t)}}),k.fn.extend({trigger:function(e,t){return this.each(function(){k.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return k.event.trigger(e,t,n,!0)}}),y.focusin||k.each({focus:"focusin",blur:"focusout"},function(n,r){var i=function(e){k.event.simulate(r,e.target,k.event.fix(e))};k.event.special[r]={setup:function(){var e=this.ownerDocument||this,t=Q.access(e,r);t||e.addEventListener(n,i,!0),Q.access(e,r,(t||0)+1)},teardown:function(){var e=this.ownerDocument||this,t=Q.access(e,r)-1;t?Q.access(e,r,t):(e.removeEventListener(n,i,!0),Q.remove(e,r))}}});var Et=C.location,kt=Date.now(),St=/\?/;k.parseXML=function(e){var t;if(!e||"string"!=typeof e)return null;try{t=(new C.DOMParser).parseFromString(e,"text/xml")}catch(e){t=void 0}return t&&!t.getElementsByTagName("parsererror").length||k.error("Invalid XML: "+e),t};var Nt=/\[\]$/,At=/\r?\n/g,Dt=/^(?:submit|button|image|reset|file)$/i,jt=/^(?:input|select|textarea|keygen)/i;function qt(n,e,r,i){var t;if(Array.isArray(e))k.each(e,function(e,t){r||Nt.test(n)?i(n,t):qt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==w(e))i(n,e);else for(t in e)qt(n+"["+t+"]",e[t],r,i)}k.param=function(e,t){var n,r=[],i=function(e,t){var n=m(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!k.isPlainObject(e))k.each(e,function(){i(this.name,this.value)});else for(n in e)qt(n,e[n],t,i);return r.join("&")},k.fn.extend({serialize:function(){return k.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=k.prop(this,"elements");return e?k.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!k(this).is(":disabled")&&jt.test(this.nodeName)&&!Dt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=k(this).val();return null==n?null:Array.isArray(n)?k.map(n,function(e){return{name:t.name,value:e.replace(At,"\r\n")}}):{name:t.name,value:n.replace(At,"\r\n")}}).get()}});var Lt=/%20/g,Ht=/#.*$/,Ot=/([?&])_=[^&]*/,Pt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Rt=/^(?:GET|HEAD)$/,Mt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Ft=E.createElement("a");function Bt(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(R)||[];if(m(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function _t(t,i,o,a){var s={},u=t===Wt;function l(e){var r;return s[e]=!0,k.each(t[e]||[],function(e,t){var n=t(i,o,a);return"string"!=typeof n||u||s[n]?u?!(r=n):void 0:(i.dataTypes.unshift(n),l(n),!1)}),r}return l(i.dataTypes[0])||!s["*"]&&l("*")}function zt(e,t){var n,r,i=k.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&k.extend(!0,e,r),e}Ft.href=Et.href,k.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Et.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(Et.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":k.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,k.ajaxSettings),t):zt(k.ajaxSettings,e)},ajaxPrefilter:Bt(It),ajaxTransport:Bt(Wt),ajax:function(e,t){"object"==typeof e&&(t=e,e=void 0),t=t||{};var c,f,p,n,d,r,h,g,i,o,v=k.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?k(y):k.event,x=k.Deferred(),b=k.Callbacks("once memory"),w=v.statusCode||{},a={},s={},u="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(h){if(!n){n={};while(t=Pt.exec(p))n[t[1].toLowerCase()+" "]=(n[t[1].toLowerCase()+" "]||[]).concat(t[2])}t=n[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return h?p:null},setRequestHeader:function(e,t){return null==h&&(e=s[e.toLowerCase()]=s[e.toLowerCase()]||e,a[e]=t),this},overrideMimeType:function(e){return null==h&&(v.mimeType=e),this},statusCode:function(e){var t;if(e)if(h)T.always(e[T.status]);else for(t in e)w[t]=[w[t],e[t]];return this},abort:function(e){var t=e||u;return c&&c.abort(t),l(0,t),this}};if(x.promise(T),v.url=((e||v.url||Et.href)+"").replace(Mt,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(R)||[""],null==v.crossDomain){r=E.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Ft.protocol+"//"+Ft.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=k.param(v.data,v.traditional)),_t(It,v,t,T),h)return T;for(i in(g=k.event&&v.global)&&0==k.active++&&k.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Rt.test(v.type),f=v.url.replace(Ht,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Lt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(St.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(Ot,"$1"),o=(St.test(f)?"&":"?")+"_="+kt+++o),v.url=f+o),v.ifModified&&(k.lastModified[f]&&T.setRequestHeader("If-Modified-Since",k.lastModified[f]),k.etag[f]&&T.setRequestHeader("If-None-Match",k.etag[f])),(v.data&&v.hasContent&&!1!==v.contentType||t.contentType)&&T.setRequestHeader("Content-Type",v.contentType),T.setRequestHeader("Accept",v.dataTypes[0]&&v.accepts[v.dataTypes[0]]?v.accepts[v.dataTypes[0]]+("*"!==v.dataTypes[0]?", "+$t+"; q=0.01":""):v.accepts["*"]),v.headers)T.setRequestHeader(i,v.headers[i]);if(v.beforeSend&&(!1===v.beforeSend.call(y,T,v)||h))return T.abort();if(u="abort",b.add(v.complete),T.done(v.success),T.fail(v.error),c=_t(Wt,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=C.setTimeout(function(){T.abort("timeout")},v.timeout));try{h=!1,c.send(a,l)}catch(e){if(h)throw e;l(-1,e)}}else l(-1,"No Transport");function l(e,t,n,r){var i,o,a,s,u,l=t;h||(h=!0,d&&C.clearTimeout(d),c=void 0,p=r||"",T.readyState=0<e?4:0,i=200<=e&&e<300||304===e,n&&(s=function(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}(v,T,n)),s=function(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}(v,s,T,i),i?(v.ifModified&&((u=T.getResponseHeader("Last-Modified"))&&(k.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(k.etag[f]=u)),204===e||"HEAD"===v.type?l="nocontent":304===e?l="notmodified":(l=s.state,o=s.data,i=!(a=s.error))):(a=l,!e&&l||(l="error",e<0&&(e=0))),T.status=e,T.statusText=(t||l)+"",i?x.resolveWith(y,[o,l,T]):x.rejectWith(y,[T,l,a]),T.statusCode(w),w=void 0,g&&m.trigger(i?"ajaxSuccess":"ajaxError",[T,v,i?o:a]),b.fireWith(y,[T,l]),g&&(m.trigger("ajaxComplete",[T,v]),--k.active||k.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return k.get(e,t,n,"json")},getScript:function(e,t){return k.get(e,void 0,t,"script")}}),k.each(["get","post"],function(e,i){k[i]=function(e,t,n,r){return m(t)&&(r=r||n,n=t,t=void 0),k.ajax(k.extend({url:e,type:i,dataType:r,data:t,success:n},k.isPlainObject(e)&&e))}}),k._evalUrl=function(e,t){return k.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){k.globalEval(e,t)}})},k.fn.extend({wrapAll:function(e){var t;return this[0]&&(m(e)&&(e=e.call(this[0])),t=k(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(n){return m(n)?this.each(function(e){k(this).wrapInner(n.call(this,e))}):this.each(function(){var e=k(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=m(t);return this.each(function(e){k(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){k(this).replaceWith(this.childNodes)}),this}}),k.expr.pseudos.hidden=function(e){return!k.expr.pseudos.visible(e)},k.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},k.ajaxSettings.xhr=function(){try{return new C.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Xt=k.ajaxSettings.xhr();y.cors=!!Xt&&"withCredentials"in Xt,y.ajax=Xt=!!Xt,k.ajaxTransport(function(i){var o,a;if(y.cors||Xt&&!i.crossDomain)return{send:function(e,t){var n,r=i.xhr();if(r.open(i.type,i.url,i.async,i.username,i.password),i.xhrFields)for(n in i.xhrFields)r[n]=i.xhrFields[n];for(n in i.mimeType&&r.overrideMimeType&&r.overrideMimeType(i.mimeType),i.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest"),e)r.setRequestHeader(n,e[n]);o=function(e){return function(){o&&(o=a=r.onload=r.onerror=r.onabort=r.ontimeout=r.onreadystatechange=null,"abort"===e?r.abort():"error"===e?"number"!=typeof r.status?t(0,"error"):t(r.status,r.statusText):t(Ut[r.status]||r.status,r.statusText,"text"!==(r.responseType||"text")||"string"!=typeof r.responseText?{binary:r.response}:{text:r.responseText},r.getAllResponseHeaders()))}},r.onload=o(),a=r.onerror=r.ontimeout=o("error"),void 0!==r.onabort?r.onabort=a:r.onreadystatechange=function(){4===r.readyState&&C.setTimeout(function(){o&&a()})},o=o("abort");try{r.send(i.hasContent&&i.data||null)}catch(e){if(o)throw e}},abort:function(){o&&o()}}}),k.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),k.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return k.globalEval(e),e}}}),k.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),k.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=k("<script>").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=mt(e.slice(s)),e=e.slice(0,s)),m(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&k.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?k("<div>").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}}),k.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),k.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),k.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),m(e))return r=s.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(s.call(arguments)))}).guid=e.guid=e.guid||k.guid++,i},k.holdReady=function(e){e?k.readyWait++:k.ready(!0)},k.isArray=Array.isArray,k.parseJSON=JSON.parse,k.nodeName=A,k.isFunction=m,k.isWindow=x,k.camelCase=V,k.type=w,k.now=Date.now,k.isNumeric=function(e){var t=k.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},"function"==typeof define&&define.amd&&define("jquery",[],function(){return k});var Qt=C.jQuery,Jt=C.$;return k.noConflict=function(e){return C.$===k&&(C.$=Jt),e&&C.jQuery===k&&(C.jQuery=Qt),k},e||(C.jQuery=C.$=k),k});
-/*! jQuery Migrate v3.1.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */
-"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"function"==typeof define&&define.amd?define(["jquery"],function(e){return t(e,window)}):"object"==typeof module&&module.exports?module.exports=t(require("jquery"),window):t(jQuery,window)}(function(s,n){"use strict";function e(e){return 0<=function(e,t){for(var r=/^(\d+)\.(\d+)\.(\d+)/,n=r.exec(e)||[],o=r.exec(t)||[],i=1;i<=3;i++){if(+n[i]>+o[i])return 1;if(+n[i]<+o[i])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.1.0",n.console&&n.console.log&&(s&&e("3.0.0")||n.console.log("JQMIGRATE: jQuery 3.0.0+ REQUIRED"),s.migrateWarnings&&n.console.log("JQMIGRATE: Migrate plugin loaded multiple times"),n.console.log("JQMIGRATE: Migrate is installed"+(s.migrateMute?"":" with logging active")+", version "+s.migrateVersion));var r={};function u(e){var t=n.console;r[e]||(r[e]=!0,s.migrateWarnings.push(e),t&&t.warn&&!s.migrateMute&&(t.warn("JQMIGRATE: "+e),s.migrateTrace&&t.trace&&t.trace()))}function t(e,t,r,n){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n),r},set:function(e){u(n),r=e}})}function o(e,t,r,n){e[t]=function(){return u(n),r.apply(this,arguments)}}s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){r={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("jQuery is not compatible with Quirks Mode");var i,a=s.fn.init,c=s.isNumeric,d=s.find,l=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,p=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g;for(i in s.fn.init=function(e){var t=Array.prototype.slice.call(arguments);return"string"==typeof e&&"#"===e&&(u("jQuery( '#' ) is not a valid selector"),t[0]=[]),a.apply(this,t)},s.fn.init.prototype=s.fn,s.find=function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&l.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(p,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("Attribute selector with '#' was not fixed: "+r[0])}}return d.apply(this,r)},d)Object.prototype.hasOwnProperty.call(d,i)&&(s.find[i]=d[i]);s.fn.size=function(){return u("jQuery.fn.size() is deprecated and removed; use the .length property"),this.length},s.parseJSON=function(){return u("jQuery.parseJSON is deprecated; use JSON.parse"),JSON.parse.apply(null,arguments)},s.isNumeric=function(e){var t,r,n=c(e),o=(r=(t=e)&&t.toString(),!s.isArray(t)&&0<=r-parseFloat(r)+1);return n!==o&&u("jQuery.isNumeric() should not be called on constructed objects"),o},e("3.3.0")&&o(s,"isWindow",function(e){return null!=e&&e===e.window},"jQuery.isWindow() is deprecated"),o(s,"holdReady",s.holdReady,"jQuery.holdReady is deprecated"),o(s,"unique",s.uniqueSort,"jQuery.unique is deprecated; use jQuery.uniqueSort"),t(s.expr,"filters",s.expr.pseudos,"jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),t(s.expr,":",s.expr.pseudos,"jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.2.0")&&o(s,"nodeName",s.nodeName,"jQuery.nodeName is deprecated");var f=s.ajax;s.ajax=function(){var e=f.apply(this,arguments);return e.promise&&(o(e,"success",e.done,"jQXHR.success is deprecated and removed"),o(e,"error",e.fail,"jQXHR.error is deprecated and removed"),o(e,"complete",e.always,"jQXHR.complete is deprecated and removed")),e};var y=s.fn.removeAttr,m=s.fn.toggleClass,h=/\S+/g;s.fn.removeAttr=function(e){var r=this;return s.each(e.match(h),function(e,t){s.expr.match.bool.test(t)&&(u("jQuery.fn.removeAttr no longer sets boolean properties: "+t),r.prop(t,!1))}),y.apply(this,arguments)};var g=!(s.fn.toggleClass=function(t){return void 0!==t&&"boolean"!=typeof t?m.apply(this,arguments):(u("jQuery.fn.toggleClass( boolean ) is deprecated"),this.each(function(){var e=this.getAttribute&&this.getAttribute("class")||"";e&&s.data(this,"__className__",e),this.setAttribute&&this.setAttribute("class",e||!1===t?"":s.data(this,"__className__")||"")}))});s.swap&&s.each(["height","width","reliableMarginRight"],function(e,t){var r=s.cssHooks[t]&&s.cssHooks[t].get;r&&(s.cssHooks[t].get=function(){var e;return g=!0,e=r.apply(this,arguments),g=!1,e})}),s.swap=function(e,t,r,n){var o,i,a={};for(i in g||u("jQuery.swap() is undocumented and deprecated"),t)a[i]=e.style[i],e.style[i]=t[i];for(i in o=r.apply(e,n||[]),t)e.style[i]=a[i];return o};var v=s.data;s.data=function(e,t,r){var n;if(t&&"object"==typeof t&&2===arguments.length){n=s.hasData(e)&&v.call(this,e);var o={};for(var i in t)i!==s.camelCase(i)?(u("jQuery.data() always sets/gets camelCased names: "+i),n[i]=t[i]):o[i]=t[i];return v.call(this,e,o),t}return t&&"string"==typeof t&&t!==s.camelCase(t)&&(n=s.hasData(e)&&v.call(this,e))&&t in n?(u("jQuery.data() always sets/gets camelCased names: "+t),2<arguments.length&&(n[t]=r),n[t]):v.apply(this,arguments)};function j(e){return e}var Q=s.Tween.prototype.run;s.Tween.prototype.run=function(){1<s.easing[this.easing].length&&(u("'jQuery.easing."+this.easing.toString()+"' should use only one argument"),s.easing[this.easing]=j),Q.apply(this,arguments)};var w=s.fx.interval||13,b="jQuery.fx.interval is deprecated";n.requestAnimationFrame&&Object.defineProperty(s.fx,"interval",{configurable:!0,enumerable:!0,get:function(){return n.document.hidden||u(b),w},set:function(e){u(b),w=e}});var x=s.fn.load,k=s.event.add,A=s.event.fix;s.event.props=[],s.event.fixHooks={},t(s.event.props,"concat",s.event.props.concat,"jQuery.event.props.concat() is deprecated and removed"),s.event.fix=function(e){var t,r=e.type,n=this.fixHooks[r],o=s.event.props;if(o.length){u("jQuery.event.props are deprecated and removed: "+o.join());while(o.length)s.event.addProp(o.pop())}if(n&&!n._migrated_&&(n._migrated_=!0,u("jQuery.event.fixHooks are deprecated and removed: "+r),(o=n.props)&&o.length))while(o.length)s.event.addProp(o.pop());return t=A.call(this,e),n&&n.filter?n.filter(t,e):t},s.event.add=function(e,t){return e===n&&"load"===t&&"complete"===n.document.readyState&&u("jQuery(window).on('load'...) called after load event occurred"),k.apply(this,arguments)},s.each(["load","unload","error"],function(e,t){s.fn[t]=function(){var e=Array.prototype.slice.call(arguments,0);return"load"===t&&"string"==typeof e[0]?x.apply(this,e):(u("jQuery.fn."+t+"() is deprecated"),e.splice(0,0,t),arguments.length?this.on.apply(this,e):(this.triggerHandler.apply(this,e),this))}}),s.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,r){s.fn[r]=function(e,t){return u("jQuery.fn."+r+"() event shorthand is deprecated"),0<arguments.length?this.on(r,null,e,t):this.trigger(r)}}),s(function(){s(n.document).triggerHandler("ready")}),s.event.special.ready={setup:function(){this===n.document&&u("'ready' event is deprecated")}},s.fn.extend({bind:function(e,t,r){return u("jQuery.fn.bind() is deprecated"),this.on(e,null,t,r)},unbind:function(e,t){return u("jQuery.fn.unbind() is deprecated"),this.off(e,null,t)},delegate:function(e,t,r,n){return u("jQuery.fn.delegate() is deprecated"),this.on(t,e,r,n)},undelegate:function(e,t,r){return u("jQuery.fn.undelegate() is deprecated"),1===arguments.length?this.off(e,"**"):this.off(t,e||"**",r)},hover:function(e,t){return u("jQuery.fn.hover() is deprecated"),this.on("mouseenter",e).on("mouseleave",t||e)}});var S=s.fn.offset;s.fn.offset=function(){var e,t=this[0],r={top:0,left:0};return t&&t.nodeType?(e=(t.ownerDocument||n.document).documentElement,s.contains(e,t)?S.apply(this,arguments):(u("jQuery.fn.offset() requires an element connected to a document"),r)):(u("jQuery.fn.offset() requires a valid DOM element"),r)};var q=s.param;s.param=function(e,t){var r=s.ajaxSettings&&s.ajaxSettings.traditional;return void 0===t&&r&&(u("jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),t=r),q.call(this,e,t)};var C=s.fn.andSelf||s.fn.addBack;s.fn.andSelf=function(){return u("jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),C.apply(this,arguments)};var M=s.Deferred,R=[["resolve","done",s.Callbacks("once memory"),s.Callbacks("once memory"),"resolved"],["reject","fail",s.Callbacks("once memory"),s.Callbacks("once memory"),"rejected"],["notify","progress",s.Callbacks("memory"),s.Callbacks("memory")]];return s.Deferred=function(e){var i=M(),a=i.promise();return i.pipe=a.pipe=function(){var o=arguments;return u("deferred.pipe() is deprecated"),s.Deferred(function(n){s.each(R,function(e,t){var r=s.isFunction(o[e])&&o[e];i[t[1]](function(){var e=r&&r.apply(this,arguments);e&&s.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[t[0]+"With"](this===a?n.promise():this,r?[e]:arguments)})}),o=null}).promise()},e&&e.call(i,i),i},s.Deferred.exceptionHook=M.exceptionHook,s});
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.bundle.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.bundle.min.js
new file mode 100644
index 0000000..cc0a255
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.bundle.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Bootstrap v5.1.3 (https://getbootstrap.com/)
+ * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;s<o;s++){const o=t[n[s]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function S(t,e,i){const n="string"==typeof e,s=n?i:e;let o=P(t);return k.has(o)||(o=t),[n,s,o]}function N(t,e,i,n,s){if("string"!=typeof e||!t)return;if(i||(i=n,n=null),C.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e<i.length;e++)if(Number.parseInt(i[e].getAttribute("data-bs-slide-to"),10)===this._getItemIndex(t)){i[e].classList.add(it),i[e].setAttribute("aria-current","true");break}}}_updateInterval(){const t=this._activeElement||V.findOne(nt,this._element);if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}_slide(t,e){const i=this._directionToOrder(t),n=V.findOne(nt,this._element),s=this._getItemIndex(n),o=e||this._getItemByOrder(i,n),r=this._getItemIndex(o),a=Boolean(this._interval),l=i===Q,c=l?"carousel-item-start":"carousel-item-end",h=l?"carousel-item-next":"carousel-item-prev",d=this._orderToDirection(i);if(o&&o.classList.contains(it))return void(this._isSliding=!1);if(this._isSliding)return;if(this._triggerSlideEvent(o,d).defaultPrevented)return;if(!n||!o)return;this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(o),this._activeElement=o;const f=()=>{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;e<i;e++)st.carouselInterface(t[e],st.getInstance(t[e]))})),g(st);const ot="collapse",rt={toggle:!0,parent:null},at={toggle:"boolean",parent:"(null|element)"},lt="show",ct="collapse",ht="collapsing",dt="collapsed",ut=":scope .collapse .collapse",ft='[data-bs-toggle="collapse"]';class pt extends B{constructor(t,e){super(t),this._isTransitioning=!1,this._config=this._getConfig(e),this._triggerArray=[];const n=V.find(ft);for(let t=0,e=n.length;t<e;t++){const e=n[t],s=i(e),o=V.find(s).filter((t=>t===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t<e;t++){const e=this._triggerArray[t],i=n(e);i&&!this._isShown(i)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O<v.length;O++){var C=v[O],k=Ut(C),L=ce(C)===wt,x=[mt,gt].indexOf(k)>=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some((function(t){return!(t&&"function"==typeof t.getBoundingClientRect)}))}function We(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?Be:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:"bottom",orderedModifiers:[],options:Object.assign({},Be,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s="function"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:$t(t)?Ae(t):t.contextElement?Ae(t.contextElement):[],popper:Ae(e)};var r,c,u=function(t){var e=He(t);return Bt.reduce((function(t,i){return t.concat(e.filter((function(t){return t.phase===i})))}),[])}((r=[].concat(n,a.options.modifiers),c=r.reduce((function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t}),{}),Object.keys(c).map((function(t){return c[t]}))));return a.orderedModifiers=u.filter((function(t){return t.enabled})),a.orderedModifiers.forEach((function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if("function"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}})),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(Re(e,i)){a.rects={reference:Me(e,te(i),"fixed"===a.options.strategy),popper:Kt(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach((function(t){return a.modifiersData[t.name]=Object.assign({},t.data)}));for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;"function"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise((function(t){h.forceUpdate(),t(a)}))},function(){return r||(r=new Promise((function(t){Promise.resolve().then((function(){r=void 0,t(s())}))}))),r}),destroy:function(){d(),c=!0}};if(!Re(t,e))return h;function d(){l.forEach((function(t){return t()})),l=[]}return h.setOptions(i).then((function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)})),h}}var $e=We(),ze=We({defaultModifiers:[pe,Pe,ue,Ft]}),qe=We({defaultModifiers:[pe,Pe,ue,Ft,Ie,xe,je,le,Ne]});const Fe=Object.freeze({__proto__:null,popperGenerator:We,detectOverflow:ke,createPopperBase:$e,createPopper:qe,createPopperLite:ze,top:mt,bottom:gt,right:_t,left:bt,auto:vt,basePlacements:yt,start:wt,end:Et,clippingParents:At,viewport:Tt,popper:Ot,reference:Ct,variationPlacements:kt,placements:Lt,beforeRead:xt,read:Dt,afterRead:St,beforeMain:Nt,main:It,afterMain:Pt,beforeWrite:jt,write:Mt,afterWrite:Ht,modifierPhases:Bt,applyStyles:Ft,arrow:le,computeStyles:ue,eventListeners:pe,flip:xe,hide:Ne,offset:Ie,popperOffsets:Pe,preventOverflow:je}),Ue="dropdown",Ve="Escape",Ke="Space",Xe="ArrowUp",Ye="ArrowDown",Qe=new RegExp("ArrowUp|ArrowDown|Escape"),Ge="click.bs.dropdown.data-api",Ze="keydown.bs.dropdown.data-api",Je="show",ti='[data-bs-toggle="dropdown"]',ei=".dropdown-menu",ii=m()?"top-end":"top-start",ni=m()?"top-start":"top-end",si=m()?"bottom-end":"bottom-start",oi=m()?"bottom-start":"bottom-end",ri=m()?"left-start":"right-start",ai=m()?"right-start":"left-start",li={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},ci={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class hi extends B{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar()}static get Default(){return li}static get DefaultType(){return ci}static get NAME(){return Ue}toggle(){return this._isShown()?this.hide():this.show()}show(){if(c(this._element)||this._isShown(this._menu))return;const t={relatedTarget:this._element};if(j.trigger(this._element,"show.bs.dropdown",t).defaultPrevented)return;const e=hi.getParentFromElement(this._element);this._inNavbar?U.setDataAttribute(this._menu,"popper","none"):this._createPopper(e),"ontouchstart"in document.documentElement&&!e.closest(".navbar-nav")&&[].concat(...document.body.children).forEach((t=>j.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;i<n;i++){const n=hi.getInstance(e[i]);if(!n||!1===n._config.autoClose)continue;if(!n._isShown())continue;const s={relatedTarget:n._element};if(t){const e=t.composedPath(),i=e.includes(n._menu);if(e.includes(n._element)||"inside"===n._config.autoClose&&!i||"outside"===n._config.autoClose&&i)continue;if(n._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;"click"===t.type&&(s.clickEvent=t)}n._completeHide(s)}}static getParentFromElement(t){return n(t)||t.parentNode}static dataApiKeydownHandler(t){if(/input|textarea/i.test(t.target.tagName)?t.key===Ke||t.key!==Ve&&(t.key!==Ye&&t.key!==Xe||t.target.closest(ei)):!Qe.test(t.key))return;const e=this.classList.contains(Je);if(!e&&t.key===Ve)return;if(t.preventDefault(),t.stopPropagation(),c(this))return;const i=this.matches(ti)?this:V.prev(this,ti)[0],n=hi.getOrCreateInstance(i);if(t.key!==Ve)return t.key===Xe||t.key===Ye?(e||n.show(),void n._selectMenuItem(t)):void(e&&t.key!==Ke||hi.clearMenus());n.hide()}}j.on(document,Ze,ti,hi.dataApiKeydownHandler),j.on(document,Ze,ei,hi.dataApiKeydownHandler),j.on(document,Ge,hi.clearMenus),j.on(document,"keyup.bs.dropdown.data-api",hi.clearMenus),j.on(document,Ge,ti,(function(t){t.preventDefault(),hi.getOrCreateInstance(this).toggle()})),g(hi);const di=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ui=".sticky-top";class fi{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",(e=>e+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t<e;t++)if(n[t].test(i))return!0;return!1};function Yi(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(let t=0,i=s.length;t<i;t++){const i=s[t],n=i.nodeName.toLowerCase();if(!Object.keys(e).includes(n)){i.remove();continue}const o=[].concat(...i.attributes),r=[].concat(e["*"]||[],e[n]||[]);o.forEach((t=>{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t<this._offsets[e+1])&&this._activate(this._targets[e])}}_activate(t){this._activeTarget=t,this._clear();const e=wn.split(",").map((e=>`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}}));
+//# sourceMappingURL=bootstrap.bundle.min.js.map
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.min.js
deleted file mode 100644
index 9bcd2fc..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/001-bootstrap.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Bootstrap v3.3.7 (http://getbootstrap.com)
- * Copyright 2011-2016 Twitter, Inc.
- * Licensed under the MIT license
- */
-if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",c).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f,g.prototype.keydown).on("keydown.bs.dropdown.data-api",".dropdown-menu",g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$dialog=this.$element.find(".modal-dialog"),this.$backdrop=null,this.isShown=null,this.originalBodyPad=null,this.scrollbarWidth=0,this.ignoreBackdropClick=!1,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=300,c.BACKDROP_TRANSITION_DURATION=150,c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var d=this,e=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(e),this.isShown||e.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.setScrollbar(),this.$body.addClass("modal-open"),this.escape(),this.resize(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.$dialog.on("mousedown.dismiss.bs.modal",function(){d.$element.one("mouseup.dismiss.bs.modal",function(b){a(b.target).is(d.$element)&&(d.ignoreBackdropClick=!0)})}),this.backdrop(function(){var e=a.support.transition&&d.$element.hasClass("fade");d.$element.parent().length||d.$element.appendTo(d.$body),d.$element.show().scrollTop(0),d.adjustDialog(),e&&d.$element[0].offsetWidth,d.$element.addClass("in"),d.enforceFocus();var f=a.Event("shown.bs.modal",{relatedTarget:b});e?d.$dialog.one("bsTransitionEnd",function(){d.$element.trigger("focus").trigger(f)}).emulateTransitionEnd(c.TRANSITION_DURATION):d.$element.trigger("focus").trigger(f)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.escape(),this.resize(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"),this.$dialog.off("mousedown.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(c.TRANSITION_DURATION):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){document===a.target||this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keydown.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keydown.dismiss.bs.modal")},c.prototype.resize=function(){this.isShown?a(window).on("resize.bs.modal",a.proxy(this.handleUpdate,this)):a(window).off("resize.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$body.removeClass("modal-open"),a.resetAdjustments(),a.resetScrollbar(),a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var d=this,e=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var f=a.support.transition&&e;if(this.$backdrop=a(document.createElement("div")).addClass("modal-backdrop "+e).appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){return this.ignoreBackdropClick?void(this.ignoreBackdropClick=!1):void(a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus():this.hide()))},this)),f&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;f?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var g=function(){d.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION):g()}else b&&b()},c.prototype.handleUpdate=function(){this.adjustDialog()},c.prototype.adjustDialog=function(){var a=this.$element[0].scrollHeight>document.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth<a,this.scrollbarWidth=this.measureScrollbar()},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.originalBodyPad=document.body.style.paddingRight||"",this.bodyIsOverflowing&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right",this.originalBodyPad)},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=null,this.options=null,this.enabled=null,this.timeout=null,this.hoverState=null,this.$element=null,this.inState=null,this.init("tooltip",a,b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-m<o.top?"bottom":"right"==h&&k.right+l>o.width?"left":"left"==h&&k.left-l<o.left?"right":h,f.removeClass(n).addClass(h)}var p=this.getCalculatedOffset(h,k,l,m);this.applyPlacement(p,h);var q=function(){var a=e.hoverState;e.$element.trigger("shown.bs."+e.type),e.hoverState=null,"out"==a&&e.leave(e)};a.support.transition&&this.$tip.hasClass("fade")?f.one("bsTransitionEnd",q).emulateTransitionEnd(c.TRANSITION_DURATION):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top+=g,b.left+=h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=/top|bottom/.test(c),m=l?2*k.left-e+i:2*k.top-f+j,n=l?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(m,d[0][n],l)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c?"left":"top",50*(1-a/b)+"%").css(c?"top":"left","")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(b){function d(){"in"!=e.hoverState&&f.detach(),e.$element&&e.$element.removeAttr("aria-describedby").trigger("hidden.bs."+e.type),b&&b()}var e=this,f=a(this.$tip),g=a.Event("hide.bs."+this.type);if(this.$element.trigger(g),!g.isDefaultPrevented())return f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",d).emulateTransitionEnd(c.TRANSITION_DURATION):d(),this.hoverState=null,this},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName,e=c.getBoundingClientRect();null==e.width&&(e=a.extend({},e,{width:e.right-e.left,height:e.bottom-e.top}));var f=window.SVGElement&&c instanceof window.SVGElement,g=d?{top:0,left:0}:f?null:b.offset(),h={scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop()},i=d?{width:a(window).width(),height:a(window).height()}:null;return a.extend({},e,h,i,g)},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<e[0])return this.activeTarget=null,this.clear();for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(void 0===e[a+1]||b<e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){
-this.activeTarget=b,this.clear();var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")},b.prototype.clear=function(){a(this.selector).parentsUntil(this.options.target,".active").removeClass("active")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.3.7",c.TRANSITION_DURATION=150,c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a"),f=a.Event("hide.bs.tab",{relatedTarget:b[0]}),g=a.Event("show.bs.tab",{relatedTarget:e[0]});if(e.trigger(f),b.trigger(g),!g.isDefaultPrevented()&&!f.isDefaultPrevented()){var h=a(d);this.activate(b.closest("li"),c),this.activate(h,h.parent(),function(){e.trigger({type:"hidden.bs.tab",relatedTarget:b[0]}),b.trigger({type:"shown.bs.tab",relatedTarget:e[0]})})}}},c.prototype.activate=function(b,d,e){function f(){g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e<c&&"top";if("bottom"==this.affixed)return null!=c?!(e+this.unpin<=f.top)&&"bottom":!(e+g<=a-d)&&"bottom";var h=null==this.affixed,i=h?e:f.top,j=h?g:b;return null!=c&&e<=c?"top":null!=d&&i+j>=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/003-slider.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/002-slider.min.js
similarity index 100%
rename from mailcow/src/mailcow-dockerized/data/web/js/build/003-slider.min.js
rename to mailcow/src/mailcow-dockerized/data/web/js/build/002-slider.min.js
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/003-bootstrap-select.js b/mailcow/src/mailcow-dockerized/data/web/js/build/003-bootstrap-select.js
new file mode 100644
index 0000000..b632f65
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/003-bootstrap-select.js
@@ -0,0 +1,3603 @@
+(function ($) {
+ 'use strict';
+
+ var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'];
+
+ var uriAttrs = [
+ 'background',
+ 'cite',
+ 'href',
+ 'itemtype',
+ 'longdesc',
+ 'poster',
+ 'src',
+ 'xlink:href'
+ ];
+
+ var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
+
+ var DefaultWhitelist = {
+ // Global attributes allowed on any supplied element below.
+ '*': ['class', 'dir', 'id', 'lang', 'role', 'tabindex', 'style', ARIA_ATTRIBUTE_PATTERN],
+ a: ['target', 'href', 'title', 'rel'],
+ area: [],
+ b: [],
+ br: [],
+ col: [],
+ code: [],
+ div: [],
+ em: [],
+ hr: [],
+ h1: [],
+ h2: [],
+ h3: [],
+ h4: [],
+ h5: [],
+ h6: [],
+ i: [],
+ img: ['src', 'alt', 'title', 'width', 'height'],
+ li: [],
+ ol: [],
+ p: [],
+ pre: [],
+ s: [],
+ small: [],
+ span: [],
+ sub: [],
+ sup: [],
+ strong: [],
+ u: [],
+ ul: []
+ };
+
+ /**
+ * A pattern that recognizes a commonly useful subset of URLs that are safe.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+ var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi;
+
+ /**
+ * A pattern that matches safe data URLs. Only matches image, video and audio types.
+ *
+ * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
+ */
+ var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i;
+
+ var ParseableAttributes = ['title', 'placeholder']; // attributes to use as settings, can add others in the future
+
+ function allowedAttribute (attr, allowedAttributeList) {
+ var attrName = attr.nodeName.toLowerCase();
+
+ if ($.inArray(attrName, allowedAttributeList) !== -1) {
+ if ($.inArray(attrName, uriAttrs) !== -1) {
+ return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN));
+ }
+
+ return true;
+ }
+
+ var regExp = $(allowedAttributeList).filter(function (index, value) {
+ return value instanceof RegExp;
+ });
+
+ // Check if a regular expression validates the attribute.
+ for (var i = 0, l = regExp.length; i < l; i++) {
+ if (attrName.match(regExp[i])) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ function sanitizeHtml (unsafeElements, whiteList, sanitizeFn) {
+ if (sanitizeFn && typeof sanitizeFn === 'function') {
+ return sanitizeFn(unsafeElements);
+ }
+
+ var whitelistKeys = Object.keys(whiteList);
+
+ for (var i = 0, len = unsafeElements.length; i < len; i++) {
+ var elements = unsafeElements[i].querySelectorAll('*');
+
+ for (var j = 0, len2 = elements.length; j < len2; j++) {
+ var el = elements[j];
+ var elName = el.nodeName.toLowerCase();
+
+ if (whitelistKeys.indexOf(elName) === -1) {
+ el.parentNode.removeChild(el);
+
+ continue;
+ }
+
+ var attributeList = [].slice.call(el.attributes);
+ var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []);
+
+ for (var k = 0, len3 = attributeList.length; k < len3; k++) {
+ var attr = attributeList[k];
+
+ if (!allowedAttribute(attr, whitelistedAttributes)) {
+ el.removeAttribute(attr.nodeName);
+ }
+ }
+ }
+ }
+ }
+
+ function getAttributesObject ($select) {
+ var attributesObject = {},
+ attrVal;
+
+ ParseableAttributes.forEach(function (item) {
+ attrVal = $select.attr(item);
+ if (attrVal) attributesObject[item] = attrVal;
+ });
+
+ // for backwards compatibility
+ // (using title as placeholder is deprecated - remove in v2.0.0)
+ if (!attributesObject.placeholder && attributesObject.title) {
+ attributesObject.placeholder = attributesObject.title;
+ }
+
+ return attributesObject;
+ }
+
+ // Polyfill for browsers with no classList support
+ // Remove in v2
+ if (!('classList' in document.createElement('_'))) {
+ (function (view) {
+ if (!('Element' in view)) return;
+
+ var classListProp = 'classList',
+ protoProp = 'prototype',
+ elemCtrProto = view.Element[protoProp],
+ objCtr = Object,
+ classListGetter = function () {
+ var $elem = $(this);
+
+ return {
+ add: function (classes) {
+ classes = Array.prototype.slice.call(arguments).join(' ');
+ return $elem.addClass(classes);
+ },
+ remove: function (classes) {
+ classes = Array.prototype.slice.call(arguments).join(' ');
+ return $elem.removeClass(classes);
+ },
+ toggle: function (classes, force) {
+ return $elem.toggleClass(classes, force);
+ },
+ contains: function (classes) {
+ return $elem.hasClass(classes);
+ }
+ };
+ };
+
+ if (objCtr.defineProperty) {
+ var classListPropDesc = {
+ get: classListGetter,
+ enumerable: true,
+ configurable: true
+ };
+ try {
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ } catch (ex) { // IE 8 doesn't support enumerable:true
+ // adding undefined to fight this issue https://github.com/eligrey/classList.js/issues/36
+ // modernie IE8-MSW7 machine has IE8 8.0.6001.18702 and is affected
+ if (ex.number === undefined || ex.number === -0x7FF5EC54) {
+ classListPropDesc.enumerable = false;
+ objCtr.defineProperty(elemCtrProto, classListProp, classListPropDesc);
+ }
+ }
+ } else if (objCtr[protoProp].__defineGetter__) {
+ elemCtrProto.__defineGetter__(classListProp, classListGetter);
+ }
+ }(window));
+ }
+
+ var testElement = document.createElement('_');
+
+ testElement.classList.add('c1', 'c2');
+
+ if (!testElement.classList.contains('c2')) {
+ var _add = DOMTokenList.prototype.add,
+ _remove = DOMTokenList.prototype.remove;
+
+ DOMTokenList.prototype.add = function () {
+ Array.prototype.forEach.call(arguments, _add.bind(this));
+ };
+
+ DOMTokenList.prototype.remove = function () {
+ Array.prototype.forEach.call(arguments, _remove.bind(this));
+ };
+ }
+
+ testElement.classList.toggle('c3', false);
+
+ // Polyfill for IE 10 and Firefox <24, where classList.toggle does not
+ // support the second argument.
+ if (testElement.classList.contains('c3')) {
+ var _toggle = DOMTokenList.prototype.toggle;
+
+ DOMTokenList.prototype.toggle = function (token, force) {
+ if (1 in arguments && !this.contains(token) === !force) {
+ return force;
+ } else {
+ return _toggle.call(this, token);
+ }
+ };
+ }
+
+ testElement = null;
+
+ // Polyfill for IE (remove in v2)
+ Object.values = typeof Object.values === 'function' ? Object.values : function (obj) {
+ return Object.keys(obj).map(function (key) {
+ return obj[key];
+ });
+ };
+
+ // shallow array comparison
+ function isEqual (array1, array2) {
+ return array1.length === array2.length && array1.every(function (element, index) {
+ return element === array2[index];
+ });
+ };
+
+ // <editor-fold desc="Shims">
+ if (!String.prototype.startsWith) {
+ (function () {
+ 'use strict'; // needed to support `apply`/`call` with `undefined`/`null`
+ var toString = {}.toString;
+ var startsWith = function (search) {
+ if (this == null) {
+ throw new TypeError();
+ }
+ var string = String(this);
+ if (search && toString.call(search) == '[object RegExp]') {
+ throw new TypeError();
+ }
+ var stringLength = string.length;
+ var searchString = String(search);
+ var searchLength = searchString.length;
+ var position = arguments.length > 1 ? arguments[1] : undefined;
+ // `ToInteger`
+ var pos = position ? Number(position) : 0;
+ if (pos != pos) { // better `isNaN`
+ pos = 0;
+ }
+ var start = Math.min(Math.max(pos, 0), stringLength);
+ // Avoid the `indexOf` call if no match is possible
+ if (searchLength + start > stringLength) {
+ return false;
+ }
+ var index = -1;
+ while (++index < searchLength) {
+ if (string.charCodeAt(start + index) != searchString.charCodeAt(index)) {
+ return false;
+ }
+ }
+ return true;
+ };
+ if (Object.defineProperty) {
+ Object.defineProperty(String.prototype, 'startsWith', {
+ 'value': startsWith,
+ 'configurable': true,
+ 'writable': true
+ });
+ } else {
+ String.prototype.startsWith = startsWith;
+ }
+ }());
+ }
+
+ function toKebabCase (str) {
+ return str.replace(/[A-Z]+(?![a-z])|[A-Z]/g, function ($, ofs) {
+ return (ofs ? '-' : '') + $.toLowerCase();
+ });
+ }
+
+ function getSelectedOptions () {
+ var options = this.selectpicker.main.data;
+
+ if (this.options.source.data || this.options.source.search) {
+ options = Object.values(this.selectpicker.optionValuesDataMap);
+ }
+
+ var selectedOptions = options.filter(function (item) {
+ if (item.selected) {
+ if (this.options.hideDisabled && item.disabled) return false;
+ return true;
+ }
+
+ return false;
+ }, this);
+
+ // ensure only 1 option is selected if multiple are set in the data source
+ if (this.options.source.data && !this.multiple && selectedOptions.length > 1) {
+ for (var i = 0; i < selectedOptions.length - 1; i++) {
+ selectedOptions[i].selected = false;
+ }
+
+ selectedOptions = [ selectedOptions[selectedOptions.length - 1] ];
+ }
+
+ return selectedOptions;
+ }
+
+ // much faster than $.val()
+ function getSelectValues (selectedOptions) {
+ var value = [],
+ options = selectedOptions || getSelectedOptions.call(this),
+ opt;
+
+ for (var i = 0, len = options.length; i < len; i++) {
+ opt = options[i];
+
+ if (!opt.disabled) {
+ value.push(opt.value === undefined ? opt.text : opt.value);
+ }
+ }
+
+ if (!this.multiple) {
+ return !value.length ? null : value[0];
+ }
+
+ return value;
+ }
+
+ // set data-selected on select element if the value has been programmatically selected
+ // prior to initialization of bootstrap-select
+ // * consider removing or replacing an alternative method *
+ var valHooks = {
+ useDefault: false,
+ _set: $.valHooks.select.set
+ };
+
+ $.valHooks.select.set = function (elem, value) {
+ if (value && !valHooks.useDefault) $(elem).data('selected', true);
+
+ return valHooks._set.apply(this, arguments);
+ };
+
+ var changedArguments = null;
+
+ var EventIsSupported = (function () {
+ try {
+ new Event('change');
+ return true;
+ } catch (e) {
+ return false;
+ }
+ })();
+
+ $.fn.triggerNative = function (eventName) {
+ var el = this[0],
+ event;
+
+ if (el.dispatchEvent) { // for modern browsers & IE9+
+ if (EventIsSupported) {
+ // For modern browsers
+ event = new Event(eventName, {
+ bubbles: true
+ });
+ } else {
+ // For IE since it doesn't support Event constructor
+ event = document.createEvent('Event');
+ event.initEvent(eventName, true, false);
+ }
+
+ el.dispatchEvent(event);
+ }
+ };
+ // </editor-fold>
+
+ function stringSearch (li, searchString, method, normalize) {
+ var stringTypes = [
+ 'display',
+ 'subtext',
+ 'tokens'
+ ],
+ searchSuccess = false;
+
+ for (var i = 0; i < stringTypes.length; i++) {
+ var stringType = stringTypes[i],
+ string = li[stringType];
+
+ if (string) {
+ string = string.toString();
+
+ // Strip HTML tags. This isn't perfect, but it's much faster than any other method
+ if (stringType === 'display') {
+ string = string.replace(/<[^>]+>/g, '');
+ }
+
+ if (normalize) string = normalizeToBase(string);
+ string = string.toUpperCase();
+
+ if (typeof method === 'function') {
+ searchSuccess = method(string, searchString);
+ } else if (method === 'contains') {
+ searchSuccess = string.indexOf(searchString) >= 0;
+ } else {
+ searchSuccess = string.startsWith(searchString);
+ }
+
+ if (searchSuccess) break;
+ }
+ }
+
+ return searchSuccess;
+ }
+
+ function toInteger (value) {
+ return parseInt(value, 10) || 0;
+ }
+
+ // Borrowed from Lodash (_.deburr)
+ /** Used to map Latin Unicode letters to basic Latin letters. */
+ var deburredLetters = {
+ // Latin-1 Supplement block.
+ '\xc0': 'A', '\xc1': 'A', '\xc2': 'A', '\xc3': 'A', '\xc4': 'A', '\xc5': 'A',
+ '\xe0': 'a', '\xe1': 'a', '\xe2': 'a', '\xe3': 'a', '\xe4': 'a', '\xe5': 'a',
+ '\xc7': 'C', '\xe7': 'c',
+ '\xd0': 'D', '\xf0': 'd',
+ '\xc8': 'E', '\xc9': 'E', '\xca': 'E', '\xcb': 'E',
+ '\xe8': 'e', '\xe9': 'e', '\xea': 'e', '\xeb': 'e',
+ '\xcc': 'I', '\xcd': 'I', '\xce': 'I', '\xcf': 'I',
+ '\xec': 'i', '\xed': 'i', '\xee': 'i', '\xef': 'i',
+ '\xd1': 'N', '\xf1': 'n',
+ '\xd2': 'O', '\xd3': 'O', '\xd4': 'O', '\xd5': 'O', '\xd6': 'O', '\xd8': 'O',
+ '\xf2': 'o', '\xf3': 'o', '\xf4': 'o', '\xf5': 'o', '\xf6': 'o', '\xf8': 'o',
+ '\xd9': 'U', '\xda': 'U', '\xdb': 'U', '\xdc': 'U',
+ '\xf9': 'u', '\xfa': 'u', '\xfb': 'u', '\xfc': 'u',
+ '\xdd': 'Y', '\xfd': 'y', '\xff': 'y',
+ '\xc6': 'Ae', '\xe6': 'ae',
+ '\xde': 'Th', '\xfe': 'th',
+ '\xdf': 'ss',
+ // Latin Extended-A block.
+ '\u0100': 'A', '\u0102': 'A', '\u0104': 'A',
+ '\u0101': 'a', '\u0103': 'a', '\u0105': 'a',
+ '\u0106': 'C', '\u0108': 'C', '\u010a': 'C', '\u010c': 'C',
+ '\u0107': 'c', '\u0109': 'c', '\u010b': 'c', '\u010d': 'c',
+ '\u010e': 'D', '\u0110': 'D', '\u010f': 'd', '\u0111': 'd',
+ '\u0112': 'E', '\u0114': 'E', '\u0116': 'E', '\u0118': 'E', '\u011a': 'E',
+ '\u0113': 'e', '\u0115': 'e', '\u0117': 'e', '\u0119': 'e', '\u011b': 'e',
+ '\u011c': 'G', '\u011e': 'G', '\u0120': 'G', '\u0122': 'G',
+ '\u011d': 'g', '\u011f': 'g', '\u0121': 'g', '\u0123': 'g',
+ '\u0124': 'H', '\u0126': 'H', '\u0125': 'h', '\u0127': 'h',
+ '\u0128': 'I', '\u012a': 'I', '\u012c': 'I', '\u012e': 'I', '\u0130': 'I',
+ '\u0129': 'i', '\u012b': 'i', '\u012d': 'i', '\u012f': 'i', '\u0131': 'i',
+ '\u0134': 'J', '\u0135': 'j',
+ '\u0136': 'K', '\u0137': 'k', '\u0138': 'k',
+ '\u0139': 'L', '\u013b': 'L', '\u013d': 'L', '\u013f': 'L', '\u0141': 'L',
+ '\u013a': 'l', '\u013c': 'l', '\u013e': 'l', '\u0140': 'l', '\u0142': 'l',
+ '\u0143': 'N', '\u0145': 'N', '\u0147': 'N', '\u014a': 'N',
+ '\u0144': 'n', '\u0146': 'n', '\u0148': 'n', '\u014b': 'n',
+ '\u014c': 'O', '\u014e': 'O', '\u0150': 'O',
+ '\u014d': 'o', '\u014f': 'o', '\u0151': 'o',
+ '\u0154': 'R', '\u0156': 'R', '\u0158': 'R',
+ '\u0155': 'r', '\u0157': 'r', '\u0159': 'r',
+ '\u015a': 'S', '\u015c': 'S', '\u015e': 'S', '\u0160': 'S',
+ '\u015b': 's', '\u015d': 's', '\u015f': 's', '\u0161': 's',
+ '\u0162': 'T', '\u0164': 'T', '\u0166': 'T',
+ '\u0163': 't', '\u0165': 't', '\u0167': 't',
+ '\u0168': 'U', '\u016a': 'U', '\u016c': 'U', '\u016e': 'U', '\u0170': 'U', '\u0172': 'U',
+ '\u0169': 'u', '\u016b': 'u', '\u016d': 'u', '\u016f': 'u', '\u0171': 'u', '\u0173': 'u',
+ '\u0174': 'W', '\u0175': 'w',
+ '\u0176': 'Y', '\u0177': 'y', '\u0178': 'Y',
+ '\u0179': 'Z', '\u017b': 'Z', '\u017d': 'Z',
+ '\u017a': 'z', '\u017c': 'z', '\u017e': 'z',
+ '\u0132': 'IJ', '\u0133': 'ij',
+ '\u0152': 'Oe', '\u0153': 'oe',
+ '\u0149': "'n", '\u017f': 's'
+ };
+
+ /** Used to match Latin Unicode letters (excluding mathematical operators). */
+ var reLatin = /[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g;
+
+ /** Used to compose unicode character classes. */
+ var rsComboMarksRange = '\\u0300-\\u036f',
+ reComboHalfMarksRange = '\\ufe20-\\ufe2f',
+ rsComboSymbolsRange = '\\u20d0-\\u20ff',
+ rsComboMarksExtendedRange = '\\u1ab0-\\u1aff',
+ rsComboMarksSupplementRange = '\\u1dc0-\\u1dff',
+ rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange + rsComboMarksExtendedRange + rsComboMarksSupplementRange;
+
+ /** Used to compose unicode capture groups. */
+ var rsCombo = '[' + rsComboRange + ']';
+
+ /**
+ * Used to match [combining diacritical marks](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks) and
+ * [combining diacritical marks for symbols](https://en.wikipedia.org/wiki/Combining_Diacritical_Marks_for_Symbols).
+ */
+ var reComboMark = RegExp(rsCombo, 'g');
+
+ function deburrLetter (key) {
+ return deburredLetters[key];
+ };
+
+ function normalizeToBase (string) {
+ string = string.toString();
+ return string && string.replace(reLatin, deburrLetter).replace(reComboMark, '');
+ }
+
+ // List of HTML entities for escaping.
+ var escapeMap = {
+ '&': '&',
+ '<': '<',
+ '>': '>',
+ '"': '"',
+ "'": ''',
+ '`': '`'
+ };
+
+ // Functions for escaping and unescaping strings to/from HTML interpolation.
+ var createEscaper = function (map) {
+ var escaper = function (match) {
+ return map[match];
+ };
+ // Regexes for identifying a key that needs to be escaped.
+ var source = '(?:' + Object.keys(map).join('|') + ')';
+ var testRegexp = RegExp(source);
+ var replaceRegexp = RegExp(source, 'g');
+ return function (string) {
+ string = string == null ? '' : '' + string;
+ return testRegexp.test(string) ? string.replace(replaceRegexp, escaper) : string;
+ };
+ };
+
+ var htmlEscape = createEscaper(escapeMap);
+
+ /**
+ * ------------------------------------------------------------------------
+ * Constants
+ * ------------------------------------------------------------------------
+ */
+
+ var keyCodeMap = {
+ 32: ' ',
+ 48: '0',
+ 49: '1',
+ 50: '2',
+ 51: '3',
+ 52: '4',
+ 53: '5',
+ 54: '6',
+ 55: '7',
+ 56: '8',
+ 57: '9',
+ 59: ';',
+ 65: 'A',
+ 66: 'B',
+ 67: 'C',
+ 68: 'D',
+ 69: 'E',
+ 70: 'F',
+ 71: 'G',
+ 72: 'H',
+ 73: 'I',
+ 74: 'J',
+ 75: 'K',
+ 76: 'L',
+ 77: 'M',
+ 78: 'N',
+ 79: 'O',
+ 80: 'P',
+ 81: 'Q',
+ 82: 'R',
+ 83: 'S',
+ 84: 'T',
+ 85: 'U',
+ 86: 'V',
+ 87: 'W',
+ 88: 'X',
+ 89: 'Y',
+ 90: 'Z',
+ 96: '0',
+ 97: '1',
+ 98: '2',
+ 99: '3',
+ 100: '4',
+ 101: '5',
+ 102: '6',
+ 103: '7',
+ 104: '8',
+ 105: '9'
+ };
+
+ var keyCodes = {
+ ESCAPE: 27, // KeyboardEvent.which value for Escape (Esc) key
+ ENTER: 13, // KeyboardEvent.which value for Enter key
+ SPACE: 32, // KeyboardEvent.which value for space key
+ TAB: 9, // KeyboardEvent.which value for tab key
+ ARROW_UP: 38, // KeyboardEvent.which value for up arrow key
+ ARROW_DOWN: 40 // KeyboardEvent.which value for down arrow key
+ };
+
+ // eslint-disable-next-line no-undef
+ var Dropdown = window.Dropdown || bootstrap.Dropdown;
+
+ function getVersion () {
+ var version;
+
+ try {
+ version = $.fn.dropdown.Constructor.VERSION;
+ } catch (err) {
+ version = Dropdown.VERSION;
+ }
+
+ return version;
+ }
+
+ var version = {
+ success: false,
+ major: '3'
+ };
+
+ try {
+ version.full = (getVersion() || '').split(' ')[0].split('.');
+ version.major = version.full[0];
+ version.success = true;
+ } catch (err) {
+ // do nothing
+ }
+
+ var selectId = 0;
+
+ var EVENT_KEY = '.bs.select';
+
+ var classNames = {
+ DISABLED: 'disabled',
+ DIVIDER: 'divider',
+ SHOW: 'open',
+ DROPUP: 'dropup',
+ MENU: 'dropdown-menu',
+ MENURIGHT: 'dropdown-menu-right',
+ MENULEFT: 'dropdown-menu-left',
+ // to-do: replace with more advanced template/customization options
+ BUTTONCLASS: 'btn-secondary',
+ POPOVERHEADER: 'popover-title',
+ ICONBASE: 'glyphicon',
+ TICKICON: 'glyphicon-ok'
+ };
+
+ var Selector = {
+ MENU: '.' + classNames.MENU,
+ DATA_TOGGLE: 'data-toggle="dropdown"'
+ };
+
+ var elementTemplates = {
+ div: document.createElement('div'),
+ span: document.createElement('span'),
+ i: document.createElement('i'),
+ subtext: document.createElement('small'),
+ a: document.createElement('a'),
+ li: document.createElement('li'),
+ whitespace: document.createTextNode('\u00A0'),
+ fragment: document.createDocumentFragment(),
+ option: document.createElement('option')
+ };
+
+ elementTemplates.selectedOption = elementTemplates.option.cloneNode(false);
+ elementTemplates.selectedOption.setAttribute('selected', true);
+
+ elementTemplates.noResults = elementTemplates.li.cloneNode(false);
+ elementTemplates.noResults.className = 'no-results';
+
+ elementTemplates.a.setAttribute('role', 'option');
+ elementTemplates.a.className = 'dropdown-item';
+
+ elementTemplates.subtext.className = 'text-muted';
+
+ elementTemplates.text = elementTemplates.span.cloneNode(false);
+ elementTemplates.text.className = 'text';
+
+ elementTemplates.checkMark = elementTemplates.span.cloneNode(false);
+
+ var REGEXP_ARROW = new RegExp(keyCodes.ARROW_UP + '|' + keyCodes.ARROW_DOWN);
+ var REGEXP_TAB_OR_ESCAPE = new RegExp('^' + keyCodes.TAB + '$|' + keyCodes.ESCAPE);
+
+ var generateOption = {
+ li: function (content, classes, optgroup) {
+ var li = elementTemplates.li.cloneNode(false);
+
+ if (content) {
+ if (content.nodeType === 1 || content.nodeType === 11) {
+ li.appendChild(content);
+ } else {
+ li.innerHTML = content;
+ }
+ }
+
+ if (typeof classes !== 'undefined' && classes !== '') li.className = classes;
+ if (typeof optgroup !== 'undefined' && optgroup !== null) li.classList.add('optgroup-' + optgroup);
+
+ return li;
+ },
+
+ a: function (text, classes, inline) {
+ var a = elementTemplates.a.cloneNode(true);
+
+ if (text) {
+ if (text.nodeType === 11) {
+ a.appendChild(text);
+ } else {
+ a.insertAdjacentHTML('beforeend', text);
+ }
+ }
+
+ if (typeof classes !== 'undefined' && classes !== '') a.classList.add.apply(a.classList, classes.split(/\s+/));
+ if (inline) a.setAttribute('style', inline);
+
+ return a;
+ },
+
+ text: function (options, useFragment) {
+ var textElement = elementTemplates.text.cloneNode(false),
+ subtextElement,
+ iconElement;
+
+ if (options.content) {
+ textElement.innerHTML = options.content;
+ } else {
+ textElement.textContent = options.text;
+
+ if (options.icon) {
+ var whitespace = elementTemplates.whitespace.cloneNode(false);
+
+ // need to use <i> for icons in the button to prevent a breaking change
+ // note: switch to span in next major release
+ iconElement = (useFragment === true ? elementTemplates.i : elementTemplates.span).cloneNode(false);
+ iconElement.className = this.options.iconBase + ' ' + options.icon;
+
+ elementTemplates.fragment.appendChild(iconElement);
+ elementTemplates.fragment.appendChild(whitespace);
+ }
+
+ if (options.subtext) {
+ subtextElement = elementTemplates.subtext.cloneNode(false);
+ subtextElement.textContent = options.subtext;
+ textElement.appendChild(subtextElement);
+ }
+ }
+
+ if (useFragment === true) {
+ while (textElement.childNodes.length > 0) {
+ elementTemplates.fragment.appendChild(textElement.childNodes[0]);
+ }
+ } else {
+ elementTemplates.fragment.appendChild(textElement);
+ }
+
+ return elementTemplates.fragment;
+ },
+
+ label: function (options) {
+ var textElement = elementTemplates.text.cloneNode(false),
+ subtextElement,
+ iconElement;
+
+ textElement.innerHTML = options.display;
+
+ if (options.icon) {
+ var whitespace = elementTemplates.whitespace.cloneNode(false);
+
+ iconElement = elementTemplates.span.cloneNode(false);
+ iconElement.className = this.options.iconBase + ' ' + options.icon;
+
+ elementTemplates.fragment.appendChild(iconElement);
+ elementTemplates.fragment.appendChild(whitespace);
+ }
+
+ if (options.subtext) {
+ subtextElement = elementTemplates.subtext.cloneNode(false);
+ subtextElement.textContent = options.subtext;
+ textElement.appendChild(subtextElement);
+ }
+
+ elementTemplates.fragment.appendChild(textElement);
+
+ return elementTemplates.fragment;
+ }
+ };
+
+ var getOptionData = {
+ fromOption: function (option, type) {
+ var value;
+
+ switch (type) {
+ case 'divider':
+ value = option.getAttribute('data-divider') === 'true';
+ break;
+
+ case 'text':
+ value = option.textContent;
+ break;
+
+ case 'label':
+ value = option.label;
+ break;
+
+ case 'style':
+ value = option.style.cssText;
+ break;
+
+ case 'title':
+ value = option.title;
+ break;
+
+ default:
+ value = option.getAttribute('data-' + toKebabCase(type));
+ break;
+ }
+
+ return value;
+ },
+ fromDataSource: function (option, type) {
+ var value;
+
+ switch (type) {
+ case 'text':
+ case 'label':
+ value = option.text || option.value || '';
+ break;
+
+ default:
+ value = option[type];
+ break;
+ }
+
+ return value;
+ }
+ };
+
+ function showNoResults (searchMatch, searchValue) {
+ if (!searchMatch.length) {
+ elementTemplates.noResults.innerHTML = this.options.noneResultsText.replace('{0}', '"' + htmlEscape(searchValue) + '"');
+ this.$menuInner[0].firstChild.appendChild(elementTemplates.noResults);
+ }
+ }
+
+ function filterHidden (item) {
+ return !(item.hidden || this.options.hideDisabled && item.disabled);
+ }
+
+ var Selectpicker = function (element, options) {
+ var that = this;
+
+ // bootstrap-select has been initialized - revert valHooks.select.set back to its original function
+ if (!valHooks.useDefault) {
+ $.valHooks.select.set = valHooks._set;
+ valHooks.useDefault = true;
+ }
+
+ this.$element = $(element);
+ this.$newElement = null;
+ this.$button = null;
+ this.$menu = null;
+ this.options = options;
+ this.selectpicker = {
+ main: {
+ data: [],
+ optionQueue: elementTemplates.fragment.cloneNode(false),
+ hasMore: false
+ },
+ search: {
+ data: [],
+ hasMore: false
+ },
+ current: {}, // current is either equal to main or search depending on if a search is in progress
+ view: {},
+ // map of option values and their respective data (only used in conjunction with options.source)
+ optionValuesDataMap: {},
+ isSearching: false,
+ keydown: {
+ keyHistory: '',
+ resetKeyHistory: {
+ start: function () {
+ return setTimeout(function () {
+ that.selectpicker.keydown.keyHistory = '';
+ }, 800);
+ }
+ }
+ }
+ };
+
+ this.sizeInfo = {};
+
+ // Format window padding
+ var winPad = this.options.windowPadding;
+ if (typeof winPad === 'number') {
+ this.options.windowPadding = [winPad, winPad, winPad, winPad];
+ }
+
+ // Expose public methods
+ this.val = Selectpicker.prototype.val;
+ this.render = Selectpicker.prototype.render;
+ this.refresh = Selectpicker.prototype.refresh;
+ this.setStyle = Selectpicker.prototype.setStyle;
+ this.selectAll = Selectpicker.prototype.selectAll;
+ this.deselectAll = Selectpicker.prototype.deselectAll;
+ this.destroy = Selectpicker.prototype.destroy;
+ this.remove = Selectpicker.prototype.remove;
+ this.show = Selectpicker.prototype.show;
+ this.hide = Selectpicker.prototype.hide;
+
+ this.init();
+ };
+
+ Selectpicker.VERSION = '1.14.0-beta3';
+
+ // part of this is duplicated in i18n/defaults-en_US.js. Make sure to update both.
+ Selectpicker.DEFAULTS = {
+ noneSelectedText: 'Nothing selected',
+ noneResultsText: 'No results matched {0}',
+ countSelectedText: function (numSelected, numTotal) {
+ return (numSelected == 1) ? '{0} item selected' : '{0} items selected';
+ },
+ maxOptionsText: function (numAll, numGroup) {
+ return [
+ (numAll == 1) ? 'Limit reached ({n} item max)' : 'Limit reached ({n} items max)',
+ (numGroup == 1) ? 'Group limit reached ({n} item max)' : 'Group limit reached ({n} items max)'
+ ];
+ },
+ selectAllText: 'Select All',
+ deselectAllText: 'Deselect All',
+ source: {
+ pageSize: 40
+ },
+ chunkSize: 40,
+ doneButton: false,
+ doneButtonText: 'Close',
+ multipleSeparator: ', ',
+ styleBase: 'btn',
+ style: classNames.BUTTONCLASS,
+ size: 'auto',
+ title: null,
+ placeholder: null,
+ allowClear: false,
+ selectedTextFormat: 'values',
+ width: false,
+ container: false,
+ hideDisabled: false,
+ showSubtext: false,
+ showIcon: true,
+ showContent: true,
+ dropupAuto: true,
+ header: false,
+ liveSearch: false,
+ liveSearchPlaceholder: null,
+ liveSearchNormalize: false,
+ liveSearchStyle: 'contains',
+ actionsBox: false,
+ iconBase: classNames.ICONBASE,
+ tickIcon: classNames.TICKICON,
+ showTick: false,
+ template: {
+ caret: '<span class="caret"></span>'
+ },
+ maxOptions: false,
+ mobile: false,
+ selectOnTab: true,
+ dropdownAlignRight: false,
+ windowPadding: 0,
+ virtualScroll: 600,
+ display: false,
+ sanitize: true,
+ sanitizeFn: null,
+ whiteList: DefaultWhitelist
+ };
+
+ Selectpicker.prototype = {
+
+ constructor: Selectpicker,
+
+ init: function () {
+ var that = this,
+ id = this.$element.attr('id'),
+ element = this.$element[0],
+ form = element.form;
+
+ selectId++;
+ this.selectId = 'bs-select-' + selectId;
+
+ element.classList.add('bs-select-hidden');
+
+ this.multiple = this.$element.prop('multiple');
+ this.autofocus = this.$element.prop('autofocus');
+
+ if (element.classList.contains('show-tick')) {
+ this.options.showTick = true;
+ }
+
+ this.$newElement = this.createDropdown();
+
+ this.$element
+ .after(this.$newElement)
+ .prependTo(this.$newElement);
+
+ // ensure select is associated with form element if it got unlinked after moving it inside newElement
+ if (form && element.form === null) {
+ if (!form.id) form.id = 'form-' + this.selectId;
+ element.setAttribute('form', form.id);
+ }
+
+ this.$button = this.$newElement.children('button');
+ if (this.options.allowClear) this.$clearButton = this.$button.children('.bs-select-clear-selected');
+ this.$menu = this.$newElement.children(Selector.MENU);
+ this.$menuInner = this.$menu.children('.inner');
+ this.$searchbox = this.$menu.find('input');
+
+ element.classList.remove('bs-select-hidden');
+
+ this.fetchData(function () {
+ that.render(true);
+ that.buildList();
+
+ requestAnimationFrame(function () {
+ that.$element.trigger('loaded' + EVENT_KEY);
+ });
+ });
+
+ if (this.options.dropdownAlignRight === true) this.$menu[0].classList.add(classNames.MENURIGHT);
+
+ if (typeof id !== 'undefined') {
+ this.$button.attr('data-id', id);
+ }
+
+ this.checkDisabled();
+ this.clickListener();
+
+ if (version.major > 4) this.dropdown = new Dropdown(this.$button[0]);
+
+ if (this.options.liveSearch) {
+ this.liveSearchListener();
+ this.focusedParent = this.$searchbox[0];
+ } else {
+ this.focusedParent = this.$menuInner[0];
+ }
+
+ this.setStyle();
+ this.setWidth();
+ if (this.options.container) {
+ this.selectPosition();
+ } else {
+ this.$element.on('hide' + EVENT_KEY, function () {
+ if (that.isVirtual()) {
+ // empty menu on close
+ var menuInner = that.$menuInner[0],
+ emptyMenu = menuInner.firstChild.cloneNode(false);
+
+ // replace the existing UL with an empty one - this is faster than $.empty() or innerHTML = ''
+ menuInner.replaceChild(emptyMenu, menuInner.firstChild);
+ menuInner.scrollTop = 0;
+ }
+ });
+ }
+ this.$menu.data('this', this);
+ this.$newElement.data('this', this);
+ if (this.options.mobile) this.mobile();
+
+ this.$newElement.on({
+ 'hide.bs.dropdown': function (e) {
+ that.$element.trigger('hide' + EVENT_KEY, e);
+ },
+ 'hidden.bs.dropdown': function (e) {
+ that.$element.trigger('hidden' + EVENT_KEY, e);
+ },
+ 'show.bs.dropdown': function (e) {
+ that.$element.trigger('show' + EVENT_KEY, e);
+ },
+ 'shown.bs.dropdown': function (e) {
+ that.$element.trigger('shown' + EVENT_KEY, e);
+ }
+ });
+
+ if (element.hasAttribute('required')) {
+ this.$element.on('invalid' + EVENT_KEY, function () {
+ that.$button[0].classList.add('bs-invalid');
+
+ that.$element
+ .on('shown' + EVENT_KEY + '.invalid', function () {
+ that.$element
+ .val(that.$element.val()) // set the value to hide the validation message in Chrome when menu is opened
+ .off('shown' + EVENT_KEY + '.invalid');
+ })
+ .on('rendered' + EVENT_KEY, function () {
+ // if select is no longer invalid, remove the bs-invalid class
+ if (this.validity.valid) that.$button[0].classList.remove('bs-invalid');
+ that.$element.off('rendered' + EVENT_KEY);
+ });
+
+ that.$button.on('blur' + EVENT_KEY, function () {
+ that.$element.trigger('focus').trigger('blur');
+ that.$button.off('blur' + EVENT_KEY);
+ });
+ });
+ }
+
+ if (form) {
+ $(form).on('reset' + EVENT_KEY, function () {
+ requestAnimationFrame(function () {
+ that.render();
+ });
+ });
+ }
+ },
+
+ createDropdown: function () {
+ // Options
+ // If we are multiple or showTick option is set, then add the show-tick class
+ var showTick = (this.multiple || this.options.showTick) ? ' show-tick' : '',
+ multiselectable = this.multiple ? ' aria-multiselectable="true"' : '',
+ inputGroup = '',
+ autofocus = this.autofocus ? ' autofocus' : '';
+
+ if (version.major < 4 && this.$element.parent().hasClass('input-group')) {
+ inputGroup = ' input-group-btn';
+ }
+
+ // Elements
+ var drop,
+ header = '',
+ searchbox = '',
+ actionsbox = '',
+ donebutton = '',
+ clearButton = '';
+
+ if (this.options.header) {
+ header =
+ '<div class="' + classNames.POPOVERHEADER + '">' +
+ '<button type="button" class="close" aria-hidden="true">×</button>' +
+ this.options.header +
+ '</div>';
+ }
+
+ if (this.options.liveSearch) {
+ searchbox =
+ '<div class="bs-searchbox">' +
+ '<input type="search" class="form-control" autocomplete="off"' +
+ (
+ this.options.liveSearchPlaceholder === null ? ''
+ :
+ ' placeholder="' + htmlEscape(this.options.liveSearchPlaceholder) + '"'
+ ) +
+ ' role="combobox" aria-label="Search" aria-controls="' + this.selectId + '" aria-autocomplete="list">' +
+ '</div>';
+ }
+
+ if (this.multiple && this.options.actionsBox) {
+ actionsbox =
+ '<div class="bs-actionsbox">' +
+ '<div class="btn-group btn-group-sm">' +
+ '<button type="button" class="actions-btn bs-select-all btn ' + classNames.BUTTONCLASS + '">' +
+ this.options.selectAllText +
+ '</button>' +
+ '<button type="button" class="actions-btn bs-deselect-all btn ' + classNames.BUTTONCLASS + '">' +
+ this.options.deselectAllText +
+ '</button>' +
+ '</div>' +
+ '</div>';
+ }
+
+ if (this.multiple && this.options.doneButton) {
+ donebutton =
+ '<div class="bs-donebutton">' +
+ '<div class="btn-group">' +
+ '<button type="button" class="btn btn-sm ' + classNames.BUTTONCLASS + '">' +
+ this.options.doneButtonText +
+ '</button>' +
+ '</div>' +
+ '</div>';
+ }
+
+ if (this.options.allowClear) {
+ clearButton = '<span class="close bs-select-clear-selected" title="' + this.options.deselectAllText + '"><span>×</span>';
+ }
+
+ drop =
+ '<div class="dropdown bootstrap-select' + showTick + inputGroup + '">' +
+ '<button type="button" tabindex="-1" class="' +
+ this.options.styleBase +
+ ' dropdown-toggle" ' +
+ (this.options.display === 'static' ? 'data-display="static"' : '') +
+ Selector.DATA_TOGGLE +
+ autofocus +
+ ' role="combobox" aria-owns="' +
+ this.selectId +
+ '" aria-haspopup="listbox" aria-expanded="false">' +
+ '<div class="filter-option">' +
+ '<div class="filter-option-inner">' +
+ '<div class="filter-option-inner-inner"> </div>' +
+ '</div> ' +
+ '</div>' +
+ clearButton +
+ '</span>' +
+ (
+ version.major >= '4' ? ''
+ :
+ '<span class="bs-caret">' +
+ this.options.template.caret +
+ '</span>'
+ ) +
+ '</button>' +
+ '<div class="' + classNames.MENU + ' ' + (version.major >= '4' ? '' : classNames.SHOW) + '">' +
+ header +
+ searchbox +
+ actionsbox +
+ '<div class="inner ' + classNames.SHOW + '" role="listbox" id="' + this.selectId + '" tabindex="-1" ' + multiselectable + '>' +
+ '<ul class="' + classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '') + '" role="presentation">' +
+ '</ul>' +
+ '</div>' +
+ donebutton +
+ '</div>' +
+ '</div>';
+
+ return $(drop);
+ },
+
+ setPositionData: function () {
+ this.selectpicker.view.canHighlight = [];
+ this.selectpicker.view.size = 0;
+ this.selectpicker.view.firstHighlightIndex = false;
+
+ for (var i = 0; i < this.selectpicker.current.data.length; i++) {
+ var li = this.selectpicker.current.data[i],
+ canHighlight = true;
+
+ if (li.type === 'divider') {
+ canHighlight = false;
+ li.height = this.sizeInfo.dividerHeight;
+ } else if (li.type === 'optgroup-label') {
+ canHighlight = false;
+ li.height = this.sizeInfo.dropdownHeaderHeight;
+ } else {
+ li.height = this.sizeInfo.liHeight;
+ }
+
+ if (li.disabled) canHighlight = false;
+
+ this.selectpicker.view.canHighlight.push(canHighlight);
+
+ if (canHighlight) {
+ this.selectpicker.view.size++;
+ li.posinset = this.selectpicker.view.size;
+ if (this.selectpicker.view.firstHighlightIndex === false) this.selectpicker.view.firstHighlightIndex = i;
+ }
+
+ li.position = (i === 0 ? 0 : this.selectpicker.current.data[i - 1].position) + li.height;
+ }
+ },
+
+ isVirtual: function () {
+ return (this.options.virtualScroll !== false) && (this.selectpicker.main.data.length >= this.options.virtualScroll) || this.options.virtualScroll === true;
+ },
+
+ createView: function (isSearching, setSize, refresh) {
+ var that = this,
+ scrollTop = 0;
+
+ this.selectpicker.isSearching = isSearching;
+ this.selectpicker.current = isSearching ? this.selectpicker.search : this.selectpicker.main;
+
+ this.setPositionData();
+
+ if (setSize) {
+ if (refresh) {
+ scrollTop = this.$menuInner[0].scrollTop;
+ } else if (!that.multiple) {
+ var element = that.$element[0],
+ selectedIndex = (element.options[element.selectedIndex] || {}).liIndex;
+
+ if (typeof selectedIndex === 'number' && that.options.size !== false) {
+ var selectedData = that.selectpicker.main.data[selectedIndex],
+ position = selectedData && selectedData.position;
+
+ if (position) {
+ scrollTop = position - ((that.sizeInfo.menuInnerHeight + that.sizeInfo.liHeight) / 2);
+ }
+ }
+ }
+ }
+
+ scroll(scrollTop, true);
+
+ this.$menuInner.off('scroll.createView').on('scroll.createView', function (e, updateValue) {
+ if (!that.noScroll) scroll(this.scrollTop, updateValue);
+ that.noScroll = false;
+ });
+
+ function scroll (scrollTop, init) {
+ var size = that.selectpicker.current.data.length,
+ chunks = [],
+ chunkSize,
+ chunkCount,
+ firstChunk,
+ lastChunk,
+ currentChunk,
+ prevPositions,
+ positionIsDifferent,
+ previousElements,
+ menuIsDifferent = true,
+ isVirtual = that.isVirtual();
+
+ that.selectpicker.view.scrollTop = scrollTop;
+
+ chunkSize = that.options.chunkSize; // number of options in a chunk
+ chunkCount = Math.ceil(size / chunkSize) || 1; // number of chunks
+
+ for (var i = 0; i < chunkCount; i++) {
+ var endOfChunk = (i + 1) * chunkSize;
+
+ if (i === chunkCount - 1) {
+ endOfChunk = size;
+ }
+
+ chunks[i] = [
+ (i) * chunkSize + (!i ? 0 : 1),
+ endOfChunk
+ ];
+
+ if (!size) break;
+
+ if (currentChunk === undefined && scrollTop - 1 <= that.selectpicker.current.data[endOfChunk - 1].position - that.sizeInfo.menuInnerHeight) {
+ currentChunk = i;
+ }
+ }
+
+ if (currentChunk === undefined) currentChunk = 0;
+
+ prevPositions = [that.selectpicker.view.position0, that.selectpicker.view.position1];
+
+ // always display previous, current, and next chunks
+ firstChunk = Math.max(0, currentChunk - 1);
+ lastChunk = Math.min(chunkCount - 1, currentChunk + 1);
+
+ that.selectpicker.view.position0 = isVirtual === false ? 0 : (Math.max(0, chunks[firstChunk][0]) || 0);
+ that.selectpicker.view.position1 = isVirtual === false ? size : (Math.min(size, chunks[lastChunk][1]) || 0);
+
+ positionIsDifferent = prevPositions[0] !== that.selectpicker.view.position0 || prevPositions[1] !== that.selectpicker.view.position1;
+
+ if (that.activeElement !== undefined) {
+ if (init) {
+ if (that.activeElement !== that.selectedElement) {
+ that.defocusItem(that.activeElement);
+ }
+ that.activeElement = undefined;
+ }
+
+ if (that.activeElement !== that.selectedElement) {
+ that.defocusItem(that.selectedElement);
+ }
+ }
+
+ if (that.prevActiveElement !== undefined && that.prevActiveElement !== that.activeElement && that.prevActiveElement !== that.selectedElement) {
+ that.defocusItem(that.prevActiveElement);
+ }
+
+ if (init || positionIsDifferent || that.selectpicker.current.hasMore) {
+ previousElements = that.selectpicker.view.visibleElements ? that.selectpicker.view.visibleElements.slice() : [];
+
+ if (isVirtual === false) {
+ that.selectpicker.view.visibleElements = that.selectpicker.current.elements;
+ } else {
+ that.selectpicker.view.visibleElements = that.selectpicker.current.elements.slice(that.selectpicker.view.position0, that.selectpicker.view.position1);
+ }
+
+ that.setOptionStatus();
+
+ // if searching, check to make sure the list has actually been updated before updating DOM
+ // this prevents unnecessary repaints
+ if (isSearching || (isVirtual === false && init)) menuIsDifferent = !isEqual(previousElements, that.selectpicker.view.visibleElements);
+
+ // if virtual scroll is disabled and not searching,
+ // menu should never need to be updated more than once
+ if ((init || isVirtual === true) && menuIsDifferent) {
+ var menuInner = that.$menuInner[0],
+ menuFragment = document.createDocumentFragment(),
+ emptyMenu = menuInner.firstChild.cloneNode(false),
+ marginTop,
+ marginBottom,
+ elements = that.selectpicker.view.visibleElements,
+ toSanitize = [];
+
+ // replace the existing UL with an empty one - this is faster than $.empty()
+ menuInner.replaceChild(emptyMenu, menuInner.firstChild);
+
+ for (var i = 0, visibleElementsLen = elements.length; i < visibleElementsLen; i++) {
+ var element = elements[i],
+ elText,
+ elementData;
+
+ if (that.options.sanitize) {
+ elText = element.lastChild;
+
+ if (elText) {
+ elementData = that.selectpicker.current.data[i + that.selectpicker.view.position0];
+
+ if (elementData && elementData.content && !elementData.sanitized) {
+ toSanitize.push(elText);
+ elementData.sanitized = true;
+ }
+ }
+ }
+
+ menuFragment.appendChild(element);
+ }
+
+ if (that.options.sanitize && toSanitize.length) {
+ sanitizeHtml(toSanitize, that.options.whiteList, that.options.sanitizeFn);
+ }
+
+ if (isVirtual === true) {
+ marginTop = (that.selectpicker.view.position0 === 0 ? 0 : that.selectpicker.current.data[that.selectpicker.view.position0 - 1].position);
+ marginBottom = (that.selectpicker.view.position1 > size - 1 ? 0 : that.selectpicker.current.data[size - 1].position - that.selectpicker.current.data[that.selectpicker.view.position1 - 1].position);
+
+ menuInner.firstChild.style.marginTop = marginTop + 'px';
+ menuInner.firstChild.style.marginBottom = marginBottom + 'px';
+ } else {
+ menuInner.firstChild.style.marginTop = 0;
+ menuInner.firstChild.style.marginBottom = 0;
+ }
+
+ menuInner.firstChild.appendChild(menuFragment);
+
+ // if an option is encountered that is wider than the current menu width, update the menu width accordingly
+ // switch to ResizeObserver with increased browser support
+ if (isVirtual === true && that.sizeInfo.hasScrollBar) {
+ var menuInnerInnerWidth = menuInner.firstChild.offsetWidth;
+
+ if (init && menuInnerInnerWidth < that.sizeInfo.menuInnerInnerWidth && that.sizeInfo.totalMenuWidth > that.sizeInfo.selectWidth) {
+ menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
+ } else if (menuInnerInnerWidth > that.sizeInfo.menuInnerInnerWidth) {
+ // set to 0 to get actual width of menu
+ that.$menu[0].style.minWidth = 0;
+
+ var actualMenuWidth = menuInner.firstChild.offsetWidth;
+
+ if (actualMenuWidth > that.sizeInfo.menuInnerInnerWidth) {
+ that.sizeInfo.menuInnerInnerWidth = actualMenuWidth;
+ menuInner.firstChild.style.minWidth = that.sizeInfo.menuInnerInnerWidth + 'px';
+ }
+
+ // reset to default CSS styling
+ that.$menu[0].style.minWidth = '';
+ }
+ }
+ }
+
+ if ((!isSearching && that.options.source.data || isSearching && that.options.source.search) && that.selectpicker.current.hasMore && currentChunk === chunkCount - 1) {
+ // Don't load the next chunk until scrolling has started
+ // This prevents unnecessary requests while the user is typing if pageSize is <= chunkSize
+ if (scrollTop > 0) {
+ // Chunks use 0-based indexing, but pages use 1-based. Add 1 to convert and add 1 again to get next page
+ var page = Math.floor((currentChunk * that.options.chunkSize) / that.options.source.pageSize) + 2;
+
+ that.fetchData(function () {
+ that.render();
+ that.buildList(size, isSearching);
+ that.setPositionData();
+ scroll(scrollTop);
+ }, isSearching ? 'search' : 'data', page, isSearching ? that.selectpicker.search.previousValue : undefined);
+ }
+ }
+ }
+
+ that.prevActiveElement = that.activeElement;
+
+ if (!that.options.liveSearch) {
+ that.$menuInner.trigger('focus');
+ } else if (isSearching && init) {
+ var index = 0,
+ newActive;
+
+ if (!that.selectpicker.view.canHighlight[index]) {
+ index = 1 + that.selectpicker.view.canHighlight.slice(1).indexOf(true);
+ }
+
+ newActive = that.selectpicker.view.visibleElements[index];
+
+ that.defocusItem(that.selectpicker.view.currentActive);
+
+ that.activeElement = (that.selectpicker.current.data[index] || {}).element;
+
+ that.focusItem(newActive);
+ }
+ }
+
+ $(window)
+ .off('resize' + EVENT_KEY + '.' + this.selectId + '.createView')
+ .on('resize' + EVENT_KEY + '.' + this.selectId + '.createView', function () {
+ var isActive = that.$newElement.hasClass(classNames.SHOW);
+
+ if (isActive) scroll(that.$menuInner[0].scrollTop);
+ });
+ },
+
+ focusItem: function (li, liData, noStyle) {
+ if (li) {
+ liData = liData || this.selectpicker.current.data[this.selectpicker.current.elements.indexOf(this.activeElement)];
+ var a = li.firstChild;
+
+ if (a) {
+ a.setAttribute('aria-setsize', this.selectpicker.view.size);
+ a.setAttribute('aria-posinset', liData.posinset);
+
+ if (noStyle !== true) {
+ this.focusedParent.setAttribute('aria-activedescendant', a.id);
+ li.classList.add('active');
+ a.classList.add('active');
+ }
+ }
+ }
+ },
+
+ defocusItem: function (li) {
+ if (li) {
+ li.classList.remove('active');
+ if (li.firstChild) li.firstChild.classList.remove('active');
+ }
+ },
+
+ setPlaceholder: function () {
+ var that = this,
+ updateIndex = false;
+
+ if ((this.options.placeholder || this.options.allowClear) && !this.multiple) {
+ if (!this.selectpicker.view.titleOption) this.selectpicker.view.titleOption = document.createElement('option');
+
+ // this option doesn't create a new <li> element, but does add a new option at the start,
+ // so startIndex should increase to prevent having to check every option for the bs-title-option class
+ updateIndex = true;
+
+ var element = this.$element[0],
+ selectTitleOption = false,
+ titleNotAppended = !this.selectpicker.view.titleOption.parentNode,
+ selectedIndex = element.selectedIndex,
+ selectedOption = element.options[selectedIndex],
+ firstSelectable = element.querySelector('select > *:not(:disabled)'),
+ firstSelectableIndex = firstSelectable ? firstSelectable.index : 0,
+ navigation = window.performance && window.performance.getEntriesByType('navigation'),
+ // Safari doesn't support getEntriesByType('navigation') - fall back to performance.navigation
+ isNotBackForward = (navigation && navigation.length) ? navigation[0].type !== 'back_forward' : window.performance.navigation.type !== 2;
+
+ if (titleNotAppended) {
+ // Use native JS to prepend option (faster)
+ this.selectpicker.view.titleOption.className = 'bs-title-option';
+ this.selectpicker.view.titleOption.value = '';
+
+ // Check if selected or data-selected attribute is already set on an option. If not, select the titleOption option.
+ // the selected item may have been changed by user or programmatically before the bootstrap select plugin runs,
+ // if so, the select will have the data-selected attribute
+ selectTitleOption = !selectedOption || (selectedIndex === firstSelectableIndex && selectedOption.defaultSelected === false && this.$element.data('selected') === undefined);
+ }
+
+ if (titleNotAppended || this.selectpicker.view.titleOption.index !== 0) {
+ element.insertBefore(this.selectpicker.view.titleOption, element.firstChild);
+ }
+
+ // Set selected *after* appending to select,
+ // otherwise the option doesn't get selected in IE
+ // set using selectedIndex, as setting the selected attr to true here doesn't work in IE11
+ if (selectTitleOption && isNotBackForward) {
+ element.selectedIndex = 0;
+ } else if (document.readyState !== 'complete') {
+ // if navigation type is back_forward, there's a chance the select will have its value set by BFCache
+ // wait for that value to be set, then run render again
+ window.addEventListener('pageshow', function () {
+ if (that.selectpicker.view.displayedValue !== element.value) that.render();
+ });
+ }
+ }
+
+ return updateIndex;
+ },
+
+ fetchData: function (callback, type, page, searchValue) {
+ page = page || 1;
+ type = type || 'data';
+
+ var that = this,
+ data = this.options.source[type],
+ builtData;
+
+ if (data) {
+ this.options.virtualScroll = true;
+
+ if (typeof data === 'function') {
+ data.call(
+ this,
+ function (data, more, totalItems) {
+ var current = that.selectpicker[type === 'search' ? 'search' : 'main'];
+ current.hasMore = more;
+ current.totalItems = totalItems;
+ builtData = that.buildData(data, type);
+ callback.call(that, builtData);
+ that.$element.trigger('fetched' + EVENT_KEY);
+ },
+ page,
+ searchValue
+ );
+ } else if (Array.isArray(data)) {
+ builtData = that.buildData(data, type);
+ callback.call(that, builtData);
+ }
+ } else {
+ builtData = this.buildData(false, type);
+ callback.call(that, builtData);
+ }
+ },
+
+ buildData: function (data, type) {
+ var that = this;
+ var dataGetter = data === false ? getOptionData.fromOption : getOptionData.fromDataSource;
+
+ var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([style*="display: none"])',
+ mainData = [],
+ startLen = this.selectpicker.main.data ? this.selectpicker.main.data.length : 0,
+ optID = 0,
+ startIndex = this.setPlaceholder() && !data ? 1 : 0; // append the titleOption if necessary and skip the first option in the loop
+
+ if (type === 'search') {
+ startLen = this.selectpicker.search.data.length;
+ }
+
+ if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
+
+ var selectOptions = data ? data.filter(filterHidden, this) : this.$element[0].querySelectorAll('select > *' + optionSelector);
+
+ function addDivider (config) {
+ var previousData = mainData[mainData.length - 1];
+
+ // ensure optgroup doesn't create back-to-back dividers
+ if (
+ previousData &&
+ previousData.type === 'divider' &&
+ (previousData.optID || config.optID)
+ ) {
+ return;
+ }
+
+ config = config || {};
+ config.type = 'divider';
+
+ mainData.push(config);
+ }
+
+ function addOption (item, config) {
+ config = config || {};
+
+ config.divider = dataGetter(item, 'divider');
+
+ if (config.divider === true) {
+ addDivider({
+ optID: config.optID
+ });
+ } else {
+ var liIndex = mainData.length + startLen,
+ cssText = dataGetter(item, 'style'),
+ inlineStyle = cssText ? htmlEscape(cssText) : '',
+ optionClass = (item.className || '') + (config.optgroupClass || '');
+
+ if (config.optID) optionClass = 'opt ' + optionClass;
+
+ config.optionClass = optionClass.trim();
+ config.inlineStyle = inlineStyle;
+
+ config.text = dataGetter(item, 'text');
+ config.title = dataGetter(item, 'title');
+ config.content = dataGetter(item, 'content');
+ config.tokens = dataGetter(item, 'tokens');
+ config.subtext = dataGetter(item, 'subtext');
+ config.icon = dataGetter(item, 'icon');
+
+ config.display = config.content || config.text;
+ config.value = item.value === undefined ? item.text : item.value;
+ config.type = 'option';
+ config.index = liIndex;
+
+ config.option = !item.option ? item : item.option; // reference option element if it exists
+ config.option.liIndex = liIndex;
+ config.selected = !!item.selected;
+ config.disabled = config.disabled || !!item.disabled;
+
+ if (data !== false) {
+ if (that.selectpicker.optionValuesDataMap[config.value]) {
+ config = $.extend(that.selectpicker.optionValuesDataMap[config.value], config);
+ } else {
+ that.selectpicker.optionValuesDataMap[config.value] = config;
+ }
+ }
+
+ mainData.push(config);
+ }
+ }
+
+ function addOptgroup (index, selectOptions) {
+ var optgroup = selectOptions[index],
+ // skip placeholder option
+ previous = index - 1 < startIndex ? false : selectOptions[index - 1],
+ next = selectOptions[index + 1],
+ options = data ? optgroup.children.filter(filterHidden, this) : optgroup.querySelectorAll('option' + optionSelector);
+
+ if (!options.length) return;
+
+ var config = {
+ display: htmlEscape(dataGetter(item, 'label')),
+ subtext: dataGetter(optgroup, 'subtext'),
+ icon: dataGetter(optgroup, 'icon'),
+ type: 'optgroup-label',
+ optgroupClass: ' ' + (optgroup.className || ''),
+ optgroup: optgroup
+ },
+ headerIndex,
+ lastIndex;
+
+ optID++;
+
+ if (previous) {
+ addDivider({ optID: optID });
+ }
+
+ config.optID = optID;
+
+ mainData.push(config);
+
+ for (var j = 0, len = options.length; j < len; j++) {
+ var option = options[j];
+
+ if (j === 0) {
+ headerIndex = mainData.length - 1;
+ lastIndex = headerIndex + len;
+ }
+
+ addOption(option, {
+ headerIndex: headerIndex,
+ lastIndex: lastIndex,
+ optID: config.optID,
+ optgroupClass: config.optgroupClass,
+ disabled: optgroup.disabled
+ });
+ }
+
+ if (next) {
+ addDivider({ optID: optID });
+ }
+ }
+
+ for (var len = selectOptions.length, i = startIndex; i < len; i++) {
+ var item = selectOptions[i],
+ children = item.children;
+
+ if (children && children.length) {
+ addOptgroup.call(this, i, selectOptions);
+ } else {
+ addOption.call(this, item, {});
+ }
+ }
+
+ switch (type) {
+ case 'data': {
+ if (!this.selectpicker.main.data) {
+ this.selectpicker.main.data = [];
+ }
+ Array.prototype.push.apply(this.selectpicker.main.data, mainData);
+ this.selectpicker.current.data = this.selectpicker.main.data;
+ break;
+ }
+ case 'search': {
+ Array.prototype.push.apply(this.selectpicker.search.data, mainData);
+ break;
+ }
+ }
+
+ return mainData;
+ },
+
+ buildList: function (size, searching) {
+ var that = this,
+ selectData = searching ? this.selectpicker.search.data : this.selectpicker.main.data,
+ mainElements = [],
+ widestOptionLength = 0;
+
+ if ((that.options.showTick || that.multiple) && !elementTemplates.checkMark.parentNode) {
+ elementTemplates.checkMark.className = this.options.iconBase + ' ' + that.options.tickIcon + ' check-mark';
+ elementTemplates.a.appendChild(elementTemplates.checkMark);
+ }
+
+ function buildElement (mainElements, item) {
+ var liElement,
+ combinedLength = 0;
+
+ switch (item.type) {
+ case 'divider':
+ liElement = generateOption.li(
+ false,
+ classNames.DIVIDER,
+ (item.optID ? item.optID + 'div' : undefined)
+ );
+
+ break;
+
+ case 'option':
+ liElement = generateOption.li(
+ generateOption.a(
+ generateOption.text.call(that, item),
+ item.optionClass,
+ item.inlineStyle
+ ),
+ '',
+ item.optID
+ );
+
+ if (liElement.firstChild) {
+ liElement.firstChild.id = that.selectId + '-' + item.index;
+ }
+
+ break;
+
+ case 'optgroup-label':
+ liElement = generateOption.li(
+ generateOption.label.call(that, item),
+ 'dropdown-header' + item.optgroupClass,
+ item.optID
+ );
+
+ break;
+ }
+
+ if (!item.element) {
+ item.element = liElement;
+ } else {
+ item.element.innerHTML = liElement.innerHTML;
+ }
+ mainElements.push(item.element);
+
+ // count the number of characters in the option - not perfect, but should work in most cases
+ if (item.display) combinedLength += item.display.length;
+ if (item.subtext) combinedLength += item.subtext.length;
+ // if there is an icon, ensure this option's width is checked
+ if (item.icon) combinedLength += 1;
+
+ if (combinedLength > widestOptionLength) {
+ widestOptionLength = combinedLength;
+
+ // guess which option is the widest
+ // use this when calculating menu width
+ // not perfect, but it's fast, and the width will be updating accordingly when scrolling
+ that.selectpicker.view.widestOption = mainElements[mainElements.length - 1];
+ }
+ }
+
+ var startIndex = size || 0;
+
+ for (var len = selectData.length, i = startIndex; i < len; i++) {
+ var item = selectData[i];
+
+ buildElement(mainElements, item);
+ }
+
+ if (size) {
+ if (searching) {
+ Array.prototype.push.apply(this.selectpicker.search.elements, mainElements);
+ } else {
+ Array.prototype.push.apply(this.selectpicker.main.elements, mainElements);
+ this.selectpicker.current.elements = this.selectpicker.main.elements;
+ }
+ } else {
+ if (searching) {
+ this.selectpicker.search.elements = mainElements;
+ } else {
+ this.selectpicker.main.elements = this.selectpicker.current.elements = mainElements;
+ }
+ }
+ },
+
+ findLis: function () {
+ return this.$menuInner.find('.inner > li');
+ },
+
+ render: function (init) {
+ var that = this,
+ element = this.$element[0],
+ // ensure titleOption is appended and selected (if necessary) before getting selectedOptions
+ placeholderSelected = this.setPlaceholder() && element.selectedIndex === 0,
+ selectedOptions = getSelectedOptions.call(this),
+ selectedCount = selectedOptions.length,
+ selectedValues = getSelectValues.call(this, selectedOptions),
+ button = this.$button[0],
+ buttonInner = button.querySelector('.filter-option-inner-inner'),
+ multipleSeparator = document.createTextNode(this.options.multipleSeparator),
+ titleFragment = elementTemplates.fragment.cloneNode(false),
+ showCount,
+ countMax,
+ hasContent = false;
+
+ function createSelected (item) {
+ if (item.selected) {
+ that.createOption(item, true);
+ } else if (item.children && item.children.length) {
+ item.children.map(createSelected);
+ }
+ }
+
+ // create selected option elements to ensure select value is correct
+ if (this.options.source.data && init) {
+ selectedOptions.map(createSelected);
+ element.appendChild(this.selectpicker.main.optionQueue);
+
+ if (placeholderSelected) placeholderSelected = element.selectedIndex === 0;
+ }
+
+ button.classList.toggle('bs-placeholder', that.multiple ? !selectedCount : !selectedValues && selectedValues !== 0);
+
+ if (!that.multiple && selectedOptions.length === 1) {
+ that.selectpicker.view.displayedValue = selectedValues;
+ }
+
+ if (this.options.selectedTextFormat === 'static') {
+ titleFragment = generateOption.text.call(this, { text: this.options.placeholder }, true);
+ } else {
+ showCount = this.multiple && this.options.selectedTextFormat.indexOf('count') !== -1 && selectedCount > 0;
+
+ // determine if the number of selected options will be shown (showCount === true)
+ if (showCount) {
+ countMax = this.options.selectedTextFormat.split('>');
+ showCount = (countMax.length > 1 && selectedCount > countMax[1]) || (countMax.length === 1 && selectedCount >= 2);
+ }
+
+ // only loop through all selected options if the count won't be shown
+ if (showCount === false) {
+ if (!placeholderSelected) {
+ for (var selectedIndex = 0; selectedIndex < selectedCount; selectedIndex++) {
+ if (selectedIndex < 50) {
+ var option = selectedOptions[selectedIndex],
+ titleOptions = {};
+
+ if (option) {
+ if (this.multiple && selectedIndex > 0) {
+ titleFragment.appendChild(multipleSeparator.cloneNode(false));
+ }
+
+ if (option.title) {
+ titleOptions.text = option.title;
+ } else if (option.content && that.options.showContent) {
+ titleOptions.content = option.content.toString();
+ hasContent = true;
+ } else {
+ if (that.options.showIcon) {
+ titleOptions.icon = option.icon;
+ }
+ if (that.options.showSubtext && !that.multiple && option.subtext) titleOptions.subtext = ' ' + option.subtext;
+ titleOptions.text = option.text.trim();
+ }
+
+ titleFragment.appendChild(generateOption.text.call(this, titleOptions, true));
+ }
+ } else {
+ break;
+ }
+ }
+
+ // add ellipsis
+ if (selectedCount > 49) {
+ titleFragment.appendChild(document.createTextNode('...'));
+ }
+ }
+ } else {
+ var optionSelector = ':not([hidden]):not([data-hidden="true"]):not([data-divider="true"]):not([style*="display: none"])';
+ if (this.options.hideDisabled) optionSelector += ':not(:disabled)';
+
+ // If this is a multiselect, and selectedTextFormat is count, then show 1 of 2 selected, etc.
+ var totalCount = this.$element[0].querySelectorAll('select > option' + optionSelector + ', optgroup' + optionSelector + ' option' + optionSelector).length,
+ tr8nText = (typeof this.options.countSelectedText === 'function') ? this.options.countSelectedText(selectedCount, totalCount) : this.options.countSelectedText;
+
+ titleFragment = generateOption.text.call(this, {
+ text: tr8nText.replace('{0}', selectedCount.toString()).replace('{1}', totalCount.toString())
+ }, true);
+ }
+ }
+
+ // If the select doesn't have a title, then use the default, or if nothing is set at all, use noneSelectedText
+ if (!titleFragment.childNodes.length) {
+ titleFragment = generateOption.text.call(this, {
+ text: this.options.placeholder ? this.options.placeholder : this.options.noneSelectedText
+ }, true);
+ }
+
+ // if the select has a title, apply it to the button, and if not, apply titleFragment text
+ // strip all HTML tags and trim the result, then unescape any escaped tags
+ button.title = titleFragment.textContent.replace(/<[^>]*>?/g, '').trim();
+
+ if (this.options.sanitize && hasContent) {
+ sanitizeHtml([titleFragment], that.options.whiteList, that.options.sanitizeFn);
+ }
+
+ buttonInner.innerHTML = '';
+ buttonInner.appendChild(titleFragment);
+
+ if (version.major < 4 && this.$newElement[0].classList.contains('bs3-has-addon')) {
+ var filterExpand = button.querySelector('.filter-expand'),
+ clone = buttonInner.cloneNode(true);
+
+ clone.className = 'filter-expand';
+
+ if (filterExpand) {
+ button.replaceChild(clone, filterExpand);
+ } else {
+ button.appendChild(clone);
+ }
+ }
+
+ this.$element.trigger('rendered' + EVENT_KEY);
+ },
+
+ /**
+ * @param [style]
+ * @param [status]
+ */
+ setStyle: function (newStyle, status) {
+ var button = this.$button[0],
+ newElement = this.$newElement[0],
+ style = this.options.style.trim(),
+ buttonClass;
+
+ if (this.$element.attr('class')) {
+ this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi, ''));
+ }
+
+ if (version.major < 4) {
+ newElement.classList.add('bs3');
+
+ if (newElement.parentNode.classList && newElement.parentNode.classList.contains('input-group') &&
+ (newElement.previousElementSibling || newElement.nextElementSibling) &&
+ (newElement.previousElementSibling || newElement.nextElementSibling).classList.contains('input-group-addon')
+ ) {
+ newElement.classList.add('bs3-has-addon');
+ }
+ }
+
+ if (newStyle) {
+ buttonClass = newStyle.trim();
+ } else {
+ buttonClass = style;
+ }
+
+ if (status == 'add') {
+ if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
+ } else if (status == 'remove') {
+ if (buttonClass) button.classList.remove.apply(button.classList, buttonClass.split(' '));
+ } else {
+ if (style) button.classList.remove.apply(button.classList, style.split(' '));
+ if (buttonClass) button.classList.add.apply(button.classList, buttonClass.split(' '));
+ }
+ },
+
+ liHeight: function (refresh) {
+ if (!refresh && (this.options.size === false || Object.keys(this.sizeInfo).length)) return;
+
+ var newElement = elementTemplates.div.cloneNode(false),
+ menu = elementTemplates.div.cloneNode(false),
+ menuInner = elementTemplates.div.cloneNode(false),
+ menuInnerInner = document.createElement('ul'),
+ divider = elementTemplates.li.cloneNode(false),
+ dropdownHeader = elementTemplates.li.cloneNode(false),
+ li,
+ a = elementTemplates.a.cloneNode(false),
+ text = elementTemplates.span.cloneNode(false),
+ header = this.options.header && this.$menu.find('.' + classNames.POPOVERHEADER).length > 0 ? this.$menu.find('.' + classNames.POPOVERHEADER)[0].cloneNode(true) : null,
+ search = this.options.liveSearch ? elementTemplates.div.cloneNode(false) : null,
+ actions = this.options.actionsBox && this.multiple && this.$menu.find('.bs-actionsbox').length > 0 ? this.$menu.find('.bs-actionsbox')[0].cloneNode(true) : null,
+ doneButton = this.options.doneButton && this.multiple && this.$menu.find('.bs-donebutton').length > 0 ? this.$menu.find('.bs-donebutton')[0].cloneNode(true) : null,
+ firstOption = this.$element[0].options[0];
+
+ this.sizeInfo.selectWidth = this.$newElement[0].offsetWidth;
+
+ text.className = 'text';
+ a.className = 'dropdown-item ' + (firstOption ? firstOption.className : '');
+ newElement.className = this.$menu[0].parentNode.className + ' ' + classNames.SHOW;
+ newElement.style.width = 0; // ensure button width doesn't affect natural width of menu when calculating
+ if (this.options.width === 'auto') menu.style.minWidth = 0;
+ menu.className = classNames.MENU + ' ' + classNames.SHOW;
+ menuInner.className = 'inner ' + classNames.SHOW;
+ menuInnerInner.className = classNames.MENU + ' inner ' + (version.major >= '4' ? classNames.SHOW : '');
+ divider.className = classNames.DIVIDER;
+ dropdownHeader.className = 'dropdown-header';
+
+ text.appendChild(document.createTextNode('\u200b'));
+
+ if (this.selectpicker.current.data.length) {
+ for (var i = 0; i < this.selectpicker.current.data.length; i++) {
+ var data = this.selectpicker.current.data[i];
+ if (data.type === 'option' && $(data.element.firstChild).css('display') !== 'none') {
+ li = data.element;
+ break;
+ }
+ }
+ } else {
+ li = elementTemplates.li.cloneNode(false);
+ a.appendChild(text);
+ li.appendChild(a);
+ }
+
+ dropdownHeader.appendChild(text.cloneNode(true));
+
+ if (this.selectpicker.view.widestOption) {
+ menuInnerInner.appendChild(this.selectpicker.view.widestOption.cloneNode(true));
+ }
+
+ menuInnerInner.appendChild(li);
+ menuInnerInner.appendChild(divider);
+ menuInnerInner.appendChild(dropdownHeader);
+ if (header) menu.appendChild(header);
+ if (search) {
+ var input = document.createElement('input');
+ search.className = 'bs-searchbox';
+ input.className = 'form-control';
+ search.appendChild(input);
+ menu.appendChild(search);
+ }
+ if (actions) menu.appendChild(actions);
+ menuInner.appendChild(menuInnerInner);
+ menu.appendChild(menuInner);
+ if (doneButton) menu.appendChild(doneButton);
+ newElement.appendChild(menu);
+
+ document.body.appendChild(newElement);
+
+ var liHeight = li.offsetHeight,
+ dropdownHeaderHeight = dropdownHeader ? dropdownHeader.offsetHeight : 0,
+ headerHeight = header ? header.offsetHeight : 0,
+ searchHeight = search ? search.offsetHeight : 0,
+ actionsHeight = actions ? actions.offsetHeight : 0,
+ doneButtonHeight = doneButton ? doneButton.offsetHeight : 0,
+ dividerHeight = $(divider).outerHeight(true),
+ menuStyle = window.getComputedStyle(menu),
+ menuWidth = menu.offsetWidth,
+ menuPadding = {
+ vert: toInteger(menuStyle.paddingTop) +
+ toInteger(menuStyle.paddingBottom) +
+ toInteger(menuStyle.borderTopWidth) +
+ toInteger(menuStyle.borderBottomWidth),
+ horiz: toInteger(menuStyle.paddingLeft) +
+ toInteger(menuStyle.paddingRight) +
+ toInteger(menuStyle.borderLeftWidth) +
+ toInteger(menuStyle.borderRightWidth)
+ },
+ menuExtras = {
+ vert: menuPadding.vert +
+ toInteger(menuStyle.marginTop) +
+ toInteger(menuStyle.marginBottom) + 2,
+ horiz: menuPadding.horiz +
+ toInteger(menuStyle.marginLeft) +
+ toInteger(menuStyle.marginRight) + 2
+ },
+ scrollBarWidth;
+
+ menuInner.style.overflowY = 'scroll';
+
+ scrollBarWidth = menu.offsetWidth - menuWidth;
+
+ document.body.removeChild(newElement);
+
+ this.sizeInfo.liHeight = liHeight;
+ this.sizeInfo.dropdownHeaderHeight = dropdownHeaderHeight;
+ this.sizeInfo.headerHeight = headerHeight;
+ this.sizeInfo.searchHeight = searchHeight;
+ this.sizeInfo.actionsHeight = actionsHeight;
+ this.sizeInfo.doneButtonHeight = doneButtonHeight;
+ this.sizeInfo.dividerHeight = dividerHeight;
+ this.sizeInfo.menuPadding = menuPadding;
+ this.sizeInfo.menuExtras = menuExtras;
+ this.sizeInfo.menuWidth = menuWidth;
+ this.sizeInfo.menuInnerInnerWidth = menuWidth - menuPadding.horiz;
+ this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth;
+ this.sizeInfo.scrollBarWidth = scrollBarWidth;
+ this.sizeInfo.selectHeight = this.$newElement[0].offsetHeight;
+
+ this.setPositionData();
+ },
+
+ getSelectPosition: function () {
+ var that = this,
+ $window = $(window),
+ pos = that.$newElement.offset(),
+ $container = $(that.options.container),
+ containerPos;
+
+ if (that.options.container && $container.length && !$container.is('body')) {
+ containerPos = $container.offset();
+ containerPos.top += parseInt($container.css('borderTopWidth'));
+ containerPos.left += parseInt($container.css('borderLeftWidth'));
+ } else {
+ containerPos = { top: 0, left: 0 };
+ }
+
+ var winPad = that.options.windowPadding;
+
+ this.sizeInfo.selectOffsetTop = pos.top - containerPos.top - $window.scrollTop();
+ this.sizeInfo.selectOffsetBot = $window.height() - this.sizeInfo.selectOffsetTop - this.sizeInfo.selectHeight - containerPos.top - winPad[2];
+ this.sizeInfo.selectOffsetLeft = pos.left - containerPos.left - $window.scrollLeft();
+ this.sizeInfo.selectOffsetRight = $window.width() - this.sizeInfo.selectOffsetLeft - this.sizeInfo.selectWidth - containerPos.left - winPad[1];
+ this.sizeInfo.selectOffsetTop -= winPad[0];
+ this.sizeInfo.selectOffsetLeft -= winPad[3];
+ },
+
+ setMenuSize: function (isAuto) {
+ this.getSelectPosition();
+
+ var selectWidth = this.sizeInfo.selectWidth,
+ liHeight = this.sizeInfo.liHeight,
+ headerHeight = this.sizeInfo.headerHeight,
+ searchHeight = this.sizeInfo.searchHeight,
+ actionsHeight = this.sizeInfo.actionsHeight,
+ doneButtonHeight = this.sizeInfo.doneButtonHeight,
+ divHeight = this.sizeInfo.dividerHeight,
+ menuPadding = this.sizeInfo.menuPadding,
+ menuInnerHeight,
+ menuHeight,
+ divLength = 0,
+ minHeight,
+ _minHeight,
+ maxHeight,
+ menuInnerMinHeight,
+ estimate,
+ isDropup;
+
+ if (this.options.dropupAuto) {
+ // Get the estimated height of the menu without scrollbars.
+ // This is useful for smaller menus, where there might be plenty of room
+ // below the button without setting dropup, but we can't know
+ // the exact height of the menu until createView is called later
+ estimate = liHeight * this.selectpicker.current.data.length + menuPadding.vert;
+
+ isDropup = this.sizeInfo.selectOffsetTop - this.sizeInfo.selectOffsetBot > this.sizeInfo.menuExtras.vert && estimate + this.sizeInfo.menuExtras.vert + 50 > this.sizeInfo.selectOffsetBot;
+
+ // ensure dropup doesn't change while searching (so menu doesn't bounce back and forth)
+ if (this.selectpicker.isSearching === true) {
+ isDropup = this.selectpicker.dropup;
+ }
+
+ this.$newElement.toggleClass(classNames.DROPUP, isDropup);
+ this.selectpicker.dropup = isDropup;
+ }
+
+ if (this.options.size === 'auto') {
+ _minHeight = this.selectpicker.current.data.length > 3 ? this.sizeInfo.liHeight * 3 + this.sizeInfo.menuExtras.vert - 2 : 0;
+ menuHeight = this.sizeInfo.selectOffsetBot - this.sizeInfo.menuExtras.vert;
+ minHeight = _minHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
+ menuInnerMinHeight = Math.max(_minHeight - menuPadding.vert, 0);
+
+ if (this.$newElement.hasClass(classNames.DROPUP)) {
+ menuHeight = this.sizeInfo.selectOffsetTop - this.sizeInfo.menuExtras.vert;
+ }
+
+ maxHeight = menuHeight;
+ menuInnerHeight = menuHeight - headerHeight - searchHeight - actionsHeight - doneButtonHeight - menuPadding.vert;
+ } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
+ for (var i = 0; i < this.options.size; i++) {
+ if (this.selectpicker.current.data[i].type === 'divider') divLength++;
+ }
+
+ menuHeight = liHeight * this.options.size + divLength * divHeight + menuPadding.vert;
+ menuInnerHeight = menuHeight - menuPadding.vert;
+ maxHeight = menuHeight + headerHeight + searchHeight + actionsHeight + doneButtonHeight;
+ minHeight = menuInnerMinHeight = '';
+ }
+
+ this.$menu.css({
+ 'max-height': maxHeight + 'px',
+ 'overflow': 'hidden',
+ 'min-height': minHeight + 'px'
+ });
+
+ this.$menuInner.css({
+ 'max-height': menuInnerHeight + 'px',
+ 'overflow': 'hidden auto',
+ 'min-height': menuInnerMinHeight + 'px'
+ });
+
+ // ensure menuInnerHeight is always a positive number to prevent issues calculating chunkSize in createView
+ this.sizeInfo.menuInnerHeight = Math.max(menuInnerHeight, 1);
+
+ if (this.selectpicker.current.data.length && this.selectpicker.current.data[this.selectpicker.current.data.length - 1].position > this.sizeInfo.menuInnerHeight) {
+ this.sizeInfo.hasScrollBar = true;
+ this.sizeInfo.totalMenuWidth = this.sizeInfo.menuWidth + this.sizeInfo.scrollBarWidth;
+ }
+
+ if (this.options.dropdownAlignRight === 'auto') {
+ this.$menu.toggleClass(classNames.MENURIGHT, this.sizeInfo.selectOffsetLeft > this.sizeInfo.selectOffsetRight && this.sizeInfo.selectOffsetRight < (this.sizeInfo.totalMenuWidth - selectWidth));
+ }
+
+ if (this.dropdown && this.dropdown._popper) this.dropdown._popper.update();
+ },
+
+ setSize: function (refresh) {
+ this.liHeight(refresh);
+
+ if (this.options.header) this.$menu.css('padding-top', 0);
+
+ if (this.options.size !== false) {
+ var that = this,
+ $window = $(window);
+
+ this.setMenuSize();
+
+ if (this.options.liveSearch) {
+ this.$searchbox
+ .off('input.setMenuSize propertychange.setMenuSize')
+ .on('input.setMenuSize propertychange.setMenuSize', function () {
+ return that.setMenuSize();
+ });
+ }
+
+ if (this.options.size === 'auto') {
+ $window
+ .off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize')
+ .on('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize', function () {
+ return that.setMenuSize();
+ });
+ } else if (this.options.size && this.options.size != 'auto' && this.selectpicker.current.elements.length > this.options.size) {
+ $window.off('resize' + EVENT_KEY + '.' + this.selectId + '.setMenuSize' + ' scroll' + EVENT_KEY + '.' + this.selectId + '.setMenuSize');
+ }
+ }
+
+ this.createView(false, true, refresh);
+ },
+
+ setWidth: function () {
+ var that = this;
+
+ if (this.options.width === 'auto') {
+ requestAnimationFrame(function () {
+ that.$menu.css('min-width', '0');
+
+ that.$element.on('loaded' + EVENT_KEY, function () {
+ that.liHeight();
+ that.setMenuSize();
+
+ // Get correct width if element is hidden
+ var $selectClone = that.$newElement.clone().appendTo('body'),
+ btnWidth = $selectClone.css('width', 'auto').children('button').outerWidth();
+
+ $selectClone.remove();
+
+ // Set width to whatever's larger, button title or longest option
+ that.sizeInfo.selectWidth = Math.max(that.sizeInfo.totalMenuWidth, btnWidth);
+ that.$newElement.css('width', that.sizeInfo.selectWidth + 'px');
+ });
+ });
+ } else if (this.options.width === 'fit') {
+ // Remove inline min-width so width can be changed from 'auto'
+ this.$menu.css('min-width', '');
+ this.$newElement.css('width', '').addClass('fit-width');
+ } else if (this.options.width) {
+ // Remove inline min-width so width can be changed from 'auto'
+ this.$menu.css('min-width', '');
+ this.$newElement.css('width', this.options.width);
+ } else {
+ // Remove inline min-width/width so width can be changed
+ this.$menu.css('min-width', '');
+ this.$newElement.css('width', '');
+ }
+ // Remove fit-width class if width is changed programmatically
+ if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
+ this.$newElement[0].classList.remove('fit-width');
+ }
+ },
+
+ selectPosition: function () {
+ this.$bsContainer = $('<div class="bs-container" />');
+
+ var that = this,
+ $container = $(this.options.container),
+ pos,
+ containerPos,
+ actualHeight,
+ getPlacement = function ($element) {
+ var containerPosition = {},
+ // fall back to dropdown's default display setting if display is not manually set
+ display = that.options.display || (
+ // Bootstrap 3 doesn't have $.fn.dropdown.Constructor.Default
+ $.fn.dropdown.Constructor.Default ? $.fn.dropdown.Constructor.Default.display
+ : false
+ );
+
+ that.$bsContainer.addClass($element.attr('class').replace(/form-control|fit-width/gi, '')).toggleClass(classNames.DROPUP, $element.hasClass(classNames.DROPUP));
+ pos = $element.offset();
+
+ if (!$container.is('body')) {
+ containerPos = $container.offset();
+ containerPos.top += parseInt($container.css('borderTopWidth')) - $container.scrollTop();
+ containerPos.left += parseInt($container.css('borderLeftWidth')) - $container.scrollLeft();
+ } else {
+ containerPos = { top: 0, left: 0 };
+ }
+
+ actualHeight = $element.hasClass(classNames.DROPUP) ? 0 : $element[0].offsetHeight;
+
+ // Bootstrap 4+ uses Popper for menu positioning
+ if (version.major < 4 || display === 'static') {
+ containerPosition.top = pos.top - containerPos.top + actualHeight;
+ containerPosition.left = pos.left - containerPos.left;
+ }
+
+ containerPosition.width = $element[0].offsetWidth;
+
+ that.$bsContainer.css(containerPosition);
+ };
+
+ this.$button.on('click.bs.dropdown.data-api', function () {
+ if (that.isDisabled()) {
+ return;
+ }
+
+ getPlacement(that.$newElement);
+
+ that.$bsContainer
+ .appendTo(that.options.container)
+ .toggleClass(classNames.SHOW, !that.$button.hasClass(classNames.SHOW))
+ .append(that.$menu);
+ });
+
+ $(window)
+ .off('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId)
+ .on('resize' + EVENT_KEY + '.' + this.selectId + ' scroll' + EVENT_KEY + '.' + this.selectId, function () {
+ var isActive = that.$newElement.hasClass(classNames.SHOW);
+
+ if (isActive) getPlacement(that.$newElement);
+ });
+
+ this.$element.on('hide' + EVENT_KEY, function () {
+ that.$menu.data('height', that.$menu.height());
+ that.$bsContainer.detach();
+ });
+ },
+
+ createOption: function (data, init) {
+ var optionData = !data.option ? data : data.option;
+
+ if (optionData && optionData.nodeType !== 1) {
+ var option = (init ? elementTemplates.selectedOption : elementTemplates.option).cloneNode(true);
+ if (optionData.value !== undefined) option.value = optionData.value;
+ option.textContent = optionData.text;
+
+ option.selected = true;
+
+ if (optionData.liIndex !== undefined) {
+ option.liIndex = optionData.liIndex;
+ } else if (!init) {
+ option.liIndex = data.index;
+ }
+
+ data.option = option;
+
+ this.selectpicker.main.optionQueue.appendChild(option);
+ }
+ },
+
+ setOptionStatus: function (selectedOnly) {
+ var that = this;
+
+ that.noScroll = false;
+
+ if (that.selectpicker.view.visibleElements && that.selectpicker.view.visibleElements.length) {
+ for (var i = 0; i < that.selectpicker.view.visibleElements.length; i++) {
+ var liData = that.selectpicker.current.data[i + that.selectpicker.view.position0],
+ option = liData.option;
+
+ if (option) {
+ if (selectedOnly !== true) {
+ that.setDisabled(liData);
+ }
+
+ that.setSelected(liData);
+ }
+ }
+
+ // append optionQueue (documentFragment with option elements for select options)
+ if (this.options.source.data) this.$element[0].appendChild(this.selectpicker.main.optionQueue);
+ }
+ },
+
+ /**
+ * @param {Object} liData - the option object that is being changed
+ * @param {boolean} selected - true if the option is being selected, false if being deselected
+ */
+ setSelected: function (liData, selected) {
+ selected = selected === undefined ? liData.selected : selected;
+
+ var li = liData.element,
+ activeElementIsSet = this.activeElement !== undefined,
+ thisIsActive = this.activeElement === li,
+ prevActive,
+ a,
+ // if current option is already active
+ // OR
+ // if the current option is being selected, it's NOT multiple, and
+ // activeElement is undefined:
+ // - when the menu is first being opened, OR
+ // - after a search has been performed, OR
+ // - when retainActive is false when selecting a new option (i.e. index of the newly selected option is not the same as the current activeElement)
+ keepActive = thisIsActive || (selected && !this.multiple && !activeElementIsSet);
+
+ if (!li) return;
+
+ if (selected !== undefined) {
+ liData.selected = selected;
+ if (liData.option) liData.option.selected = selected;
+ }
+
+ if (selected && this.options.source.data) {
+ this.createOption(liData, false);
+ }
+
+ a = li.firstChild;
+
+ if (selected) {
+ this.selectedElement = li;
+ }
+
+ li.classList.toggle('selected', selected);
+
+ if (keepActive) {
+ this.focusItem(li, liData);
+ this.selectpicker.view.currentActive = li;
+ this.activeElement = li;
+ } else {
+ this.defocusItem(li);
+ }
+
+ if (a) {
+ a.classList.toggle('selected', selected);
+
+ if (selected) {
+ a.setAttribute('aria-selected', true);
+ } else {
+ if (this.multiple) {
+ a.setAttribute('aria-selected', false);
+ } else {
+ a.removeAttribute('aria-selected');
+ }
+ }
+ }
+
+ if (!keepActive && !activeElementIsSet && selected && this.prevActiveElement !== undefined) {
+ prevActive = this.prevActiveElement;
+
+ this.defocusItem(prevActive);
+ }
+ },
+
+ /**
+ * @param {number} index - the index of the option that is being disabled
+ * @param {boolean} disabled - true if the option is being disabled, false if being enabled
+ */
+ setDisabled: function (liData) {
+ var disabled = liData.disabled,
+ li = liData.element,
+ a;
+
+ if (!li) return;
+
+ a = li.firstChild;
+
+ li.classList.toggle(classNames.DISABLED, disabled);
+
+ if (a) {
+ if (version.major >= '4') a.classList.toggle(classNames.DISABLED, disabled);
+
+ if (disabled) {
+ a.setAttribute('aria-disabled', disabled);
+ a.setAttribute('tabindex', -1);
+ } else {
+ a.removeAttribute('aria-disabled');
+ a.setAttribute('tabindex', 0);
+ }
+ }
+ },
+
+ isDisabled: function () {
+ return this.$element[0].disabled;
+ },
+
+ checkDisabled: function () {
+ if (this.isDisabled()) {
+ this.$newElement[0].classList.add(classNames.DISABLED);
+ this.$button.addClass(classNames.DISABLED).attr('aria-disabled', true);
+ } else {
+ if (this.$button[0].classList.contains(classNames.DISABLED)) {
+ this.$newElement[0].classList.remove(classNames.DISABLED);
+ this.$button.removeClass(classNames.DISABLED).attr('aria-disabled', false);
+ }
+ }
+ },
+
+ clickListener: function () {
+ var that = this,
+ $document = $(document);
+
+ $document.data('spaceSelect', false);
+
+ this.$button.on('keyup', function (e) {
+ if (/(32)/.test(e.keyCode.toString(10)) && $document.data('spaceSelect')) {
+ e.preventDefault();
+ $document.data('spaceSelect', false);
+ }
+ });
+
+ this.$newElement.on('show.bs.dropdown', function () {
+ if (!that.dropdown && version.major === '4') {
+ that.dropdown = that.$button.data('bs.dropdown');
+ that.dropdown._menu = that.$menu[0];
+ }
+ });
+
+ function clearSelection (e) {
+ if (that.multiple) {
+ that.deselectAll();
+ } else {
+ var element = that.$element[0],
+ prevValue = element.value,
+ prevIndex = element.selectedIndex,
+ prevOption = element.options[prevIndex],
+ prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false;
+
+ if (prevData) {
+ that.setSelected(prevData, false);
+ }
+
+ element.selectedIndex = 0;
+
+ changedArguments = [prevIndex, false, prevValue];
+ that.$element.triggerNative('change');
+ }
+
+ // remove selected styling if menu is open
+ if (that.$newElement.hasClass(classNames.SHOW)) {
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ }
+
+ that.createView(false);
+ }
+ }
+
+ this.$button.on('click.bs.dropdown.data-api', function (e) {
+ if (that.options.allowClear) {
+ var target = e.target,
+ clearButton = that.$clearButton[0];
+
+ // IE doesn't support event listeners on child elements of buttons
+ if (/MSIE|Trident/.test(window.navigator.userAgent)) {
+ target = document.elementFromPoint(e.clientX, e.clientY);
+ }
+
+ if (target === clearButton || target.parentElement === clearButton) {
+ e.stopImmediatePropagation();
+ clearSelection(e);
+ }
+ }
+
+ if (!that.$newElement.hasClass(classNames.SHOW)) {
+ that.setSize();
+ }
+ });
+
+ function setFocus () {
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ } else {
+ that.$menuInner.trigger('focus');
+ }
+ }
+
+ function checkPopperExists () {
+ if (that.dropdown && that.dropdown._popper && that.dropdown._popper.state) {
+ setFocus();
+ } else {
+ requestAnimationFrame(checkPopperExists);
+ }
+ }
+
+ this.$element.on('shown' + EVENT_KEY, function () {
+ if (that.$menuInner[0].scrollTop !== that.selectpicker.view.scrollTop) {
+ that.$menuInner[0].scrollTop = that.selectpicker.view.scrollTop;
+ }
+
+ if (version.major > 3) {
+ requestAnimationFrame(checkPopperExists);
+ } else {
+ setFocus();
+ }
+ });
+
+ // ensure posinset and setsize are correct before selecting an option via a click
+ this.$menuInner.on('mouseenter', 'li a', function (e) {
+ var hoverLi = this.parentElement,
+ position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
+ index = Array.prototype.indexOf.call(hoverLi.parentElement.children, hoverLi),
+ hoverData = that.selectpicker.current.data[index + position0];
+
+ that.focusItem(hoverLi, hoverData, true);
+ });
+
+ this.$menuInner.on('click', 'li a', function (e, retainActive) {
+ var $this = $(this),
+ element = that.$element[0],
+ position0 = that.isVirtual() ? that.selectpicker.view.position0 : 0,
+ clickedData = that.selectpicker.current.data[$this.parent().index() + position0],
+ clickedElement = clickedData.element,
+ prevValue = getSelectValues.call(that),
+ prevIndex = element.selectedIndex,
+ prevOption = element.options[prevIndex],
+ prevData = prevOption ? that.selectpicker.main.data[prevOption.liIndex] : false,
+ triggerChange = true;
+
+ // Don't close on multi choice menu
+ if (that.multiple && that.options.maxOptions !== 1) {
+ e.stopPropagation();
+ }
+
+ e.preventDefault();
+
+ // Don't run if the select is disabled
+ if (!that.isDisabled() && !$this.parent().hasClass(classNames.DISABLED)) {
+ var option = clickedData.option,
+ $option = $(option),
+ state = option.selected,
+ optgroupData = that.selectpicker.current.data.find(function (datum) {
+ return datum.optID === clickedData.optID && datum.type === 'optgroup-label';
+ }),
+ optgroup = optgroupData ? optgroupData.optgroup : undefined,
+ dataGetter = optgroup instanceof Element ? getOptionData.fromOption : getOptionData.fromDataSource,
+ optgroupOptions = optgroup && optgroup.children,
+ maxOptions = parseInt(that.options.maxOptions),
+ maxOptionsGrp = optgroup && parseInt(dataGetter(optgroup, 'maxOptions')) || false;
+
+ if (clickedElement === that.activeElement) retainActive = true;
+
+ if (!retainActive) {
+ that.prevActiveElement = that.activeElement;
+ that.activeElement = undefined;
+ }
+
+ if (!that.multiple || maxOptions === 1) { // Deselect previous option if not multi select
+ if (prevData) that.setSelected(prevData, false);
+ that.setSelected(clickedData, true);
+ } else { // Toggle the clicked option if multi select.
+ that.setSelected(clickedData, !state);
+ that.focusedParent.focus();
+
+ if (maxOptions !== false || maxOptionsGrp !== false) {
+ var maxReached = maxOptions < getSelectedOptions.call(that).length,
+ selectedGroupOptions = 0;
+
+ if (optgroup && optgroup.children) {
+ for (var i = 0; i < optgroup.children.length; i++) {
+ if (optgroup.children[i].selected) selectedGroupOptions++;
+ }
+ }
+
+ var maxReachedGrp = maxOptionsGrp < selectedGroupOptions;
+
+ if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
+ if (maxOptions && maxOptions === 1) {
+ element.selectedIndex = -1;
+ that.setOptionStatus(true);
+ } else if (maxOptionsGrp && maxOptionsGrp === 1) {
+ for (var i = 0; i < optgroupOptions.length; i++) {
+ var _option = optgroupOptions[i];
+ that.setSelected(that.selectpicker.current.data[_option.liIndex], false);
+ }
+
+ that.setSelected(clickedData, true);
+ } else {
+ var maxOptionsText = typeof that.options.maxOptionsText === 'string' ? [that.options.maxOptionsText, that.options.maxOptionsText] : that.options.maxOptionsText,
+ maxOptionsArr = typeof maxOptionsText === 'function' ? maxOptionsText(maxOptions, maxOptionsGrp) : maxOptionsText,
+ maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
+ maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
+ $notify = $('<div class="notify"></div>');
+ // If {var} is set in array, replace it
+ /** @deprecated */
+ if (maxOptionsArr[2]) {
+ maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
+ maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
+ }
+
+ that.$menu.append($notify);
+
+ if (maxOptions && maxReached) {
+ $notify.append($('<div>' + maxTxt + '</div>'));
+ triggerChange = false;
+ that.$element.trigger('maxReached' + EVENT_KEY);
+ }
+
+ if (maxOptionsGrp && maxReachedGrp) {
+ $notify.append($('<div>' + maxTxtGrp + '</div>'));
+ triggerChange = false;
+ that.$element.trigger('maxReachedGrp' + EVENT_KEY);
+ }
+
+ setTimeout(function () {
+ that.setSelected(clickedData, false);
+ }, 10);
+
+ $notify[0].classList.add('fadeOut');
+
+ setTimeout(function () {
+ $notify.remove();
+ }, 1050);
+ }
+ }
+ }
+ }
+
+ if (that.options.source.data) that.$element[0].appendChild(that.selectpicker.main.optionQueue);
+
+ if (!that.multiple || (that.multiple && that.options.maxOptions === 1)) {
+ that.$button.trigger('focus');
+ } else if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ }
+
+ // Trigger select 'change'
+ if (triggerChange) {
+ if (that.multiple || prevIndex !== element.selectedIndex) {
+ // $option.prop('selected') is current option state (selected/unselected). prevValue is the value of the select prior to being changed.
+ changedArguments = [option.index, $option.prop('selected'), prevValue];
+ that.$element
+ .triggerNative('change');
+ }
+ }
+ }
+ });
+
+ this.$menu.on('click', 'li.' + classNames.DISABLED + ' a, .' + classNames.POPOVERHEADER + ', .' + classNames.POPOVERHEADER + ' :not(.close)', function (e) {
+ if (e.currentTarget == this) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (that.options.liveSearch && !$(e.target).hasClass('close')) {
+ that.$searchbox.trigger('focus');
+ } else {
+ that.$button.trigger('focus');
+ }
+ }
+ });
+
+ this.$menuInner.on('click', '.divider, .dropdown-header', function (e) {
+ e.preventDefault();
+ e.stopPropagation();
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ } else {
+ that.$button.trigger('focus');
+ }
+ });
+
+ this.$menu.on('click', '.' + classNames.POPOVERHEADER + ' .close', function () {
+ that.$button.trigger('click');
+ });
+
+ this.$searchbox.on('click', function (e) {
+ e.stopPropagation();
+ });
+
+ this.$menu.on('click', '.actions-btn', function (e) {
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ } else {
+ that.$button.trigger('focus');
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ if ($(this).hasClass('bs-select-all')) {
+ that.selectAll();
+ } else {
+ that.deselectAll();
+ }
+ });
+
+ this.$button
+ .on('focus' + EVENT_KEY, function (e) {
+ var tabindex = that.$element[0].getAttribute('tabindex');
+
+ // only change when button is actually focused
+ if (tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
+ // apply select element's tabindex to ensure correct order is followed when tabbing to the next element
+ this.setAttribute('tabindex', tabindex);
+ // set element's tabindex to -1 to allow for reverse tabbing
+ that.$element[0].setAttribute('tabindex', -1);
+ that.selectpicker.view.tabindex = tabindex;
+ }
+ })
+ .on('blur' + EVENT_KEY, function (e) {
+ // revert everything to original tabindex
+ if (that.selectpicker.view.tabindex !== undefined && e.originalEvent && e.originalEvent.isTrusted) {
+ that.$element[0].setAttribute('tabindex', that.selectpicker.view.tabindex);
+ this.setAttribute('tabindex', -1);
+ that.selectpicker.view.tabindex = undefined;
+ }
+ });
+
+ this.$element
+ .on('change' + EVENT_KEY, function () {
+ that.render();
+ that.$element.trigger('changed' + EVENT_KEY, changedArguments);
+ changedArguments = null;
+ })
+ .on('focus' + EVENT_KEY, function () {
+ if (!that.options.mobile) that.$button[0].focus();
+ });
+ },
+
+ liveSearchListener: function () {
+ var that = this;
+
+ this.$button.on('click.bs.dropdown.data-api', function () {
+ if (!!that.$searchbox.val()) {
+ that.$searchbox.val('');
+ that.selectpicker.search.previousValue = undefined;
+ }
+ });
+
+ this.$searchbox.on('click.bs.dropdown.data-api focus.bs.dropdown.data-api touchend.bs.dropdown.data-api', function (e) {
+ e.stopPropagation();
+ });
+
+ this.$searchbox.on('input propertychange', function () {
+ var searchValue = that.$searchbox[0].value;
+
+ that.selectpicker.search.elements = [];
+ that.selectpicker.search.data = [];
+
+ if (searchValue) {
+ that.selectpicker.search.previousValue = searchValue;
+
+ if (that.options.source.search) {
+ that.fetchData(function (builtData) {
+ that.render();
+ that.buildList(undefined, true);
+ that.noScroll = true;
+ that.$menuInner.scrollTop(0);
+ that.createView(true);
+ showNoResults.call(that, builtData, searchValue);
+ }, 'search', 0, searchValue);
+ } else {
+ var i,
+ searchMatch = [],
+ q = searchValue.toUpperCase(),
+ cache = {},
+ cacheArr = [],
+ searchStyle = that._searchStyle(),
+ normalizeSearch = that.options.liveSearchNormalize;
+
+ if (normalizeSearch) q = normalizeToBase(q);
+
+ for (var i = 0; i < that.selectpicker.main.data.length; i++) {
+ var li = that.selectpicker.main.data[i];
+
+ if (!cache[i]) {
+ cache[i] = stringSearch(li, q, searchStyle, normalizeSearch);
+ }
+
+ if (cache[i] && li.headerIndex !== undefined && cacheArr.indexOf(li.headerIndex) === -1) {
+ if (li.headerIndex > 0) {
+ cache[li.headerIndex - 1] = true;
+ cacheArr.push(li.headerIndex - 1);
+ }
+
+ cache[li.headerIndex] = true;
+ cacheArr.push(li.headerIndex);
+
+ cache[li.lastIndex + 1] = true;
+ }
+
+ if (cache[i] && li.type !== 'optgroup-label') cacheArr.push(i);
+ }
+
+ for (var i = 0, cacheLen = cacheArr.length; i < cacheLen; i++) {
+ var index = cacheArr[i],
+ prevIndex = cacheArr[i - 1],
+ li = that.selectpicker.main.data[index],
+ liPrev = that.selectpicker.main.data[prevIndex];
+
+ if (li.type !== 'divider' || (li.type === 'divider' && liPrev && liPrev.type !== 'divider' && cacheLen - 1 !== i)) {
+ that.selectpicker.search.data.push(li);
+ searchMatch.push(that.selectpicker.main.elements[index]);
+ }
+ }
+
+ that.activeElement = undefined;
+ that.noScroll = true;
+ that.$menuInner.scrollTop(0);
+ that.selectpicker.search.elements = searchMatch;
+ that.createView(true);
+ showNoResults.call(that, searchMatch, searchValue);
+ }
+ } else if (that.selectpicker.search.previousValue) { // for IE11 (#2402)
+ that.$menuInner.scrollTop(0);
+ that.createView(false);
+ }
+ });
+ },
+
+ _searchStyle: function () {
+ return this.options.liveSearchStyle || 'contains';
+ },
+
+ val: function (value) {
+ var element = this.$element[0];
+
+ if (typeof value !== 'undefined') {
+ var selectedOptions = getSelectedOptions.call(this),
+ prevValue = getSelectValues.call(this, selectedOptions);
+
+ changedArguments = [null, null, prevValue];
+
+ if (!Array.isArray(value)) value = [ value ];
+
+ value.map(String);
+
+ for (var i = 0; i < selectedOptions.length; i++) {
+ var item = selectedOptions[i];
+
+ if (item && value.indexOf(String(item.value)) === -1) {
+ this.setSelected(item, false);
+ }
+ }
+
+ // only update selected value if it matches an existing option
+ this.selectpicker.main.data.filter(function (item) {
+ if (value.indexOf(String(item.value)) !== -1) {
+ this.setSelected(item, true);
+ return true;
+ }
+
+ return false;
+ }, this);
+
+ if (this.options.source.data) element.appendChild(this.selectpicker.main.optionQueue);
+
+ this.$element.trigger('changed' + EVENT_KEY, changedArguments);
+
+ if (this.$newElement.hasClass(classNames.SHOW)) {
+ if (this.multiple) {
+ this.setOptionStatus(true);
+ } else {
+ var liSelectedIndex = (element.options[element.selectedIndex] || {}).liIndex;
+
+ if (typeof liSelectedIndex === 'number') {
+ this.setSelected(this.selectpicker.current.data[liSelectedIndex], true);
+ }
+ }
+ }
+
+ this.render();
+
+ changedArguments = null;
+
+ return this.$element;
+ } else {
+ return this.$element.val();
+ }
+ },
+
+ changeAll: function (status) {
+ if (!this.multiple) return;
+ if (typeof status === 'undefined') status = true;
+
+ var element = this.$element[0],
+ previousSelected = 0,
+ currentSelected = 0,
+ prevValue = getSelectValues.call(this);
+
+ element.classList.add('bs-select-hidden');
+
+ for (var i = 0, data = this.selectpicker.current.data, len = data.length; i < len; i++) {
+ var liData = data[i],
+ option = liData.option;
+
+ if (option && !liData.disabled && liData.type !== 'divider') {
+ if (liData.selected) previousSelected++;
+ option.selected = status;
+ liData.selected = status;
+ if (status === true) currentSelected++;
+ }
+ }
+
+ element.classList.remove('bs-select-hidden');
+
+ if (previousSelected === currentSelected) return;
+
+ this.setOptionStatus();
+
+ changedArguments = [null, null, prevValue];
+
+ this.$element
+ .triggerNative('change');
+ },
+
+ selectAll: function () {
+ return this.changeAll(true);
+ },
+
+ deselectAll: function () {
+ return this.changeAll(false);
+ },
+
+ toggle: function (e, state) {
+ var isActive,
+ triggerClick = state === undefined;
+
+ e = e || window.event;
+
+ if (e) e.stopPropagation();
+
+ if (triggerClick === false) {
+ isActive = this.$newElement[0].classList.contains(classNames.SHOW);
+ triggerClick = state === true && isActive === false || state === false && isActive === true;
+ }
+
+ if (triggerClick) this.$button.trigger('click.bs.dropdown.data-api');
+ },
+
+ open: function (e) {
+ this.toggle(e, true);
+ },
+
+ close: function (e) {
+ this.toggle(e, false);
+ },
+
+ keydown: function (e) {
+ var $this = $(this),
+ isToggle = $this.hasClass('dropdown-toggle'),
+ $parent = isToggle ? $this.closest('.dropdown') : $this.closest(Selector.MENU),
+ that = $parent.data('this'),
+ $items = that.findLis(),
+ index,
+ isActive,
+ liActive,
+ activeLi,
+ offset,
+ updateScroll = false,
+ downOnTab = e.which === keyCodes.TAB && !isToggle && !that.options.selectOnTab,
+ isArrowKey = REGEXP_ARROW.test(e.which) || downOnTab,
+ scrollTop = that.$menuInner[0].scrollTop,
+ isVirtual = that.isVirtual(),
+ position0 = isVirtual === true ? that.selectpicker.view.position0 : 0;
+
+ // do nothing if a function key is pressed
+ if (e.which >= 112 && e.which <= 123) return;
+
+ isActive = that.$menu.hasClass(classNames.SHOW);
+
+ if (
+ !isActive &&
+ (
+ isArrowKey ||
+ (e.which >= 48 && e.which <= 57) ||
+ (e.which >= 96 && e.which <= 105) ||
+ (e.which >= 65 && e.which <= 90)
+ )
+ ) {
+ that.$button.trigger('click.bs.dropdown.data-api');
+
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ return;
+ }
+ }
+
+ if (e.which === keyCodes.ESCAPE && isActive) {
+ e.preventDefault();
+ that.$button.trigger('click.bs.dropdown.data-api').trigger('focus');
+ }
+
+ if (isArrowKey) { // if up or down
+ if (!$items.length) return;
+
+ liActive = that.activeElement;
+ index = liActive ? Array.prototype.indexOf.call(liActive.parentElement.children, liActive) : -1;
+
+ if (index !== -1) {
+ that.defocusItem(liActive);
+ }
+
+ if (e.which === keyCodes.ARROW_UP) { // up
+ if (index !== -1) index--;
+ if (index + position0 < 0) index += $items.length;
+
+ if (!that.selectpicker.view.canHighlight[index + position0]) {
+ index = that.selectpicker.view.canHighlight.slice(0, index + position0).lastIndexOf(true) - position0;
+ if (index === -1) index = $items.length - 1;
+ }
+ } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
+ index++;
+ if (index + position0 >= that.selectpicker.view.canHighlight.length) index = that.selectpicker.view.firstHighlightIndex;
+
+ if (!that.selectpicker.view.canHighlight[index + position0]) {
+ index = index + 1 + that.selectpicker.view.canHighlight.slice(index + position0 + 1).indexOf(true);
+ }
+ }
+
+ e.preventDefault();
+
+ var liActiveIndex = position0 + index;
+
+ if (e.which === keyCodes.ARROW_UP) { // up
+ // scroll to bottom and highlight last option
+ if (position0 === 0 && index === $items.length - 1) {
+ that.$menuInner[0].scrollTop = that.$menuInner[0].scrollHeight;
+
+ liActiveIndex = that.selectpicker.current.elements.length - 1;
+ } else {
+ activeLi = that.selectpicker.current.data[liActiveIndex];
+
+ // could be undefined if no results exist
+ if (activeLi) {
+ offset = activeLi.position - activeLi.height;
+
+ updateScroll = offset < scrollTop;
+ }
+ }
+ } else if (e.which === keyCodes.ARROW_DOWN || downOnTab) { // down
+ // scroll to top and highlight first option
+ if (index === that.selectpicker.view.firstHighlightIndex) {
+ that.$menuInner[0].scrollTop = 0;
+
+ liActiveIndex = that.selectpicker.view.firstHighlightIndex;
+ } else {
+ activeLi = that.selectpicker.current.data[liActiveIndex];
+
+ // could be undefined if no results exist
+ if (activeLi) {
+ offset = activeLi.position - that.sizeInfo.menuInnerHeight;
+
+ updateScroll = offset > scrollTop;
+ }
+ }
+ }
+
+ liActive = that.selectpicker.current.elements[liActiveIndex];
+
+ that.activeElement = (that.selectpicker.current.data[liActiveIndex] || {}).element;
+
+ that.focusItem(liActive);
+
+ that.selectpicker.view.currentActive = liActive;
+
+ if (updateScroll) that.$menuInner[0].scrollTop = offset;
+
+ if (that.options.liveSearch) {
+ that.$searchbox.trigger('focus');
+ } else {
+ $this.trigger('focus');
+ }
+ } else if (
+ (!$this.is('input') && !REGEXP_TAB_OR_ESCAPE.test(e.which)) ||
+ (e.which === keyCodes.SPACE && that.selectpicker.keydown.keyHistory)
+ ) {
+ var searchMatch,
+ matches = [],
+ keyHistory;
+
+ e.preventDefault();
+
+ that.selectpicker.keydown.keyHistory += keyCodeMap[e.which];
+
+ if (that.selectpicker.keydown.resetKeyHistory.cancel) clearTimeout(that.selectpicker.keydown.resetKeyHistory.cancel);
+ that.selectpicker.keydown.resetKeyHistory.cancel = that.selectpicker.keydown.resetKeyHistory.start();
+
+ keyHistory = that.selectpicker.keydown.keyHistory;
+
+ // if all letters are the same, set keyHistory to just the first character when searching
+ if (/^(.)\1+$/.test(keyHistory)) {
+ keyHistory = keyHistory.charAt(0);
+ }
+
+ // find matches
+ for (var i = 0; i < that.selectpicker.current.data.length; i++) {
+ var li = that.selectpicker.current.data[i],
+ hasMatch;
+
+ hasMatch = stringSearch(li, keyHistory, 'startsWith', true);
+
+ if (hasMatch && that.selectpicker.view.canHighlight[i]) {
+ matches.push(li.element);
+ }
+ }
+
+ if (matches.length) {
+ var matchIndex = 0;
+
+ $items.removeClass('active').find('a').removeClass('active');
+
+ // either only one key has been pressed or they are all the same key
+ if (keyHistory.length === 1) {
+ matchIndex = matches.indexOf(that.activeElement);
+
+ if (matchIndex === -1 || matchIndex === matches.length - 1) {
+ matchIndex = 0;
+ } else {
+ matchIndex++;
+ }
+ }
+
+ searchMatch = matches[matchIndex];
+
+ activeLi = that.selectpicker.main.data[searchMatch];
+
+ if (scrollTop - activeLi.position > 0) {
+ offset = activeLi.position - activeLi.height;
+ updateScroll = true;
+ } else {
+ offset = activeLi.position - that.sizeInfo.menuInnerHeight;
+ // if the option is already visible at the current scroll position, just keep it the same
+ updateScroll = activeLi.position > scrollTop + that.sizeInfo.menuInnerHeight;
+ }
+
+ liActive = that.selectpicker.main.elements[searchMatch];
+
+ that.activeElement = liActive;
+
+ that.focusItem(liActive);
+
+ if (liActive) liActive.firstChild.focus();
+
+ if (updateScroll) that.$menuInner[0].scrollTop = offset;
+
+ $this.trigger('focus');
+ }
+ }
+
+ // Select focused option if "Enter", "Spacebar" or "Tab" (when selectOnTab is true) are pressed inside the menu.
+ if (
+ isActive &&
+ (
+ (e.which === keyCodes.SPACE && !that.selectpicker.keydown.keyHistory) ||
+ e.which === keyCodes.ENTER ||
+ (e.which === keyCodes.TAB && that.options.selectOnTab)
+ )
+ ) {
+ if (e.which !== keyCodes.SPACE) e.preventDefault();
+
+ if (!that.options.liveSearch || e.which !== keyCodes.SPACE) {
+ that.$menuInner.find('.active a').trigger('click', true); // retain active class
+ $this.trigger('focus');
+
+ if (!that.options.liveSearch) {
+ // Prevent screen from scrolling if the user hits the spacebar
+ e.preventDefault();
+ // Fixes spacebar selection of dropdown items in FF & IE
+ $(document).data('spaceSelect', true);
+ }
+ }
+ }
+ },
+
+ mobile: function () {
+ // ensure mobile is set to true if mobile function is called after init
+ this.options.mobile = true;
+ this.$element[0].classList.add('mobile-device');
+ },
+
+ refresh: function () {
+ var that = this;
+ // update options if data attributes have been changed
+ var config = $.extend({}, this.options, getAttributesObject(this.$element), this.$element.data()); // in this order on refresh, as user may change attributes on select, and options object is not passed on refresh
+ this.options = config;
+
+ if (this.options.source.data) {
+ this.render();
+ this.buildList();
+ } else {
+ this.fetchData(function () {
+ that.render();
+ that.buildList();
+ });
+ }
+
+ this.checkDisabled();
+ this.setStyle();
+ this.setWidth();
+
+ this.setSize(true);
+
+ this.$element.trigger('refreshed' + EVENT_KEY);
+ },
+
+ hide: function () {
+ this.$newElement.hide();
+ },
+
+ show: function () {
+ this.$newElement.show();
+ },
+
+ remove: function () {
+ this.$newElement.remove();
+ this.$element.remove();
+ },
+
+ destroy: function () {
+ this.$newElement.before(this.$element).remove();
+
+ if (this.$bsContainer) {
+ this.$bsContainer.remove();
+ } else {
+ this.$menu.remove();
+ }
+
+ if (this.selectpicker.view.titleOption && this.selectpicker.view.titleOption.parentNode) {
+ this.selectpicker.view.titleOption.parentNode.removeChild(this.selectpicker.view.titleOption);
+ }
+
+ this.$element
+ .off(EVENT_KEY)
+ .removeData('selectpicker')
+ .removeClass('bs-select-hidden selectpicker mobile-device');
+
+ $(window).off(EVENT_KEY + '.' + this.selectId);
+ }
+ };
+
+ // SELECTPICKER PLUGIN DEFINITION
+ // ==============================
+ function Plugin (option) {
+ // get the args of the outer function..
+ var args = arguments;
+ // The arguments of the function are explicitly re-defined from the argument list, because the shift causes them
+ // to get lost/corrupted in android 2.3 and IE9 #715 #775
+ var _option = option;
+
+ [].shift.apply(args);
+
+ // if the version was not set successfully
+ if (!version.success) {
+ // try to retreive it again
+ try {
+ version.full = (getVersion() || '').split(' ')[0].split('.');
+ } catch (err) {
+ // fall back to use BootstrapVersion if set
+ if (Selectpicker.BootstrapVersion) {
+ version.full = Selectpicker.BootstrapVersion.split(' ')[0].split('.');
+ } else {
+ version.full = [version.major, '0', '0'];
+
+ console.warn(
+ 'There was an issue retrieving Bootstrap\'s version. ' +
+ 'Ensure Bootstrap is being loaded before bootstrap-select and there is no namespace collision. ' +
+ 'If loading Bootstrap asynchronously, the version may need to be manually specified via $.fn.selectpicker.Constructor.BootstrapVersion.',
+ err
+ );
+ }
+ }
+
+ version.major = version.full[0];
+ version.success = true;
+ }
+
+ if (version.major >= '4') {
+ // some defaults need to be changed if using Bootstrap 4
+ // check to see if they have already been manually changed before forcing them to update
+ var toUpdate = [];
+
+ if (Selectpicker.DEFAULTS.style === classNames.BUTTONCLASS) toUpdate.push({ name: 'style', className: 'BUTTONCLASS' });
+ if (Selectpicker.DEFAULTS.iconBase === classNames.ICONBASE) toUpdate.push({ name: 'iconBase', className: 'ICONBASE' });
+ if (Selectpicker.DEFAULTS.tickIcon === classNames.TICKICON) toUpdate.push({ name: 'tickIcon', className: 'TICKICON' });
+
+ classNames.DIVIDER = 'dropdown-divider';
+ classNames.SHOW = 'show';
+ classNames.BUTTONCLASS = 'btn-light';
+ classNames.POPOVERHEADER = 'popover-header';
+ classNames.ICONBASE = '';
+ classNames.TICKICON = 'bs-ok-default';
+
+ for (var i = 0; i < toUpdate.length; i++) {
+ var option = toUpdate[i];
+ Selectpicker.DEFAULTS[option.name] = classNames[option.className];
+ }
+ }
+
+ if (version.major > '4') {
+ Selector.DATA_TOGGLE = 'data-bs-toggle="dropdown"';
+ }
+
+ var value;
+ var chain = this.each(function () {
+ var $this = $(this);
+ if ($this.is('select')) {
+ var data = $this.data('selectpicker'),
+ options = typeof _option == 'object' && _option;
+
+ // for backwards compatibility
+ // (using title as placeholder is deprecated - remove in v2.0.0)
+ if (options.title) options.placeholder = options.title;
+
+ if (!data) {
+ var dataAttributes = $this.data();
+
+ for (var dataAttr in dataAttributes) {
+ if (Object.prototype.hasOwnProperty.call(dataAttributes, dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
+ delete dataAttributes[dataAttr];
+ }
+ }
+
+ var config = $.extend({}, Selectpicker.DEFAULTS, $.fn.selectpicker.defaults || {}, getAttributesObject($this), dataAttributes, options); // this is correct order on initial render
+ config.template = $.extend({}, Selectpicker.DEFAULTS.template, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.template : {}), dataAttributes.template, options.template);
+ config.source = $.extend({}, Selectpicker.DEFAULTS.source, ($.fn.selectpicker.defaults ? $.fn.selectpicker.defaults.source : {}), options.source);
+ $this.data('selectpicker', (data = new Selectpicker(this, config)));
+ } else if (options) {
+ for (var i in options) {
+ if (Object.prototype.hasOwnProperty.call(options, i)) {
+ data.options[i] = options[i];
+ }
+ }
+ }
+
+ if (typeof _option == 'string') {
+ if (data[_option] instanceof Function) {
+ value = data[_option].apply(data, args);
+ } else {
+ value = data.options[_option];
+ }
+ }
+ }
+ });
+
+ if (typeof value !== 'undefined') {
+ // noinspection JSUnusedAssignment
+ return value;
+ } else {
+ return chain;
+ }
+ }
+
+ var old = $.fn.selectpicker;
+ $.fn.selectpicker = Plugin;
+ $.fn.selectpicker.Constructor = Selectpicker;
+
+ // SELECTPICKER NO CONFLICT
+ // ========================
+ $.fn.selectpicker.noConflict = function () {
+ $.fn.selectpicker = old;
+ return this;
+ };
+
+ // get Bootstrap's keydown event handler for either Bootstrap 4 or Bootstrap 3
+ function keydownHandler () {
+ if (version.major < 5) {
+ if ($.fn.dropdown) {
+ // wait to define until function is called in case Bootstrap isn't loaded yet
+ var bootstrapKeydown = $.fn.dropdown.Constructor._dataApiKeydownHandler || $.fn.dropdown.Constructor.prototype.keydown;
+ return bootstrapKeydown.apply(this, arguments);
+ }
+ } else {
+ return Dropdown.dataApiKeydownHandler;
+ }
+ }
+
+ $(document)
+ .off('keydown.bs.dropdown.data-api')
+ .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > [' + Selector.DATA_TOGGLE + ']', keydownHandler)
+ .on('keydown.bs.dropdown.data-api', ':not(.bootstrap-select) > .dropdown-menu', keydownHandler)
+ .on('keydown' + EVENT_KEY, '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', Selectpicker.prototype.keydown)
+ .on('focusin.modal', '.bootstrap-select [' + Selector.DATA_TOGGLE + '], .bootstrap-select [role="listbox"], .bootstrap-select .bs-searchbox input', function (e) {
+ e.stopPropagation();
+ });
+
+ // SELECTPICKER DATA-API
+ // =====================
+ document.addEventListener('DOMContentLoaded', function () {
+ $('.selectpicker').each(function () {
+ var $selectpicker = $(this);
+ Plugin.call($selectpicker, $selectpicker.data());
+ });
+ });
+})(jQuery);
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/004-bootstrap-select.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/004-bootstrap-select.min.js
deleted file mode 100644
index 9af7c9f..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/004-bootstrap-select.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/*!
- * Bootstrap-select v1.12.2 (http://silviomoreto.github.io/bootstrap-select)
- *
- * Copyright 2013-2017 bootstrap-select
- * Licensed under MIT (https://github.com/silviomoreto/bootstrap-select/blob/master/LICENSE)
- */
-!function(a,b){"function"==typeof define&&define.amd?define(["jquery"],function(a){return b(a)}):"object"==typeof module&&module.exports?module.exports=b(require("jquery")):b(a.jQuery)}(this,function(a){!function(a){"use strict";function b(b){var c=[{re:/[\xC0-\xC6]/g,ch:"A"},{re:/[\xE0-\xE6]/g,ch:"a"},{re:/[\xC8-\xCB]/g,ch:"E"},{re:/[\xE8-\xEB]/g,ch:"e"},{re:/[\xCC-\xCF]/g,ch:"I"},{re:/[\xEC-\xEF]/g,ch:"i"},{re:/[\xD2-\xD6]/g,ch:"O"},{re:/[\xF2-\xF6]/g,ch:"o"},{re:/[\xD9-\xDC]/g,ch:"U"},{re:/[\xF9-\xFC]/g,ch:"u"},{re:/[\xC7-\xE7]/g,ch:"c"},{re:/[\xD1]/g,ch:"N"},{re:/[\xF1]/g,ch:"n"}];return a.each(c,function(){b=b?b.replace(this.re,this.ch):""}),b}function c(b){var c=arguments,d=b;[].shift.apply(c);var e,f=this.each(function(){var b=a(this);if(b.is("select")){var f=b.data("selectpicker"),g="object"==typeof d&&d;if(f){if(g)for(var h in g)g.hasOwnProperty(h)&&(f.options[h]=g[h])}else{var i=a.extend({},k.DEFAULTS,a.fn.selectpicker.defaults||{},b.data(),g);i.template=a.extend({},k.DEFAULTS.template,a.fn.selectpicker.defaults?a.fn.selectpicker.defaults.template:{},b.data().template,g.template),b.data("selectpicker",f=new k(this,i))}"string"==typeof d&&(e=f[d]instanceof Function?f[d].apply(f,c):f.options[d])}});return"undefined"!=typeof e?e:f}String.prototype.includes||!function(){var a={}.toString,b=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),c="".indexOf,d=function(b){if(null==this)throw new TypeError;var d=String(this);if(b&&"[object RegExp]"==a.call(b))throw new TypeError;var e=d.length,f=String(b),g=f.length,h=arguments.length>1?arguments[1]:void 0,i=h?Number(h):0;i!=i&&(i=0);var j=Math.min(Math.max(i,0),e);return!(g+j>e)&&c.call(d,f,i)!=-1};b?b(String.prototype,"includes",{value:d,configurable:!0,writable:!0}):String.prototype.includes=d}(),String.prototype.startsWith||!function(){var a=function(){try{var a={},b=Object.defineProperty,c=b(a,a,a)&&b}catch(a){}return c}(),b={}.toString,c=function(a){if(null==this)throw new TypeError;var c=String(this);if(a&&"[object RegExp]"==b.call(a))throw new TypeError;var d=c.length,e=String(a),f=e.length,g=arguments.length>1?arguments[1]:void 0,h=g?Number(g):0;h!=h&&(h=0);var i=Math.min(Math.max(h,0),d);if(f+i>d)return!1;for(var j=-1;++j<f;)if(c.charCodeAt(i+j)!=e.charCodeAt(j))return!1;return!0};a?a(String.prototype,"startsWith",{value:c,configurable:!0,writable:!0}):String.prototype.startsWith=c}(),Object.keys||(Object.keys=function(a,b,c){c=[];for(b in a)c.hasOwnProperty.call(a,b)&&c.push(b);return c});var d={useDefault:!1,_set:a.valHooks.select.set};a.valHooks.select.set=function(b,c){return c&&!d.useDefault&&a(b).data("selected",!0),d._set.apply(this,arguments)};var e=null;a.fn.triggerNative=function(a){var b,c=this[0];c.dispatchEvent?("function"==typeof Event?b=new Event(a,{bubbles:!0}):(b=document.createEvent("Event"),b.initEvent(a,!0,!1)),c.dispatchEvent(b)):c.fireEvent?(b=document.createEventObject(),b.eventType=a,c.fireEvent("on"+a,b)):this.trigger(a)},a.expr.pseudos.icontains=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.text()).toString().toUpperCase();return f.includes(d[3].toUpperCase())},a.expr.pseudos.ibegins=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.text()).toString().toUpperCase();return f.startsWith(d[3].toUpperCase())},a.expr.pseudos.aicontains=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.data("normalizedText")||e.text()).toString().toUpperCase();return f.includes(d[3].toUpperCase())},a.expr.pseudos.aibegins=function(b,c,d){var e=a(b),f=(e.data("tokens")||e.data("normalizedText")||e.text()).toString().toUpperCase();return f.startsWith(d[3].toUpperCase())};var f={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},g={"&":"&","<":"<",">":">",""":'"',"'":"'","`":"`"},h=function(a){var b=function(b){return a[b]},c="(?:"+Object.keys(a).join("|")+")",d=RegExp(c),e=RegExp(c,"g");return function(a){return a=null==a?"":""+a,d.test(a)?a.replace(e,b):a}},i=h(f),j=h(g),k=function(b,c){d.useDefault||(a.valHooks.select.set=d._set,d.useDefault=!0),this.$element=a(b),this.$newElement=null,this.$button=null,this.$menu=null,this.$lis=null,this.options=c,null===this.options.title&&(this.options.title=this.$element.attr("title"));var e=this.options.windowPadding;"number"==typeof e&&(this.options.windowPadding=[e,e,e,e]),this.val=k.prototype.val,this.render=k.prototype.render,this.refresh=k.prototype.refresh,this.setStyle=k.prototype.setStyle,this.selectAll=k.prototype.selectAll,this.deselectAll=k.prototype.deselectAll,this.destroy=k.prototype.destroy,this.remove=k.prototype.remove,this.show=k.prototype.show,this.hide=k.prototype.hide,this.init()};k.VERSION="1.12.2",k.DEFAULTS={noneSelectedText:"Nothing selected",noneResultsText:"No results matched {0}",countSelectedText:function(a,b){return 1==a?"{0} item selected":"{0} items selected"},maxOptionsText:function(a,b){return[1==a?"Limit reached ({n} item max)":"Limit reached ({n} items max)",1==b?"Group limit reached ({n} item max)":"Group limit reached ({n} items max)"]},selectAllText:"Select All",deselectAllText:"Deselect All",doneButton:!1,doneButtonText:"Close",multipleSeparator:", ",styleBase:"btn",style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,liveSearchPlaceholder:null,liveSearchNormalize:!1,liveSearchStyle:"contains",actionsBox:!1,iconBase:"bi",tickIcon:"bi-check-lg",showTick:!1,template:{caret:'<span class="caret"></span>'},maxOptions:!1,mobile:!1,selectOnTab:!1,dropdownAlignRight:!1,windowPadding:0},k.prototype={constructor:k,init:function(){var b=this,c=this.$element.attr("id");this.$element.addClass("bs-select-hidden"),this.liObj={},this.multiple=this.$element.prop("multiple"),this.autofocus=this.$element.prop("autofocus"),this.$newElement=this.createView(),this.$element.after(this.$newElement).appendTo(this.$newElement),this.$button=this.$newElement.children("button"),this.$menu=this.$newElement.children(".dropdown-menu"),this.$menuInner=this.$menu.children(".inner"),this.$searchbox=this.$menu.find("input"),this.$element.removeClass("bs-select-hidden"),this.options.dropdownAlignRight===!0&&this.$menu.addClass("dropdown-menu-right"),"undefined"!=typeof c&&(this.$button.attr("data-id",c),a('label[for="'+c+'"]').click(function(a){a.preventDefault(),b.$button.focus()})),this.checkDisabled(),this.clickListener(),this.options.liveSearch&&this.liveSearchListener(),this.render(),this.setStyle(),this.setWidth(),this.options.container&&this.selectPosition(),this.$menu.data("this",this),this.$newElement.data("this",this),this.options.mobile&&this.mobile(),this.$newElement.on({"hide.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!1),b.$element.trigger("hide.bs.select",a)},"hidden.bs.dropdown":function(a){b.$element.trigger("hidden.bs.select",a)},"show.bs.dropdown":function(a){b.$menuInner.attr("aria-expanded",!0),b.$element.trigger("show.bs.select",a)},"shown.bs.dropdown":function(a){b.$element.trigger("shown.bs.select",a)}}),b.$element[0].hasAttribute("required")&&this.$element.on("invalid",function(){b.$button.addClass("bs-invalid").focus(),b.$element.on({"focus.bs.select":function(){b.$button.focus(),b.$element.off("focus.bs.select")},"shown.bs.select":function(){b.$element.val(b.$element.val()).off("shown.bs.select")},"rendered.bs.select":function(){this.validity.valid&&b.$button.removeClass("bs-invalid"),b.$element.off("rendered.bs.select")}})}),setTimeout(function(){b.$element.trigger("loaded.bs.select")})},createDropdown:function(){var b=this.multiple||this.options.showTick?" show-tick":"",c=this.$element.parent().hasClass("input-group")?" input-group-btn":"",d=this.autofocus?" autofocus":"",e=this.options.header?'<div class="popover-title"><button type="button" class="close" aria-hidden="true">×</button>'+this.options.header+"</div>":"",f=this.options.liveSearch?'<div class="bs-searchbox"><input type="text" class="form-control" autocomplete="off"'+(null===this.options.liveSearchPlaceholder?"":' placeholder="'+i(this.options.liveSearchPlaceholder)+'"')+' role="textbox" aria-label="Search"></div>':"",g=this.multiple&&this.options.actionsBox?'<div class="bs-actionsbox"><div class="btn-group btn-group-sm btn-block"><button type="button" class="actions-btn bs-select-all btn btn-default">'+this.options.selectAllText+'</button><button type="button" class="actions-btn bs-deselect-all btn btn-default">'+this.options.deselectAllText+"</button></div></div>":"",h=this.multiple&&this.options.doneButton?'<div class="bs-donebutton"><div class="btn-group btn-block"><button type="button" class="btn btn-sm btn-default">'+this.options.doneButtonText+"</button></div></div>":"",j='<div class="btn-group bootstrap-select'+b+c+'"><button type="button" class="'+this.options.styleBase+' dropdown-toggle" data-toggle="dropdown"'+d+' role="button"><span class="filter-option pull-left"></span> <span class="bs-caret">'+this.options.template.caret+'</span></button><div class="dropdown-menu open" role="combobox">'+e+f+g+'<ul class="dropdown-menu inner" role="listbox" aria-expanded="false"></ul>'+h+"</div></div>";return a(j)},createView:function(){var a=this.createDropdown(),b=this.createLi();return a.find("ul")[0].innerHTML=b,a},reloadLi:function(){var a=this.createLi();this.$menuInner[0].innerHTML=a},createLi:function(){var c=this,d=[],e=0,f=document.createElement("option"),g=-1,h=function(a,b,c,d){return"<li"+("undefined"!=typeof c&""!==c?' class="'+c+'"':"")+("undefined"!=typeof b&null!==b?' data-original-index="'+b+'"':"")+("undefined"!=typeof d&null!==d?'data-optgroup="'+d+'"':"")+">"+a+"</li>"},j=function(d,e,f,g){return'<a tabindex="0"'+("undefined"!=typeof e?' class="'+e+'"':"")+(f?' style="'+f+'"':"")+(c.options.liveSearchNormalize?' data-normalized-text="'+b(i(a(d).html()))+'"':"")+("undefined"!=typeof g||null!==g?' data-tokens="'+g+'"':"")+' role="option">'+d+'<span class="'+c.options.iconBase+" "+c.options.tickIcon+' check-mark"></span></a>'};if(this.options.title&&!this.multiple&&(g--,!this.$element.find(".bs-title-option").length)){var k=this.$element[0];f.className="bs-title-option",f.innerHTML=this.options.title,f.value="",k.insertBefore(f,k.firstChild);var l=a(k.options[k.selectedIndex]);void 0===l.attr("selected")&&void 0===this.$element.data("selected")&&(f.selected=!0)}return this.$element.find("option").each(function(b){var f=a(this);if(g++,!f.hasClass("bs-title-option")){var k=this.className||"",l=this.style.cssText,m=f.data("content")?f.data("content"):f.html(),n=f.data("tokens")?f.data("tokens"):null,o="undefined"!=typeof f.data("subtext")?'<small class="text-muted">'+f.data("subtext")+"</small>":"",p="undefined"!=typeof f.data("icon")?'<span class="'+c.options.iconBase+" "+f.data("icon")+'"></span> ':"",q=f.parent(),r="OPTGROUP"===q[0].tagName,s=r&&q[0].disabled,t=this.disabled||s;if(""!==p&&t&&(p="<span>"+p+"</span>"),c.options.hideDisabled&&(t&&!r||s))return void g--;if(f.data("content")||(m=p+'<span class="text">'+m+o+"</span>"),r&&f.data("divider")!==!0){if(c.options.hideDisabled&&t){if(void 0===q.data("allOptionsDisabled")){var u=q.children();q.data("allOptionsDisabled",u.filter(":disabled").length===u.length)}if(q.data("allOptionsDisabled"))return void g--}var v=" "+q[0].className||"";if(0===f.index()){e+=1;var w=q[0].label,x="undefined"!=typeof q.data("subtext")?'<small class="text-muted">'+q.data("subtext")+"</small>":"",y=q.data("icon")?'<span class="'+c.options.iconBase+" "+q.data("icon")+'"></span> ':"";w=y+'<span class="text">'+i(w)+x+"</span>",0!==b&&d.length>0&&(g++,d.push(h("",null,"divider",e+"div"))),g++,d.push(h(w,null,"dropdown-header"+v,e))}if(c.options.hideDisabled&&t)return void g--;d.push(h(j(m,"opt "+k+v,l,n),b,"",e))}else if(f.data("divider")===!0)d.push(h("",b,"divider"));else if(f.data("hidden")===!0)d.push(h(j(m,k,l,n),b,"hidden is-hidden"));else{var z=this.previousElementSibling&&"OPTGROUP"===this.previousElementSibling.tagName;if(!z&&c.options.hideDisabled)for(var A=a(this).prevAll(),B=0;B<A.length;B++)if("OPTGROUP"===A[B].tagName){for(var C=0,D=0;D<B;D++){var E=A[D];(E.disabled||a(E).data("hidden")===!0)&&C++}C===B&&(z=!0);break}z&&(g++,d.push(h("",null,"divider",e+"div"))),d.push(h(j(m,k,l,n),b))}c.liObj[b]=g}}),this.multiple||0!==this.$element.find("option:selected").length||this.options.title||this.$element.find("option").eq(0).prop("selected",!0).attr("selected","selected"),d.join("")},findLis:function(){return null==this.$lis&&(this.$lis=this.$menu.find("li")),this.$lis},render:function(b){var c,d=this;b!==!1&&this.$element.find("option").each(function(a){var b=d.findLis().eq(d.liObj[a]);d.setDisabled(a,this.disabled||"OPTGROUP"===this.parentNode.tagName&&this.parentNode.disabled,b),d.setSelected(a,this.selected,b)}),this.togglePlaceholder(),this.tabIndex();var e=this.$element.find("option").map(function(){if(this.selected){if(d.options.hideDisabled&&(this.disabled||"OPTGROUP"===this.parentNode.tagName&&this.parentNode.disabled))return;var b,c=a(this),e=c.data("icon")&&d.options.showIcon?'<i class="'+d.options.iconBase+" "+c.data("icon")+'"></i> ':"";return b=d.options.showSubtext&&c.data("subtext")&&!d.multiple?' <small class="text-muted">'+c.data("subtext")+"</small>":"","undefined"!=typeof c.attr("title")?c.attr("title"):c.data("content")&&d.options.showContent?c.data("content").toString():e+c.html()+b}}).toArray(),f=this.multiple?e.join(this.options.multipleSeparator):e[0];if(this.multiple&&this.options.selectedTextFormat.indexOf("count")>-1){var g=this.options.selectedTextFormat.split(">");if(g.length>1&&e.length>g[1]||1==g.length&&e.length>=2){c=this.options.hideDisabled?", [disabled]":"";var h=this.$element.find("option").not('[data-divider="true"], [data-hidden="true"]'+c).length,i="function"==typeof this.options.countSelectedText?this.options.countSelectedText(e.length,h):this.options.countSelectedText;f=i.replace("{0}",e.length.toString()).replace("{1}",h.toString())}}void 0==this.options.title&&(this.options.title=this.$element.attr("title")),"static"==this.options.selectedTextFormat&&(f=this.options.title),f||(f="undefined"!=typeof this.options.title?this.options.title:this.options.noneSelectedText),this.$button.attr("title",j(a.trim(f.replace(/<[^>]*>?/g,"")))),this.$button.children(".filter-option").html(f),this.$element.trigger("rendered.bs.select")},setStyle:function(a,b){this.$element.attr("class")&&this.$newElement.addClass(this.$element.attr("class").replace(/selectpicker|mobile-device|bs-select-hidden|validate\[.*\]/gi,""));var c=a?a:this.options.style;"add"==b?this.$button.addClass(c):"remove"==b?this.$button.removeClass(c):(this.$button.removeClass(this.options.style),this.$button.addClass(c))},liHeight:function(b){if(b||this.options.size!==!1&&!this.sizeInfo){var c=document.createElement("div"),d=document.createElement("div"),e=document.createElement("ul"),f=document.createElement("li"),g=document.createElement("li"),h=document.createElement("a"),i=document.createElement("span"),j=this.options.header&&this.$menu.find(".popover-title").length>0?this.$menu.find(".popover-title")[0].cloneNode(!0):null,k=this.options.liveSearch?document.createElement("div"):null,l=this.options.actionsBox&&this.multiple&&this.$menu.find(".bs-actionsbox").length>0?this.$menu.find(".bs-actionsbox")[0].cloneNode(!0):null,m=this.options.doneButton&&this.multiple&&this.$menu.find(".bs-donebutton").length>0?this.$menu.find(".bs-donebutton")[0].cloneNode(!0):null;if(i.className="text",c.className=this.$menu[0].parentNode.className+" open",d.className="dropdown-menu open",e.className="dropdown-menu inner",f.className="divider",i.appendChild(document.createTextNode("Inner text")),h.appendChild(i),g.appendChild(h),e.appendChild(g),e.appendChild(f),j&&d.appendChild(j),k){var n=document.createElement("input");k.className="bs-searchbox",n.className="form-control",k.appendChild(n),d.appendChild(k)}l&&d.appendChild(l),d.appendChild(e),m&&d.appendChild(m),c.appendChild(d),document.body.appendChild(c);var o=h.offsetHeight,p=j?j.offsetHeight:0,q=k?k.offsetHeight:0,r=l?l.offsetHeight:0,s=m?m.offsetHeight:0,t=a(f).outerHeight(!0),u="function"==typeof getComputedStyle&&getComputedStyle(d),v=u?null:a(d),w={vert:parseInt(u?u.paddingTop:v.css("paddingTop"))+parseInt(u?u.paddingBottom:v.css("paddingBottom"))+parseInt(u?u.borderTopWidth:v.css("borderTopWidth"))+parseInt(u?u.borderBottomWidth:v.css("borderBottomWidth")),horiz:parseInt(u?u.paddingLeft:v.css("paddingLeft"))+parseInt(u?u.paddingRight:v.css("paddingRight"))+parseInt(u?u.borderLeftWidth:v.css("borderLeftWidth"))+parseInt(u?u.borderRightWidth:v.css("borderRightWidth"))},x={vert:w.vert+parseInt(u?u.marginTop:v.css("marginTop"))+parseInt(u?u.marginBottom:v.css("marginBottom"))+2,horiz:w.horiz+parseInt(u?u.marginLeft:v.css("marginLeft"))+parseInt(u?u.marginRight:v.css("marginRight"))+2};document.body.removeChild(c),this.sizeInfo={liHeight:o,headerHeight:p,searchHeight:q,actionsHeight:r,doneButtonHeight:s,dividerHeight:t,menuPadding:w,menuExtras:x}}},setSize:function(){if(this.findLis(),this.liHeight(),this.options.header&&this.$menu.css("padding-top",0),this.options.size!==!1){var b,c,d,e,f,g,h,i,j=this,k=this.$menu,l=this.$menuInner,m=a(window),n=this.$newElement[0].offsetHeight,o=this.$newElement[0].offsetWidth,p=this.sizeInfo.liHeight,q=this.sizeInfo.headerHeight,r=this.sizeInfo.searchHeight,s=this.sizeInfo.actionsHeight,t=this.sizeInfo.doneButtonHeight,u=this.sizeInfo.dividerHeight,v=this.sizeInfo.menuPadding,w=this.sizeInfo.menuExtras,x=this.options.hideDisabled?".disabled":"",y=function(){var b,c=j.$newElement.offset(),d=a(j.options.container);j.options.container&&!d.is("body")?(b=d.offset(),b.top+=parseInt(d.css("borderTopWidth")),b.left+=parseInt(d.css("borderLeftWidth"))):b={top:0,left:0};var e=j.options.windowPadding;f=c.top-b.top-m.scrollTop(),g=m.height()-f-n-b.top-e[2],h=c.left-b.left-m.scrollLeft(),i=m.width()-h-o-b.left-e[1],f-=e[0],h-=e[3]};if(y(),"auto"===this.options.size){var z=function(){var m,n=function(b,c){return function(d){return c?d.classList?d.classList.contains(b):a(d).hasClass(b):!(d.classList?d.classList.contains(b):a(d).hasClass(b))}},u=j.$menuInner[0].getElementsByTagName("li"),x=Array.prototype.filter?Array.prototype.filter.call(u,n("hidden",!1)):j.$lis.not(".hidden"),z=Array.prototype.filter?Array.prototype.filter.call(x,n("dropdown-header",!0)):x.filter(".dropdown-header");y(),b=g-w.vert,c=i-w.horiz,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height"),k.data("width")||k.data("width",k.width()),e=k.data("width")):(d=k.height(),e=k.width()),j.options.dropupAuto&&j.$newElement.toggleClass("dropup",f>g&&b-w.vert<d),j.$newElement.hasClass("dropup")&&(b=f-w.vert),"auto"===j.options.dropdownAlignRight&&k.toggleClass("dropdown-menu-right",h>i&&c-w.horiz<e-o),m=x.length+z.length>3?3*p+w.vert-2:0,k.css({"max-height":b+"px",overflow:"hidden","min-height":m+q+r+s+t+"px"}),l.css({"max-height":b-q-r-s-t-v.vert+"px","overflow-y":"auto","min-height":Math.max(m-v.vert,0)+"px"})};z(),this.$searchbox.off("input.getSize propertychange.getSize").on("input.getSize propertychange.getSize",z),m.off("resize.getSize scroll.getSize").on("resize.getSize scroll.getSize",z)}else if(this.options.size&&"auto"!=this.options.size&&this.$lis.not(x).length>this.options.size){var A=this.$lis.not(".divider").not(x).children().slice(0,this.options.size).last().parent().index(),B=this.$lis.slice(0,A+1).filter(".divider").length;b=p*this.options.size+B*u+v.vert,j.options.container?(k.data("height")||k.data("height",k.height()),d=k.data("height")):d=k.height(),j.options.dropupAuto&&this.$newElement.toggleClass("dropup",f>g&&b-w.vert<d),k.css({"max-height":b+q+r+s+t+"px",overflow:"hidden","min-height":""}),l.css({"max-height":b-v.vert+"px","overflow-y":"auto","min-height":""})}}},setWidth:function(){if("auto"===this.options.width){this.$menu.css("min-width","0");var a=this.$menu.parent().clone().appendTo("body"),b=this.options.container?this.$newElement.clone().appendTo("body"):a,c=a.children(".dropdown-menu").outerWidth(),d=b.css("width","auto").children("button").outerWidth();a.remove(),b.remove(),this.$newElement.css("width",Math.max(c,d)+"px")}else"fit"===this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width","").addClass("fit-width")):this.options.width?(this.$menu.css("min-width",""),this.$newElement.css("width",this.options.width)):(this.$menu.css("min-width",""),this.$newElement.css("width",""));this.$newElement.hasClass("fit-width")&&"fit"!==this.options.width&&this.$newElement.removeClass("fit-width")},selectPosition:function(){this.$bsContainer=a('<div class="bs-container" />');var b,c,d,e=this,f=a(this.options.container),g=function(a){e.$bsContainer.addClass(a.attr("class").replace(/form-control|fit-width/gi,"")).toggleClass("dropup",a.hasClass("dropup")),b=a.offset(),f.is("body")?c={top:0,left:0}:(c=f.offset(),c.top+=parseInt(f.css("borderTopWidth"))-f.scrollTop(),c.left+=parseInt(f.css("borderLeftWidth"))-f.scrollLeft()),d=a.hasClass("dropup")?0:a[0].offsetHeight,e.$bsContainer.css({top:b.top-c.top+d,left:b.left-c.left,width:a[0].offsetWidth})};this.$button.on("click",function(){var b=a(this);e.isDisabled()||(g(e.$newElement),e.$bsContainer.appendTo(e.options.container).toggleClass("open",!b.hasClass("open")).append(e.$menu))}),a(window).on("resize scroll",function(){g(e.$newElement)}),this.$element.on("hide.bs.select",function(){e.$menu.data("height",e.$menu.height()),e.$bsContainer.detach()})},setSelected:function(a,b,c){c||(this.togglePlaceholder(),c=this.findLis().eq(this.liObj[a])),c.toggleClass("selected",b).find("a").attr("aria-selected",b)},setDisabled:function(a,b,c){c||(c=this.findLis().eq(this.liObj[a])),b?c.addClass("disabled").children("a").attr("href","#").attr("tabindex",-1).attr("aria-disabled",!0):c.removeClass("disabled").children("a").removeAttr("href").attr("tabindex",0).attr("aria-disabled",!1)},isDisabled:function(){return this.$element[0].disabled},checkDisabled:function(){var a=this;this.isDisabled()?(this.$newElement.addClass("disabled"),this.$button.addClass("disabled").attr("tabindex",-1).attr("aria-disabled",!0)):(this.$button.hasClass("disabled")&&(this.$newElement.removeClass("disabled"),this.$button.removeClass("disabled").attr("aria-disabled",!1)),this.$button.attr("tabindex")!=-1||this.$element.data("tabindex")||this.$button.removeAttr("tabindex")),this.$button.click(function(){return!a.isDisabled()})},togglePlaceholder:function(){var a=this.$element.val();this.$button.toggleClass("bs-placeholder",null===a||""===a||a.constructor===Array&&0===a.length)},tabIndex:function(){this.$element.data("tabindex")!==this.$element.attr("tabindex")&&this.$element.attr("tabindex")!==-98&&"-98"!==this.$element.attr("tabindex")&&(this.$element.data("tabindex",this.$element.attr("tabindex")),this.$button.attr("tabindex",this.$element.data("tabindex"))),this.$element.attr("tabindex",-98)},clickListener:function(){var b=this,c=a(document);c.data("spaceSelect",!1),this.$button.on("keyup",function(a){/(32)/.test(a.keyCode.toString(10))&&c.data("spaceSelect")&&(a.preventDefault(),c.data("spaceSelect",!1))}),this.$button.on("click",function(){b.setSize()}),this.$element.on("shown.bs.select",function(){if(b.options.liveSearch||b.multiple){if(!b.multiple){var a=b.liObj[b.$element[0].selectedIndex];if("number"!=typeof a||b.options.size===!1)return;var c=b.$lis.eq(a)[0].offsetTop-b.$menuInner[0].offsetTop;c=c-b.$menuInner[0].offsetHeight/2+b.sizeInfo.liHeight/2,b.$menuInner[0].scrollTop=c}}else b.$menuInner.find(".selected a").focus()}),this.$menuInner.on("click","li a",function(c){var d=a(this),f=d.parent().data("originalIndex"),g=b.$element.val(),h=b.$element.prop("selectedIndex"),i=!0;if(b.multiple&&1!==b.options.maxOptions&&c.stopPropagation(),c.preventDefault(),!b.isDisabled()&&!d.parent().hasClass("disabled")){var j=b.$element.find("option"),k=j.eq(f),l=k.prop("selected"),m=k.parent("optgroup"),n=b.options.maxOptions,o=m.data("maxOptions")||!1;if(b.multiple){if(k.prop("selected",!l),b.setSelected(f,!l),d.blur(),n!==!1||o!==!1){var p=n<j.filter(":selected").length,q=o<m.find("option:selected").length;if(n&&p||o&&q)if(n&&1==n)j.prop("selected",!1),k.prop("selected",!0),b.$menuInner.find(".selected").removeClass("selected"),b.setSelected(f,!0);else if(o&&1==o){m.find("option:selected").prop("selected",!1),k.prop("selected",!0);var r=d.parent().data("optgroup");b.$menuInner.find('[data-optgroup="'+r+'"]').removeClass("selected"),b.setSelected(f,!0)}else{var s="string"==typeof b.options.maxOptionsText?[b.options.maxOptionsText,b.options.maxOptionsText]:b.options.maxOptionsText,t="function"==typeof s?s(n,o):s,u=t[0].replace("{n}",n),v=t[1].replace("{n}",o),w=a('<div class="notify"></div>');t[2]&&(u=u.replace("{var}",t[2][n>1?0:1]),v=v.replace("{var}",t[2][o>1?0:1])),k.prop("selected",!1),b.$menu.append(w),n&&p&&(w.append(a("<div>"+u+"</div>")),i=!1,b.$element.trigger("maxReached.bs.select")),o&&q&&(w.append(a("<div>"+v+"</div>")),i=!1,b.$element.trigger("maxReachedGrp.bs.select")),setTimeout(function(){b.setSelected(f,!1)},10),w.delay(750).fadeOut(300,function(){a(this).remove()})}}}else j.prop("selected",!1),k.prop("selected",!0),b.$menuInner.find(".selected").removeClass("selected").find("a").attr("aria-selected",!1),b.setSelected(f,!0);!b.multiple||b.multiple&&1===b.options.maxOptions?b.$button.focus():b.options.liveSearch&&b.$searchbox.focus(),i&&(g!=b.$element.val()&&b.multiple||h!=b.$element.prop("selectedIndex")&&!b.multiple)&&(e=[f,k.prop("selected"),l],b.$element.triggerNative("change"))}}),this.$menu.on("click","li.disabled a, .popover-title, .popover-title :not(.close)",function(c){c.currentTarget==this&&(c.preventDefault(),c.stopPropagation(),b.options.liveSearch&&!a(c.target).hasClass("close")?b.$searchbox.focus():b.$button.focus())}),this.$menuInner.on("click",".divider, .dropdown-header",function(a){a.preventDefault(),a.stopPropagation(),b.options.liveSearch?b.$searchbox.focus():b.$button.focus()}),this.$menu.on("click",".popover-title .close",function(){b.$button.click()}),this.$searchbox.on("click",function(a){a.stopPropagation()}),this.$menu.on("click",".actions-btn",function(c){b.options.liveSearch?b.$searchbox.focus():b.$button.focus(),c.preventDefault(),c.stopPropagation(),a(this).hasClass("bs-select-all")?b.selectAll():b.deselectAll()}),this.$element.change(function(){b.render(!1),b.$element.trigger("changed.bs.select",e),e=null})},liveSearchListener:function(){var c=this,d=a('<li class="no-results"></li>');this.$button.on("click.dropdown.data-api",function(){c.$menuInner.find(".active").removeClass("active"),c.$searchbox.val()&&(c.$searchbox.val(""),c.$lis.not(".is-hidden").removeClass("hidden"),d.parent().length&&d.remove()),c.multiple||c.$menuInner.find(".selected").addClass("active"),setTimeout(function(){c.$searchbox.focus()},10)}),this.$searchbox.on("click.dropdown.data-api focus.dropdown.data-api touchend.dropdown.data-api",function(a){a.stopPropagation()}),this.$searchbox.on("input propertychange",function(){if(c.$lis.not(".is-hidden").removeClass("hidden"),c.$lis.filter(".active").removeClass("active"),d.remove(),c.$searchbox.val()){var e,f=c.$lis.not(".is-hidden, .divider, .dropdown-header");if(e=c.options.liveSearchNormalize?f.find("a").not(":a"+c._searchStyle()+'("'+b(c.$searchbox.val())+'")'):f.find("a").not(":"+c._searchStyle()+'("'+c.$searchbox.val()+'")'),e.length===f.length)d.html(c.options.noneResultsText.replace("{0}",'"'+i(c.$searchbox.val())+'"')),c.$menuInner.append(d),c.$lis.addClass("hidden");else{e.parent().addClass("hidden");var g,h=c.$lis.not(".hidden");h.each(function(b){var c=a(this);c.hasClass("divider")?void 0===g?c.addClass("hidden"):(g&&g.addClass("hidden"),g=c):c.hasClass("dropdown-header")&&h.eq(b+1).data("optgroup")!==c.data("optgroup")?c.addClass("hidden"):g=null}),g&&g.addClass("hidden"),f.not(".hidden").first().addClass("active")}}})},_searchStyle:function(){var a={begins:"ibegins",startsWith:"ibegins"};return a[this.options.liveSearchStyle]||"icontains"},val:function(a){return"undefined"!=typeof a?(this.$element.val(a),this.render(),this.$element):this.$element.val()},changeAll:function(b){if(this.multiple){"undefined"==typeof b&&(b=!0),this.findLis();var c=this.$element.find("option"),d=this.$lis.not(".divider, .dropdown-header, .disabled, .hidden"),e=d.length,f=[];if(b){if(d.filter(".selected").length===d.length)return}else if(0===d.filter(".selected").length)return;d.toggleClass("selected",b);for(var g=0;g<e;g++){var h=d[g].getAttribute("data-original-index");f[f.length]=c.eq(h)[0]}a(f).prop("selected",b),this.render(!1),this.togglePlaceholder(),this.$element.triggerNative("change")}},selectAll:function(){return this.changeAll(!0)},deselectAll:function(){return this.changeAll(!1)},toggle:function(a){a=a||window.event,a&&a.stopPropagation(),this.$button.trigger("click")},keydown:function(c){var d,e,f,g,h,i,j,k,l,m=a(this),n=m.is("input")?m.parent().parent():m.parent(),o=n.data("this"),p=":not(.disabled, .hidden, .dropdown-header, .divider)",q={32:" ",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",59:";",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9"};if(o.options.liveSearch&&(n=m.parent().parent()),o.options.container&&(n=o.$menu),d=a('[role="listbox"] li',n),l=o.$newElement.hasClass("open"),!l&&(c.keyCode>=48&&c.keyCode<=57||c.keyCode>=96&&c.keyCode<=105||c.keyCode>=65&&c.keyCode<=90))return o.options.container?o.$button.trigger("click"):(o.setSize(),o.$menu.parent().addClass("open"),l=!0),void o.$searchbox.focus();if(o.options.liveSearch&&(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(c.preventDefault(),c.stopPropagation(),o.$menuInner.click(),o.$button.focus()),d=a('[role="listbox"] li'+p,n),m.val()||/(38|40)/.test(c.keyCode.toString(10))||0===d.filter(".active").length&&(d=o.$menuInner.find("li"),d=o.options.liveSearchNormalize?d.filter(":a"+o._searchStyle()+"("+b(q[c.keyCode])+")"):d.filter(":"+o._searchStyle()+"("+q[c.keyCode]+")"))),d.length){if(/(38|40)/.test(c.keyCode.toString(10)))e=d.index(d.find("a").filter(":focus").parent()),g=d.filter(p).first().index(),h=d.filter(p).last().index(),f=d.eq(e).nextAll(p).eq(0).index(),i=d.eq(e).prevAll(p).eq(0).index(),j=d.eq(f).prevAll(p).eq(0).index(),o.options.liveSearch&&(d.each(function(b){a(this).hasClass("disabled")||a(this).data("index",b)}),e=d.index(d.filter(".active")),g=d.first().data("index"),h=d.last().data("index"),f=d.eq(e).nextAll().eq(0).data("index"),i=d.eq(e).prevAll().eq(0).data("index"),j=d.eq(f).prevAll().eq(0).data("index")),k=m.data("prevIndex"),38==c.keyCode?(o.options.liveSearch&&e--,e!=j&&e>i&&(e=i),e<g&&(e=g),e==k&&(e=h)):40==c.keyCode&&(o.options.liveSearch&&e++,e==-1&&(e=0),e!=j&&e<f&&(e=f),e>h&&(e=h),e==k&&(e=g)),m.data("prevIndex",e),o.options.liveSearch?(c.preventDefault(),m.hasClass("dropdown-toggle")||(d.removeClass("active").eq(e).addClass("active").children("a").focus(),m.focus())):d.eq(e).children("a").focus();else if(!m.is("input")){var r,s,t=[];d.each(function(){a(this).hasClass("disabled")||a.trim(a(this).children("a").text().toLowerCase()).substring(0,1)==q[c.keyCode]&&t.push(a(this).index())}),r=a(document).data("keycount"),r++,a(document).data("keycount",r),s=a.trim(a(":focus").text().toLowerCase()).substring(0,1),s!=q[c.keyCode]?(r=1,a(document).data("keycount",r)):r>=t.length&&(a(document).data("keycount",0),r>t.length&&(r=1)),d.eq(t[r-1]).children("a").focus()}if((/(13|32)/.test(c.keyCode.toString(10))||/(^9$)/.test(c.keyCode.toString(10))&&o.options.selectOnTab)&&l){if(/(32)/.test(c.keyCode.toString(10))||c.preventDefault(),o.options.liveSearch)/(32)/.test(c.keyCode.toString(10))||(o.$menuInner.find(".active a").click(),
-m.focus());else{var u=a(":focus");u.click(),u.focus(),c.preventDefault(),a(document).data("spaceSelect",!0)}a(document).data("keycount",0)}(/(^9$|27)/.test(c.keyCode.toString(10))&&l&&(o.multiple||o.options.liveSearch)||/(27)/.test(c.keyCode.toString(10))&&!l)&&(o.$menu.parent().removeClass("open"),o.options.container&&o.$newElement.removeClass("open"),o.$button.focus())}},mobile:function(){this.$element.addClass("mobile-device")},refresh:function(){this.$lis=null,this.liObj={},this.reloadLi(),this.render(),this.checkDisabled(),this.liHeight(!0),this.setStyle(),this.setWidth(),this.$lis&&this.$searchbox.trigger("propertychange"),this.$element.trigger("refreshed.bs.select")},hide:function(){this.$newElement.hide()},show:function(){this.$newElement.show()},remove:function(){this.$newElement.remove(),this.$element.remove()},destroy:function(){this.$newElement.before(this.$element).remove(),this.$bsContainer?this.$bsContainer.remove():this.$menu.remove(),this.$element.off(".bs.select").removeData("selectpicker").removeClass("bs-select-hidden selectpicker")}};var l=a.fn.selectpicker;a.fn.selectpicker=c,a.fn.selectpicker.Constructor=k,a.fn.selectpicker.noConflict=function(){return a.fn.selectpicker=l,this},a(document).data("keycount",0).on("keydown.bs.select",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',k.prototype.keydown).on("focusin.modal",'.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role="listbox"], .bs-searchbox input',function(a){a.stopPropagation()}),a(window).on("load.bs.select.data-api",function(){a(".selectpicker").each(function(){var b=a(this);c.call(b,b.data())})})}(a)});
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/004-datatables.js b/mailcow/src/mailcow-dockerized/data/web/js/build/004-datatables.js
new file mode 100644
index 0000000..9ece8ea
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/004-datatables.js
@@ -0,0 +1,18781 @@
+/*
+ * This combined file was created by the DataTables downloader builder:
+ * https://datatables.net/download
+ *
+ * To rebuild or modify this file with the latest versions of the included
+ * software please visit:
+ * https://datatables.net/download/#bs5/dt-1.13.1/r-2.4.0/sl-1.5.0
+ *
+ * Included libraries:
+ * DataTables 1.13.1, Responsive 2.4.0, Select 1.5.0
+ */
+
+/*! DataTables 1.13.1
+ * ©2008-2022 SpryMedia Ltd - datatables.net/license
+ */
+
+/**
+ * @summary DataTables
+ * @description Paginate, search and order HTML tables
+ * @version 1.13.1
+ * @author SpryMedia Ltd
+ * @contact www.datatables.net
+ * @copyright SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ * MIT license - http://datatables.net/license
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/*jslint evil: true, undef: true, browser: true */
+/*globals $,require,jQuery,define,_selector_run,_selector_opts,_selector_first,_selector_row_indexes,_ext,_Api,_api_register,_api_registerPlural,_re_new_lines,_re_html,_re_formatted_numeric,_re_escape_regex,_empty,_intVal,_numToDecimal,_isNumber,_isHtml,_htmlNumeric,_pluck,_pluck_order,_range,_stripHtml,_unique,_fnBuildAjax,_fnAjaxUpdate,_fnAjaxParameters,_fnAjaxUpdateDraw,_fnAjaxDataSrc,_fnAddColumn,_fnColumnOptions,_fnAdjustColumnSizing,_fnVisibleToColumnIndex,_fnColumnIndexToVisible,_fnVisbleColumns,_fnGetColumns,_fnColumnTypes,_fnApplyColumnDefs,_fnHungarianMap,_fnCamelToHungarian,_fnLanguageCompat,_fnBrowserDetect,_fnAddData,_fnAddTr,_fnNodeToDataIndex,_fnNodeToColumnIndex,_fnGetCellData,_fnSetCellData,_fnSplitObjNotation,_fnGetObjectDataFn,_fnSetObjectDataFn,_fnGetDataMaster,_fnClearTable,_fnDeleteIndex,_fnInvalidate,_fnGetRowElements,_fnCreateTr,_fnBuildHead,_fnDrawHead,_fnDraw,_fnReDraw,_fnAddOptionsHtml,_fnDetectHeader,_fnGetUniqueThs,_fnFeatureHtmlFilter,_fnFilterComplete,_fnFilterCustom,_fnFilterColumn,_fnFilter,_fnFilterCreateSearch,_fnEscapeRegex,_fnFilterData,_fnFeatureHtmlInfo,_fnUpdateInfo,_fnInfoMacros,_fnInitialise,_fnInitComplete,_fnLengthChange,_fnFeatureHtmlLength,_fnFeatureHtmlPaginate,_fnPageChange,_fnFeatureHtmlProcessing,_fnProcessingDisplay,_fnFeatureHtmlTable,_fnScrollDraw,_fnApplyToChildren,_fnCalculateColumnWidths,_fnThrottle,_fnConvertToWidth,_fnGetWidestNode,_fnGetMaxLenString,_fnStringToCss,_fnSortFlatten,_fnSort,_fnSortAria,_fnSortListener,_fnSortAttachListener,_fnSortingClasses,_fnSortData,_fnSaveState,_fnLoadState,_fnSettingsFromNode,_fnLog,_fnMap,_fnBindAction,_fnCallbackReg,_fnCallbackFire,_fnLengthOverflow,_fnRenderer,_fnDataSource,_fnRowAttributes*/
+
+(function( factory ) {
+ "use strict";
+
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ window.DataTable = factory( jQuery, window, document );
+ }
+}
+(function( $, window, document, undefined ) {
+ "use strict";
+
+
+ var DataTable = function ( selector, options )
+ {
+ // When creating with `new`, create a new DataTable, returning the API instance
+ if (this instanceof DataTable) {
+ return $(selector).DataTable(options);
+ }
+ else {
+ // Argument switching
+ options = selector;
+ }
+
+ /**
+ * Perform a jQuery selector action on the table's TR elements (from the tbody) and
+ * return the resulting jQuery object.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select TR elements that meet the current filter
+ * criterion ("applied") or all TR elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the TR elements in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {object} jQuery object, filtered by the given selector.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Highlight every second row
+ * oTable.$('tr:odd').css('backgroundColor', 'blue');
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to rows with 'Webkit' in them, add a background colour and then
+ * // remove the filter, thus highlighting the 'Webkit' rows only.
+ * oTable.fnFilter('Webkit');
+ * oTable.$('tr', {"search": "applied"}).css('backgroundColor', 'blue');
+ * oTable.fnFilter('');
+ * } );
+ */
+ this.$ = function ( sSelector, oOpts )
+ {
+ return this.api(true).$( sSelector, oOpts );
+ };
+
+
+ /**
+ * Almost identical to $ in operation, but in this case returns the data for the matched
+ * rows - as such, the jQuery selector used should match TR row nodes or TD/TH cell nodes
+ * rather than any descendants, so the data can be obtained for the row/cell. If matching
+ * rows are found, the data returned is the original data array/object that was used to
+ * create the row (or a generated array if from a DOM source).
+ *
+ * This method is often useful in-combination with $ where both functions are given the
+ * same parameters and the array indexes will match identically.
+ * @param {string|node|jQuery} sSelector jQuery selector or node collection to act on
+ * @param {object} [oOpts] Optional parameters for modifying the rows to be included
+ * @param {string} [oOpts.filter=none] Select elements that meet the current filter
+ * criterion ("applied") or all elements (i.e. no filter).
+ * @param {string} [oOpts.order=current] Order of the data in the processed array.
+ * Can be either 'current', whereby the current sorting of the table is used, or
+ * 'original' whereby the original order the data was read into the table is used.
+ * @param {string} [oOpts.page=all] Limit the selection to the currently displayed page
+ * ("current") or not ("all"). If 'current' is given, then order is assumed to be
+ * 'current' and filter is 'applied', regardless of what they might be given as.
+ * @returns {array} Data for the matched elements. If any elements, as a result of the
+ * selector, were not TR, TD or TH elements in the DataTable, they will have a null
+ * entry in the array.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the data from the first row in the table
+ * var data = oTable._('tr:first');
+ *
+ * // Do something useful with the data
+ * alert( "First cell is: "+data[0] );
+ * } );
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Filter to 'Webkit' and get all data for
+ * oTable.fnFilter('Webkit');
+ * var data = oTable._('tr', {"search": "applied"});
+ *
+ * // Do something with the data
+ * alert( data.length+" rows matched the search" );
+ * } );
+ */
+ this._ = function ( sSelector, oOpts )
+ {
+ return this.api(true).rows( sSelector, oOpts ).data();
+ };
+
+
+ /**
+ * Create a DataTables Api instance, with the currently selected tables for
+ * the Api's context.
+ * @param {boolean} [traditional=false] Set the API instance's context to be
+ * only the table referred to by the `DataTable.ext.iApiIndex` option, as was
+ * used in the API presented by DataTables 1.9- (i.e. the traditional mode),
+ * or if all tables captured in the jQuery object should be used.
+ * @return {DataTables.Api}
+ */
+ this.api = function ( traditional )
+ {
+ return traditional ?
+ new _Api(
+ _fnSettingsFromNode( this[ _ext.iApiIndex ] )
+ ) :
+ new _Api( this );
+ };
+
+
+ /**
+ * Add a single new row or multiple rows of data to the table. Please note
+ * that this is suitable for client-side processing only - if you are using
+ * server-side processing (i.e. "bServerSide": true), then to add data, you
+ * must add it to the data source, i.e. the server-side, through an Ajax call.
+ * @param {array|object} data The data to be added to the table. This can be:
+ * <ul>
+ * <li>1D array of data - add a single row with the data provided</li>
+ * <li>2D array of arrays - add multiple rows in a single call</li>
+ * <li>object - data object when using <i>mData</i></li>
+ * <li>array of objects - multiple data objects when using <i>mData</i></li>
+ * </ul>
+ * @param {bool} [redraw=true] redraw the table or not
+ * @returns {array} An array of integers, representing the list of indexes in
+ * <i>aoData</i> ({@link DataTable.models.oSettings}) that have been added to
+ * the table.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * // Global var for counter
+ * var giCount = 2;
+ *
+ * $(document).ready(function() {
+ * $('#example').dataTable();
+ * } );
+ *
+ * function fnClickAddRow() {
+ * $('#example').dataTable().fnAddData( [
+ * giCount+".1",
+ * giCount+".2",
+ * giCount+".3",
+ * giCount+".4" ]
+ * );
+ *
+ * giCount++;
+ * }
+ */
+ this.fnAddData = function( data, redraw )
+ {
+ var api = this.api( true );
+
+ /* Check if we want to add multiple rows or not */
+ var rows = Array.isArray(data) && ( Array.isArray(data[0]) || $.isPlainObject(data[0]) ) ?
+ api.rows.add( data ) :
+ api.row.add( data );
+
+ if ( redraw === undefined || redraw ) {
+ api.draw();
+ }
+
+ return rows.flatten().toArray();
+ };
+
+
+ /**
+ * This function will make DataTables recalculate the column sizes, based on the data
+ * contained in the table and the sizes applied to the columns (in the DOM, CSS or
+ * through the sWidth parameter). This can be useful when the width of the table's
+ * parent element changes (for example a window resize).
+ * @param {boolean} [bRedraw=true] Redraw the table or not, you will typically want to
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable( {
+ * "sScrollY": "200px",
+ * "bPaginate": false
+ * } );
+ *
+ * $(window).on('resize', function () {
+ * oTable.fnAdjustColumnSizing();
+ * } );
+ * } );
+ */
+ this.fnAdjustColumnSizing = function ( bRedraw )
+ {
+ var api = this.api( true ).columns.adjust();
+ var settings = api.settings()[0];
+ var scroll = settings.oScroll;
+
+ if ( bRedraw === undefined || bRedraw ) {
+ api.draw( false );
+ }
+ else if ( scroll.sX !== "" || scroll.sY !== "" ) {
+ /* If not redrawing, but scrolling, we want to apply the new column sizes anyway */
+ _fnScrollDraw( settings );
+ }
+ };
+
+
+ /**
+ * Quickly and simply clear a table
+ * @param {bool} [bRedraw=true] redraw the table or not
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately 'nuke' the current rows (perhaps waiting for an Ajax callback...)
+ * oTable.fnClearTable();
+ * } );
+ */
+ this.fnClearTable = function( bRedraw )
+ {
+ var api = this.api( true ).clear();
+
+ if ( bRedraw === undefined || bRedraw ) {
+ api.draw();
+ }
+ };
+
+
+ /**
+ * The exact opposite of 'opening' a row, this function will close any rows which
+ * are currently 'open'.
+ * @param {node} nTr the table row to 'close'
+ * @returns {int} 0 on success, or 1 if failed (can't find the row)
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnClose = function( nTr )
+ {
+ this.api( true ).row( nTr ).child.hide();
+ };
+
+
+ /**
+ * Remove a row for the table
+ * @param {mixed} target The index of the row from aoData to be deleted, or
+ * the TR element you want to delete
+ * @param {function|null} [callBack] Callback function
+ * @param {bool} [redraw=true] Redraw the table or not
+ * @returns {array} The row that was deleted
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Immediately remove the first row
+ * oTable.fnDeleteRow( 0 );
+ * } );
+ */
+ this.fnDeleteRow = function( target, callback, redraw )
+ {
+ var api = this.api( true );
+ var rows = api.rows( target );
+ var settings = rows.settings()[0];
+ var data = settings.aoData[ rows[0][0] ];
+
+ rows.remove();
+
+ if ( callback ) {
+ callback.call( this, settings, data );
+ }
+
+ if ( redraw === undefined || redraw ) {
+ api.draw();
+ }
+
+ return data;
+ };
+
+
+ /**
+ * Restore the table to it's original state in the DOM by removing all of DataTables
+ * enhancements, alterations to the DOM structure of the table and event listeners.
+ * @param {boolean} [remove=false] Completely remove the table from the DOM
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * // This example is fairly pointless in reality, but shows how fnDestroy can be used
+ * var oTable = $('#example').dataTable();
+ * oTable.fnDestroy();
+ * } );
+ */
+ this.fnDestroy = function ( remove )
+ {
+ this.api( true ).destroy( remove );
+ };
+
+
+ /**
+ * Redraw the table
+ * @param {bool} [complete=true] Re-filter and resort (if enabled) the table before the draw.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Re-draw the table - you wouldn't want to do it here, but it's an example :-)
+ * oTable.fnDraw();
+ * } );
+ */
+ this.fnDraw = function( complete )
+ {
+ // Note that this isn't an exact match to the old call to _fnDraw - it takes
+ // into account the new data, but can hold position.
+ this.api( true ).draw( complete );
+ };
+
+
+ /**
+ * Filter the input based on data
+ * @param {string} sInput String to filter the table on
+ * @param {int|null} [iColumn] Column to limit filtering to
+ * @param {bool} [bRegex=false] Treat as regular expression or not
+ * @param {bool} [bSmart=true] Perform smart filtering or not
+ * @param {bool} [bShowGlobal=true] Show the input global filter in it's input box(es)
+ * @param {bool} [bCaseInsensitive=true] Do case-insensitive matching (true) or not (false)
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sometime later - filter...
+ * oTable.fnFilter( 'test string' );
+ * } );
+ */
+ this.fnFilter = function( sInput, iColumn, bRegex, bSmart, bShowGlobal, bCaseInsensitive )
+ {
+ var api = this.api( true );
+
+ if ( iColumn === null || iColumn === undefined ) {
+ api.search( sInput, bRegex, bSmart, bCaseInsensitive );
+ }
+ else {
+ api.column( iColumn ).search( sInput, bRegex, bSmart, bCaseInsensitive );
+ }
+
+ api.draw();
+ };
+
+
+ /**
+ * Get the data for the whole table, an individual row or an individual cell based on the
+ * provided parameters.
+ * @param {int|node} [src] A TR row node, TD/TH cell node or an integer. If given as
+ * a TR node then the data source for the whole row will be returned. If given as a
+ * TD/TH cell node then iCol will be automatically calculated and the data for the
+ * cell returned. If given as an integer, then this is treated as the aoData internal
+ * data index for the row (see fnGetPosition) and the data for that row used.
+ * @param {int} [col] Optional column index that you want the data of.
+ * @returns {array|object|string} If mRow is undefined, then the data for all rows is
+ * returned. If mRow is defined, just data for that row, and is iCol is
+ * defined, only data for the designated cell is returned.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * // Row data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('tr').click( function () {
+ * var data = oTable.fnGetData( this );
+ * // ... do something with the array / object of data for the row
+ * } );
+ * } );
+ *
+ * @example
+ * // Individual cell data
+ * $(document).ready(function() {
+ * oTable = $('#example').dataTable();
+ *
+ * oTable.$('td').click( function () {
+ * var sData = oTable.fnGetData( this );
+ * alert( 'The cell clicked on had the value of '+sData );
+ * } );
+ * } );
+ */
+ this.fnGetData = function( src, col )
+ {
+ var api = this.api( true );
+
+ if ( src !== undefined ) {
+ var type = src.nodeName ? src.nodeName.toLowerCase() : '';
+
+ return col !== undefined || type == 'td' || type == 'th' ?
+ api.cell( src, col ).data() :
+ api.row( src ).data() || null;
+ }
+
+ return api.data().toArray();
+ };
+
+
+ /**
+ * Get an array of the TR nodes that are used in the table's body. Note that you will
+ * typically want to use the '$' API method in preference to this as it is more
+ * flexible.
+ * @param {int} [iRow] Optional row index for the TR element you want
+ * @returns {array|node} If iRow is undefined, returns an array of all TR elements
+ * in the table's body, or iRow is defined, just the TR element requested.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Get the nodes from the table
+ * var nNodes = oTable.fnGetNodes( );
+ * } );
+ */
+ this.fnGetNodes = function( iRow )
+ {
+ var api = this.api( true );
+
+ return iRow !== undefined ?
+ api.row( iRow ).node() :
+ api.rows().nodes().flatten().toArray();
+ };
+
+
+ /**
+ * Get the array indexes of a particular cell from it's DOM element
+ * and column index including hidden columns
+ * @param {node} node this can either be a TR, TD or TH in the table's body
+ * @returns {int} If nNode is given as a TR, then a single index is returned, or
+ * if given as a cell, an array of [row index, column index (visible),
+ * column index (all)] is given.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * $('#example tbody td').click( function () {
+ * // Get the position of the current data from the node
+ * var aPos = oTable.fnGetPosition( this );
+ *
+ * // Get the data array for this row
+ * var aData = oTable.fnGetData( aPos[0] );
+ *
+ * // Update the data array and return the value
+ * aData[ aPos[1] ] = 'clicked';
+ * this.innerHTML = 'clicked';
+ * } );
+ *
+ * // Init DataTables
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnGetPosition = function( node )
+ {
+ var api = this.api( true );
+ var nodeName = node.nodeName.toUpperCase();
+
+ if ( nodeName == 'TR' ) {
+ return api.row( node ).index();
+ }
+ else if ( nodeName == 'TD' || nodeName == 'TH' ) {
+ var cell = api.cell( node ).index();
+
+ return [
+ cell.row,
+ cell.columnVisible,
+ cell.column
+ ];
+ }
+ return null;
+ };
+
+
+ /**
+ * Check to see if a row is 'open' or not.
+ * @param {node} nTr the table row to check
+ * @returns {boolean} true if the row is currently open, false otherwise
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnIsOpen = function( nTr )
+ {
+ return this.api( true ).row( nTr ).child.isShown();
+ };
+
+
+ /**
+ * This function will place a new row directly after a row which is currently
+ * on display on the page, with the HTML contents that is passed into the
+ * function. This can be used, for example, to ask for confirmation that a
+ * particular record should be deleted.
+ * @param {node} nTr The table row to 'open'
+ * @param {string|node|jQuery} mHtml The HTML to put into the row
+ * @param {string} sClass Class to give the new TD cell
+ * @returns {node} The row opened. Note that if the table row passed in as the
+ * first parameter, is not found in the table, this method will silently
+ * return.
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable;
+ *
+ * // 'open' an information row when a row is clicked on
+ * $('#example tbody tr').click( function () {
+ * if ( oTable.fnIsOpen(this) ) {
+ * oTable.fnClose( this );
+ * } else {
+ * oTable.fnOpen( this, "Temporary row opened", "info_row" );
+ * }
+ * } );
+ *
+ * oTable = $('#example').dataTable();
+ * } );
+ */
+ this.fnOpen = function( nTr, mHtml, sClass )
+ {
+ return this.api( true )
+ .row( nTr )
+ .child( mHtml, sClass )
+ .show()
+ .child()[0];
+ };
+
+
+ /**
+ * Change the pagination - provides the internal logic for pagination in a simple API
+ * function. With this function you can have a DataTables table go to the next,
+ * previous, first or last pages.
+ * @param {string|int} mAction Paging action to take: "first", "previous", "next" or "last"
+ * or page number to jump to (integer), note that page 0 is the first page.
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnPageChange( 'next' );
+ * } );
+ */
+ this.fnPageChange = function ( mAction, bRedraw )
+ {
+ var api = this.api( true ).page( mAction );
+
+ if ( bRedraw === undefined || bRedraw ) {
+ api.draw(false);
+ }
+ };
+
+
+ /**
+ * Show a particular column
+ * @param {int} iCol The column whose display should be changed
+ * @param {bool} bShow Show (true) or hide (false) the column
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Hide the second column after initialisation
+ * oTable.fnSetColumnVis( 1, false );
+ * } );
+ */
+ this.fnSetColumnVis = function ( iCol, bShow, bRedraw )
+ {
+ var api = this.api( true ).column( iCol ).visible( bShow );
+
+ if ( bRedraw === undefined || bRedraw ) {
+ api.columns.adjust().draw();
+ }
+ };
+
+
+ /**
+ * Get the settings for a particular table for external manipulation
+ * @returns {object} DataTables settings object. See
+ * {@link DataTable.models.oSettings}
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * var oSettings = oTable.fnSettings();
+ *
+ * // Show an example parameter from the settings
+ * alert( oSettings._iDisplayStart );
+ * } );
+ */
+ this.fnSettings = function()
+ {
+ return _fnSettingsFromNode( this[_ext.iApiIndex] );
+ };
+
+
+ /**
+ * Sort the table by a particular column
+ * @param {int} iCol the data index to sort on. Note that this will not match the
+ * 'display index' if you have hidden data entries
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort immediately with columns 0 and 1
+ * oTable.fnSort( [ [0,'asc'], [1,'asc'] ] );
+ * } );
+ */
+ this.fnSort = function( aaSort )
+ {
+ this.api( true ).order( aaSort ).draw();
+ };
+
+
+ /**
+ * Attach a sort listener to an element for a given column
+ * @param {node} nNode the element to attach the sort listener to
+ * @param {int} iColumn the column that a click on this node will sort on
+ * @param {function} [fnCallback] callback function when sort is run
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ *
+ * // Sort on column 1, when 'sorter' is clicked on
+ * oTable.fnSortListener( document.getElementById('sorter'), 1 );
+ * } );
+ */
+ this.fnSortListener = function( nNode, iColumn, fnCallback )
+ {
+ this.api( true ).order.listener( nNode, iColumn, fnCallback );
+ };
+
+
+ /**
+ * Update a table cell or row - this method will accept either a single value to
+ * update the cell with, an array of values with one element for each column or
+ * an object in the same format as the original data source. The function is
+ * self-referencing in order to make the multi column updates easier.
+ * @param {object|array|string} mData Data to update the cell/row with
+ * @param {node|int} mRow TR element you want to update or the aoData index
+ * @param {int} [iColumn] The column to update, give as null or undefined to
+ * update a whole row.
+ * @param {bool} [bRedraw=true] Redraw the table or not
+ * @param {bool} [bAction=true] Perform pre-draw actions or not
+ * @returns {int} 0 on success, 1 on error
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * oTable.fnUpdate( 'Example update', 0, 0 ); // Single cell
+ * oTable.fnUpdate( ['a', 'b', 'c', 'd', 'e'], $('tbody tr')[0] ); // Row
+ * } );
+ */
+ this.fnUpdate = function( mData, mRow, iColumn, bRedraw, bAction )
+ {
+ var api = this.api( true );
+
+ if ( iColumn === undefined || iColumn === null ) {
+ api.row( mRow ).data( mData );
+ }
+ else {
+ api.cell( mRow, iColumn ).data( mData );
+ }
+
+ if ( bAction === undefined || bAction ) {
+ api.columns.adjust();
+ }
+
+ if ( bRedraw === undefined || bRedraw ) {
+ api.draw();
+ }
+ return 0;
+ };
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being used, in order
+ * to ensure compatibility.
+ * @param {string} sVersion Version string to check for, in the format "X.Y.Z". Note that the
+ * formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to the required
+ * version, or false if this version of DataTales is not suitable
+ * @method
+ * @dtopt API
+ * @deprecated Since v1.10
+ *
+ * @example
+ * $(document).ready(function() {
+ * var oTable = $('#example').dataTable();
+ * alert( oTable.fnVersionCheck( '1.9.0' ) );
+ * } );
+ */
+ this.fnVersionCheck = _ext.fnVersionCheck;
+
+
+ var _that = this;
+ var emptyInit = options === undefined;
+ var len = this.length;
+
+ if ( emptyInit ) {
+ options = {};
+ }
+
+ this.oApi = this.internal = _ext.internal;
+
+ // Extend with old style plug-in API methods
+ for ( var fn in DataTable.ext.internal ) {
+ if ( fn ) {
+ this[fn] = _fnExternApiFunc(fn);
+ }
+ }
+
+ this.each(function() {
+ // For each initialisation we want to give it a clean initialisation
+ // object that can be bashed around
+ var o = {};
+ var oInit = len > 1 ? // optimisation for single table case
+ _fnExtend( o, options, true ) :
+ options;
+
+ /*global oInit,_that,emptyInit*/
+ var i=0, iLen, j, jLen, k, kLen;
+ var sId = this.getAttribute( 'id' );
+ var bInitHandedOff = false;
+ var defaults = DataTable.defaults;
+ var $this = $(this);
+
+
+ /* Sanity check */
+ if ( this.nodeName.toLowerCase() != 'table' )
+ {
+ _fnLog( null, 0, 'Non-table node initialisation ('+this.nodeName+')', 2 );
+ return;
+ }
+
+ /* Backwards compatibility for the defaults */
+ _fnCompatOpts( defaults );
+ _fnCompatCols( defaults.column );
+
+ /* Convert the camel-case defaults to Hungarian */
+ _fnCamelToHungarian( defaults, defaults, true );
+ _fnCamelToHungarian( defaults.column, defaults.column, true );
+
+ /* Setting up the initialisation object */
+ _fnCamelToHungarian( defaults, $.extend( oInit, $this.data() ), true );
+
+
+
+ /* Check to see if we are re-initialising a table */
+ var allSettings = DataTable.settings;
+ for ( i=0, iLen=allSettings.length ; i<iLen ; i++ )
+ {
+ var s = allSettings[i];
+
+ /* Base check on table node */
+ if (
+ s.nTable == this ||
+ (s.nTHead && s.nTHead.parentNode == this) ||
+ (s.nTFoot && s.nTFoot.parentNode == this)
+ ) {
+ var bRetrieve = oInit.bRetrieve !== undefined ? oInit.bRetrieve : defaults.bRetrieve;
+ var bDestroy = oInit.bDestroy !== undefined ? oInit.bDestroy : defaults.bDestroy;
+
+ if ( emptyInit || bRetrieve )
+ {
+ return s.oInstance;
+ }
+ else if ( bDestroy )
+ {
+ s.oInstance.fnDestroy();
+ break;
+ }
+ else
+ {
+ _fnLog( s, 0, 'Cannot reinitialise DataTable', 3 );
+ return;
+ }
+ }
+
+ /* If the element we are initialising has the same ID as a table which was previously
+ * initialised, but the table nodes don't match (from before) then we destroy the old
+ * instance by simply deleting it. This is under the assumption that the table has been
+ * destroyed by other methods. Anyone using non-id selectors will need to do this manually
+ */
+ if ( s.sTableId == this.id )
+ {
+ allSettings.splice( i, 1 );
+ break;
+ }
+ }
+
+ /* Ensure the table has an ID - required for accessibility */
+ if ( sId === null || sId === "" )
+ {
+ sId = "DataTables_Table_"+(DataTable.ext._unique++);
+ this.id = sId;
+ }
+
+ /* Create the settings object for this table and set some of the default parameters */
+ var oSettings = $.extend( true, {}, DataTable.models.oSettings, {
+ "sDestroyWidth": $this[0].style.width,
+ "sInstance": sId,
+ "sTableId": sId
+ } );
+ oSettings.nTable = this;
+ oSettings.oApi = _that.internal;
+ oSettings.oInit = oInit;
+
+ allSettings.push( oSettings );
+
+ // Need to add the instance after the instance after the settings object has been added
+ // to the settings array, so we can self reference the table instance if more than one
+ oSettings.oInstance = (_that.length===1) ? _that : $this.dataTable();
+
+ // Backwards compatibility, before we apply all the defaults
+ _fnCompatOpts( oInit );
+ _fnLanguageCompat( oInit.oLanguage );
+
+ // If the length menu is given, but the init display length is not, use the length menu
+ if ( oInit.aLengthMenu && ! oInit.iDisplayLength )
+ {
+ oInit.iDisplayLength = Array.isArray( oInit.aLengthMenu[0] ) ?
+ oInit.aLengthMenu[0][0] : oInit.aLengthMenu[0];
+ }
+
+ // Apply the defaults and init options to make a single init object will all
+ // options defined from defaults and instance options.
+ oInit = _fnExtend( $.extend( true, {}, defaults ), oInit );
+
+
+ // Map the initialisation options onto the settings object
+ _fnMap( oSettings.oFeatures, oInit, [
+ "bPaginate",
+ "bLengthChange",
+ "bFilter",
+ "bSort",
+ "bSortMulti",
+ "bInfo",
+ "bProcessing",
+ "bAutoWidth",
+ "bSortClasses",
+ "bServerSide",
+ "bDeferRender"
+ ] );
+ _fnMap( oSettings, oInit, [
+ "asStripeClasses",
+ "ajax",
+ "fnServerData",
+ "fnFormatNumber",
+ "sServerMethod",
+ "aaSorting",
+ "aaSortingFixed",
+ "aLengthMenu",
+ "sPaginationType",
+ "sAjaxSource",
+ "sAjaxDataProp",
+ "iStateDuration",
+ "sDom",
+ "bSortCellsTop",
+ "iTabIndex",
+ "fnStateLoadCallback",
+ "fnStateSaveCallback",
+ "renderer",
+ "searchDelay",
+ "rowId",
+ [ "iCookieDuration", "iStateDuration" ], // backwards compat
+ [ "oSearch", "oPreviousSearch" ],
+ [ "aoSearchCols", "aoPreSearchCols" ],
+ [ "iDisplayLength", "_iDisplayLength" ]
+ ] );
+ _fnMap( oSettings.oScroll, oInit, [
+ [ "sScrollX", "sX" ],
+ [ "sScrollXInner", "sXInner" ],
+ [ "sScrollY", "sY" ],
+ [ "bScrollCollapse", "bCollapse" ]
+ ] );
+ _fnMap( oSettings.oLanguage, oInit, "fnInfoCallback" );
+
+ /* Callback functions which are array driven */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', oInit.fnDrawCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoServerParams', oInit.fnServerParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateSaveParams', oInit.fnStateSaveParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoadParams', oInit.fnStateLoadParams, 'user' );
+ _fnCallbackReg( oSettings, 'aoStateLoaded', oInit.fnStateLoaded, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCallback', oInit.fnRowCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoRowCreatedCallback', oInit.fnCreatedRow, 'user' );
+ _fnCallbackReg( oSettings, 'aoHeaderCallback', oInit.fnHeaderCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoFooterCallback', oInit.fnFooterCallback, 'user' );
+ _fnCallbackReg( oSettings, 'aoInitComplete', oInit.fnInitComplete, 'user' );
+ _fnCallbackReg( oSettings, 'aoPreDrawCallback', oInit.fnPreDrawCallback, 'user' );
+
+ oSettings.rowIdFn = _fnGetObjectDataFn( oInit.rowId );
+
+ /* Browser support detection */
+ _fnBrowserDetect( oSettings );
+
+ var oClasses = oSettings.oClasses;
+
+ $.extend( oClasses, DataTable.ext.classes, oInit.oClasses );
+ $this.addClass( oClasses.sTable );
+
+
+ if ( oSettings.iInitDisplayStart === undefined )
+ {
+ /* Display start point, taking into account the save saving */
+ oSettings.iInitDisplayStart = oInit.iDisplayStart;
+ oSettings._iDisplayStart = oInit.iDisplayStart;
+ }
+
+ if ( oInit.iDeferLoading !== null )
+ {
+ oSettings.bDeferLoading = true;
+ var tmp = Array.isArray( oInit.iDeferLoading );
+ oSettings._iRecordsDisplay = tmp ? oInit.iDeferLoading[0] : oInit.iDeferLoading;
+ oSettings._iRecordsTotal = tmp ? oInit.iDeferLoading[1] : oInit.iDeferLoading;
+ }
+
+ /* Language definitions */
+ var oLanguage = oSettings.oLanguage;
+ $.extend( true, oLanguage, oInit.oLanguage );
+
+ if ( oLanguage.sUrl )
+ {
+ /* Get the language definitions from a file - because this Ajax call makes the language
+ * get async to the remainder of this function we use bInitHandedOff to indicate that
+ * _fnInitialise will be fired by the returned Ajax handler, rather than the constructor
+ */
+ $.ajax( {
+ dataType: 'json',
+ url: oLanguage.sUrl,
+ success: function ( json ) {
+ _fnCamelToHungarian( defaults.oLanguage, json );
+ _fnLanguageCompat( json );
+ $.extend( true, oLanguage, json, oSettings.oInit.oLanguage );
+
+ _fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
+ _fnInitialise( oSettings );
+ },
+ error: function () {
+ // Error occurred loading language file, continue on as best we can
+ _fnInitialise( oSettings );
+ }
+ } );
+ bInitHandedOff = true;
+ }
+ else {
+ _fnCallbackFire( oSettings, null, 'i18n', [oSettings]);
+ }
+
+ /*
+ * Stripes
+ */
+ if ( oInit.asStripeClasses === null )
+ {
+ oSettings.asStripeClasses =[
+ oClasses.sStripeOdd,
+ oClasses.sStripeEven
+ ];
+ }
+
+ /* Remove row stripe classes if they are already on the table row */
+ var stripeClasses = oSettings.asStripeClasses;
+ var rowOne = $this.children('tbody').find('tr').eq(0);
+ if ( $.inArray( true, $.map( stripeClasses, function(el, i) {
+ return rowOne.hasClass(el);
+ } ) ) !== -1 ) {
+ $('tbody tr', this).removeClass( stripeClasses.join(' ') );
+ oSettings.asDestroyStripes = stripeClasses.slice();
+ }
+
+ /*
+ * Columns
+ * See if we should load columns automatically or use defined ones
+ */
+ var anThs = [];
+ var aoColumnsInit;
+ var nThead = this.getElementsByTagName('thead');
+ if ( nThead.length !== 0 )
+ {
+ _fnDetectHeader( oSettings.aoHeader, nThead[0] );
+ anThs = _fnGetUniqueThs( oSettings );
+ }
+
+ /* If not given a column array, generate one with nulls */
+ if ( oInit.aoColumns === null )
+ {
+ aoColumnsInit = [];
+ for ( i=0, iLen=anThs.length ; i<iLen ; i++ )
+ {
+ aoColumnsInit.push( null );
+ }
+ }
+ else
+ {
+ aoColumnsInit = oInit.aoColumns;
+ }
+
+ /* Add the columns */
+ for ( i=0, iLen=aoColumnsInit.length ; i<iLen ; i++ )
+ {
+ _fnAddColumn( oSettings, anThs ? anThs[i] : null );
+ }
+
+ /* Apply the column definitions */
+ _fnApplyColumnDefs( oSettings, oInit.aoColumnDefs, aoColumnsInit, function (iCol, oDef) {
+ _fnColumnOptions( oSettings, iCol, oDef );
+ } );
+
+ /* HTML5 attribute detection - build an mData object automatically if the
+ * attributes are found
+ */
+ if ( rowOne.length ) {
+ var a = function ( cell, name ) {
+ return cell.getAttribute( 'data-'+name ) !== null ? name : null;
+ };
+
+ $( rowOne[0] ).children('th, td').each( function (i, cell) {
+ var col = oSettings.aoColumns[i];
+
+ if (! col) {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+ }
+
+ if ( col.mData === i ) {
+ var sort = a( cell, 'sort' ) || a( cell, 'order' );
+ var filter = a( cell, 'filter' ) || a( cell, 'search' );
+
+ if ( sort !== null || filter !== null ) {
+ col.mData = {
+ _: i+'.display',
+ sort: sort !== null ? i+'.@data-'+sort : undefined,
+ type: sort !== null ? i+'.@data-'+sort : undefined,
+ filter: filter !== null ? i+'.@data-'+filter : undefined
+ };
+
+ _fnColumnOptions( oSettings, i );
+ }
+ }
+ } );
+ }
+
+ var features = oSettings.oFeatures;
+ var loadedInit = function () {
+ /*
+ * Sorting
+ * @todo For modularisation (1.11) this needs to do into a sort start up handler
+ */
+
+ // If aaSorting is not defined, then we use the first indicator in asSorting
+ // in case that has been altered, so the default sort reflects that option
+ if ( oInit.aaSorting === undefined ) {
+ var sorting = oSettings.aaSorting;
+ for ( i=0, iLen=sorting.length ; i<iLen ; i++ ) {
+ sorting[i][1] = oSettings.aoColumns[ i ].asSorting[0];
+ }
+ }
+
+ /* Do a first pass on the sorting classes (allows any size changes to be taken into
+ * account, and also will apply sorting disabled classes if disabled
+ */
+ _fnSortingClasses( oSettings );
+
+ if ( features.bSort ) {
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
+ if ( oSettings.bSorted ) {
+ var aSort = _fnSortFlatten( oSettings );
+ var sortedColumns = {};
+
+ $.each( aSort, function (i, val) {
+ sortedColumns[ val.src ] = val.dir;
+ } );
+
+ _fnCallbackFire( oSettings, null, 'order', [oSettings, aSort, sortedColumns] );
+ _fnSortAria( oSettings );
+ }
+ } );
+ }
+
+ _fnCallbackReg( oSettings, 'aoDrawCallback', function () {
+ if ( oSettings.bSorted || _fnDataSource( oSettings ) === 'ssp' || features.bDeferRender ) {
+ _fnSortingClasses( oSettings );
+ }
+ }, 'sc' );
+
+
+ /*
+ * Final init
+ * Cache the header, body and footer as required, creating them if needed
+ */
+
+ // Work around for Webkit bug 83867 - store the caption-side before removing from doc
+ var captions = $this.children('caption').each( function () {
+ this._captionSide = $(this).css('caption-side');
+ } );
+
+ var thead = $this.children('thead');
+ if ( thead.length === 0 ) {
+ thead = $('<thead/>').appendTo($this);
+ }
+ oSettings.nTHead = thead[0];
+
+ var tbody = $this.children('tbody');
+ if ( tbody.length === 0 ) {
+ tbody = $('<tbody/>').insertAfter(thead);
+ }
+ oSettings.nTBody = tbody[0];
+
+ var tfoot = $this.children('tfoot');
+ if ( tfoot.length === 0 && captions.length > 0 && (oSettings.oScroll.sX !== "" || oSettings.oScroll.sY !== "") ) {
+ // If we are a scrolling table, and no footer has been given, then we need to create
+ // a tfoot element for the caption element to be appended to
+ tfoot = $('<tfoot/>').appendTo($this);
+ }
+
+ if ( tfoot.length === 0 || tfoot.children().length === 0 ) {
+ $this.addClass( oClasses.sNoFooter );
+ }
+ else if ( tfoot.length > 0 ) {
+ oSettings.nTFoot = tfoot[0];
+ _fnDetectHeader( oSettings.aoFooter, oSettings.nTFoot );
+ }
+
+ /* Check if there is data passing into the constructor */
+ if ( oInit.aaData ) {
+ for ( i=0 ; i<oInit.aaData.length ; i++ ) {
+ _fnAddData( oSettings, oInit.aaData[ i ] );
+ }
+ }
+ else if ( oSettings.bDeferLoading || _fnDataSource( oSettings ) == 'dom' ) {
+ /* Grab the data from the page - only do this when deferred loading or no Ajax
+ * source since there is no point in reading the DOM data if we are then going
+ * to replace it with Ajax data
+ */
+ _fnAddTr( oSettings, $(oSettings.nTBody).children('tr') );
+ }
+
+ /* Copy the data index array */
+ oSettings.aiDisplay = oSettings.aiDisplayMaster.slice();
+
+ /* Initialisation complete - table can be drawn */
+ oSettings.bInitialised = true;
+
+ /* Check if we need to initialise the table (it might not have been handed off to the
+ * language processor)
+ */
+ if ( bInitHandedOff === false ) {
+ _fnInitialise( oSettings );
+ }
+ };
+
+ /* Must be done after everything which can be overridden by the state saving! */
+ _fnCallbackReg( oSettings, 'aoDrawCallback', _fnSaveState, 'state_save' );
+
+ if ( oInit.bStateSave )
+ {
+ features.bStateSave = true;
+ _fnLoadState( oSettings, oInit, loadedInit );
+ }
+ else {
+ loadedInit();
+ }
+
+ } );
+ _that = null;
+ return this;
+ };
+
+
+ /*
+ * It is useful to have variables which are scoped locally so only the
+ * DataTables functions can access them and they don't leak into global space.
+ * At the same time these functions are often useful over multiple files in the
+ * core and API, so we list, or at least document, all variables which are used
+ * by DataTables as private variables here. This also ensures that there is no
+ * clashing of variable names and that they can easily referenced for reuse.
+ */
+
+
+ // Defined else where
+ // _selector_run
+ // _selector_opts
+ // _selector_first
+ // _selector_row_indexes
+
+ var _ext; // DataTable.ext
+ var _Api; // DataTable.Api
+ var _api_register; // DataTable.Api.register
+ var _api_registerPlural; // DataTable.Api.registerPlural
+
+ var _re_dic = {};
+ var _re_new_lines = /[\r\n\u2028]/g;
+ var _re_html = /<.*?>/g;
+
+ // This is not strict ISO8601 - Date.parse() is quite lax, although
+ // implementations differ between browsers.
+ var _re_date = /^\d{2,4}[\.\/\-]\d{1,2}[\.\/\-]\d{1,2}([T ]{1}\d{1,2}[:\.]\d{2}([\.:]\d{2})?)?$/;
+
+ // Escape regular expression special characters
+ var _re_escape_regex = new RegExp( '(\\' + [ '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\', '$', '^', '-' ].join('|\\') + ')', 'g' );
+
+ // http://en.wikipedia.org/wiki/Foreign_exchange_market
+ // - \u20BD - Russian ruble.
+ // - \u20a9 - South Korean Won
+ // - \u20BA - Turkish Lira
+ // - \u20B9 - Indian Rupee
+ // - R - Brazil (R$) and South Africa
+ // - fr - Swiss Franc
+ // - kr - Swedish krona, Norwegian krone and Danish krone
+ // - \u2009 is thin space and \u202F is narrow no-break space, both used in many
+ // - Ƀ - Bitcoin
+ // - Ξ - Ethereum
+ // standards as thousands separators.
+ var _re_formatted_numeric = /['\u00A0,$£€¥%\u2009\u202F\u20BD\u20a9\u20BArfkɃΞ]/gi;
+
+
+ var _empty = function ( d ) {
+ return !d || d === true || d === '-' ? true : false;
+ };
+
+
+ var _intVal = function ( s ) {
+ var integer = parseInt( s, 10 );
+ return !isNaN(integer) && isFinite(s) ? integer : null;
+ };
+
+ // Convert from a formatted number with characters other than `.` as the
+ // decimal place, to a Javascript number
+ var _numToDecimal = function ( num, decimalPoint ) {
+ // Cache created regular expressions for speed as this function is called often
+ if ( ! _re_dic[ decimalPoint ] ) {
+ _re_dic[ decimalPoint ] = new RegExp( _fnEscapeRegex( decimalPoint ), 'g' );
+ }
+ return typeof num === 'string' && decimalPoint !== '.' ?
+ num.replace( /\./g, '' ).replace( _re_dic[ decimalPoint ], '.' ) :
+ num;
+ };
+
+
+ var _isNumber = function ( d, decimalPoint, formatted ) {
+ var strType = typeof d === 'string';
+
+ // If empty return immediately so there must be a number if it is a
+ // formatted string (this stops the string "k", or "kr", etc being detected
+ // as a formatted number for currency
+ if ( _empty( d ) ) {
+ return true;
+ }
+
+ if ( decimalPoint && strType ) {
+ d = _numToDecimal( d, decimalPoint );
+ }
+
+ if ( formatted && strType ) {
+ d = d.replace( _re_formatted_numeric, '' );
+ }
+
+ return !isNaN( parseFloat(d) ) && isFinite( d );
+ };
+
+
+ // A string without HTML in it can be considered to be HTML still
+ var _isHtml = function ( d ) {
+ return _empty( d ) || typeof d === 'string';
+ };
+
+
+ var _htmlNumeric = function ( d, decimalPoint, formatted ) {
+ if ( _empty( d ) ) {
+ return true;
+ }
+
+ var html = _isHtml( d );
+ return ! html ?
+ null :
+ _isNumber( _stripHtml( d ), decimalPoint, formatted ) ?
+ true :
+ null;
+ };
+
+
+ var _pluck = function ( a, prop, prop2 ) {
+ var out = [];
+ var i=0, ien=a.length;
+
+ // Could have the test in the loop for slightly smaller code, but speed
+ // is essential here
+ if ( prop2 !== undefined ) {
+ for ( ; i<ien ; i++ ) {
+ if ( a[i] && a[i][ prop ] ) {
+ out.push( a[i][ prop ][ prop2 ] );
+ }
+ }
+ }
+ else {
+ for ( ; i<ien ; i++ ) {
+ if ( a[i] ) {
+ out.push( a[i][ prop ] );
+ }
+ }
+ }
+
+ return out;
+ };
+
+
+ // Basically the same as _pluck, but rather than looping over `a` we use `order`
+ // as the indexes to pick from `a`
+ var _pluck_order = function ( a, order, prop, prop2 )
+ {
+ var out = [];
+ var i=0, ien=order.length;
+
+ // Could have the test in the loop for slightly smaller code, but speed
+ // is essential here
+ if ( prop2 !== undefined ) {
+ for ( ; i<ien ; i++ ) {
+ if ( a[ order[i] ][ prop ] ) {
+ out.push( a[ order[i] ][ prop ][ prop2 ] );
+ }
+ }
+ }
+ else {
+ for ( ; i<ien ; i++ ) {
+ out.push( a[ order[i] ][ prop ] );
+ }
+ }
+
+ return out;
+ };
+
+
+ var _range = function ( len, start )
+ {
+ var out = [];
+ var end;
+
+ if ( start === undefined ) {
+ start = 0;
+ end = len;
+ }
+ else {
+ end = start;
+ start = len;
+ }
+
+ for ( var i=start ; i<end ; i++ ) {
+ out.push( i );
+ }
+
+ return out;
+ };
+
+
+ var _removeEmpty = function ( a )
+ {
+ var out = [];
+
+ for ( var i=0, ien=a.length ; i<ien ; i++ ) {
+ if ( a[i] ) { // careful - will remove all falsy values!
+ out.push( a[i] );
+ }
+ }
+
+ return out;
+ };
+
+
+ var _stripHtml = function ( d ) {
+ return d.replace( _re_html, '' );
+ };
+
+
+ /**
+ * Determine if all values in the array are unique. This means we can short
+ * cut the _unique method at the cost of a single loop. A sorted array is used
+ * to easily check the values.
+ *
+ * @param {array} src Source array
+ * @return {boolean} true if all unique, false otherwise
+ * @ignore
+ */
+ var _areAllUnique = function ( src ) {
+ if ( src.length < 2 ) {
+ return true;
+ }
+
+ var sorted = src.slice().sort();
+ var last = sorted[0];
+
+ for ( var i=1, ien=sorted.length ; i<ien ; i++ ) {
+ if ( sorted[i] === last ) {
+ return false;
+ }
+
+ last = sorted[i];
+ }
+
+ return true;
+ };
+
+
+ /**
+ * Find the unique elements in a source array.
+ *
+ * @param {array} src Source array
+ * @return {array} Array of unique items
+ * @ignore
+ */
+ var _unique = function ( src )
+ {
+ if ( _areAllUnique( src ) ) {
+ return src.slice();
+ }
+
+ // A faster unique method is to use object keys to identify used values,
+ // but this doesn't work with arrays or objects, which we must also
+ // consider. See jsperf.com/compare-array-unique-versions/4 for more
+ // information.
+ var
+ out = [],
+ val,
+ i, ien=src.length,
+ j, k=0;
+
+ again: for ( i=0 ; i<ien ; i++ ) {
+ val = src[i];
+
+ for ( j=0 ; j<k ; j++ ) {
+ if ( out[j] === val ) {
+ continue again;
+ }
+ }
+
+ out.push( val );
+ k++;
+ }
+
+ return out;
+ };
+
+ // Surprisingly this is faster than [].concat.apply
+ // https://jsperf.com/flatten-an-array-loop-vs-reduce/2
+ var _flatten = function (out, val) {
+ if (Array.isArray(val)) {
+ for (var i=0 ; i<val.length ; i++) {
+ _flatten(out, val[i]);
+ }
+ }
+ else {
+ out.push(val);
+ }
+
+ return out;
+ }
+
+ var _includes = function (search, start) {
+ if (start === undefined) {
+ start = 0;
+ }
+
+ return this.indexOf(search, start) !== -1;
+ };
+
+ // Array.isArray polyfill.
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray
+ if (! Array.isArray) {
+ Array.isArray = function(arg) {
+ return Object.prototype.toString.call(arg) === '[object Array]';
+ };
+ }
+
+ if (! Array.prototype.includes) {
+ Array.prototype.includes = _includes;
+ }
+
+ // .trim() polyfill
+ // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim
+ if (!String.prototype.trim) {
+ String.prototype.trim = function () {
+ return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+ };
+ }
+
+ if (! String.prototype.includes) {
+ String.prototype.includes = _includes;
+ }
+
+ /**
+ * DataTables utility methods
+ *
+ * This namespace provides helper methods that DataTables uses internally to
+ * create a DataTable, but which are not exclusively used only for DataTables.
+ * These methods can be used by extension authors to save the duplication of
+ * code.
+ *
+ * @namespace
+ */
+ DataTable.util = {
+ /**
+ * Throttle the calls to a function. Arguments and context are maintained
+ * for the throttled function.
+ *
+ * @param {function} fn Function to be called
+ * @param {integer} freq Call frequency in mS
+ * @return {function} Wrapped function
+ */
+ throttle: function ( fn, freq ) {
+ var
+ frequency = freq !== undefined ? freq : 200,
+ last,
+ timer;
+
+ return function () {
+ var
+ that = this,
+ now = +new Date(),
+ args = arguments;
+
+ if ( last && now < last + frequency ) {
+ clearTimeout( timer );
+
+ timer = setTimeout( function () {
+ last = undefined;
+ fn.apply( that, args );
+ }, frequency );
+ }
+ else {
+ last = now;
+ fn.apply( that, args );
+ }
+ };
+ },
+
+
+ /**
+ * Escape a string such that it can be used in a regular expression
+ *
+ * @param {string} val string to escape
+ * @returns {string} escaped string
+ */
+ escapeRegex: function ( val ) {
+ return val.replace( _re_escape_regex, '\\$1' );
+ },
+
+ /**
+ * Create a function that will write to a nested object or array
+ * @param {*} source JSON notation string
+ * @returns Write function
+ */
+ set: function ( source ) {
+ if ( $.isPlainObject( source ) ) {
+ /* Unlike get, only the underscore (global) option is used for for
+ * setting data since we don't know the type here. This is why an object
+ * option is not documented for `mData` (which is read/write), but it is
+ * for `mRender` which is read only.
+ */
+ return DataTable.util.set( source._ );
+ }
+ else if ( source === null ) {
+ // Nothing to do when the data source is null
+ return function () {};
+ }
+ else if ( typeof source === 'function' ) {
+ return function (data, val, meta) {
+ source( data, 'set', val, meta );
+ };
+ }
+ else if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||
+ source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )
+ {
+ // Like the get, we need to get data from a nested object
+ var setData = function (data, val, src) {
+ var a = _fnSplitObjNotation( src ), b;
+ var aLast = a[a.length-1];
+ var arrayNotation, funcNotation, o, innerSrc;
+
+ for ( var i=0, iLen=a.length-1 ; i<iLen ; i++ ) {
+ // Protect against prototype pollution
+ if (a[i] === '__proto__' || a[i] === 'constructor') {
+ throw new Error('Cannot set prototype values');
+ }
+
+ // Check if we are dealing with an array notation request
+ arrayNotation = a[i].match(__reArray);
+ funcNotation = a[i].match(__reFn);
+
+ if ( arrayNotation ) {
+ a[i] = a[i].replace(__reArray, '');
+ data[ a[i] ] = [];
+
+ // Get the remainder of the nested object to set so we can recurse
+ b = a.slice();
+ b.splice( 0, i+1 );
+ innerSrc = b.join('.');
+
+ // Traverse each entry in the array setting the properties requested
+ if ( Array.isArray( val ) ) {
+ for ( var j=0, jLen=val.length ; j<jLen ; j++ ) {
+ o = {};
+ setData( o, val[j], innerSrc );
+ data[ a[i] ].push( o );
+ }
+ }
+ else {
+ // We've been asked to save data to an array, but it
+ // isn't array data to be saved. Best that can be done
+ // is to just save the value.
+ data[ a[i] ] = val;
+ }
+
+ // The inner call to setData has already traversed through the remainder
+ // of the source and has set the data, thus we can exit here
+ return;
+ }
+ else if ( funcNotation ) {
+ // Function call
+ a[i] = a[i].replace(__reFn, '');
+ data = data[ a[i] ]( val );
+ }
+
+ // If the nested object doesn't currently exist - since we are
+ // trying to set the value - create it
+ if ( data[ a[i] ] === null || data[ a[i] ] === undefined ) {
+ data[ a[i] ] = {};
+ }
+ data = data[ a[i] ];
+ }
+
+ // Last item in the input - i.e, the actual set
+ if ( aLast.match(__reFn ) ) {
+ // Function call
+ data = data[ aLast.replace(__reFn, '') ]( val );
+ }
+ else {
+ // If array notation is used, we just want to strip it and use the property name
+ // and assign the value. If it isn't used, then we get the result we want anyway
+ data[ aLast.replace(__reArray, '') ] = val;
+ }
+ };
+
+ return function (data, val) { // meta is also passed in, but not used
+ return setData( data, val, source );
+ };
+ }
+ else {
+ // Array or flat object mapping
+ return function (data, val) { // meta is also passed in, but not used
+ data[source] = val;
+ };
+ }
+ },
+
+ /**
+ * Create a function that will read nested objects from arrays, based on JSON notation
+ * @param {*} source JSON notation string
+ * @returns Value read
+ */
+ get: function ( source ) {
+ if ( $.isPlainObject( source ) ) {
+ // Build an object of get functions, and wrap them in a single call
+ var o = {};
+ $.each( source, function (key, val) {
+ if ( val ) {
+ o[key] = DataTable.util.get( val );
+ }
+ } );
+
+ return function (data, type, row, meta) {
+ var t = o[type] || o._;
+ return t !== undefined ?
+ t(data, type, row, meta) :
+ data;
+ };
+ }
+ else if ( source === null ) {
+ // Give an empty string for rendering / sorting etc
+ return function (data) { // type, row and meta also passed, but not used
+ return data;
+ };
+ }
+ else if ( typeof source === 'function' ) {
+ return function (data, type, row, meta) {
+ return source( data, type, row, meta );
+ };
+ }
+ else if ( typeof source === 'string' && (source.indexOf('.') !== -1 ||
+ source.indexOf('[') !== -1 || source.indexOf('(') !== -1) )
+ {
+ /* If there is a . in the source string then the data source is in a
+ * nested object so we loop over the data for each level to get the next
+ * level down. On each loop we test for undefined, and if found immediately
+ * return. This allows entire objects to be missing and sDefaultContent to
+ * be used if defined, rather than throwing an error
+ */
+ var fetchData = function (data, type, src) {
+ var arrayNotation, funcNotation, out, innerSrc;
+
+ if ( src !== "" ) {
+ var a = _fnSplitObjNotation( src );
+
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ ) {
+ // Check if we are dealing with special notation
+ arrayNotation = a[i].match(__reArray);
+ funcNotation = a[i].match(__reFn);
+
+ if ( arrayNotation ) {
+ // Array notation
+ a[i] = a[i].replace(__reArray, '');
+
+ // Condition allows simply [] to be passed in
+ if ( a[i] !== "" ) {
+ data = data[ a[i] ];
+ }
+ out = [];
+
+ // Get the remainder of the nested object to get
+ a.splice( 0, i+1 );
+ innerSrc = a.join('.');
+
+ // Traverse each entry in the array getting the properties requested
+ if ( Array.isArray( data ) ) {
+ for ( var j=0, jLen=data.length ; j<jLen ; j++ ) {
+ out.push( fetchData( data[j], type, innerSrc ) );
+ }
+ }
+
+ // If a string is given in between the array notation indicators, that
+ // is used to join the strings together, otherwise an array is returned
+ var join = arrayNotation[0].substring(1, arrayNotation[0].length-1);
+ data = (join==="") ? out : out.join(join);
+
+ // The inner call to fetchData has already traversed through the remainder
+ // of the source requested, so we exit from the loop
+ break;
+ }
+ else if ( funcNotation ) {
+ // Function call
+ a[i] = a[i].replace(__reFn, '');
+ data = data[ a[i] ]();
+ continue;
+ }
+
+ if ( data === null || data[ a[i] ] === undefined ) {
+ return undefined;
+ }
+
+ data = data[ a[i] ];
+ }
+ }
+
+ return data;
+ };
+
+ return function (data, type) { // row and meta also passed, but not used
+ return fetchData( data, type, source );
+ };
+ }
+ else {
+ // Array or flat object mapping
+ return function (data, type) { // row and meta also passed, but not used
+ return data[source];
+ };
+ }
+ }
+ };
+
+
+
+ /**
+ * Create a mapping object that allows camel case parameters to be looked up
+ * for their Hungarian counterparts. The mapping is stored in a private
+ * parameter called `_hungarianMap` which can be accessed on the source object.
+ * @param {object} o
+ * @memberof DataTable#oApi
+ */
+ function _fnHungarianMap ( o )
+ {
+ var
+ hungarian = 'a aa ai ao as b fn i m o s ',
+ match,
+ newKey,
+ map = {};
+
+ $.each( o, function (key, val) {
+ match = key.match(/^([^A-Z]+?)([A-Z])/);
+
+ if ( match && hungarian.indexOf(match[1]+' ') !== -1 )
+ {
+ newKey = key.replace( match[0], match[2].toLowerCase() );
+ map[ newKey ] = key;
+
+ if ( match[1] === 'o' )
+ {
+ _fnHungarianMap( o[key] );
+ }
+ }
+ } );
+
+ o._hungarianMap = map;
+ }
+
+
+ /**
+ * Convert from camel case parameters to Hungarian, based on a Hungarian map
+ * created by _fnHungarianMap.
+ * @param {object} src The model object which holds all parameters that can be
+ * mapped.
+ * @param {object} user The object to convert from camel case to Hungarian.
+ * @param {boolean} force When set to `true`, properties which already have a
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
+ * won't be.
+ * @memberof DataTable#oApi
+ */
+ function _fnCamelToHungarian ( src, user, force )
+ {
+ if ( ! src._hungarianMap ) {
+ _fnHungarianMap( src );
+ }
+
+ var hungarianKey;
+
+ $.each( user, function (key, val) {
+ hungarianKey = src._hungarianMap[ key ];
+
+ if ( hungarianKey !== undefined && (force || user[hungarianKey] === undefined) )
+ {
+ // For objects, we need to buzz down into the object to copy parameters
+ if ( hungarianKey.charAt(0) === 'o' )
+ {
+ // Copy the camelCase options over to the hungarian
+ if ( ! user[ hungarianKey ] ) {
+ user[ hungarianKey ] = {};
+ }
+ $.extend( true, user[hungarianKey], user[key] );
+
+ _fnCamelToHungarian( src[hungarianKey], user[hungarianKey], force );
+ }
+ else {
+ user[hungarianKey] = user[ key ];
+ }
+ }
+ } );
+ }
+
+
+ /**
+ * Language compatibility - when certain options are given, and others aren't, we
+ * need to duplicate the values over, in order to provide backwards compatibility
+ * with older language files.
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnLanguageCompat( lang )
+ {
+ // Note the use of the Hungarian notation for the parameters in this method as
+ // this is called after the mapping of camelCase to Hungarian
+ var defaults = DataTable.defaults.oLanguage;
+
+ // Default mapping
+ var defaultDecimal = defaults.sDecimal;
+ if ( defaultDecimal ) {
+ _addNumericSort( defaultDecimal );
+ }
+
+ if ( lang ) {
+ var zeroRecords = lang.sZeroRecords;
+
+ // Backwards compatibility - if there is no sEmptyTable given, then use the same as
+ // sZeroRecords - assuming that is given.
+ if ( ! lang.sEmptyTable && zeroRecords &&
+ defaults.sEmptyTable === "No data available in table" )
+ {
+ _fnMap( lang, lang, 'sZeroRecords', 'sEmptyTable' );
+ }
+
+ // Likewise with loading records
+ if ( ! lang.sLoadingRecords && zeroRecords &&
+ defaults.sLoadingRecords === "Loading..." )
+ {
+ _fnMap( lang, lang, 'sZeroRecords', 'sLoadingRecords' );
+ }
+
+ // Old parameter name of the thousands separator mapped onto the new
+ if ( lang.sInfoThousands ) {
+ lang.sThousands = lang.sInfoThousands;
+ }
+
+ var decimal = lang.sDecimal;
+ if ( decimal && defaultDecimal !== decimal ) {
+ _addNumericSort( decimal );
+ }
+ }
+ }
+
+
+ /**
+ * Map one parameter onto another
+ * @param {object} o Object to map
+ * @param {*} knew The new parameter name
+ * @param {*} old The old parameter name
+ */
+ var _fnCompatMap = function ( o, knew, old ) {
+ if ( o[ knew ] !== undefined ) {
+ o[ old ] = o[ knew ];
+ }
+ };
+
+
+ /**
+ * Provide backwards compatibility for the main DT options. Note that the new
+ * options are mapped onto the old parameters, so this is an external interface
+ * change only.
+ * @param {object} init Object to map
+ */
+ function _fnCompatOpts ( init )
+ {
+ _fnCompatMap( init, 'ordering', 'bSort' );
+ _fnCompatMap( init, 'orderMulti', 'bSortMulti' );
+ _fnCompatMap( init, 'orderClasses', 'bSortClasses' );
+ _fnCompatMap( init, 'orderCellsTop', 'bSortCellsTop' );
+ _fnCompatMap( init, 'order', 'aaSorting' );
+ _fnCompatMap( init, 'orderFixed', 'aaSortingFixed' );
+ _fnCompatMap( init, 'paging', 'bPaginate' );
+ _fnCompatMap( init, 'pagingType', 'sPaginationType' );
+ _fnCompatMap( init, 'pageLength', 'iDisplayLength' );
+ _fnCompatMap( init, 'searching', 'bFilter' );
+
+ // Boolean initialisation of x-scrolling
+ if ( typeof init.sScrollX === 'boolean' ) {
+ init.sScrollX = init.sScrollX ? '100%' : '';
+ }
+ if ( typeof init.scrollX === 'boolean' ) {
+ init.scrollX = init.scrollX ? '100%' : '';
+ }
+
+ // Column search objects are in an array, so it needs to be converted
+ // element by element
+ var searchCols = init.aoSearchCols;
+
+ if ( searchCols ) {
+ for ( var i=0, ien=searchCols.length ; i<ien ; i++ ) {
+ if ( searchCols[i] ) {
+ _fnCamelToHungarian( DataTable.models.oSearch, searchCols[i] );
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Provide backwards compatibility for column options. Note that the new options
+ * are mapped onto the old parameters, so this is an external interface change
+ * only.
+ * @param {object} init Object to map
+ */
+ function _fnCompatCols ( init )
+ {
+ _fnCompatMap( init, 'orderable', 'bSortable' );
+ _fnCompatMap( init, 'orderData', 'aDataSort' );
+ _fnCompatMap( init, 'orderSequence', 'asSorting' );
+ _fnCompatMap( init, 'orderDataType', 'sortDataType' );
+
+ // orderData can be given as an integer
+ var dataSort = init.aDataSort;
+ if ( typeof dataSort === 'number' && ! Array.isArray( dataSort ) ) {
+ init.aDataSort = [ dataSort ];
+ }
+ }
+
+
+ /**
+ * Browser feature detection for capabilities, quirks
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBrowserDetect( settings )
+ {
+ // We don't need to do this every time DataTables is constructed, the values
+ // calculated are specific to the browser and OS configuration which we
+ // don't expect to change between initialisations
+ if ( ! DataTable.__browser ) {
+ var browser = {};
+ DataTable.__browser = browser;
+
+ // Scrolling feature / quirks detection
+ var n = $('<div/>')
+ .css( {
+ position: 'fixed',
+ top: 0,
+ left: $(window).scrollLeft()*-1, // allow for scrolling
+ height: 1,
+ width: 1,
+ overflow: 'hidden'
+ } )
+ .append(
+ $('<div/>')
+ .css( {
+ position: 'absolute',
+ top: 1,
+ left: 1,
+ width: 100,
+ overflow: 'scroll'
+ } )
+ .append(
+ $('<div/>')
+ .css( {
+ width: '100%',
+ height: 10
+ } )
+ )
+ )
+ .appendTo( 'body' );
+
+ var outer = n.children();
+ var inner = outer.children();
+
+ // Numbers below, in order, are:
+ // inner.offsetWidth, inner.clientWidth, outer.offsetWidth, outer.clientWidth
+ //
+ // IE6 XP: 100 100 100 83
+ // IE7 Vista: 100 100 100 83
+ // IE 8+ Windows: 83 83 100 83
+ // Evergreen Windows: 83 83 100 83
+ // Evergreen Mac with scrollbars: 85 85 100 85
+ // Evergreen Mac without scrollbars: 100 100 100 100
+
+ // Get scrollbar width
+ browser.barWidth = outer[0].offsetWidth - outer[0].clientWidth;
+
+ // IE6/7 will oversize a width 100% element inside a scrolling element, to
+ // include the width of the scrollbar, while other browsers ensure the inner
+ // element is contained without forcing scrolling
+ browser.bScrollOversize = inner[0].offsetWidth === 100 && outer[0].clientWidth !== 100;
+
+ // In rtl text layout, some browsers (most, but not all) will place the
+ // scrollbar on the left, rather than the right.
+ browser.bScrollbarLeft = Math.round( inner.offset().left ) !== 1;
+
+ // IE8- don't provide height and width for getBoundingClientRect
+ browser.bBounding = n[0].getBoundingClientRect().width ? true : false;
+
+ n.remove();
+ }
+
+ $.extend( settings.oBrowser, DataTable.__browser );
+ settings.oScroll.iBarWidth = DataTable.__browser.barWidth;
+ }
+
+
+ /**
+ * Array.prototype reduce[Right] method, used for browsers which don't support
+ * JS 1.6. Done this way to reduce code size, since we iterate either way
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnReduce ( that, fn, init, start, end, inc )
+ {
+ var
+ i = start,
+ value,
+ isSet = false;
+
+ if ( init !== undefined ) {
+ value = init;
+ isSet = true;
+ }
+
+ while ( i !== end ) {
+ if ( ! that.hasOwnProperty(i) ) {
+ continue;
+ }
+
+ value = isSet ?
+ fn( value, that[i], i, that ) :
+ that[i];
+
+ isSet = true;
+ i += inc;
+ }
+
+ return value;
+ }
+
+ /**
+ * Add a column to the list used for the table with default values
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nTh The th element for this column
+ * @memberof DataTable#oApi
+ */
+ function _fnAddColumn( oSettings, nTh )
+ {
+ // Add column to aoColumns array
+ var oDefaults = DataTable.defaults.column;
+ var iCol = oSettings.aoColumns.length;
+ var oCol = $.extend( {}, DataTable.models.oColumn, oDefaults, {
+ "nTh": nTh ? nTh : document.createElement('th'),
+ "sTitle": oDefaults.sTitle ? oDefaults.sTitle : nTh ? nTh.innerHTML : '',
+ "aDataSort": oDefaults.aDataSort ? oDefaults.aDataSort : [iCol],
+ "mData": oDefaults.mData ? oDefaults.mData : iCol,
+ idx: iCol
+ } );
+ oSettings.aoColumns.push( oCol );
+
+ // Add search object for column specific search. Note that the `searchCols[ iCol ]`
+ // passed into extend can be undefined. This allows the user to give a default
+ // with only some of the parameters defined, and also not give a default
+ var searchCols = oSettings.aoPreSearchCols;
+ searchCols[ iCol ] = $.extend( {}, DataTable.models.oSearch, searchCols[ iCol ] );
+
+ // Use the default column options function to initialise classes etc
+ _fnColumnOptions( oSettings, iCol, $(nTh).data() );
+ }
+
+
+ /**
+ * Apply options for a column
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iCol column index to consider
+ * @param {object} oOptions object with sType, bVisible and bSearchable etc
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnOptions( oSettings, iCol, oOptions )
+ {
+ var oCol = oSettings.aoColumns[ iCol ];
+ var oClasses = oSettings.oClasses;
+ var th = $(oCol.nTh);
+
+ // Try to get width information from the DOM. We can't get it from CSS
+ // as we'd need to parse the CSS stylesheet. `width` option can override
+ if ( ! oCol.sWidthOrig ) {
+ // Width attribute
+ oCol.sWidthOrig = th.attr('width') || null;
+
+ // Style attribute
+ var t = (th.attr('style') || '').match(/width:\s*(\d+[pxem%]+)/);
+ if ( t ) {
+ oCol.sWidthOrig = t[1];
+ }
+ }
+
+ /* User specified column options */
+ if ( oOptions !== undefined && oOptions !== null )
+ {
+ // Backwards compatibility
+ _fnCompatCols( oOptions );
+
+ // Map camel case parameters to their Hungarian counterparts
+ _fnCamelToHungarian( DataTable.defaults.column, oOptions, true );
+
+ /* Backwards compatibility for mDataProp */
+ if ( oOptions.mDataProp !== undefined && !oOptions.mData )
+ {
+ oOptions.mData = oOptions.mDataProp;
+ }
+
+ if ( oOptions.sType )
+ {
+ oCol._sManualType = oOptions.sType;
+ }
+
+ // `class` is a reserved word in Javascript, so we need to provide
+ // the ability to use a valid name for the camel case input
+ if ( oOptions.className && ! oOptions.sClass )
+ {
+ oOptions.sClass = oOptions.className;
+ }
+ if ( oOptions.sClass ) {
+ th.addClass( oOptions.sClass );
+ }
+
+ var origClass = oCol.sClass;
+
+ $.extend( oCol, oOptions );
+ _fnMap( oCol, oOptions, "sWidth", "sWidthOrig" );
+
+ // Merge class from previously defined classes with this one, rather than just
+ // overwriting it in the extend above
+ if (origClass !== oCol.sClass) {
+ oCol.sClass = origClass + ' ' + oCol.sClass;
+ }
+
+ /* iDataSort to be applied (backwards compatibility), but aDataSort will take
+ * priority if defined
+ */
+ if ( oOptions.iDataSort !== undefined )
+ {
+ oCol.aDataSort = [ oOptions.iDataSort ];
+ }
+ _fnMap( oCol, oOptions, "aDataSort" );
+ }
+
+ /* Cache the data get and set functions for speed */
+ var mDataSrc = oCol.mData;
+ var mData = _fnGetObjectDataFn( mDataSrc );
+ var mRender = oCol.mRender ? _fnGetObjectDataFn( oCol.mRender ) : null;
+
+ var attrTest = function( src ) {
+ return typeof src === 'string' && src.indexOf('@') !== -1;
+ };
+ oCol._bAttrSrc = $.isPlainObject( mDataSrc ) && (
+ attrTest(mDataSrc.sort) || attrTest(mDataSrc.type) || attrTest(mDataSrc.filter)
+ );
+ oCol._setter = null;
+
+ oCol.fnGetData = function (rowData, type, meta) {
+ var innerData = mData( rowData, type, undefined, meta );
+
+ return mRender && type ?
+ mRender( innerData, type, rowData, meta ) :
+ innerData;
+ };
+ oCol.fnSetData = function ( rowData, val, meta ) {
+ return _fnSetObjectDataFn( mDataSrc )( rowData, val, meta );
+ };
+
+ // Indicate if DataTables should read DOM data as an object or array
+ // Used in _fnGetRowElements
+ if ( typeof mDataSrc !== 'number' ) {
+ oSettings._rowReadObject = true;
+ }
+
+ /* Feature sorting overrides column specific when off */
+ if ( !oSettings.oFeatures.bSort )
+ {
+ oCol.bSortable = false;
+ th.addClass( oClasses.sSortableNone ); // Have to add class here as order event isn't called
+ }
+
+ /* Check that the class assignment is correct for sorting */
+ var bAsc = $.inArray('asc', oCol.asSorting) !== -1;
+ var bDesc = $.inArray('desc', oCol.asSorting) !== -1;
+ if ( !oCol.bSortable || (!bAsc && !bDesc) )
+ {
+ oCol.sSortingClass = oClasses.sSortableNone;
+ oCol.sSortingClassJUI = "";
+ }
+ else if ( bAsc && !bDesc )
+ {
+ oCol.sSortingClass = oClasses.sSortableAsc;
+ oCol.sSortingClassJUI = oClasses.sSortJUIAscAllowed;
+ }
+ else if ( !bAsc && bDesc )
+ {
+ oCol.sSortingClass = oClasses.sSortableDesc;
+ oCol.sSortingClassJUI = oClasses.sSortJUIDescAllowed;
+ }
+ else
+ {
+ oCol.sSortingClass = oClasses.sSortable;
+ oCol.sSortingClassJUI = oClasses.sSortJUI;
+ }
+ }
+
+
+ /**
+ * Adjust the table column widths for new data. Note: you would probably want to
+ * do a redraw after calling this function!
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAdjustColumnSizing ( settings )
+ {
+ /* Not interested in doing column width calculation if auto-width is disabled */
+ if ( settings.oFeatures.bAutoWidth !== false )
+ {
+ var columns = settings.aoColumns;
+
+ _fnCalculateColumnWidths( settings );
+ for ( var i=0 , iLen=columns.length ; i<iLen ; i++ )
+ {
+ columns[i].nTh.style.width = columns[i].sWidth;
+ }
+ }
+
+ var scroll = settings.oScroll;
+ if ( scroll.sY !== '' || scroll.sX !== '')
+ {
+ _fnScrollDraw( settings );
+ }
+
+ _fnCallbackFire( settings, null, 'column-sizing', [settings] );
+ }
+
+
+ /**
+ * Convert the index of a visible column to the index in the data array (take account
+ * of hidden columns)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iMatch Visible column index to lookup
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnVisibleToColumnIndex( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+
+ return typeof aiVis[iMatch] === 'number' ?
+ aiVis[iMatch] :
+ null;
+ }
+
+
+ /**
+ * Convert the index of an index in the data array and convert it to the visible
+ * column index (take account of hidden columns)
+ * @param {int} iMatch Column index to lookup
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the data index
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnIndexToVisible( oSettings, iMatch )
+ {
+ var aiVis = _fnGetColumns( oSettings, 'bVisible' );
+ var iPos = $.inArray( iMatch, aiVis );
+
+ return iPos !== -1 ? iPos : null;
+ }
+
+
+ /**
+ * Get the number of visible columns
+ * @param {object} oSettings dataTables settings object
+ * @returns {int} i the number of visible columns
+ * @memberof DataTable#oApi
+ */
+ function _fnVisbleColumns( oSettings )
+ {
+ var vis = 0;
+
+ // No reduce in IE8, use a loop for now
+ $.each( oSettings.aoColumns, function ( i, col ) {
+ if ( col.bVisible && $(col.nTh).css('display') !== 'none' ) {
+ vis++;
+ }
+ } );
+
+ return vis;
+ }
+
+
+ /**
+ * Get an array of column indexes that match a given property
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sParam Parameter in aoColumns to look for - typically
+ * bVisible or bSearchable
+ * @returns {array} Array of indexes with matched properties
+ * @memberof DataTable#oApi
+ */
+ function _fnGetColumns( oSettings, sParam )
+ {
+ var a = [];
+
+ $.map( oSettings.aoColumns, function(val, i) {
+ if ( val[sParam] ) {
+ a.push( i );
+ }
+ } );
+
+ return a;
+ }
+
+
+ /**
+ * Calculate the 'type' of a column
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnColumnTypes ( settings )
+ {
+ var columns = settings.aoColumns;
+ var data = settings.aoData;
+ var types = DataTable.ext.type.detect;
+ var i, ien, j, jen, k, ken;
+ var col, cell, detectedType, cache;
+
+ // For each column, spin over the
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ col = columns[i];
+ cache = [];
+
+ if ( ! col.sType && col._sManualType ) {
+ col.sType = col._sManualType;
+ }
+ else if ( ! col.sType ) {
+ for ( j=0, jen=types.length ; j<jen ; j++ ) {
+ for ( k=0, ken=data.length ; k<ken ; k++ ) {
+ // Use a cache array so we only need to get the type data
+ // from the formatter once (when using multiple detectors)
+ if ( cache[k] === undefined ) {
+ cache[k] = _fnGetCellData( settings, k, i, 'type' );
+ }
+
+ detectedType = types[j]( cache[k], settings );
+
+ // If null, then this type can't apply to this column, so
+ // rather than testing all cells, break out. There is an
+ // exception for the last type which is `html`. We need to
+ // scan all rows since it is possible to mix string and HTML
+ // types
+ if ( ! detectedType && j !== types.length-1 ) {
+ break;
+ }
+
+ // Only a single match is needed for html type since it is
+ // bottom of the pile and very similar to string - but it
+ // must not be empty
+ if ( detectedType === 'html' && ! _empty(cache[k]) ) {
+ break;
+ }
+ }
+
+ // Type is valid for all data points in the column - use this
+ // type
+ if ( detectedType ) {
+ col.sType = detectedType;
+ break;
+ }
+ }
+
+ // Fall back - if no type was detected, always use string
+ if ( ! col.sType ) {
+ col.sType = 'string';
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Take the column definitions and static columns arrays and calculate how
+ * they relate to column indexes. The callback function will then apply the
+ * definition found for a column to a suitable configuration object.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aoColDefs The aoColumnDefs array that is to be applied
+ * @param {array} aoCols The aoColumns array that defines columns individually
+ * @param {function} fn Callback function - takes two parameters, the calculated
+ * column index and the definition for that column.
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyColumnDefs( oSettings, aoColDefs, aoCols, fn )
+ {
+ var i, iLen, j, jLen, k, kLen, def;
+ var columns = oSettings.aoColumns;
+
+ // Column definitions with aTargets
+ if ( aoColDefs )
+ {
+ /* Loop over the definitions array - loop in reverse so first instance has priority */
+ for ( i=aoColDefs.length-1 ; i>=0 ; i-- )
+ {
+ def = aoColDefs[i];
+
+ /* Each definition can target multiple columns, as it is an array */
+ var aTargets = def.target !== undefined
+ ? def.target
+ : def.targets !== undefined
+ ? def.targets
+ : def.aTargets;
+
+ if ( ! Array.isArray( aTargets ) )
+ {
+ aTargets = [ aTargets ];
+ }
+
+ for ( j=0, jLen=aTargets.length ; j<jLen ; j++ )
+ {
+ if ( typeof aTargets[j] === 'number' && aTargets[j] >= 0 )
+ {
+ /* Add columns that we don't yet know about */
+ while( columns.length <= aTargets[j] )
+ {
+ _fnAddColumn( oSettings );
+ }
+
+ /* Integer, basic index */
+ fn( aTargets[j], def );
+ }
+ else if ( typeof aTargets[j] === 'number' && aTargets[j] < 0 )
+ {
+ /* Negative integer, right to left column counting */
+ fn( columns.length+aTargets[j], def );
+ }
+ else if ( typeof aTargets[j] === 'string' )
+ {
+ /* Class name matching on TH element */
+ for ( k=0, kLen=columns.length ; k<kLen ; k++ )
+ {
+ if ( aTargets[j] == "_all" ||
+ $(columns[k].nTh).hasClass( aTargets[j] ) )
+ {
+ fn( k, def );
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // Statically defined columns array
+ if ( aoCols )
+ {
+ for ( i=0, iLen=aoCols.length ; i<iLen ; i++ )
+ {
+ fn( i, aoCols[i] );
+ }
+ }
+ }
+
+ /**
+ * Add a data array to the table, creating DOM node etc. This is the parallel to
+ * _fnGatherData, but for adding rows from a Javascript source, rather than a
+ * DOM source.
+ * @param {object} oSettings dataTables settings object
+ * @param {array} aData data array to be added
+ * @param {node} [nTr] TR element to add to the table - optional. If not given,
+ * DataTables will create a row automatically
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
+ * if nTr is.
+ * @returns {int} >=0 if successful (index of new aoData entry), -1 if failed
+ * @memberof DataTable#oApi
+ */
+ function _fnAddData ( oSettings, aDataIn, nTr, anTds )
+ {
+ /* Create the object for storing information about this new row */
+ var iRow = oSettings.aoData.length;
+ var oData = $.extend( true, {}, DataTable.models.oRow, {
+ src: nTr ? 'dom' : 'data',
+ idx: iRow
+ } );
+
+ oData._aData = aDataIn;
+ oSettings.aoData.push( oData );
+
+ /* Create the cells */
+ var nTd, sThisType;
+ var columns = oSettings.aoColumns;
+
+ // Invalidate the column types as the new data needs to be revalidated
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
+ {
+ columns[i].sType = null;
+ }
+
+ /* Add to the display array */
+ oSettings.aiDisplayMaster.push( iRow );
+
+ var id = oSettings.rowIdFn( aDataIn );
+ if ( id !== undefined ) {
+ oSettings.aIds[ id ] = oData;
+ }
+
+ /* Create the DOM information, or register it if already present */
+ if ( nTr || ! oSettings.oFeatures.bDeferRender )
+ {
+ _fnCreateTr( oSettings, iRow, nTr, anTds );
+ }
+
+ return iRow;
+ }
+
+
+ /**
+ * Add one or more TR elements to the table. Generally we'd expect to
+ * use this for reading data from a DOM sourced table, but it could be
+ * used for an TR element. Note that if a TR is given, it is used (i.e.
+ * it is not cloned).
+ * @param {object} settings dataTables settings object
+ * @param {array|node|jQuery} trs The TR element(s) to add to the table
+ * @returns {array} Array of indexes for the added rows
+ * @memberof DataTable#oApi
+ */
+ function _fnAddTr( settings, trs )
+ {
+ var row;
+
+ // Allow an individual node to be passed in
+ if ( ! (trs instanceof $) ) {
+ trs = $(trs);
+ }
+
+ return trs.map( function (i, el) {
+ row = _fnGetRowElements( settings, el );
+ return _fnAddData( settings, row.data, el, row.cells );
+ } );
+ }
+
+
+ /**
+ * Take a TR element and convert it to an index in aoData
+ * @param {object} oSettings dataTables settings object
+ * @param {node} n the TR element to find
+ * @returns {int} index if the node is found, null if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToDataIndex( oSettings, n )
+ {
+ return (n._DT_RowIndex!==undefined) ? n._DT_RowIndex : null;
+ }
+
+
+ /**
+ * Take a TD element and convert it into a column data index (not the visible index)
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow The row number the TD/TH can be found in
+ * @param {node} n The TD/TH element to find
+ * @returns {int} index if the node is found, -1 if not
+ * @memberof DataTable#oApi
+ */
+ function _fnNodeToColumnIndex( oSettings, iRow, n )
+ {
+ return $.inArray( n, oSettings.aoData[ iRow ].anCells );
+ }
+
+
+ /**
+ * Get the data for a given cell from the internal cache, taking into account data mapping
+ * @param {object} settings dataTables settings object
+ * @param {int} rowIdx aoData row id
+ * @param {int} colIdx Column index
+ * @param {string} type data get type ('display', 'type' 'filter|search' 'sort|order')
+ * @returns {*} Cell data
+ * @memberof DataTable#oApi
+ */
+ function _fnGetCellData( settings, rowIdx, colIdx, type )
+ {
+ if (type === 'search') {
+ type = 'filter';
+ }
+ else if (type === 'order') {
+ type = 'sort';
+ }
+
+ var draw = settings.iDraw;
+ var col = settings.aoColumns[colIdx];
+ var rowData = settings.aoData[rowIdx]._aData;
+ var defaultContent = col.sDefaultContent;
+ var cellData = col.fnGetData( rowData, type, {
+ settings: settings,
+ row: rowIdx,
+ col: colIdx
+ } );
+
+ if ( cellData === undefined ) {
+ if ( settings.iDrawError != draw && defaultContent === null ) {
+ _fnLog( settings, 0, "Requested unknown parameter "+
+ (typeof col.mData=='function' ? '{function}' : "'"+col.mData+"'")+
+ " for row "+rowIdx+", column "+colIdx, 4 );
+ settings.iDrawError = draw;
+ }
+ return defaultContent;
+ }
+
+ // When the data source is null and a specific data type is requested (i.e.
+ // not the original data), we can use default column data
+ if ( (cellData === rowData || cellData === null) && defaultContent !== null && type !== undefined ) {
+ cellData = defaultContent;
+ }
+ else if ( typeof cellData === 'function' ) {
+ // If the data source is a function, then we run it and use the return,
+ // executing in the scope of the data object (for instances)
+ return cellData.call( rowData );
+ }
+
+ if ( cellData === null && type === 'display' ) {
+ return '';
+ }
+
+ if ( type === 'filter' ) {
+ var fomatters = DataTable.ext.type.search;
+
+ if ( fomatters[ col.sType ] ) {
+ cellData = fomatters[ col.sType ]( cellData );
+ }
+ }
+
+ return cellData;
+ }
+
+
+ /**
+ * Set the value for a specific cell, into the internal data cache
+ * @param {object} settings dataTables settings object
+ * @param {int} rowIdx aoData row id
+ * @param {int} colIdx Column index
+ * @param {*} val Value to set
+ * @memberof DataTable#oApi
+ */
+ function _fnSetCellData( settings, rowIdx, colIdx, val )
+ {
+ var col = settings.aoColumns[colIdx];
+ var rowData = settings.aoData[rowIdx]._aData;
+
+ col.fnSetData( rowData, val, {
+ settings: settings,
+ row: rowIdx,
+ col: colIdx
+ } );
+ }
+
+
+ // Private variable that is used to match action syntax in the data property object
+ var __reArray = /\[.*?\]$/;
+ var __reFn = /\(\)$/;
+
+ /**
+ * Split string on periods, taking into account escaped periods
+ * @param {string} str String to split
+ * @return {array} Split string
+ */
+ function _fnSplitObjNotation( str )
+ {
+ return $.map( str.match(/(\\.|[^\.])+/g) || [''], function ( s ) {
+ return s.replace(/\\\./g, '.');
+ } );
+ }
+
+
+ /**
+ * Return a function that can be used to get data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data get function
+ * @memberof DataTable#oApi
+ */
+ var _fnGetObjectDataFn = DataTable.util.get;
+
+
+ /**
+ * Return a function that can be used to set data from a source object, taking
+ * into account the ability to use nested objects as a source
+ * @param {string|int|function} mSource The data source for the object
+ * @returns {function} Data set function
+ * @memberof DataTable#oApi
+ */
+ var _fnSetObjectDataFn = DataTable.util.set;
+
+
+ /**
+ * Return an array with the full table data
+ * @param {object} oSettings dataTables settings object
+ * @returns array {array} aData Master data array
+ * @memberof DataTable#oApi
+ */
+ function _fnGetDataMaster ( settings )
+ {
+ return _pluck( settings.aoData, '_aData' );
+ }
+
+
+ /**
+ * Nuke the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnClearTable( settings )
+ {
+ settings.aoData.length = 0;
+ settings.aiDisplayMaster.length = 0;
+ settings.aiDisplay.length = 0;
+ settings.aIds = {};
+ }
+
+
+ /**
+ * Take an array of integers (index array) and remove a target integer (value - not
+ * the key!)
+ * @param {array} a Index array to target
+ * @param {int} iTarget value to find
+ * @memberof DataTable#oApi
+ */
+ function _fnDeleteIndex( a, iTarget, splice )
+ {
+ var iTargetIndex = -1;
+
+ for ( var i=0, iLen=a.length ; i<iLen ; i++ )
+ {
+ if ( a[i] == iTarget )
+ {
+ iTargetIndex = i;
+ }
+ else if ( a[i] > iTarget )
+ {
+ a[i]--;
+ }
+ }
+
+ if ( iTargetIndex != -1 && splice === undefined )
+ {
+ a.splice( iTargetIndex, 1 );
+ }
+ }
+
+
+ /**
+ * Mark cached data as invalid such that a re-read of the data will occur when
+ * the cached data is next requested. Also update from the data source object.
+ *
+ * @param {object} settings DataTables settings object
+ * @param {int} rowIdx Row index to invalidate
+ * @param {string} [src] Source to invalidate from: undefined, 'auto', 'dom'
+ * or 'data'
+ * @param {int} [colIdx] Column index to invalidate. If undefined the whole
+ * row will be invalidated
+ * @memberof DataTable#oApi
+ *
+ * @todo For the modularisation of v1.11 this will need to become a callback, so
+ * the sort and filter methods can subscribe to it. That will required
+ * initialisation options for sorting, which is why it is not already baked in
+ */
+ function _fnInvalidate( settings, rowIdx, src, colIdx )
+ {
+ var row = settings.aoData[ rowIdx ];
+ var i, ien;
+ var cellWrite = function ( cell, col ) {
+ // This is very frustrating, but in IE if you just write directly
+ // to innerHTML, and elements that are overwritten are GC'ed,
+ // even if there is a reference to them elsewhere
+ while ( cell.childNodes.length ) {
+ cell.removeChild( cell.firstChild );
+ }
+
+ cell.innerHTML = _fnGetCellData( settings, rowIdx, col, 'display' );
+ };
+
+ // Are we reading last data from DOM or the data object?
+ if ( src === 'dom' || ((! src || src === 'auto') && row.src === 'dom') ) {
+ // Read the data from the DOM
+ row._aData = _fnGetRowElements(
+ settings, row, colIdx, colIdx === undefined ? undefined : row._aData
+ )
+ .data;
+ }
+ else {
+ // Reading from data object, update the DOM
+ var cells = row.anCells;
+
+ if ( cells ) {
+ if ( colIdx !== undefined ) {
+ cellWrite( cells[colIdx], colIdx );
+ }
+ else {
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
+ cellWrite( cells[i], i );
+ }
+ }
+ }
+ }
+
+ // For both row and cell invalidation, the cached data for sorting and
+ // filtering is nulled out
+ row._aSortData = null;
+ row._aFilterData = null;
+
+ // Invalidate the type for a specific column (if given) or all columns since
+ // the data might have changed
+ var cols = settings.aoColumns;
+ if ( colIdx !== undefined ) {
+ cols[ colIdx ].sType = null;
+ }
+ else {
+ for ( i=0, ien=cols.length ; i<ien ; i++ ) {
+ cols[i].sType = null;
+ }
+
+ // Update DataTables special `DT_*` attributes for the row
+ _fnRowAttributes( settings, row );
+ }
+ }
+
+
+ /**
+ * Build a data source object from an HTML row, reading the contents of the
+ * cells that are in the row.
+ *
+ * @param {object} settings DataTables settings object
+ * @param {node|object} TR element from which to read data or existing row
+ * object from which to re-read the data from the cells
+ * @param {int} [colIdx] Optional column index
+ * @param {array|object} [d] Data source object. If `colIdx` is given then this
+ * parameter should also be given and will be used to write the data into.
+ * Only the column in question will be written
+ * @returns {object} Object with two parameters: `data` the data read, in
+ * document order, and `cells` and array of nodes (they can be useful to the
+ * caller, so rather than needing a second traversal to get them, just return
+ * them from here).
+ * @memberof DataTable#oApi
+ */
+ function _fnGetRowElements( settings, row, colIdx, d )
+ {
+ var
+ tds = [],
+ td = row.firstChild,
+ name, col, o, i=0, contents,
+ columns = settings.aoColumns,
+ objectRead = settings._rowReadObject;
+
+ // Allow the data object to be passed in, or construct
+ d = d !== undefined ?
+ d :
+ objectRead ?
+ {} :
+ [];
+
+ var attr = function ( str, td ) {
+ if ( typeof str === 'string' ) {
+ var idx = str.indexOf('@');
+
+ if ( idx !== -1 ) {
+ var attr = str.substring( idx+1 );
+ var setter = _fnSetObjectDataFn( str );
+ setter( d, td.getAttribute( attr ) );
+ }
+ }
+ };
+
+ // Read data from a cell and store into the data object
+ var cellProcess = function ( cell ) {
+ if ( colIdx === undefined || colIdx === i ) {
+ col = columns[i];
+ contents = (cell.innerHTML).trim();
+
+ if ( col && col._bAttrSrc ) {
+ var setter = _fnSetObjectDataFn( col.mData._ );
+ setter( d, contents );
+
+ attr( col.mData.sort, cell );
+ attr( col.mData.type, cell );
+ attr( col.mData.filter, cell );
+ }
+ else {
+ // Depending on the `data` option for the columns the data can
+ // be read to either an object or an array.
+ if ( objectRead ) {
+ if ( ! col._setter ) {
+ // Cache the setter function
+ col._setter = _fnSetObjectDataFn( col.mData );
+ }
+ col._setter( d, contents );
+ }
+ else {
+ d[i] = contents;
+ }
+ }
+ }
+
+ i++;
+ };
+
+ if ( td ) {
+ // `tr` element was passed in
+ while ( td ) {
+ name = td.nodeName.toUpperCase();
+
+ if ( name == "TD" || name == "TH" ) {
+ cellProcess( td );
+ tds.push( td );
+ }
+
+ td = td.nextSibling;
+ }
+ }
+ else {
+ // Existing row object passed in
+ tds = row.anCells;
+
+ for ( var j=0, jen=tds.length ; j<jen ; j++ ) {
+ cellProcess( tds[j] );
+ }
+ }
+
+ // Read the ID from the DOM if present
+ var rowNode = row.firstChild ? row : row.nTr;
+
+ if ( rowNode ) {
+ var id = rowNode.getAttribute( 'id' );
+
+ if ( id ) {
+ _fnSetObjectDataFn( settings.rowId )( d, id );
+ }
+ }
+
+ return {
+ data: d,
+ cells: tds
+ };
+ }
+ /**
+ * Create a new TR element (and it's TD children) for a row
+ * @param {object} oSettings dataTables settings object
+ * @param {int} iRow Row to consider
+ * @param {node} [nTrIn] TR element to add to the table - optional. If not given,
+ * DataTables will create a row automatically
+ * @param {array} [anTds] Array of TD|TH elements for the row - must be given
+ * if nTr is.
+ * @memberof DataTable#oApi
+ */
+ function _fnCreateTr ( oSettings, iRow, nTrIn, anTds )
+ {
+ var
+ row = oSettings.aoData[iRow],
+ rowData = row._aData,
+ cells = [],
+ nTr, nTd, oCol,
+ i, iLen, create;
+
+ if ( row.nTr === null )
+ {
+ nTr = nTrIn || document.createElement('tr');
+
+ row.nTr = nTr;
+ row.anCells = cells;
+
+ /* Use a private property on the node to allow reserve mapping from the node
+ * to the aoData array for fast look up
+ */
+ nTr._DT_RowIndex = iRow;
+
+ /* Special parameters can be given by the data source to be used on the row */
+ _fnRowAttributes( oSettings, row );
+
+ /* Process each column */
+ for ( i=0, iLen=oSettings.aoColumns.length ; i<iLen ; i++ )
+ {
+ oCol = oSettings.aoColumns[i];
+ create = nTrIn ? false : true;
+
+ nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
+
+ if (! nTd) {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+ }
+
+ nTd._DT_CellIndex = {
+ row: iRow,
+ column: i
+ };
+
+ cells.push( nTd );
+
+ // Need to create the HTML if new, or if a rendering function is defined
+ if ( create || ((oCol.mRender || oCol.mData !== i) &&
+ (!$.isPlainObject(oCol.mData) || oCol.mData._ !== i+'.display')
+ )) {
+ nTd.innerHTML = _fnGetCellData( oSettings, iRow, i, 'display' );
+ }
+
+ /* Add user defined class */
+ if ( oCol.sClass )
+ {
+ nTd.className += ' '+oCol.sClass;
+ }
+
+ // Visibility - add or remove as required
+ if ( oCol.bVisible && ! nTrIn )
+ {
+ nTr.appendChild( nTd );
+ }
+ else if ( ! oCol.bVisible && nTrIn )
+ {
+ nTd.parentNode.removeChild( nTd );
+ }
+
+ if ( oCol.fnCreatedCell )
+ {
+ oCol.fnCreatedCell.call( oSettings.oInstance,
+ nTd, _fnGetCellData( oSettings, iRow, i ), rowData, iRow, i
+ );
+ }
+ }
+
+ _fnCallbackFire( oSettings, 'aoRowCreatedCallback', null, [nTr, rowData, iRow, cells] );
+ }
+ }
+
+
+ /**
+ * Add attributes to a row based on the special `DT_*` parameters in a data
+ * source object.
+ * @param {object} settings DataTables settings object
+ * @param {object} DataTables row object for the row to be modified
+ * @memberof DataTable#oApi
+ */
+ function _fnRowAttributes( settings, row )
+ {
+ var tr = row.nTr;
+ var data = row._aData;
+
+ if ( tr ) {
+ var id = settings.rowIdFn( data );
+
+ if ( id ) {
+ tr.id = id;
+ }
+
+ if ( data.DT_RowClass ) {
+ // Remove any classes added by DT_RowClass before
+ var a = data.DT_RowClass.split(' ');
+ row.__rowc = row.__rowc ?
+ _unique( row.__rowc.concat( a ) ) :
+ a;
+
+ $(tr)
+ .removeClass( row.__rowc.join(' ') )
+ .addClass( data.DT_RowClass );
+ }
+
+ if ( data.DT_RowAttr ) {
+ $(tr).attr( data.DT_RowAttr );
+ }
+
+ if ( data.DT_RowData ) {
+ $(tr).data( data.DT_RowData );
+ }
+ }
+ }
+
+
+ /**
+ * Create the HTML header for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnBuildHead( oSettings )
+ {
+ var i, ien, cell, row, column;
+ var thead = oSettings.nTHead;
+ var tfoot = oSettings.nTFoot;
+ var createHeader = $('th, td', thead).length === 0;
+ var classes = oSettings.oClasses;
+ var columns = oSettings.aoColumns;
+
+ if ( createHeader ) {
+ row = $('<tr/>').appendTo( thead );
+ }
+
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ column = columns[i];
+ cell = $( column.nTh ).addClass( column.sClass );
+
+ if ( createHeader ) {
+ cell.appendTo( row );
+ }
+
+ // 1.11 move into sorting
+ if ( oSettings.oFeatures.bSort ) {
+ cell.addClass( column.sSortingClass );
+
+ if ( column.bSortable !== false ) {
+ cell
+ .attr( 'tabindex', oSettings.iTabIndex )
+ .attr( 'aria-controls', oSettings.sTableId );
+
+ _fnSortAttachListener( oSettings, column.nTh, i );
+ }
+ }
+
+ if ( column.sTitle != cell[0].innerHTML ) {
+ cell.html( column.sTitle );
+ }
+
+ _fnRenderer( oSettings, 'header' )(
+ oSettings, cell, column, classes
+ );
+ }
+
+ if ( createHeader ) {
+ _fnDetectHeader( oSettings.aoHeader, thead );
+ }
+
+ /* Deal with the footer - add classes if required */
+ $(thead).children('tr').children('th, td').addClass( classes.sHeaderTH );
+ $(tfoot).children('tr').children('th, td').addClass( classes.sFooterTH );
+
+ // Cache the footer cells. Note that we only take the cells from the first
+ // row in the footer. If there is more than one row the user wants to
+ // interact with, they need to use the table().foot() method. Note also this
+ // allows cells to be used for multiple columns using colspan
+ if ( tfoot !== null ) {
+ var cells = oSettings.aoFooter[0];
+
+ for ( i=0, ien=cells.length ; i<ien ; i++ ) {
+ column = columns[i];
+
+ if (column) {
+ column.nTf = cells[i].cell;
+
+ if ( column.sClass ) {
+ $(column.nTf).addClass( column.sClass );
+ }
+ }
+ else {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Draw the header (or footer) element based on the column visibility states. The
+ * methodology here is to use the layout array from _fnDetectHeader, modified for
+ * the instantaneous column visibility, to construct the new layout. The grid is
+ * traversed over cell at a time in a rows x columns grid fashion, although each
+ * cell insert can cover multiple elements in the grid - which is tracks using the
+ * aApplied array. Cell inserts in the grid will only occur where there isn't
+ * already a cell in that position.
+ * @param {object} oSettings dataTables settings object
+ * @param array {objects} aoSource Layout array from _fnDetectHeader
+ * @param {boolean} [bIncludeHidden=false] If true then include the hidden columns in the calc,
+ * @memberof DataTable#oApi
+ */
+ function _fnDrawHead( oSettings, aoSource, bIncludeHidden )
+ {
+ var i, iLen, j, jLen, k, kLen, n, nLocalTr;
+ var aoLocal = [];
+ var aApplied = [];
+ var iColumns = oSettings.aoColumns.length;
+ var iRowspan, iColspan;
+
+ if ( ! aoSource )
+ {
+ return;
+ }
+
+ if ( bIncludeHidden === undefined )
+ {
+ bIncludeHidden = false;
+ }
+
+ /* Make a copy of the master layout array, but without the visible columns in it */
+ for ( i=0, iLen=aoSource.length ; i<iLen ; i++ )
+ {
+ aoLocal[i] = aoSource[i].slice();
+ aoLocal[i].nTr = aoSource[i].nTr;
+
+ /* Remove any columns which are currently hidden */
+ for ( j=iColumns-1 ; j>=0 ; j-- )
+ {
+ if ( !oSettings.aoColumns[j].bVisible && !bIncludeHidden )
+ {
+ aoLocal[i].splice( j, 1 );
+ }
+ }
+
+ /* Prep the applied array - it needs an element for each row */
+ aApplied.push( [] );
+ }
+
+ for ( i=0, iLen=aoLocal.length ; i<iLen ; i++ )
+ {
+ nLocalTr = aoLocal[i].nTr;
+
+ /* All cells are going to be replaced, so empty out the row */
+ if ( nLocalTr )
+ {
+ while( (n = nLocalTr.firstChild) )
+ {
+ nLocalTr.removeChild( n );
+ }
+ }
+
+ for ( j=0, jLen=aoLocal[i].length ; j<jLen ; j++ )
+ {
+ iRowspan = 1;
+ iColspan = 1;
+
+ /* Check to see if there is already a cell (row/colspan) covering our target
+ * insert point. If there is, then there is nothing to do.
+ */
+ if ( aApplied[i][j] === undefined )
+ {
+ nLocalTr.appendChild( aoLocal[i][j].cell );
+ aApplied[i][j] = 1;
+
+ /* Expand the cell to cover as many rows as needed */
+ while ( aoLocal[i+iRowspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i+iRowspan][j].cell )
+ {
+ aApplied[i+iRowspan][j] = 1;
+ iRowspan++;
+ }
+
+ /* Expand the cell to cover as many columns as needed */
+ while ( aoLocal[i][j+iColspan] !== undefined &&
+ aoLocal[i][j].cell == aoLocal[i][j+iColspan].cell )
+ {
+ /* Must update the applied array over the rows for the columns */
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aApplied[i+k][j+iColspan] = 1;
+ }
+ iColspan++;
+ }
+
+ /* Do the actual expansion in the DOM */
+ $(aoLocal[i][j].cell)
+ .attr('rowspan', iRowspan)
+ .attr('colspan', iColspan);
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Insert the required TR nodes into the table for display
+ * @param {object} oSettings dataTables settings object
+ * @param ajaxComplete true after ajax call to complete rendering
+ * @memberof DataTable#oApi
+ */
+ function _fnDraw( oSettings, ajaxComplete )
+ {
+ // Allow for state saving and a custom start position
+ _fnStart( oSettings );
+
+ /* Provide a pre-callback function which can be used to cancel the draw is false is returned */
+ var aPreDraw = _fnCallbackFire( oSettings, 'aoPreDrawCallback', 'preDraw', [oSettings] );
+ if ( $.inArray( false, aPreDraw ) !== -1 )
+ {
+ _fnProcessingDisplay( oSettings, false );
+ return;
+ }
+
+ var anRows = [];
+ var iRowCount = 0;
+ var asStripeClasses = oSettings.asStripeClasses;
+ var iStripes = asStripeClasses.length;
+ var oLang = oSettings.oLanguage;
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
+ var aiDisplay = oSettings.aiDisplay;
+ var iDisplayStart = oSettings._iDisplayStart;
+ var iDisplayEnd = oSettings.fnDisplayEnd();
+
+ oSettings.bDrawing = true;
+
+ /* Server-side processing draw intercept */
+ if ( oSettings.bDeferLoading )
+ {
+ oSettings.bDeferLoading = false;
+ oSettings.iDraw++;
+ _fnProcessingDisplay( oSettings, false );
+ }
+ else if ( !bServerSide )
+ {
+ oSettings.iDraw++;
+ }
+ else if ( !oSettings.bDestroying && !ajaxComplete)
+ {
+ _fnAjaxUpdate( oSettings );
+ return;
+ }
+
+ if ( aiDisplay.length !== 0 )
+ {
+ var iStart = bServerSide ? 0 : iDisplayStart;
+ var iEnd = bServerSide ? oSettings.aoData.length : iDisplayEnd;
+
+ for ( var j=iStart ; j<iEnd ; j++ )
+ {
+ var iDataIndex = aiDisplay[j];
+ var aoData = oSettings.aoData[ iDataIndex ];
+ if ( aoData.nTr === null )
+ {
+ _fnCreateTr( oSettings, iDataIndex );
+ }
+
+ var nRow = aoData.nTr;
+
+ /* Remove the old striping classes and then add the new one */
+ if ( iStripes !== 0 )
+ {
+ var sStripe = asStripeClasses[ iRowCount % iStripes ];
+ if ( aoData._sRowStripe != sStripe )
+ {
+ $(nRow).removeClass( aoData._sRowStripe ).addClass( sStripe );
+ aoData._sRowStripe = sStripe;
+ }
+ }
+
+ // Row callback functions - might want to manipulate the row
+ // iRowCount and j are not currently documented. Are they at all
+ // useful?
+ _fnCallbackFire( oSettings, 'aoRowCallback', null,
+ [nRow, aoData._aData, iRowCount, j, iDataIndex] );
+
+ anRows.push( nRow );
+ iRowCount++;
+ }
+ }
+ else
+ {
+ /* Table is empty - create a row with an empty message in it */
+ var sZero = oLang.sZeroRecords;
+ if ( oSettings.iDraw == 1 && _fnDataSource( oSettings ) == 'ajax' )
+ {
+ sZero = oLang.sLoadingRecords;
+ }
+ else if ( oLang.sEmptyTable && oSettings.fnRecordsTotal() === 0 )
+ {
+ sZero = oLang.sEmptyTable;
+ }
+
+ anRows[ 0 ] = $( '<tr/>', { 'class': iStripes ? asStripeClasses[0] : '' } )
+ .append( $('<td />', {
+ 'valign': 'top',
+ 'colSpan': _fnVisbleColumns( oSettings ),
+ 'class': oSettings.oClasses.sRowEmpty
+ } ).html( sZero ) )[0];
+ }
+
+ /* Header and footer callbacks */
+ _fnCallbackFire( oSettings, 'aoHeaderCallback', 'header', [ $(oSettings.nTHead).children('tr')[0],
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+
+ _fnCallbackFire( oSettings, 'aoFooterCallback', 'footer', [ $(oSettings.nTFoot).children('tr')[0],
+ _fnGetDataMaster( oSettings ), iDisplayStart, iDisplayEnd, aiDisplay ] );
+
+ var body = $(oSettings.nTBody);
+
+ body.children().detach();
+ body.append( $(anRows) );
+
+ /* Call all required callback functions for the end of a draw */
+ _fnCallbackFire( oSettings, 'aoDrawCallback', 'draw', [oSettings] );
+
+ /* Draw is complete, sorting and filtering must be as well */
+ oSettings.bSorted = false;
+ oSettings.bFiltered = false;
+ oSettings.bDrawing = false;
+ }
+
+
+ /**
+ * Redraw the table - taking account of the various features which are enabled
+ * @param {object} oSettings dataTables settings object
+ * @param {boolean} [holdPosition] Keep the current paging position. By default
+ * the paging is reset to the first page
+ * @memberof DataTable#oApi
+ */
+ function _fnReDraw( settings, holdPosition )
+ {
+ var
+ features = settings.oFeatures,
+ sort = features.bSort,
+ filter = features.bFilter;
+
+ if ( sort ) {
+ _fnSort( settings );
+ }
+
+ if ( filter ) {
+ _fnFilterComplete( settings, settings.oPreviousSearch );
+ }
+ else {
+ // No filtering, so we want to just use the display master
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
+ }
+
+ if ( holdPosition !== true ) {
+ settings._iDisplayStart = 0;
+ }
+
+ // Let any modules know about the draw hold position state (used by
+ // scrolling internally)
+ settings._drawHold = holdPosition;
+
+ _fnDraw( settings );
+
+ settings._drawHold = false;
+ }
+
+
+ /**
+ * Add the options to the page HTML for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnAddOptionsHtml ( oSettings )
+ {
+ var classes = oSettings.oClasses;
+ var table = $(oSettings.nTable);
+ var holding = $('<div/>').insertBefore( table ); // Holding element for speed
+ var features = oSettings.oFeatures;
+
+ // All DataTables are wrapped in a div
+ var insert = $('<div/>', {
+ id: oSettings.sTableId+'_wrapper',
+ 'class': classes.sWrapper + (oSettings.nTFoot ? '' : ' '+classes.sNoFooter)
+ } );
+
+ oSettings.nHolding = holding[0];
+ oSettings.nTableWrapper = insert[0];
+ oSettings.nTableReinsertBefore = oSettings.nTable.nextSibling;
+
+ /* Loop over the user set positioning and place the elements as needed */
+ var aDom = oSettings.sDom.split('');
+ var featureNode, cOption, nNewNode, cNext, sAttr, j;
+ for ( var i=0 ; i<aDom.length ; i++ )
+ {
+ featureNode = null;
+ cOption = aDom[i];
+
+ if ( cOption == '<' )
+ {
+ /* New container div */
+ nNewNode = $('<div/>')[0];
+
+ /* Check to see if we should append an id and/or a class name to the container */
+ cNext = aDom[i+1];
+ if ( cNext == "'" || cNext == '"' )
+ {
+ sAttr = "";
+ j = 2;
+ while ( aDom[i+j] != cNext )
+ {
+ sAttr += aDom[i+j];
+ j++;
+ }
+
+ /* Replace jQuery UI constants @todo depreciated */
+ if ( sAttr == "H" )
+ {
+ sAttr = classes.sJUIHeader;
+ }
+ else if ( sAttr == "F" )
+ {
+ sAttr = classes.sJUIFooter;
+ }
+
+ /* The attribute can be in the format of "#id.class", "#id" or "class" This logic
+ * breaks the string into parts and applies them as needed
+ */
+ if ( sAttr.indexOf('.') != -1 )
+ {
+ var aSplit = sAttr.split('.');
+ nNewNode.id = aSplit[0].substr(1, aSplit[0].length-1);
+ nNewNode.className = aSplit[1];
+ }
+ else if ( sAttr.charAt(0) == "#" )
+ {
+ nNewNode.id = sAttr.substr(1, sAttr.length-1);
+ }
+ else
+ {
+ nNewNode.className = sAttr;
+ }
+
+ i += j; /* Move along the position array */
+ }
+
+ insert.append( nNewNode );
+ insert = $(nNewNode);
+ }
+ else if ( cOption == '>' )
+ {
+ /* End container div */
+ insert = insert.parent();
+ }
+ // @todo Move options into their own plugins?
+ else if ( cOption == 'l' && features.bPaginate && features.bLengthChange )
+ {
+ /* Length */
+ featureNode = _fnFeatureHtmlLength( oSettings );
+ }
+ else if ( cOption == 'f' && features.bFilter )
+ {
+ /* Filter */
+ featureNode = _fnFeatureHtmlFilter( oSettings );
+ }
+ else if ( cOption == 'r' && features.bProcessing )
+ {
+ /* pRocessing */
+ featureNode = _fnFeatureHtmlProcessing( oSettings );
+ }
+ else if ( cOption == 't' )
+ {
+ /* Table */
+ featureNode = _fnFeatureHtmlTable( oSettings );
+ }
+ else if ( cOption == 'i' && features.bInfo )
+ {
+ /* Info */
+ featureNode = _fnFeatureHtmlInfo( oSettings );
+ }
+ else if ( cOption == 'p' && features.bPaginate )
+ {
+ /* Pagination */
+ featureNode = _fnFeatureHtmlPaginate( oSettings );
+ }
+ else if ( DataTable.ext.feature.length !== 0 )
+ {
+ /* Plug-in features */
+ var aoFeatures = DataTable.ext.feature;
+ for ( var k=0, kLen=aoFeatures.length ; k<kLen ; k++ )
+ {
+ if ( cOption == aoFeatures[k].cFeature )
+ {
+ featureNode = aoFeatures[k].fnInit( oSettings );
+ break;
+ }
+ }
+ }
+
+ /* Add to the 2D features array */
+ if ( featureNode )
+ {
+ var aanFeatures = oSettings.aanFeatures;
+
+ if ( ! aanFeatures[cOption] )
+ {
+ aanFeatures[cOption] = [];
+ }
+
+ aanFeatures[cOption].push( featureNode );
+ insert.append( featureNode );
+ }
+ }
+
+ /* Built our DOM structure - replace the holding div with what we want */
+ holding.replaceWith( insert );
+ oSettings.nHolding = null;
+ }
+
+
+ /**
+ * Use the DOM source to create up an array of header cells. The idea here is to
+ * create a layout grid (array) of rows x columns, which contains a reference
+ * to the cell that that point in the grid (regardless of col/rowspan), such that
+ * any column / row could be removed and the new grid constructed
+ * @param array {object} aLayout Array to store the calculated layout in
+ * @param {node} nThead The header/footer element for the table
+ * @memberof DataTable#oApi
+ */
+ function _fnDetectHeader ( aLayout, nThead )
+ {
+ var nTrs = $(nThead).children('tr');
+ var nTr, nCell;
+ var i, k, l, iLen, jLen, iColShifted, iColumn, iColspan, iRowspan;
+ var bUnique;
+ var fnShiftCol = function ( a, i, j ) {
+ var k = a[i];
+ while ( k[j] ) {
+ j++;
+ }
+ return j;
+ };
+
+ aLayout.splice( 0, aLayout.length );
+
+ /* We know how many rows there are in the layout - so prep it */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ aLayout.push( [] );
+ }
+
+ /* Calculate a layout array */
+ for ( i=0, iLen=nTrs.length ; i<iLen ; i++ )
+ {
+ nTr = nTrs[i];
+ iColumn = 0;
+
+ /* For every cell in the row... */
+ nCell = nTr.firstChild;
+ while ( nCell ) {
+ if ( nCell.nodeName.toUpperCase() == "TD" ||
+ nCell.nodeName.toUpperCase() == "TH" )
+ {
+ /* Get the col and rowspan attributes from the DOM and sanitise them */
+ iColspan = nCell.getAttribute('colspan') * 1;
+ iRowspan = nCell.getAttribute('rowspan') * 1;
+ iColspan = (!iColspan || iColspan===0 || iColspan===1) ? 1 : iColspan;
+ iRowspan = (!iRowspan || iRowspan===0 || iRowspan===1) ? 1 : iRowspan;
+
+ /* There might be colspan cells already in this row, so shift our target
+ * accordingly
+ */
+ iColShifted = fnShiftCol( aLayout, i, iColumn );
+
+ /* Cache calculation for unique columns */
+ bUnique = iColspan === 1 ? true : false;
+
+ /* If there is col / rowspan, copy the information into the layout grid */
+ for ( l=0 ; l<iColspan ; l++ )
+ {
+ for ( k=0 ; k<iRowspan ; k++ )
+ {
+ aLayout[i+k][iColShifted+l] = {
+ "cell": nCell,
+ "unique": bUnique
+ };
+ aLayout[i+k].nTr = nTr;
+ }
+ }
+ }
+ nCell = nCell.nextSibling;
+ }
+ }
+ }
+
+
+ /**
+ * Get an array of unique th elements, one for each column
+ * @param {object} oSettings dataTables settings object
+ * @param {node} nHeader automatically detect the layout from this node - optional
+ * @param {array} aLayout thead/tfoot layout from _fnDetectHeader - optional
+ * @returns array {node} aReturn list of unique th's
+ * @memberof DataTable#oApi
+ */
+ function _fnGetUniqueThs ( oSettings, nHeader, aLayout )
+ {
+ var aReturn = [];
+ if ( !aLayout )
+ {
+ aLayout = oSettings.aoHeader;
+ if ( nHeader )
+ {
+ aLayout = [];
+ _fnDetectHeader( aLayout, nHeader );
+ }
+ }
+
+ for ( var i=0, iLen=aLayout.length ; i<iLen ; i++ )
+ {
+ for ( var j=0, jLen=aLayout[i].length ; j<jLen ; j++ )
+ {
+ if ( aLayout[i][j].unique &&
+ (!aReturn[j] || !oSettings.bSortCellsTop) )
+ {
+ aReturn[j] = aLayout[i][j].cell;
+ }
+ }
+ }
+
+ return aReturn;
+ }
+
+ /**
+ * Set the start position for draw
+ * @param {object} oSettings dataTables settings object
+ */
+ function _fnStart( oSettings )
+ {
+ var bServerSide = _fnDataSource( oSettings ) == 'ssp';
+ var iInitDisplayStart = oSettings.iInitDisplayStart;
+
+ // Check and see if we have an initial draw position from state saving
+ if ( iInitDisplayStart !== undefined && iInitDisplayStart !== -1 )
+ {
+ oSettings._iDisplayStart = bServerSide ?
+ iInitDisplayStart :
+ iInitDisplayStart >= oSettings.fnRecordsDisplay() ?
+ 0 :
+ iInitDisplayStart;
+
+ oSettings.iInitDisplayStart = -1;
+ }
+ }
+
+ /**
+ * Create an Ajax call based on the table's settings, taking into account that
+ * parameters can have multiple forms, and backwards compatibility.
+ *
+ * @param {object} oSettings dataTables settings object
+ * @param {array} data Data to send to the server, required by
+ * DataTables - may be augmented by developer callbacks
+ * @param {function} fn Callback function to run when data is obtained
+ */
+ function _fnBuildAjax( oSettings, data, fn )
+ {
+ // Compatibility with 1.9-, allow fnServerData and event to manipulate
+ _fnCallbackFire( oSettings, 'aoServerParams', 'serverParams', [data] );
+
+ // Convert to object based for 1.10+ if using the old array scheme which can
+ // come from server-side processing or serverParams
+ if ( data && Array.isArray(data) ) {
+ var tmp = {};
+ var rbracket = /(.*?)\[\]$/;
+
+ $.each( data, function (key, val) {
+ var match = val.name.match(rbracket);
+
+ if ( match ) {
+ // Support for arrays
+ var name = match[0];
+
+ if ( ! tmp[ name ] ) {
+ tmp[ name ] = [];
+ }
+ tmp[ name ].push( val.value );
+ }
+ else {
+ tmp[val.name] = val.value;
+ }
+ } );
+ data = tmp;
+ }
+
+ var ajaxData;
+ var ajax = oSettings.ajax;
+ var instance = oSettings.oInstance;
+ var callback = function ( json ) {
+ var status = oSettings.jqXHR
+ ? oSettings.jqXHR.status
+ : null;
+
+ if ( json === null || (typeof status === 'number' && status == 204 ) ) {
+ json = {};
+ _fnAjaxDataSrc( oSettings, json, [] );
+ }
+
+ var error = json.error || json.sError;
+ if ( error ) {
+ _fnLog( oSettings, 0, error );
+ }
+
+ oSettings.json = json;
+
+ _fnCallbackFire( oSettings, null, 'xhr', [oSettings, json, oSettings.jqXHR] );
+ fn( json );
+ };
+
+ if ( $.isPlainObject( ajax ) && ajax.data )
+ {
+ ajaxData = ajax.data;
+
+ var newData = typeof ajaxData === 'function' ?
+ ajaxData( data, oSettings ) : // fn can manipulate data or return
+ ajaxData; // an object object or array to merge
+
+ // If the function returned something, use that alone
+ data = typeof ajaxData === 'function' && newData ?
+ newData :
+ $.extend( true, data, newData );
+
+ // Remove the data property as we've resolved it already and don't want
+ // jQuery to do it again (it is restored at the end of the function)
+ delete ajax.data;
+ }
+
+ var baseAjax = {
+ "data": data,
+ "success": callback,
+ "dataType": "json",
+ "cache": false,
+ "type": oSettings.sServerMethod,
+ "error": function (xhr, error, thrown) {
+ var ret = _fnCallbackFire( oSettings, null, 'xhr', [oSettings, null, oSettings.jqXHR] );
+
+ if ( $.inArray( true, ret ) === -1 ) {
+ if ( error == "parsererror" ) {
+ _fnLog( oSettings, 0, 'Invalid JSON response', 1 );
+ }
+ else if ( xhr.readyState === 4 ) {
+ _fnLog( oSettings, 0, 'Ajax error', 7 );
+ }
+ }
+
+ _fnProcessingDisplay( oSettings, false );
+ }
+ };
+
+ // Store the data submitted for the API
+ oSettings.oAjaxData = data;
+
+ // Allow plug-ins and external processes to modify the data
+ _fnCallbackFire( oSettings, null, 'preXhr', [oSettings, data] );
+
+ if ( oSettings.fnServerData )
+ {
+ // DataTables 1.9- compatibility
+ oSettings.fnServerData.call( instance,
+ oSettings.sAjaxSource,
+ $.map( data, function (val, key) { // Need to convert back to 1.9 trad format
+ return { name: key, value: val };
+ } ),
+ callback,
+ oSettings
+ );
+ }
+ else if ( oSettings.sAjaxSource || typeof ajax === 'string' )
+ {
+ // DataTables 1.9- compatibility
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, {
+ url: ajax || oSettings.sAjaxSource
+ } ) );
+ }
+ else if ( typeof ajax === 'function' )
+ {
+ // Is a function - let the caller define what needs to be done
+ oSettings.jqXHR = ajax.call( instance, data, callback, oSettings );
+ }
+ else
+ {
+ // Object to extend the base settings
+ oSettings.jqXHR = $.ajax( $.extend( baseAjax, ajax ) );
+
+ // Restore for next time around
+ ajax.data = ajaxData;
+ }
+ }
+
+
+ /**
+ * Update the table using an Ajax call
+ * @param {object} settings dataTables settings object
+ * @returns {boolean} Block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdate( settings )
+ {
+ settings.iDraw++;
+ _fnProcessingDisplay( settings, true );
+
+ _fnBuildAjax(
+ settings,
+ _fnAjaxParameters( settings ),
+ function(json) {
+ _fnAjaxUpdateDraw( settings, json );
+ }
+ );
+ }
+
+
+ /**
+ * Build up the parameters in an object needed for a server-side processing
+ * request. Note that this is basically done twice, is different ways - a modern
+ * method which is used by default in DataTables 1.10 which uses objects and
+ * arrays, or the 1.9- method with is name / value pairs. 1.9 method is used if
+ * the sAjaxSource option is used in the initialisation, or the legacyAjax
+ * option is set.
+ * @param {object} oSettings dataTables settings object
+ * @returns {bool} block the table drawing or not
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxParameters( settings )
+ {
+ var
+ columns = settings.aoColumns,
+ columnCount = columns.length,
+ features = settings.oFeatures,
+ preSearch = settings.oPreviousSearch,
+ preColSearch = settings.aoPreSearchCols,
+ i, data = [], dataProp, column, columnSearch,
+ sort = _fnSortFlatten( settings ),
+ displayStart = settings._iDisplayStart,
+ displayLength = features.bPaginate !== false ?
+ settings._iDisplayLength :
+ -1;
+
+ var param = function ( name, value ) {
+ data.push( { 'name': name, 'value': value } );
+ };
+
+ // DataTables 1.9- compatible method
+ param( 'sEcho', settings.iDraw );
+ param( 'iColumns', columnCount );
+ param( 'sColumns', _pluck( columns, 'sName' ).join(',') );
+ param( 'iDisplayStart', displayStart );
+ param( 'iDisplayLength', displayLength );
+
+ // DataTables 1.10+ method
+ var d = {
+ draw: settings.iDraw,
+ columns: [],
+ order: [],
+ start: displayStart,
+ length: displayLength,
+ search: {
+ value: preSearch.sSearch,
+ regex: preSearch.bRegex
+ }
+ };
+
+ for ( i=0 ; i<columnCount ; i++ ) {
+ column = columns[i];
+ columnSearch = preColSearch[i];
+ dataProp = typeof column.mData=="function" ? 'function' : column.mData ;
+
+ d.columns.push( {
+ data: dataProp,
+ name: column.sName,
+ searchable: column.bSearchable,
+ orderable: column.bSortable,
+ search: {
+ value: columnSearch.sSearch,
+ regex: columnSearch.bRegex
+ }
+ } );
+
+ param( "mDataProp_"+i, dataProp );
+
+ if ( features.bFilter ) {
+ param( 'sSearch_'+i, columnSearch.sSearch );
+ param( 'bRegex_'+i, columnSearch.bRegex );
+ param( 'bSearchable_'+i, column.bSearchable );
+ }
+
+ if ( features.bSort ) {
+ param( 'bSortable_'+i, column.bSortable );
+ }
+ }
+
+ if ( features.bFilter ) {
+ param( 'sSearch', preSearch.sSearch );
+ param( 'bRegex', preSearch.bRegex );
+ }
+
+ if ( features.bSort ) {
+ $.each( sort, function ( i, val ) {
+ d.order.push( { column: val.col, dir: val.dir } );
+
+ param( 'iSortCol_'+i, val.col );
+ param( 'sSortDir_'+i, val.dir );
+ } );
+
+ param( 'iSortingCols', sort.length );
+ }
+
+ // If the legacy.ajax parameter is null, then we automatically decide which
+ // form to use, based on sAjaxSource
+ var legacy = DataTable.ext.legacy.ajax;
+ if ( legacy === null ) {
+ return settings.sAjaxSource ? data : d;
+ }
+
+ // Otherwise, if legacy has been specified then we use that to decide on the
+ // form
+ return legacy ? data : d;
+ }
+
+
+ /**
+ * Data the data from the server (nuking the old) and redraw the table
+ * @param {object} oSettings dataTables settings object
+ * @param {object} json json data return from the server.
+ * @param {string} json.sEcho Tracking flag for DataTables to match requests
+ * @param {int} json.iTotalRecords Number of records in the data set, not accounting for filtering
+ * @param {int} json.iTotalDisplayRecords Number of records in the data set, accounting for filtering
+ * @param {array} json.aaData The data to display on this page
+ * @param {string} [json.sColumns] Column ordering (sName, comma separated)
+ * @memberof DataTable#oApi
+ */
+ function _fnAjaxUpdateDraw ( settings, json )
+ {
+ // v1.10 uses camelCase variables, while 1.9 uses Hungarian notation.
+ // Support both
+ var compat = function ( old, modern ) {
+ return json[old] !== undefined ? json[old] : json[modern];
+ };
+
+ var data = _fnAjaxDataSrc( settings, json );
+ var draw = compat( 'sEcho', 'draw' );
+ var recordsTotal = compat( 'iTotalRecords', 'recordsTotal' );
+ var recordsFiltered = compat( 'iTotalDisplayRecords', 'recordsFiltered' );
+
+ if ( draw !== undefined ) {
+ // Protect against out of sequence returns
+ if ( draw*1 < settings.iDraw ) {
+ return;
+ }
+ settings.iDraw = draw * 1;
+ }
+
+ // No data in returned object, so rather than an array, we show an empty table
+ if ( ! data ) {
+ data = [];
+ }
+
+ _fnClearTable( settings );
+ settings._iRecordsTotal = parseInt(recordsTotal, 10);
+ settings._iRecordsDisplay = parseInt(recordsFiltered, 10);
+
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+ _fnAddData( settings, data[i] );
+ }
+ settings.aiDisplay = settings.aiDisplayMaster.slice();
+
+ _fnDraw( settings, true );
+
+ if ( ! settings._bInitComplete ) {
+ _fnInitComplete( settings, json );
+ }
+
+ _fnProcessingDisplay( settings, false );
+ }
+
+
+ /**
+ * Get the data from the JSON data source to use for drawing a table. Using
+ * `_fnGetObjectDataFn` allows the data to be sourced from a property of the
+ * source object, or from a processing function.
+ * @param {object} oSettings dataTables settings object
+ * @param {object} json Data source object / array from the server
+ * @return {array} Array of data to use
+ */
+ function _fnAjaxDataSrc ( oSettings, json, write )
+ {
+ var dataSrc = $.isPlainObject( oSettings.ajax ) && oSettings.ajax.dataSrc !== undefined ?
+ oSettings.ajax.dataSrc :
+ oSettings.sAjaxDataProp; // Compatibility with 1.9-.
+
+ if ( ! write ) {
+ if ( dataSrc === 'data' ) {
+ // If the default, then we still want to support the old style, and safely ignore
+ // it if possible
+ return json.aaData || json[dataSrc];
+ }
+
+ return dataSrc !== "" ?
+ _fnGetObjectDataFn( dataSrc )( json ) :
+ json;
+ }
+
+ // set
+ _fnSetObjectDataFn( dataSrc )( json, write );
+ }
+
+ /**
+ * Generate the node required for filtering text
+ * @returns {node} Filter control element
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlFilter ( settings )
+ {
+ var classes = settings.oClasses;
+ var tableId = settings.sTableId;
+ var language = settings.oLanguage;
+ var previousSearch = settings.oPreviousSearch;
+ var features = settings.aanFeatures;
+ var input = '<input type="search" class="'+classes.sFilterInput+'"/>';
+
+ var str = language.sSearch;
+ str = str.match(/_INPUT_/) ?
+ str.replace('_INPUT_', input) :
+ str+input;
+
+ var filter = $('<div/>', {
+ 'id': ! features.f ? tableId+'_filter' : null,
+ 'class': classes.sFilter
+ } )
+ .append( $('<label/>' ).append( str ) );
+
+ var searchFn = function(event) {
+ /* Update all other filter input elements for the new display */
+ var n = features.f;
+ var val = !this.value ? "" : this.value; // mental IE8 fix :-(
+ if(previousSearch.return && event.key !== "Enter") {
+ return;
+ }
+ /* Now do the filter */
+ if ( val != previousSearch.sSearch ) {
+ _fnFilterComplete( settings, {
+ "sSearch": val,
+ "bRegex": previousSearch.bRegex,
+ "bSmart": previousSearch.bSmart ,
+ "bCaseInsensitive": previousSearch.bCaseInsensitive,
+ "return": previousSearch.return
+ } );
+
+ // Need to redraw, without resorting
+ settings._iDisplayStart = 0;
+ _fnDraw( settings );
+ }
+ };
+
+ var searchDelay = settings.searchDelay !== null ?
+ settings.searchDelay :
+ _fnDataSource( settings ) === 'ssp' ?
+ 400 :
+ 0;
+
+ var jqFilter = $('input', filter)
+ .val( previousSearch.sSearch )
+ .attr( 'placeholder', language.sSearchPlaceholder )
+ .on(
+ 'keyup.DT search.DT input.DT paste.DT cut.DT',
+ searchDelay ?
+ _fnThrottle( searchFn, searchDelay ) :
+ searchFn
+ )
+ .on( 'mouseup', function(e) {
+ // Edge fix! Edge 17 does not trigger anything other than mouse events when clicking
+ // on the clear icon (Edge bug 17584515). This is safe in other browsers as `searchFn`
+ // checks the value to see if it has changed. In other browsers it won't have.
+ setTimeout( function () {
+ searchFn.call(jqFilter[0], e);
+ }, 10);
+ } )
+ .on( 'keypress.DT', function(e) {
+ /* Prevent form submission */
+ if ( e.keyCode == 13 ) {
+ return false;
+ }
+ } )
+ .attr('aria-controls', tableId);
+
+ // Update the input elements whenever the table is filtered
+ $(settings.nTable).on( 'search.dt.DT', function ( ev, s ) {
+ if ( settings === s ) {
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame...
+ try {
+ if ( jqFilter[0] !== document.activeElement ) {
+ jqFilter.val( previousSearch.sSearch );
+ }
+ }
+ catch ( e ) {}
+ }
+ } );
+
+ return filter[0];
+ }
+
+
+ /**
+ * Filter the table using both the global filter and column based filtering
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oSearch search information
+ * @param {int} [iForce] force a research of the master array (1) or not (undefined or 0)
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterComplete ( oSettings, oInput, iForce )
+ {
+ var oPrevSearch = oSettings.oPreviousSearch;
+ var aoPrevSearch = oSettings.aoPreSearchCols;
+ var fnSaveFilter = function ( oFilter ) {
+ /* Save the filtering values */
+ oPrevSearch.sSearch = oFilter.sSearch;
+ oPrevSearch.bRegex = oFilter.bRegex;
+ oPrevSearch.bSmart = oFilter.bSmart;
+ oPrevSearch.bCaseInsensitive = oFilter.bCaseInsensitive;
+ oPrevSearch.return = oFilter.return;
+ };
+ var fnRegex = function ( o ) {
+ // Backwards compatibility with the bEscapeRegex option
+ return o.bEscapeRegex !== undefined ? !o.bEscapeRegex : o.bRegex;
+ };
+
+ // Resolve any column types that are unknown due to addition or invalidation
+ // @todo As per sort - can this be moved into an event handler?
+ _fnColumnTypes( oSettings );
+
+ /* In server-side processing all filtering is done by the server, so no point hanging around here */
+ if ( _fnDataSource( oSettings ) != 'ssp' )
+ {
+ /* Global filter */
+ _fnFilter( oSettings, oInput.sSearch, iForce, fnRegex(oInput), oInput.bSmart, oInput.bCaseInsensitive, oInput.return );
+ fnSaveFilter( oInput );
+
+ /* Now do the individual column filter */
+ for ( var i=0 ; i<aoPrevSearch.length ; i++ )
+ {
+ _fnFilterColumn( oSettings, aoPrevSearch[i].sSearch, i, fnRegex(aoPrevSearch[i]),
+ aoPrevSearch[i].bSmart, aoPrevSearch[i].bCaseInsensitive );
+ }
+
+ /* Custom filtering */
+ _fnFilterCustom( oSettings );
+ }
+ else
+ {
+ fnSaveFilter( oInput );
+ }
+
+ /* Tell the draw function we have been filtering */
+ oSettings.bFiltered = true;
+ _fnCallbackFire( oSettings, null, 'search', [oSettings] );
+ }
+
+
+ /**
+ * Apply custom filtering functions
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCustom( settings )
+ {
+ var filters = DataTable.ext.search;
+ var displayRows = settings.aiDisplay;
+ var row, rowIdx;
+
+ for ( var i=0, ien=filters.length ; i<ien ; i++ ) {
+ var rows = [];
+
+ // Loop over each row and see if it should be included
+ for ( var j=0, jen=displayRows.length ; j<jen ; j++ ) {
+ rowIdx = displayRows[ j ];
+ row = settings.aoData[ rowIdx ];
+
+ if ( filters[i]( settings, row._aFilterData, rowIdx, row._aData, j ) ) {
+ rows.push( rowIdx );
+ }
+ }
+
+ // So the array reference doesn't break set the results into the
+ // existing array
+ displayRows.length = 0;
+ $.merge( displayRows, rows );
+ }
+ }
+
+
+ /**
+ * Filter the table on a per-column basis
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sInput string to filter on
+ * @param {int} iColumn column to filter
+ * @param {bool} bRegex treat search string as a regular expression or not
+ * @param {bool} bSmart use smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterColumn ( settings, searchStr, colIdx, regex, smart, caseInsensitive )
+ {
+ if ( searchStr === '' ) {
+ return;
+ }
+
+ var data;
+ var out = [];
+ var display = settings.aiDisplay;
+ var rpSearch = _fnFilterCreateSearch( searchStr, regex, smart, caseInsensitive );
+
+ for ( var i=0 ; i<display.length ; i++ ) {
+ data = settings.aoData[ display[i] ]._aFilterData[ colIdx ];
+
+ if ( rpSearch.test( data ) ) {
+ out.push( display[i] );
+ }
+ }
+
+ settings.aiDisplay = out;
+ }
+
+
+ /**
+ * Filter the data table based on user input and draw the table
+ * @param {object} settings dataTables settings object
+ * @param {string} input string to filter on
+ * @param {int} force optional - force a research of the master array (1) or not (undefined or 0)
+ * @param {bool} regex treat as a regular expression or not
+ * @param {bool} smart perform smart filtering or not
+ * @param {bool} caseInsensitive Do case insensitive matching or not
+ * @memberof DataTable#oApi
+ */
+ function _fnFilter( settings, input, force, regex, smart, caseInsensitive )
+ {
+ var rpSearch = _fnFilterCreateSearch( input, regex, smart, caseInsensitive );
+ var prevSearch = settings.oPreviousSearch.sSearch;
+ var displayMaster = settings.aiDisplayMaster;
+ var display, invalidated, i;
+ var filtered = [];
+
+ // Need to take account of custom filtering functions - always filter
+ if ( DataTable.ext.search.length !== 0 ) {
+ force = true;
+ }
+
+ // Check if any of the rows were invalidated
+ invalidated = _fnFilterData( settings );
+
+ // If the input is blank - we just want the full data set
+ if ( input.length <= 0 ) {
+ settings.aiDisplay = displayMaster.slice();
+ }
+ else {
+ // New search - start from the master array
+ if ( invalidated ||
+ force ||
+ regex ||
+ prevSearch.length > input.length ||
+ input.indexOf(prevSearch) !== 0 ||
+ settings.bSorted // On resort, the display master needs to be
+ // re-filtered since indexes will have changed
+ ) {
+ settings.aiDisplay = displayMaster.slice();
+ }
+
+ // Search the display array
+ display = settings.aiDisplay;
+
+ for ( i=0 ; i<display.length ; i++ ) {
+ if ( rpSearch.test( settings.aoData[ display[i] ]._sFilterRow ) ) {
+ filtered.push( display[i] );
+ }
+ }
+
+ settings.aiDisplay = filtered;
+ }
+ }
+
+
+ /**
+ * Build a regular expression object suitable for searching a table
+ * @param {string} sSearch string to search for
+ * @param {bool} bRegex treat as a regular expression or not
+ * @param {bool} bSmart perform smart filtering or not
+ * @param {bool} bCaseInsensitive Do case insensitive matching or not
+ * @returns {RegExp} constructed object
+ * @memberof DataTable#oApi
+ */
+ function _fnFilterCreateSearch( search, regex, smart, caseInsensitive )
+ {
+ search = regex ?
+ search :
+ _fnEscapeRegex( search );
+
+ if ( smart ) {
+ /* For smart filtering we want to allow the search to work regardless of
+ * word order. We also want double quoted text to be preserved, so word
+ * order is important - a la google. So this is what we want to
+ * generate:
+ *
+ * ^(?=.*?\bone\b)(?=.*?\btwo three\b)(?=.*?\bfour\b).*$
+ */
+ var a = $.map( search.match( /"[^"]+"|[^ ]+/g ) || [''], function ( word ) {
+ if ( word.charAt(0) === '"' ) {
+ var m = word.match( /^"(.*)"$/ );
+ word = m ? m[1] : word;
+ }
+
+ return word.replace('"', '');
+ } );
+
+ search = '^(?=.*?'+a.join( ')(?=.*?' )+').*$';
+ }
+
+ return new RegExp( search, caseInsensitive ? 'i' : '' );
+ }
+
+
+ /**
+ * Escape a string such that it can be used in a regular expression
+ * @param {string} sVal string to escape
+ * @returns {string} escaped string
+ * @memberof DataTable#oApi
+ */
+ var _fnEscapeRegex = DataTable.util.escapeRegex;
+
+ var __filter_div = $('<div>')[0];
+ var __filter_div_textContent = __filter_div.textContent !== undefined;
+
+ // Update the filtering data for each row if needed (by invalidation or first run)
+ function _fnFilterData ( settings )
+ {
+ var columns = settings.aoColumns;
+ var column;
+ var i, j, ien, jen, filterData, cellData, row;
+ var wasInvalidated = false;
+
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ row = settings.aoData[i];
+
+ if ( ! row._aFilterData ) {
+ filterData = [];
+
+ for ( j=0, jen=columns.length ; j<jen ; j++ ) {
+ column = columns[j];
+
+ if ( column.bSearchable ) {
+ cellData = _fnGetCellData( settings, i, j, 'filter' );
+
+ // Search in DataTables 1.10 is string based. In 1.11 this
+ // should be altered to also allow strict type checking.
+ if ( cellData === null ) {
+ cellData = '';
+ }
+
+ if ( typeof cellData !== 'string' && cellData.toString ) {
+ cellData = cellData.toString();
+ }
+ }
+ else {
+ cellData = '';
+ }
+
+ // If it looks like there is an HTML entity in the string,
+ // attempt to decode it so sorting works as expected. Note that
+ // we could use a single line of jQuery to do this, but the DOM
+ // method used here is much faster http://jsperf.com/html-decode
+ if ( cellData.indexOf && cellData.indexOf('&') !== -1 ) {
+ __filter_div.innerHTML = cellData;
+ cellData = __filter_div_textContent ?
+ __filter_div.textContent :
+ __filter_div.innerText;
+ }
+
+ if ( cellData.replace ) {
+ cellData = cellData.replace(/[\r\n\u2028]/g, '');
+ }
+
+ filterData.push( cellData );
+ }
+
+ row._aFilterData = filterData;
+ row._sFilterRow = filterData.join(' ');
+ wasInvalidated = true;
+ }
+ }
+
+ return wasInvalidated;
+ }
+
+
+ /**
+ * Convert from the internal Hungarian notation to camelCase for external
+ * interaction
+ * @param {object} obj Object to convert
+ * @returns {object} Inverted object
+ * @memberof DataTable#oApi
+ */
+ function _fnSearchToCamel ( obj )
+ {
+ return {
+ search: obj.sSearch,
+ smart: obj.bSmart,
+ regex: obj.bRegex,
+ caseInsensitive: obj.bCaseInsensitive
+ };
+ }
+
+
+
+ /**
+ * Convert from camelCase notation to the internal Hungarian. We could use the
+ * Hungarian convert function here, but this is cleaner
+ * @param {object} obj Object to convert
+ * @returns {object} Inverted object
+ * @memberof DataTable#oApi
+ */
+ function _fnSearchToHung ( obj )
+ {
+ return {
+ sSearch: obj.search,
+ bSmart: obj.smart,
+ bRegex: obj.regex,
+ bCaseInsensitive: obj.caseInsensitive
+ };
+ }
+
+ /**
+ * Generate the node required for the info display
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Information element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlInfo ( settings )
+ {
+ var
+ tid = settings.sTableId,
+ nodes = settings.aanFeatures.i,
+ n = $('<div/>', {
+ 'class': settings.oClasses.sInfo,
+ 'id': ! nodes ? tid+'_info' : null
+ } );
+
+ if ( ! nodes ) {
+ // Update display on each draw
+ settings.aoDrawCallback.push( {
+ "fn": _fnUpdateInfo,
+ "sName": "information"
+ } );
+
+ n
+ .attr( 'role', 'status' )
+ .attr( 'aria-live', 'polite' );
+
+ // Table is described by our info div
+ $(settings.nTable).attr( 'aria-describedby', tid+'_info' );
+ }
+
+ return n[0];
+ }
+
+
+ /**
+ * Update the information elements in the display
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnUpdateInfo ( settings )
+ {
+ /* Show information about the table */
+ var nodes = settings.aanFeatures.i;
+ if ( nodes.length === 0 ) {
+ return;
+ }
+
+ var
+ lang = settings.oLanguage,
+ start = settings._iDisplayStart+1,
+ end = settings.fnDisplayEnd(),
+ max = settings.fnRecordsTotal(),
+ total = settings.fnRecordsDisplay(),
+ out = total ?
+ lang.sInfo :
+ lang.sInfoEmpty;
+
+ if ( total !== max ) {
+ /* Record set after filtering */
+ out += ' ' + lang.sInfoFiltered;
+ }
+
+ // Convert the macros
+ out += lang.sInfoPostFix;
+ out = _fnInfoMacros( settings, out );
+
+ var callback = lang.fnInfoCallback;
+ if ( callback !== null ) {
+ out = callback.call( settings.oInstance,
+ settings, start, end, max, total, out
+ );
+ }
+
+ $(nodes).html( out );
+ }
+
+
+ function _fnInfoMacros ( settings, str )
+ {
+ // When infinite scrolling, we are always starting at 1. _iDisplayStart is used only
+ // internally
+ var
+ formatter = settings.fnFormatNumber,
+ start = settings._iDisplayStart+1,
+ len = settings._iDisplayLength,
+ vis = settings.fnRecordsDisplay(),
+ all = len === -1;
+
+ return str.
+ replace(/_START_/g, formatter.call( settings, start ) ).
+ replace(/_END_/g, formatter.call( settings, settings.fnDisplayEnd() ) ).
+ replace(/_MAX_/g, formatter.call( settings, settings.fnRecordsTotal() ) ).
+ replace(/_TOTAL_/g, formatter.call( settings, vis ) ).
+ replace(/_PAGE_/g, formatter.call( settings, all ? 1 : Math.ceil( start / len ) ) ).
+ replace(/_PAGES_/g, formatter.call( settings, all ? 1 : Math.ceil( vis / len ) ) );
+ }
+
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnInitialise ( settings )
+ {
+ var i, iLen, iAjaxStart=settings.iInitDisplayStart;
+ var columns = settings.aoColumns, column;
+ var features = settings.oFeatures;
+ var deferLoading = settings.bDeferLoading; // value modified by the draw
+
+ /* Ensure that the table data is fully initialised */
+ if ( ! settings.bInitialised ) {
+ setTimeout( function(){ _fnInitialise( settings ); }, 200 );
+ return;
+ }
+
+ /* Show the display HTML options */
+ _fnAddOptionsHtml( settings );
+
+ /* Build and draw the header / footer for the table */
+ _fnBuildHead( settings );
+ _fnDrawHead( settings, settings.aoHeader );
+ _fnDrawHead( settings, settings.aoFooter );
+
+ /* Okay to show that something is going on now */
+ _fnProcessingDisplay( settings, true );
+
+ /* Calculate sizes for columns */
+ if ( features.bAutoWidth ) {
+ _fnCalculateColumnWidths( settings );
+ }
+
+ for ( i=0, iLen=columns.length ; i<iLen ; i++ ) {
+ column = columns[i];
+
+ if ( column.sWidth ) {
+ column.nTh.style.width = _fnStringToCss( column.sWidth );
+ }
+ }
+
+ _fnCallbackFire( settings, null, 'preInit', [settings] );
+
+ // If there is default sorting required - let's do it. The sort function
+ // will do the drawing for us. Otherwise we draw the table regardless of the
+ // Ajax source - this allows the table to look initialised for Ajax sourcing
+ // data (show 'loading' message possibly)
+ _fnReDraw( settings );
+
+ // Server-side processing init complete is done by _fnAjaxUpdateDraw
+ var dataSrc = _fnDataSource( settings );
+ if ( dataSrc != 'ssp' || deferLoading ) {
+ // if there is an ajax source load the data
+ if ( dataSrc == 'ajax' ) {
+ _fnBuildAjax( settings, [], function(json) {
+ var aData = _fnAjaxDataSrc( settings, json );
+
+ // Got the data - add it to the table
+ for ( i=0 ; i<aData.length ; i++ ) {
+ _fnAddData( settings, aData[i] );
+ }
+
+ // Reset the init display for cookie saving. We've already done
+ // a filter, and therefore cleared it before. So we need to make
+ // it appear 'fresh'
+ settings.iInitDisplayStart = iAjaxStart;
+
+ _fnReDraw( settings );
+
+ _fnProcessingDisplay( settings, false );
+ _fnInitComplete( settings, json );
+ }, settings );
+ }
+ else {
+ _fnProcessingDisplay( settings, false );
+ _fnInitComplete( settings );
+ }
+ }
+ }
+
+
+ /**
+ * Draw the table for the first time, adding all required features
+ * @param {object} oSettings dataTables settings object
+ * @param {object} [json] JSON from the server that completed the table, if using Ajax source
+ * with client-side processing (optional)
+ * @memberof DataTable#oApi
+ */
+ function _fnInitComplete ( settings, json )
+ {
+ settings._bInitComplete = true;
+
+ // When data was added after the initialisation (data or Ajax) we need to
+ // calculate the column sizing
+ if ( json || settings.oInit.aaData ) {
+ _fnAdjustColumnSizing( settings );
+ }
+
+ _fnCallbackFire( settings, null, 'plugin-init', [settings, json] );
+ _fnCallbackFire( settings, 'aoInitComplete', 'init', [settings, json] );
+ }
+
+
+ function _fnLengthChange ( settings, val )
+ {
+ var len = parseInt( val, 10 );
+ settings._iDisplayLength = len;
+
+ _fnLengthOverflow( settings );
+
+ // Fire length change event
+ _fnCallbackFire( settings, null, 'length', [settings, len] );
+ }
+
+
+ /**
+ * Generate the node required for user display length changing
+ * @param {object} settings dataTables settings object
+ * @returns {node} Display length feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlLength ( settings )
+ {
+ var
+ classes = settings.oClasses,
+ tableId = settings.sTableId,
+ menu = settings.aLengthMenu,
+ d2 = Array.isArray( menu[0] ),
+ lengths = d2 ? menu[0] : menu,
+ language = d2 ? menu[1] : menu;
+
+ var select = $('<select/>', {
+ 'name': tableId+'_length',
+ 'aria-controls': tableId,
+ 'class': classes.sLengthSelect
+ } );
+
+ for ( var i=0, ien=lengths.length ; i<ien ; i++ ) {
+ select[0][ i ] = new Option(
+ typeof language[i] === 'number' ?
+ settings.fnFormatNumber( language[i] ) :
+ language[i],
+ lengths[i]
+ );
+ }
+
+ var div = $('<div><label/></div>').addClass( classes.sLength );
+ if ( ! settings.aanFeatures.l ) {
+ div[0].id = tableId+'_length';
+ }
+
+ div.children().append(
+ settings.oLanguage.sLengthMenu.replace( '_MENU_', select[0].outerHTML )
+ );
+
+ // Can't use `select` variable as user might provide their own and the
+ // reference is broken by the use of outerHTML
+ $('select', div)
+ .val( settings._iDisplayLength )
+ .on( 'change.DT', function(e) {
+ _fnLengthChange( settings, $(this).val() );
+ _fnDraw( settings );
+ } );
+
+ // Update node value whenever anything changes the table's length
+ $(settings.nTable).on( 'length.dt.DT', function (e, s, len) {
+ if ( settings === s ) {
+ $('select', div).val( len );
+ }
+ } );
+
+ return div[0];
+ }
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Note that most of the paging logic is done in
+ * DataTable.ext.pager
+ */
+
+ /**
+ * Generate the node required for default pagination
+ * @param {object} oSettings dataTables settings object
+ * @returns {node} Pagination feature node
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlPaginate ( settings )
+ {
+ var
+ type = settings.sPaginationType,
+ plugin = DataTable.ext.pager[ type ],
+ modern = typeof plugin === 'function',
+ redraw = function( settings ) {
+ _fnDraw( settings );
+ },
+ node = $('<div/>').addClass( settings.oClasses.sPaging + type )[0],
+ features = settings.aanFeatures;
+
+ if ( ! modern ) {
+ plugin.fnInit( settings, node, redraw );
+ }
+
+ /* Add a draw callback for the pagination on first instance, to update the paging display */
+ if ( ! features.p )
+ {
+ node.id = settings.sTableId+'_paginate';
+
+ settings.aoDrawCallback.push( {
+ "fn": function( settings ) {
+ if ( modern ) {
+ var
+ start = settings._iDisplayStart,
+ len = settings._iDisplayLength,
+ visRecords = settings.fnRecordsDisplay(),
+ all = len === -1,
+ page = all ? 0 : Math.ceil( start / len ),
+ pages = all ? 1 : Math.ceil( visRecords / len ),
+ buttons = plugin(page, pages),
+ i, ien;
+
+ for ( i=0, ien=features.p.length ; i<ien ; i++ ) {
+ _fnRenderer( settings, 'pageButton' )(
+ settings, features.p[i], i, buttons, page, pages
+ );
+ }
+ }
+ else {
+ plugin.fnUpdate( settings, redraw );
+ }
+ },
+ "sName": "pagination"
+ } );
+ }
+
+ return node;
+ }
+
+
+ /**
+ * Alter the display settings to change the page
+ * @param {object} settings DataTables settings object
+ * @param {string|int} action Paging action to take: "first", "previous",
+ * "next" or "last" or page number to jump to (integer)
+ * @param [bool] redraw Automatically draw the update or not
+ * @returns {bool} true page has changed, false - no change
+ * @memberof DataTable#oApi
+ */
+ function _fnPageChange ( settings, action, redraw )
+ {
+ var
+ start = settings._iDisplayStart,
+ len = settings._iDisplayLength,
+ records = settings.fnRecordsDisplay();
+
+ if ( records === 0 || len === -1 )
+ {
+ start = 0;
+ }
+ else if ( typeof action === "number" )
+ {
+ start = action * len;
+
+ if ( start > records )
+ {
+ start = 0;
+ }
+ }
+ else if ( action == "first" )
+ {
+ start = 0;
+ }
+ else if ( action == "previous" )
+ {
+ start = len >= 0 ?
+ start - len :
+ 0;
+
+ if ( start < 0 )
+ {
+ start = 0;
+ }
+ }
+ else if ( action == "next" )
+ {
+ if ( start + len < records )
+ {
+ start += len;
+ }
+ }
+ else if ( action == "last" )
+ {
+ start = Math.floor( (records-1) / len) * len;
+ }
+ else
+ {
+ _fnLog( settings, 0, "Unknown paging action: "+action, 5 );
+ }
+
+ var changed = settings._iDisplayStart !== start;
+ settings._iDisplayStart = start;
+
+ if ( changed ) {
+ _fnCallbackFire( settings, null, 'page', [settings] );
+
+ if ( redraw ) {
+ _fnDraw( settings );
+ }
+ }
+ else {
+ // No change event - paging was called, but no change
+ _fnCallbackFire( settings, null, 'page-nc', [settings] );
+ }
+
+ return changed;
+ }
+
+
+
+ /**
+ * Generate the node required for the processing node
+ * @param {object} settings dataTables settings object
+ * @returns {node} Processing element
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlProcessing ( settings )
+ {
+ return $('<div/>', {
+ 'id': ! settings.aanFeatures.r ? settings.sTableId+'_processing' : null,
+ 'class': settings.oClasses.sProcessing
+ } )
+ .html( settings.oLanguage.sProcessing )
+ .append('<div><div></div><div></div><div></div><div></div></div>')
+ .insertBefore( settings.nTable )[0];
+ }
+
+
+ /**
+ * Display or hide the processing indicator
+ * @param {object} settings dataTables settings object
+ * @param {bool} show Show the processing indicator (true) or not (false)
+ * @memberof DataTable#oApi
+ */
+ function _fnProcessingDisplay ( settings, show )
+ {
+ if ( settings.oFeatures.bProcessing ) {
+ $(settings.aanFeatures.r).css( 'display', show ? 'block' : 'none' );
+ }
+
+ _fnCallbackFire( settings, null, 'processing', [settings, show] );
+ }
+
+ /**
+ * Add any control elements for the table - specifically scrolling
+ * @param {object} settings dataTables settings object
+ * @returns {node} Node to add to the DOM
+ * @memberof DataTable#oApi
+ */
+ function _fnFeatureHtmlTable ( settings )
+ {
+ var table = $(settings.nTable);
+
+ // Scrolling from here on in
+ var scroll = settings.oScroll;
+
+ if ( scroll.sX === '' && scroll.sY === '' ) {
+ return settings.nTable;
+ }
+
+ var scrollX = scroll.sX;
+ var scrollY = scroll.sY;
+ var classes = settings.oClasses;
+ var caption = table.children('caption');
+ var captionSide = caption.length ? caption[0]._captionSide : null;
+ var headerClone = $( table[0].cloneNode(false) );
+ var footerClone = $( table[0].cloneNode(false) );
+ var footer = table.children('tfoot');
+ var _div = '<div/>';
+ var size = function ( s ) {
+ return !s ? null : _fnStringToCss( s );
+ };
+
+ if ( ! footer.length ) {
+ footer = null;
+ }
+
+ /*
+ * The HTML structure that we want to generate in this function is:
+ * div - scroller
+ * div - scroll head
+ * div - scroll head inner
+ * table - scroll head table
+ * thead - thead
+ * div - scroll body
+ * table - table (master table)
+ * thead - thead clone for sizing
+ * tbody - tbody
+ * div - scroll foot
+ * div - scroll foot inner
+ * table - scroll foot table
+ * tfoot - tfoot
+ */
+ var scroller = $( _div, { 'class': classes.sScrollWrapper } )
+ .append(
+ $(_div, { 'class': classes.sScrollHead } )
+ .css( {
+ overflow: 'hidden',
+ position: 'relative',
+ border: 0,
+ width: scrollX ? size(scrollX) : '100%'
+ } )
+ .append(
+ $(_div, { 'class': classes.sScrollHeadInner } )
+ .css( {
+ 'box-sizing': 'content-box',
+ width: scroll.sXInner || '100%'
+ } )
+ .append(
+ headerClone
+ .removeAttr('id')
+ .css( 'margin-left', 0 )
+ .append( captionSide === 'top' ? caption : null )
+ .append(
+ table.children('thead')
+ )
+ )
+ )
+ )
+ .append(
+ $(_div, { 'class': classes.sScrollBody } )
+ .css( {
+ position: 'relative',
+ overflow: 'auto',
+ width: size( scrollX )
+ } )
+ .append( table )
+ );
+
+ if ( footer ) {
+ scroller.append(
+ $(_div, { 'class': classes.sScrollFoot } )
+ .css( {
+ overflow: 'hidden',
+ border: 0,
+ width: scrollX ? size(scrollX) : '100%'
+ } )
+ .append(
+ $(_div, { 'class': classes.sScrollFootInner } )
+ .append(
+ footerClone
+ .removeAttr('id')
+ .css( 'margin-left', 0 )
+ .append( captionSide === 'bottom' ? caption : null )
+ .append(
+ table.children('tfoot')
+ )
+ )
+ )
+ );
+ }
+
+ var children = scroller.children();
+ var scrollHead = children[0];
+ var scrollBody = children[1];
+ var scrollFoot = footer ? children[2] : null;
+
+ // When the body is scrolled, then we also want to scroll the headers
+ if ( scrollX ) {
+ $(scrollBody).on( 'scroll.DT', function (e) {
+ var scrollLeft = this.scrollLeft;
+
+ scrollHead.scrollLeft = scrollLeft;
+
+ if ( footer ) {
+ scrollFoot.scrollLeft = scrollLeft;
+ }
+ } );
+ }
+
+ $(scrollBody).css('max-height', scrollY);
+ if (! scroll.bCollapse) {
+ $(scrollBody).css('height', scrollY);
+ }
+
+ settings.nScrollHead = scrollHead;
+ settings.nScrollBody = scrollBody;
+ settings.nScrollFoot = scrollFoot;
+
+ // On redraw - align columns
+ settings.aoDrawCallback.push( {
+ "fn": _fnScrollDraw,
+ "sName": "scrolling"
+ } );
+
+ return scroller[0];
+ }
+
+
+
+ /**
+ * Update the header, footer and body tables for resizing - i.e. column
+ * alignment.
+ *
+ * Welcome to the most horrible function DataTables. The process that this
+ * function follows is basically:
+ * 1. Re-create the table inside the scrolling div
+ * 2. Take live measurements from the DOM
+ * 3. Apply the measurements to align the columns
+ * 4. Clean up
+ *
+ * @param {object} settings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnScrollDraw ( settings )
+ {
+ // Given that this is such a monster function, a lot of variables are use
+ // to try and keep the minimised size as small as possible
+ var
+ scroll = settings.oScroll,
+ scrollX = scroll.sX,
+ scrollXInner = scroll.sXInner,
+ scrollY = scroll.sY,
+ barWidth = scroll.iBarWidth,
+ divHeader = $(settings.nScrollHead),
+ divHeaderStyle = divHeader[0].style,
+ divHeaderInner = divHeader.children('div'),
+ divHeaderInnerStyle = divHeaderInner[0].style,
+ divHeaderTable = divHeaderInner.children('table'),
+ divBodyEl = settings.nScrollBody,
+ divBody = $(divBodyEl),
+ divBodyStyle = divBodyEl.style,
+ divFooter = $(settings.nScrollFoot),
+ divFooterInner = divFooter.children('div'),
+ divFooterTable = divFooterInner.children('table'),
+ header = $(settings.nTHead),
+ table = $(settings.nTable),
+ tableEl = table[0],
+ tableStyle = tableEl.style,
+ footer = settings.nTFoot ? $(settings.nTFoot) : null,
+ browser = settings.oBrowser,
+ ie67 = browser.bScrollOversize,
+ dtHeaderCells = _pluck( settings.aoColumns, 'nTh' ),
+ headerTrgEls, footerTrgEls,
+ headerSrcEls, footerSrcEls,
+ headerCopy, footerCopy,
+ headerWidths=[], footerWidths=[],
+ headerContent=[], footerContent=[],
+ idx, correction, sanityWidth,
+ zeroOut = function(nSizer) {
+ var style = nSizer.style;
+ style.paddingTop = "0";
+ style.paddingBottom = "0";
+ style.borderTopWidth = "0";
+ style.borderBottomWidth = "0";
+ style.height = 0;
+ };
+
+ // If the scrollbar visibility has changed from the last draw, we need to
+ // adjust the column sizes as the table width will have changed to account
+ // for the scrollbar
+ var scrollBarVis = divBodyEl.scrollHeight > divBodyEl.clientHeight;
+
+ if ( settings.scrollBarVis !== scrollBarVis && settings.scrollBarVis !== undefined ) {
+ settings.scrollBarVis = scrollBarVis;
+ _fnAdjustColumnSizing( settings );
+ return; // adjust column sizing will call this function again
+ }
+ else {
+ settings.scrollBarVis = scrollBarVis;
+ }
+
+ /*
+ * 1. Re-create the table inside the scrolling div
+ */
+
+ // Remove the old minimised thead and tfoot elements in the inner table
+ table.children('thead, tfoot').remove();
+
+ if ( footer ) {
+ footerCopy = footer.clone().prependTo( table );
+ footerTrgEls = footer.find('tr'); // the original tfoot is in its own table and must be sized
+ footerSrcEls = footerCopy.find('tr');
+ footerCopy.find('[id]').removeAttr('id');
+ }
+
+ // Clone the current header and footer elements and then place it into the inner table
+ headerCopy = header.clone().prependTo( table );
+ headerTrgEls = header.find('tr'); // original header is in its own table
+ headerSrcEls = headerCopy.find('tr');
+ headerCopy.find('th, td').removeAttr('tabindex');
+ headerCopy.find('[id]').removeAttr('id');
+
+
+ /*
+ * 2. Take live measurements from the DOM - do not alter the DOM itself!
+ */
+
+ // Remove old sizing and apply the calculated column widths
+ // Get the unique column headers in the newly created (cloned) header. We want to apply the
+ // calculated sizes to this header
+ if ( ! scrollX )
+ {
+ divBodyStyle.width = '100%';
+ divHeader[0].style.width = '100%';
+ }
+
+ $.each( _fnGetUniqueThs( settings, headerCopy ), function ( i, el ) {
+ idx = _fnVisibleToColumnIndex( settings, i );
+ el.style.width = settings.aoColumns[idx].sWidth;
+ } );
+
+ if ( footer ) {
+ _fnApplyToChildren( function(n) {
+ n.style.width = "";
+ }, footerSrcEls );
+ }
+
+ // Size the table as a whole
+ sanityWidth = table.outerWidth();
+ if ( scrollX === "" ) {
+ // No x scrolling
+ tableStyle.width = "100%";
+
+ // IE7 will make the width of the table when 100% include the scrollbar
+ // - which is shouldn't. When there is a scrollbar we need to take this
+ // into account.
+ if ( ie67 && (table.find('tbody').height() > divBodyEl.offsetHeight ||
+ divBody.css('overflow-y') == "scroll")
+ ) {
+ tableStyle.width = _fnStringToCss( table.outerWidth() - barWidth);
+ }
+
+ // Recalculate the sanity width
+ sanityWidth = table.outerWidth();
+ }
+ else if ( scrollXInner !== "" ) {
+ // legacy x scroll inner has been given - use it
+ tableStyle.width = _fnStringToCss(scrollXInner);
+
+ // Recalculate the sanity width
+ sanityWidth = table.outerWidth();
+ }
+
+ // Hidden header should have zero height, so remove padding and borders. Then
+ // set the width based on the real headers
+
+ // Apply all styles in one pass
+ _fnApplyToChildren( zeroOut, headerSrcEls );
+
+ // Read all widths in next pass
+ _fnApplyToChildren( function(nSizer) {
+ var style = window.getComputedStyle ?
+ window.getComputedStyle(nSizer).width :
+ _fnStringToCss( $(nSizer).width() );
+
+ headerContent.push( nSizer.innerHTML );
+ headerWidths.push( style );
+ }, headerSrcEls );
+
+ // Apply all widths in final pass
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = headerWidths[i];
+ }, headerTrgEls );
+
+ $(headerSrcEls).css('height', 0);
+
+ /* Same again with the footer if we have one */
+ if ( footer )
+ {
+ _fnApplyToChildren( zeroOut, footerSrcEls );
+
+ _fnApplyToChildren( function(nSizer) {
+ footerContent.push( nSizer.innerHTML );
+ footerWidths.push( _fnStringToCss( $(nSizer).css('width') ) );
+ }, footerSrcEls );
+
+ _fnApplyToChildren( function(nToSize, i) {
+ nToSize.style.width = footerWidths[i];
+ }, footerTrgEls );
+
+ $(footerSrcEls).height(0);
+ }
+
+
+ /*
+ * 3. Apply the measurements
+ */
+
+ // "Hide" the header and footer that we used for the sizing. We need to keep
+ // the content of the cell so that the width applied to the header and body
+ // both match, but we want to hide it completely. We want to also fix their
+ // width to what they currently are
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = '<div class="dataTables_sizing">'+headerContent[i]+'</div>';
+ nSizer.childNodes[0].style.height = "0";
+ nSizer.childNodes[0].style.overflow = "hidden";
+ nSizer.style.width = headerWidths[i];
+ }, headerSrcEls );
+
+ if ( footer )
+ {
+ _fnApplyToChildren( function(nSizer, i) {
+ nSizer.innerHTML = '<div class="dataTables_sizing">'+footerContent[i]+'</div>';
+ nSizer.childNodes[0].style.height = "0";
+ nSizer.childNodes[0].style.overflow = "hidden";
+ nSizer.style.width = footerWidths[i];
+ }, footerSrcEls );
+ }
+
+ // Sanity check that the table is of a sensible width. If not then we are going to get
+ // misalignment - try to prevent this by not allowing the table to shrink below its min width
+ if ( Math.round(table.outerWidth()) < Math.round(sanityWidth) )
+ {
+ // The min width depends upon if we have a vertical scrollbar visible or not */
+ correction = ((divBodyEl.scrollHeight > divBodyEl.offsetHeight ||
+ divBody.css('overflow-y') == "scroll")) ?
+ sanityWidth+barWidth :
+ sanityWidth;
+
+ // IE6/7 are a law unto themselves...
+ if ( ie67 && (divBodyEl.scrollHeight >
+ divBodyEl.offsetHeight || divBody.css('overflow-y') == "scroll")
+ ) {
+ tableStyle.width = _fnStringToCss( correction-barWidth );
+ }
+
+ // And give the user a warning that we've stopped the table getting too small
+ if ( scrollX === "" || scrollXInner !== "" ) {
+ _fnLog( settings, 1, 'Possible column misalignment', 6 );
+ }
+ }
+ else
+ {
+ correction = '100%';
+ }
+
+ // Apply to the container elements
+ divBodyStyle.width = _fnStringToCss( correction );
+ divHeaderStyle.width = _fnStringToCss( correction );
+
+ if ( footer ) {
+ settings.nScrollFoot.style.width = _fnStringToCss( correction );
+ }
+
+
+ /*
+ * 4. Clean up
+ */
+ if ( ! scrollY ) {
+ /* IE7< puts a vertical scrollbar in place (when it shouldn't be) due to subtracting
+ * the scrollbar height from the visible display, rather than adding it on. We need to
+ * set the height in order to sort this. Don't want to do it in any other browsers.
+ */
+ if ( ie67 ) {
+ divBodyStyle.height = _fnStringToCss( tableEl.offsetHeight+barWidth );
+ }
+ }
+
+ /* Finally set the width's of the header and footer tables */
+ var iOuterWidth = table.outerWidth();
+ divHeaderTable[0].style.width = _fnStringToCss( iOuterWidth );
+ divHeaderInnerStyle.width = _fnStringToCss( iOuterWidth );
+
+ // Figure out if there are scrollbar present - if so then we need a the header and footer to
+ // provide a bit more space to allow "overflow" scrolling (i.e. past the scrollbar)
+ var bScrolling = table.height() > divBodyEl.clientHeight || divBody.css('overflow-y') == "scroll";
+ var padding = 'padding' + (browser.bScrollbarLeft ? 'Left' : 'Right' );
+ divHeaderInnerStyle[ padding ] = bScrolling ? barWidth+"px" : "0px";
+
+ if ( footer ) {
+ divFooterTable[0].style.width = _fnStringToCss( iOuterWidth );
+ divFooterInner[0].style.width = _fnStringToCss( iOuterWidth );
+ divFooterInner[0].style[padding] = bScrolling ? barWidth+"px" : "0px";
+ }
+
+ // Correct DOM ordering for colgroup - comes before the thead
+ table.children('colgroup').insertBefore( table.children('thead') );
+
+ /* Adjust the position of the header in case we loose the y-scrollbar */
+ divBody.trigger('scroll');
+
+ // If sorting or filtering has occurred, jump the scrolling back to the top
+ // only if we aren't holding the position
+ if ( (settings.bSorted || settings.bFiltered) && ! settings._drawHold ) {
+ divBodyEl.scrollTop = 0;
+ }
+ }
+
+
+
+ /**
+ * Apply a given function to the display child nodes of an element array (typically
+ * TD children of TR rows
+ * @param {function} fn Method to apply to the objects
+ * @param array {nodes} an1 List of elements to look through for display children
+ * @param array {nodes} an2 Another list (identical structure to the first) - optional
+ * @memberof DataTable#oApi
+ */
+ function _fnApplyToChildren( fn, an1, an2 )
+ {
+ var index=0, i=0, iLen=an1.length;
+ var nNode1, nNode2;
+
+ while ( i < iLen ) {
+ nNode1 = an1[i].firstChild;
+ nNode2 = an2 ? an2[i].firstChild : null;
+
+ while ( nNode1 ) {
+ if ( nNode1.nodeType === 1 ) {
+ if ( an2 ) {
+ fn( nNode1, nNode2, index );
+ }
+ else {
+ fn( nNode1, index );
+ }
+
+ index++;
+ }
+
+ nNode1 = nNode1.nextSibling;
+ nNode2 = an2 ? nNode2.nextSibling : null;
+ }
+
+ i++;
+ }
+ }
+
+
+
+ var __re_html_remove = /<.*?>/g;
+
+
+ /**
+ * Calculate the width of columns for the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnCalculateColumnWidths ( oSettings )
+ {
+ var
+ table = oSettings.nTable,
+ columns = oSettings.aoColumns,
+ scroll = oSettings.oScroll,
+ scrollY = scroll.sY,
+ scrollX = scroll.sX,
+ scrollXInner = scroll.sXInner,
+ columnCount = columns.length,
+ visibleColumns = _fnGetColumns( oSettings, 'bVisible' ),
+ headerCells = $('th', oSettings.nTHead),
+ tableWidthAttr = table.getAttribute('width'), // from DOM element
+ tableContainer = table.parentNode,
+ userInputs = false,
+ i, column, columnIdx, width, outerWidth,
+ browser = oSettings.oBrowser,
+ ie67 = browser.bScrollOversize;
+
+ var styleWidth = table.style.width;
+ if ( styleWidth && styleWidth.indexOf('%') !== -1 ) {
+ tableWidthAttr = styleWidth;
+ }
+
+ /* Convert any user input sizes into pixel sizes */
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ column = columns[ visibleColumns[i] ];
+
+ if ( column.sWidth !== null ) {
+ column.sWidth = _fnConvertToWidth( column.sWidthOrig, tableContainer );
+
+ userInputs = true;
+ }
+ }
+
+ /* If the number of columns in the DOM equals the number that we have to
+ * process in DataTables, then we can use the offsets that are created by
+ * the web- browser. No custom sizes can be set in order for this to happen,
+ * nor scrolling used
+ */
+ if ( ie67 || ! userInputs && ! scrollX && ! scrollY &&
+ columnCount == _fnVisbleColumns( oSettings ) &&
+ columnCount == headerCells.length
+ ) {
+ for ( i=0 ; i<columnCount ; i++ ) {
+ var colIdx = _fnVisibleToColumnIndex( oSettings, i );
+
+ if ( colIdx !== null ) {
+ columns[ colIdx ].sWidth = _fnStringToCss( headerCells.eq(i).width() );
+ }
+ }
+ }
+ else
+ {
+ // Otherwise construct a single row, worst case, table with the widest
+ // node in the data, assign any user defined widths, then insert it into
+ // the DOM and allow the browser to do all the hard work of calculating
+ // table widths
+ var tmpTable = $(table).clone() // don't use cloneNode - IE8 will remove events on the main table
+ .css( 'visibility', 'hidden' )
+ .removeAttr( 'id' );
+
+ // Clean up the table body
+ tmpTable.find('tbody tr').remove();
+ var tr = $('<tr/>').appendTo( tmpTable.find('tbody') );
+
+ // Clone the table header and footer - we can't use the header / footer
+ // from the cloned table, since if scrolling is active, the table's
+ // real header and footer are contained in different table tags
+ tmpTable.find('thead, tfoot').remove();
+ tmpTable
+ .append( $(oSettings.nTHead).clone() )
+ .append( $(oSettings.nTFoot).clone() );
+
+ // Remove any assigned widths from the footer (from scrolling)
+ tmpTable.find('tfoot th, tfoot td').css('width', '');
+
+ // Apply custom sizing to the cloned header
+ headerCells = _fnGetUniqueThs( oSettings, tmpTable.find('thead')[0] );
+
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ column = columns[ visibleColumns[i] ];
+
+ headerCells[i].style.width = column.sWidthOrig !== null && column.sWidthOrig !== '' ?
+ _fnStringToCss( column.sWidthOrig ) :
+ '';
+
+ // For scrollX we need to force the column width otherwise the
+ // browser will collapse it. If this width is smaller than the
+ // width the column requires, then it will have no effect
+ if ( column.sWidthOrig && scrollX ) {
+ $( headerCells[i] ).append( $('<div/>').css( {
+ width: column.sWidthOrig,
+ margin: 0,
+ padding: 0,
+ border: 0,
+ height: 1
+ } ) );
+ }
+ }
+
+ // Find the widest cell for each column and put it into the table
+ if ( oSettings.aoData.length ) {
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ columnIdx = visibleColumns[i];
+ column = columns[ columnIdx ];
+
+ $( _fnGetWidestNode( oSettings, columnIdx ) )
+ .clone( false )
+ .append( column.sContentPadding )
+ .appendTo( tr );
+ }
+ }
+
+ // Tidy the temporary table - remove name attributes so there aren't
+ // duplicated in the dom (radio elements for example)
+ $('[name]', tmpTable).removeAttr('name');
+
+ // Table has been built, attach to the document so we can work with it.
+ // A holding element is used, positioned at the top of the container
+ // with minimal height, so it has no effect on if the container scrolls
+ // or not. Otherwise it might trigger scrolling when it actually isn't
+ // needed
+ var holder = $('<div/>').css( scrollX || scrollY ?
+ {
+ position: 'absolute',
+ top: 0,
+ left: 0,
+ height: 1,
+ right: 0,
+ overflow: 'hidden'
+ } :
+ {}
+ )
+ .append( tmpTable )
+ .appendTo( tableContainer );
+
+ // When scrolling (X or Y) we want to set the width of the table as
+ // appropriate. However, when not scrolling leave the table width as it
+ // is. This results in slightly different, but I think correct behaviour
+ if ( scrollX && scrollXInner ) {
+ tmpTable.width( scrollXInner );
+ }
+ else if ( scrollX ) {
+ tmpTable.css( 'width', 'auto' );
+ tmpTable.removeAttr('width');
+
+ // If there is no width attribute or style, then allow the table to
+ // collapse
+ if ( tmpTable.width() < tableContainer.clientWidth && tableWidthAttr ) {
+ tmpTable.width( tableContainer.clientWidth );
+ }
+ }
+ else if ( scrollY ) {
+ tmpTable.width( tableContainer.clientWidth );
+ }
+ else if ( tableWidthAttr ) {
+ tmpTable.width( tableWidthAttr );
+ }
+
+ // Get the width of each column in the constructed table - we need to
+ // know the inner width (so it can be assigned to the other table's
+ // cells) and the outer width so we can calculate the full width of the
+ // table. This is safe since DataTables requires a unique cell for each
+ // column, but if ever a header can span multiple columns, this will
+ // need to be modified.
+ var total = 0;
+ for ( i=0 ; i<visibleColumns.length ; i++ ) {
+ var cell = $(headerCells[i]);
+ var border = cell.outerWidth() - cell.width();
+
+ // Use getBounding... where possible (not IE8-) because it can give
+ // sub-pixel accuracy, which we then want to round up!
+ var bounding = browser.bBounding ?
+ Math.ceil( headerCells[i].getBoundingClientRect().width ) :
+ cell.outerWidth();
+
+ // Total is tracked to remove any sub-pixel errors as the outerWidth
+ // of the table might not equal the total given here (IE!).
+ total += bounding;
+
+ // Width for each column to use
+ columns[ visibleColumns[i] ].sWidth = _fnStringToCss( bounding - border );
+ }
+
+ table.style.width = _fnStringToCss( total );
+
+ // Finished with the table - ditch it
+ holder.remove();
+ }
+
+ // If there is a width attr, we want to attach an event listener which
+ // allows the table sizing to automatically adjust when the window is
+ // resized. Use the width attr rather than CSS, since we can't know if the
+ // CSS is a relative value or absolute - DOM read is always px.
+ if ( tableWidthAttr ) {
+ table.style.width = _fnStringToCss( tableWidthAttr );
+ }
+
+ if ( (tableWidthAttr || scrollX) && ! oSettings._reszEvt ) {
+ var bindResize = function () {
+ $(window).on('resize.DT-'+oSettings.sInstance, _fnThrottle( function () {
+ _fnAdjustColumnSizing( oSettings );
+ } ) );
+ };
+
+ // IE6/7 will crash if we bind a resize event handler on page load.
+ // To be removed in 1.11 which drops IE6/7 support
+ if ( ie67 ) {
+ setTimeout( bindResize, 1000 );
+ }
+ else {
+ bindResize();
+ }
+
+ oSettings._reszEvt = true;
+ }
+ }
+
+
+ /**
+ * Throttle the calls to a function. Arguments and context are maintained for
+ * the throttled function
+ * @param {function} fn Function to be called
+ * @param {int} [freq=200] call frequency in mS
+ * @returns {function} wrapped function
+ * @memberof DataTable#oApi
+ */
+ var _fnThrottle = DataTable.util.throttle;
+
+
+ /**
+ * Convert a CSS unit width to pixels (e.g. 2em)
+ * @param {string} width width to be converted
+ * @param {node} parent parent to get the with for (required for relative widths) - optional
+ * @returns {int} width in pixels
+ * @memberof DataTable#oApi
+ */
+ function _fnConvertToWidth ( width, parent )
+ {
+ if ( ! width ) {
+ return 0;
+ }
+
+ var n = $('<div/>')
+ .css( 'width', _fnStringToCss( width ) )
+ .appendTo( parent || document.body );
+
+ var val = n[0].offsetWidth;
+ n.remove();
+
+ return val;
+ }
+
+
+ /**
+ * Get the widest node
+ * @param {object} settings dataTables settings object
+ * @param {int} colIdx column of interest
+ * @returns {node} widest table node
+ * @memberof DataTable#oApi
+ */
+ function _fnGetWidestNode( settings, colIdx )
+ {
+ var idx = _fnGetMaxLenString( settings, colIdx );
+ if ( idx < 0 ) {
+ return null;
+ }
+
+ var data = settings.aoData[ idx ];
+ return ! data.nTr ? // Might not have been created when deferred rendering
+ $('<td/>').html( _fnGetCellData( settings, idx, colIdx, 'display' ) )[0] :
+ data.anCells[ colIdx ];
+ }
+
+
+ /**
+ * Get the maximum strlen for each data column
+ * @param {object} settings dataTables settings object
+ * @param {int} colIdx column of interest
+ * @returns {string} max string length for each column
+ * @memberof DataTable#oApi
+ */
+ function _fnGetMaxLenString( settings, colIdx )
+ {
+ var s, max=-1, maxIdx = -1;
+
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ s = _fnGetCellData( settings, i, colIdx, 'display' )+'';
+ s = s.replace( __re_html_remove, '' );
+ s = s.replace( / /g, ' ' );
+
+ if ( s.length > max ) {
+ max = s.length;
+ maxIdx = i;
+ }
+ }
+
+ return maxIdx;
+ }
+
+
+ /**
+ * Append a CSS unit (only if required) to a string
+ * @param {string} value to css-ify
+ * @returns {string} value with css unit
+ * @memberof DataTable#oApi
+ */
+ function _fnStringToCss( s )
+ {
+ if ( s === null ) {
+ return '0px';
+ }
+
+ if ( typeof s == 'number' ) {
+ return s < 0 ?
+ '0px' :
+ s+'px';
+ }
+
+ // Check it has a unit character already
+ return s.match(/\d$/) ?
+ s+'px' :
+ s;
+ }
+
+
+
+ function _fnSortFlatten ( settings )
+ {
+ var
+ i, iLen, k, kLen,
+ aSort = [],
+ aiOrig = [],
+ aoColumns = settings.aoColumns,
+ aDataSort, iCol, sType, srcCol,
+ fixed = settings.aaSortingFixed,
+ fixedObj = $.isPlainObject( fixed ),
+ nestedSort = [],
+ add = function ( a ) {
+ if ( a.length && ! Array.isArray( a[0] ) ) {
+ // 1D array
+ nestedSort.push( a );
+ }
+ else {
+ // 2D array
+ $.merge( nestedSort, a );
+ }
+ };
+
+ // Build the sort array, with pre-fix and post-fix options if they have been
+ // specified
+ if ( Array.isArray( fixed ) ) {
+ add( fixed );
+ }
+
+ if ( fixedObj && fixed.pre ) {
+ add( fixed.pre );
+ }
+
+ add( settings.aaSorting );
+
+ if (fixedObj && fixed.post ) {
+ add( fixed.post );
+ }
+
+ for ( i=0 ; i<nestedSort.length ; i++ )
+ {
+ srcCol = nestedSort[i][0];
+ aDataSort = aoColumns[ srcCol ].aDataSort;
+
+ for ( k=0, kLen=aDataSort.length ; k<kLen ; k++ )
+ {
+ iCol = aDataSort[k];
+ sType = aoColumns[ iCol ].sType || 'string';
+
+ if ( nestedSort[i]._idx === undefined ) {
+ nestedSort[i]._idx = $.inArray( nestedSort[i][1], aoColumns[iCol].asSorting );
+ }
+
+ aSort.push( {
+ src: srcCol,
+ col: iCol,
+ dir: nestedSort[i][1],
+ index: nestedSort[i]._idx,
+ type: sType,
+ formatter: DataTable.ext.type.order[ sType+"-pre" ]
+ } );
+ }
+ }
+
+ return aSort;
+ }
+
+ /**
+ * Change the order of the table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ * @todo This really needs split up!
+ */
+ function _fnSort ( oSettings )
+ {
+ var
+ i, ien, iLen, j, jLen, k, kLen,
+ sDataType, nTh,
+ aiOrig = [],
+ oExtSort = DataTable.ext.type.order,
+ aoData = oSettings.aoData,
+ aoColumns = oSettings.aoColumns,
+ aDataSort, data, iCol, sType, oSort,
+ formatters = 0,
+ sortCol,
+ displayMaster = oSettings.aiDisplayMaster,
+ aSort;
+
+ // Resolve any column types that are unknown due to addition or invalidation
+ // @todo Can this be moved into a 'data-ready' handler which is called when
+ // data is going to be used in the table?
+ _fnColumnTypes( oSettings );
+
+ aSort = _fnSortFlatten( oSettings );
+
+ for ( i=0, ien=aSort.length ; i<ien ; i++ ) {
+ sortCol = aSort[i];
+
+ // Track if we can use the fast sort algorithm
+ if ( sortCol.formatter ) {
+ formatters++;
+ }
+
+ // Load the data needed for the sort, for each cell
+ _fnSortData( oSettings, sortCol.col );
+ }
+
+ /* No sorting required if server-side or no sorting array */
+ if ( _fnDataSource( oSettings ) != 'ssp' && aSort.length !== 0 )
+ {
+ // Create a value - key array of the current row positions such that we can use their
+ // current position during the sort, if values match, in order to perform stable sorting
+ for ( i=0, iLen=displayMaster.length ; i<iLen ; i++ ) {
+ aiOrig[ displayMaster[i] ] = i;
+ }
+
+ /* Do the sort - here we want multi-column sorting based on a given data source (column)
+ * and sorting function (from oSort) in a certain direction. It's reasonably complex to
+ * follow on it's own, but this is what we want (example two column sorting):
+ * fnLocalSorting = function(a,b){
+ * var iTest;
+ * iTest = oSort['string-asc']('data11', 'data12');
+ * if (iTest !== 0)
+ * return iTest;
+ * iTest = oSort['numeric-desc']('data21', 'data22');
+ * if (iTest !== 0)
+ * return iTest;
+ * return oSort['numeric-asc']( aiOrig[a], aiOrig[b] );
+ * }
+ * Basically we have a test for each sorting column, if the data in that column is equal,
+ * test the next column. If all columns match, then we use a numeric sort on the row
+ * positions in the original data array to provide a stable sort.
+ *
+ * Note - I know it seems excessive to have two sorting methods, but the first is around
+ * 15% faster, so the second is only maintained for backwards compatibility with sorting
+ * methods which do not have a pre-sort formatting function.
+ */
+ if ( formatters === aSort.length ) {
+ // All sort types have formatting functions
+ displayMaster.sort( function ( a, b ) {
+ var
+ x, y, k, test, sort,
+ len=aSort.length,
+ dataA = aoData[a]._aSortData,
+ dataB = aoData[b]._aSortData;
+
+ for ( k=0 ; k<len ; k++ ) {
+ sort = aSort[k];
+
+ x = dataA[ sort.col ];
+ y = dataB[ sort.col ];
+
+ test = x<y ? -1 : x>y ? 1 : 0;
+ if ( test !== 0 ) {
+ return sort.dir === 'asc' ? test : -test;
+ }
+ }
+
+ x = aiOrig[a];
+ y = aiOrig[b];
+ return x<y ? -1 : x>y ? 1 : 0;
+ } );
+ }
+ else {
+ // Depreciated - remove in 1.11 (providing a plug-in option)
+ // Not all sort types have formatting methods, so we have to call their sorting
+ // methods.
+ displayMaster.sort( function ( a, b ) {
+ var
+ x, y, k, l, test, sort, fn,
+ len=aSort.length,
+ dataA = aoData[a]._aSortData,
+ dataB = aoData[b]._aSortData;
+
+ for ( k=0 ; k<len ; k++ ) {
+ sort = aSort[k];
+
+ x = dataA[ sort.col ];
+ y = dataB[ sort.col ];
+
+ fn = oExtSort[ sort.type+"-"+sort.dir ] || oExtSort[ "string-"+sort.dir ];
+ test = fn( x, y );
+ if ( test !== 0 ) {
+ return test;
+ }
+ }
+
+ x = aiOrig[a];
+ y = aiOrig[b];
+ return x<y ? -1 : x>y ? 1 : 0;
+ } );
+ }
+ }
+
+ /* Tell the draw function that we have sorted the data */
+ oSettings.bSorted = true;
+ }
+
+
+ function _fnSortAria ( settings )
+ {
+ var label;
+ var nextSort;
+ var columns = settings.aoColumns;
+ var aSort = _fnSortFlatten( settings );
+ var oAria = settings.oLanguage.oAria;
+
+ // ARIA attributes - need to loop all columns, to update all (removing old
+ // attributes as needed)
+ for ( var i=0, iLen=columns.length ; i<iLen ; i++ )
+ {
+ var col = columns[i];
+ var asSorting = col.asSorting;
+ var sTitle = col.ariaTitle || col.sTitle.replace( /<.*?>/g, "" );
+ var th = col.nTh;
+
+ // IE7 is throwing an error when setting these properties with jQuery's
+ // attr() and removeAttr() methods...
+ th.removeAttribute('aria-sort');
+
+ /* In ARIA only the first sorting column can be marked as sorting - no multi-sort option */
+ if ( col.bSortable ) {
+ if ( aSort.length > 0 && aSort[0].col == i ) {
+ th.setAttribute('aria-sort', aSort[0].dir=="asc" ? "ascending" : "descending" );
+ nextSort = asSorting[ aSort[0].index+1 ] || asSorting[0];
+ }
+ else {
+ nextSort = asSorting[0];
+ }
+
+ label = sTitle + ( nextSort === "asc" ?
+ oAria.sSortAscending :
+ oAria.sSortDescending
+ );
+ }
+ else {
+ label = sTitle;
+ }
+
+ th.setAttribute('aria-label', label);
+ }
+ }
+
+
+ /**
+ * Function to run on user sort request
+ * @param {object} settings dataTables settings object
+ * @param {node} attachTo node to attach the handler to
+ * @param {int} colIdx column sorting index
+ * @param {boolean} [append=false] Append the requested sort to the existing
+ * sort if true (i.e. multi-column sort)
+ * @param {function} [callback] callback function
+ * @memberof DataTable#oApi
+ */
+ function _fnSortListener ( settings, colIdx, append, callback )
+ {
+ var col = settings.aoColumns[ colIdx ];
+ var sorting = settings.aaSorting;
+ var asSorting = col.asSorting;
+ var nextSortIdx;
+ var next = function ( a, overflow ) {
+ var idx = a._idx;
+ if ( idx === undefined ) {
+ idx = $.inArray( a[1], asSorting );
+ }
+
+ return idx+1 < asSorting.length ?
+ idx+1 :
+ overflow ?
+ null :
+ 0;
+ };
+
+ // Convert to 2D array if needed
+ if ( typeof sorting[0] === 'number' ) {
+ sorting = settings.aaSorting = [ sorting ];
+ }
+
+ // If appending the sort then we are multi-column sorting
+ if ( append && settings.oFeatures.bSortMulti ) {
+ // Are we already doing some kind of sort on this column?
+ var sortIdx = $.inArray( colIdx, _pluck(sorting, '0') );
+
+ if ( sortIdx !== -1 ) {
+ // Yes, modify the sort
+ nextSortIdx = next( sorting[sortIdx], true );
+
+ if ( nextSortIdx === null && sorting.length === 1 ) {
+ nextSortIdx = 0; // can't remove sorting completely
+ }
+
+ if ( nextSortIdx === null ) {
+ sorting.splice( sortIdx, 1 );
+ }
+ else {
+ sorting[sortIdx][1] = asSorting[ nextSortIdx ];
+ sorting[sortIdx]._idx = nextSortIdx;
+ }
+ }
+ else {
+ // No sort on this column yet
+ sorting.push( [ colIdx, asSorting[0], 0 ] );
+ sorting[sorting.length-1]._idx = 0;
+ }
+ }
+ else if ( sorting.length && sorting[0][0] == colIdx ) {
+ // Single column - already sorting on this column, modify the sort
+ nextSortIdx = next( sorting[0] );
+
+ sorting.length = 1;
+ sorting[0][1] = asSorting[ nextSortIdx ];
+ sorting[0]._idx = nextSortIdx;
+ }
+ else {
+ // Single column - sort only on this column
+ sorting.length = 0;
+ sorting.push( [ colIdx, asSorting[0] ] );
+ sorting[0]._idx = 0;
+ }
+
+ // Run the sort by calling a full redraw
+ _fnReDraw( settings );
+
+ // callback used for async user interaction
+ if ( typeof callback == 'function' ) {
+ callback( settings );
+ }
+ }
+
+
+ /**
+ * Attach a sort handler (click) to a node
+ * @param {object} settings dataTables settings object
+ * @param {node} attachTo node to attach the handler to
+ * @param {int} colIdx column sorting index
+ * @param {function} [callback] callback function
+ * @memberof DataTable#oApi
+ */
+ function _fnSortAttachListener ( settings, attachTo, colIdx, callback )
+ {
+ var col = settings.aoColumns[ colIdx ];
+
+ _fnBindAction( attachTo, {}, function (e) {
+ /* If the column is not sortable - don't to anything */
+ if ( col.bSortable === false ) {
+ return;
+ }
+
+ // If processing is enabled use a timeout to allow the processing
+ // display to be shown - otherwise to it synchronously
+ if ( settings.oFeatures.bProcessing ) {
+ _fnProcessingDisplay( settings, true );
+
+ setTimeout( function() {
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
+
+ // In server-side processing, the draw callback will remove the
+ // processing display
+ if ( _fnDataSource( settings ) !== 'ssp' ) {
+ _fnProcessingDisplay( settings, false );
+ }
+ }, 0 );
+ }
+ else {
+ _fnSortListener( settings, colIdx, e.shiftKey, callback );
+ }
+ } );
+ }
+
+
+ /**
+ * Set the sorting classes on table's body, Note: it is safe to call this function
+ * when bSort and bSortClasses are false
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSortingClasses( settings )
+ {
+ var oldSort = settings.aLastSort;
+ var sortClass = settings.oClasses.sSortColumn;
+ var sort = _fnSortFlatten( settings );
+ var features = settings.oFeatures;
+ var i, ien, colIdx;
+
+ if ( features.bSort && features.bSortClasses ) {
+ // Remove old sorting classes
+ for ( i=0, ien=oldSort.length ; i<ien ; i++ ) {
+ colIdx = oldSort[i].src;
+
+ // Remove column sorting
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
+ .removeClass( sortClass + (i<2 ? i+1 : 3) );
+ }
+
+ // Add new column sorting
+ for ( i=0, ien=sort.length ; i<ien ; i++ ) {
+ colIdx = sort[i].src;
+
+ $( _pluck( settings.aoData, 'anCells', colIdx ) )
+ .addClass( sortClass + (i<2 ? i+1 : 3) );
+ }
+ }
+
+ settings.aLastSort = sort;
+ }
+
+
+ // Get the data to sort a column, be it from cache, fresh (populating the
+ // cache), or from a sort formatter
+ function _fnSortData( settings, idx )
+ {
+ // Custom sorting function - provided by the sort data type
+ var column = settings.aoColumns[ idx ];
+ var customSort = DataTable.ext.order[ column.sSortDataType ];
+ var customData;
+
+ if ( customSort ) {
+ customData = customSort.call( settings.oInstance, settings, idx,
+ _fnColumnIndexToVisible( settings, idx )
+ );
+ }
+
+ // Use / populate cache
+ var row, cellData;
+ var formatter = DataTable.ext.type.order[ column.sType+"-pre" ];
+
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ row = settings.aoData[i];
+
+ if ( ! row._aSortData ) {
+ row._aSortData = [];
+ }
+
+ if ( ! row._aSortData[idx] || customSort ) {
+ cellData = customSort ?
+ customData[i] : // If there was a custom sort function, use data from there
+ _fnGetCellData( settings, i, idx, 'sort' );
+
+ row._aSortData[ idx ] = formatter ?
+ formatter( cellData ) :
+ cellData;
+ }
+ }
+ }
+
+
+
+ /**
+ * Save the state of a table
+ * @param {object} oSettings dataTables settings object
+ * @memberof DataTable#oApi
+ */
+ function _fnSaveState ( settings )
+ {
+ if (settings._bLoadingState) {
+ return;
+ }
+
+ /* Store the interesting variables */
+ var state = {
+ time: +new Date(),
+ start: settings._iDisplayStart,
+ length: settings._iDisplayLength,
+ order: $.extend( true, [], settings.aaSorting ),
+ search: _fnSearchToCamel( settings.oPreviousSearch ),
+ columns: $.map( settings.aoColumns, function ( col, i ) {
+ return {
+ visible: col.bVisible,
+ search: _fnSearchToCamel( settings.aoPreSearchCols[i] )
+ };
+ } )
+ };
+
+ settings.oSavedState = state;
+ _fnCallbackFire( settings, "aoStateSaveParams", 'stateSaveParams', [settings, state] );
+
+ if ( settings.oFeatures.bStateSave && !settings.bDestroying )
+ {
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, state );
+ }
+ }
+
+
+ /**
+ * Attempt to load a saved table state
+ * @param {object} oSettings dataTables settings object
+ * @param {object} oInit DataTables init object so we can override settings
+ * @param {function} callback Callback to execute when the state has been loaded
+ * @memberof DataTable#oApi
+ */
+ function _fnLoadState ( settings, oInit, callback )
+ {
+ if ( ! settings.oFeatures.bStateSave ) {
+ callback();
+ return;
+ }
+
+ var loaded = function(state) {
+ _fnImplementState(settings, state, callback);
+ }
+
+ var state = settings.fnStateLoadCallback.call( settings.oInstance, settings, loaded );
+
+ if ( state !== undefined ) {
+ _fnImplementState( settings, state, callback );
+ }
+ // otherwise, wait for the loaded callback to be executed
+
+ return true;
+ }
+
+ function _fnImplementState ( settings, s, callback) {
+ var i, ien;
+ var columns = settings.aoColumns;
+ settings._bLoadingState = true;
+
+ // When StateRestore was introduced the state could now be implemented at any time
+ // Not just initialisation. To do this an api instance is required in some places
+ var api = settings._bInitComplete ? new DataTable.Api(settings) : null;
+
+ if ( ! s || ! s.time ) {
+ settings._bLoadingState = false;
+ callback();
+ return;
+ }
+
+ // Allow custom and plug-in manipulation functions to alter the saved data set and
+ // cancelling of loading by returning false
+ var abStateLoad = _fnCallbackFire( settings, 'aoStateLoadParams', 'stateLoadParams', [settings, s] );
+ if ( $.inArray( false, abStateLoad ) !== -1 ) {
+ settings._bLoadingState = false;
+ callback();
+ return;
+ }
+
+ // Reject old data
+ var duration = settings.iStateDuration;
+ if ( duration > 0 && s.time < +new Date() - (duration*1000) ) {
+ settings._bLoadingState = false;
+ callback();
+ return;
+ }
+
+ // Number of columns have changed - all bets are off, no restore of settings
+ if ( s.columns && columns.length !== s.columns.length ) {
+ settings._bLoadingState = false;
+ callback();
+ return;
+ }
+
+ // Store the saved state so it might be accessed at any time
+ settings.oLoadedState = $.extend( true, {}, s );
+
+ // Page Length
+ if ( s.length !== undefined ) {
+ // If already initialised just set the value directly so that the select element is also updated
+ if (api) {
+ api.page.len(s.length)
+ }
+ else {
+ settings._iDisplayLength = s.length;
+ }
+ }
+
+ // Restore key features - todo - for 1.11 this needs to be done by
+ // subscribed events
+ if ( s.start !== undefined ) {
+ if(api === null) {
+ settings._iDisplayStart = s.start;
+ settings.iInitDisplayStart = s.start;
+ }
+ else {
+ _fnPageChange(settings, s.start/settings._iDisplayLength);
+ }
+ }
+
+ // Order
+ if ( s.order !== undefined ) {
+ settings.aaSorting = [];
+ $.each( s.order, function ( i, col ) {
+ settings.aaSorting.push( col[0] >= columns.length ?
+ [ 0, col[1] ] :
+ col
+ );
+ } );
+ }
+
+ // Search
+ if ( s.search !== undefined ) {
+ $.extend( settings.oPreviousSearch, _fnSearchToHung( s.search ) );
+ }
+
+ // Columns
+ if ( s.columns ) {
+ for ( i=0, ien=s.columns.length ; i<ien ; i++ ) {
+ var col = s.columns[i];
+
+ // Visibility
+ if ( col.visible !== undefined ) {
+ // If the api is defined, the table has been initialised so we need to use it rather than internal settings
+ if (api) {
+ // Don't redraw the columns on every iteration of this loop, we will do this at the end instead
+ api.column(i).visible(col.visible, false);
+ }
+ else {
+ columns[i].bVisible = col.visible;
+ }
+ }
+
+ // Search
+ if ( col.search !== undefined ) {
+ $.extend( settings.aoPreSearchCols[i], _fnSearchToHung( col.search ) );
+ }
+ }
+
+ // If the api is defined then we need to adjust the columns once the visibility has been changed
+ if (api) {
+ api.columns.adjust();
+ }
+ }
+
+ settings._bLoadingState = false;
+ _fnCallbackFire( settings, 'aoStateLoaded', 'stateLoaded', [settings, s] );
+ callback();
+ };
+
+
+ /**
+ * Return the settings object for a particular table
+ * @param {node} table table we are using as a dataTable
+ * @returns {object} Settings object - or null if not found
+ * @memberof DataTable#oApi
+ */
+ function _fnSettingsFromNode ( table )
+ {
+ var settings = DataTable.settings;
+ var idx = $.inArray( table, _pluck( settings, 'nTable' ) );
+
+ return idx !== -1 ?
+ settings[ idx ] :
+ null;
+ }
+
+
+ /**
+ * Log an error message
+ * @param {object} settings dataTables settings object
+ * @param {int} level log error messages, or display them to the user
+ * @param {string} msg error message
+ * @param {int} tn Technical note id to get more information about the error.
+ * @memberof DataTable#oApi
+ */
+ function _fnLog( settings, level, msg, tn )
+ {
+ msg = 'DataTables warning: '+
+ (settings ? 'table id='+settings.sTableId+' - ' : '')+msg;
+
+ if ( tn ) {
+ msg += '. For more information about this error, please see '+
+ 'http://datatables.net/tn/'+tn;
+ }
+
+ if ( ! level ) {
+ // Backwards compatibility pre 1.10
+ var ext = DataTable.ext;
+ var type = ext.sErrMode || ext.errMode;
+
+ if ( settings ) {
+ _fnCallbackFire( settings, null, 'error', [ settings, tn, msg ] );
+ }
+
+ if ( type == 'alert' ) {
+ alert( msg );
+ }
+ else if ( type == 'throw' ) {
+ throw new Error(msg);
+ }
+ else if ( typeof type == 'function' ) {
+ type( settings, tn, msg );
+ }
+ }
+ else if ( window.console && console.log ) {
+ console.log( msg );
+ }
+ }
+
+
+ /**
+ * See if a property is defined on one object, if so assign it to the other object
+ * @param {object} ret target object
+ * @param {object} src source object
+ * @param {string} name property
+ * @param {string} [mappedName] name to map too - optional, name used if not given
+ * @memberof DataTable#oApi
+ */
+ function _fnMap( ret, src, name, mappedName )
+ {
+ if ( Array.isArray( name ) ) {
+ $.each( name, function (i, val) {
+ if ( Array.isArray( val ) ) {
+ _fnMap( ret, src, val[0], val[1] );
+ }
+ else {
+ _fnMap( ret, src, val );
+ }
+ } );
+
+ return;
+ }
+
+ if ( mappedName === undefined ) {
+ mappedName = name;
+ }
+
+ if ( src[name] !== undefined ) {
+ ret[mappedName] = src[name];
+ }
+ }
+
+
+ /**
+ * Extend objects - very similar to jQuery.extend, but deep copy objects, and
+ * shallow copy arrays. The reason we need to do this, is that we don't want to
+ * deep copy array init values (such as aaSorting) since the dev wouldn't be
+ * able to override them, but we do want to deep copy arrays.
+ * @param {object} out Object to extend
+ * @param {object} extender Object from which the properties will be applied to
+ * out
+ * @param {boolean} breakRefs If true, then arrays will be sliced to take an
+ * independent copy with the exception of the `data` or `aaData` parameters
+ * if they are present. This is so you can pass in a collection to
+ * DataTables and have that used as your data source without breaking the
+ * references
+ * @returns {object} out Reference, just for convenience - out === the return.
+ * @memberof DataTable#oApi
+ * @todo This doesn't take account of arrays inside the deep copied objects.
+ */
+ function _fnExtend( out, extender, breakRefs )
+ {
+ var val;
+
+ for ( var prop in extender ) {
+ if ( extender.hasOwnProperty(prop) ) {
+ val = extender[prop];
+
+ if ( $.isPlainObject( val ) ) {
+ if ( ! $.isPlainObject( out[prop] ) ) {
+ out[prop] = {};
+ }
+ $.extend( true, out[prop], val );
+ }
+ else if ( breakRefs && prop !== 'data' && prop !== 'aaData' && Array.isArray(val) ) {
+ out[prop] = val.slice();
+ }
+ else {
+ out[prop] = val;
+ }
+ }
+ }
+
+ return out;
+ }
+
+
+ /**
+ * Bind an event handers to allow a click or return key to activate the callback.
+ * This is good for accessibility since a return on the keyboard will have the
+ * same effect as a click, if the element has focus.
+ * @param {element} n Element to bind the action to
+ * @param {object} oData Data object to pass to the triggered function
+ * @param {function} fn Callback function for when the event is triggered
+ * @memberof DataTable#oApi
+ */
+ function _fnBindAction( n, oData, fn )
+ {
+ $(n)
+ .on( 'click.DT', oData, function (e) {
+ $(n).trigger('blur'); // Remove focus outline for mouse users
+ fn(e);
+ } )
+ .on( 'keypress.DT', oData, function (e){
+ if ( e.which === 13 ) {
+ e.preventDefault();
+ fn(e);
+ }
+ } )
+ .on( 'selectstart.DT', function () {
+ /* Take the brutal approach to cancelling text selection */
+ return false;
+ } );
+ }
+
+
+ /**
+ * Register a callback function. Easily allows a callback function to be added to
+ * an array store of callback functions that can then all be called together.
+ * @param {object} oSettings dataTables settings object
+ * @param {string} sStore Name of the array storage for the callbacks in oSettings
+ * @param {function} fn Function to be called back
+ * @param {string} sName Identifying name for the callback (i.e. a label)
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackReg( oSettings, sStore, fn, sName )
+ {
+ if ( fn )
+ {
+ oSettings[sStore].push( {
+ "fn": fn,
+ "sName": sName
+ } );
+ }
+ }
+
+
+ /**
+ * Fire callback functions and trigger events. Note that the loop over the
+ * callback array store is done backwards! Further note that you do not want to
+ * fire off triggers in time sensitive applications (for example cell creation)
+ * as its slow.
+ * @param {object} settings dataTables settings object
+ * @param {string} callbackArr Name of the array storage for the callbacks in
+ * oSettings
+ * @param {string} eventName Name of the jQuery custom event to trigger. If
+ * null no trigger is fired
+ * @param {array} args Array of arguments to pass to the callback function /
+ * trigger
+ * @memberof DataTable#oApi
+ */
+ function _fnCallbackFire( settings, callbackArr, eventName, args )
+ {
+ var ret = [];
+
+ if ( callbackArr ) {
+ ret = $.map( settings[callbackArr].slice().reverse(), function (val, i) {
+ return val.fn.apply( settings.oInstance, args );
+ } );
+ }
+
+ if ( eventName !== null ) {
+ var e = $.Event( eventName+'.dt' );
+
+ $(settings.nTable).trigger( e, args );
+
+ ret.push( e.result );
+ }
+
+ return ret;
+ }
+
+
+ function _fnLengthOverflow ( settings )
+ {
+ var
+ start = settings._iDisplayStart,
+ end = settings.fnDisplayEnd(),
+ len = settings._iDisplayLength;
+
+ /* If we have space to show extra rows (backing up from the end point - then do so */
+ if ( start >= end )
+ {
+ start = end - len;
+ }
+
+ // Keep the start record on the current page
+ start -= (start % len);
+
+ if ( len === -1 || start < 0 )
+ {
+ start = 0;
+ }
+
+ settings._iDisplayStart = start;
+ }
+
+
+ function _fnRenderer( settings, type )
+ {
+ var renderer = settings.renderer;
+ var host = DataTable.ext.renderer[type];
+
+ if ( $.isPlainObject( renderer ) && renderer[type] ) {
+ // Specific renderer for this type. If available use it, otherwise use
+ // the default.
+ return host[renderer[type]] || host._;
+ }
+ else if ( typeof renderer === 'string' ) {
+ // Common renderer - if there is one available for this type use it,
+ // otherwise use the default
+ return host[renderer] || host._;
+ }
+
+ // Use the default
+ return host._;
+ }
+
+
+ /**
+ * Detect the data source being used for the table. Used to simplify the code
+ * a little (ajax) and to make it compress a little smaller.
+ *
+ * @param {object} settings dataTables settings object
+ * @returns {string} Data source
+ * @memberof DataTable#oApi
+ */
+ function _fnDataSource ( settings )
+ {
+ if ( settings.oFeatures.bServerSide ) {
+ return 'ssp';
+ }
+ else if ( settings.ajax || settings.sAjaxSource ) {
+ return 'ajax';
+ }
+ return 'dom';
+ }
+
+
+
+
+ /**
+ * Computed structure of the DataTables API, defined by the options passed to
+ * `DataTable.Api.register()` when building the API.
+ *
+ * The structure is built in order to speed creation and extension of the Api
+ * objects since the extensions are effectively pre-parsed.
+ *
+ * The array is an array of objects with the following structure, where this
+ * base array represents the Api prototype base:
+ *
+ * [
+ * {
+ * name: 'data' -- string - Property name
+ * val: function () {}, -- function - Api method (or undefined if just an object
+ * methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
+ * propExt: [ ... ] -- array - Array of Api object definitions to extend the property
+ * },
+ * {
+ * name: 'row'
+ * val: {},
+ * methodExt: [ ... ],
+ * propExt: [
+ * {
+ * name: 'data'
+ * val: function () {},
+ * methodExt: [ ... ],
+ * propExt: [ ... ]
+ * },
+ * ...
+ * ]
+ * }
+ * ]
+ *
+ * @type {Array}
+ * @ignore
+ */
+ var __apiStruct = [];
+
+
+ /**
+ * `Array.prototype` reference.
+ *
+ * @type object
+ * @ignore
+ */
+ var __arrayProto = Array.prototype;
+
+
+ /**
+ * Abstraction for `context` parameter of the `Api` constructor to allow it to
+ * take several different forms for ease of use.
+ *
+ * Each of the input parameter types will be converted to a DataTables settings
+ * object where possible.
+ *
+ * @param {string|node|jQuery|object} mixed DataTable identifier. Can be one
+ * of:
+ *
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
+ * with be found and used.
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
+ * * `object` - DataTables settings object
+ * * `DataTables.Api` - API instance
+ * @return {array|null} Matching DataTables settings objects. `null` or
+ * `undefined` is returned if no matching DataTable is found.
+ * @ignore
+ */
+ var _toSettings = function ( mixed )
+ {
+ var idx, jq;
+ var settings = DataTable.settings;
+ var tables = $.map( settings, function (el, i) {
+ return el.nTable;
+ } );
+
+ if ( ! mixed ) {
+ return [];
+ }
+ else if ( mixed.nTable && mixed.oApi ) {
+ // DataTables settings object
+ return [ mixed ];
+ }
+ else if ( mixed.nodeName && mixed.nodeName.toLowerCase() === 'table' ) {
+ // Table node
+ idx = $.inArray( mixed, tables );
+ return idx !== -1 ? [ settings[idx] ] : null;
+ }
+ else if ( mixed && typeof mixed.settings === 'function' ) {
+ return mixed.settings().toArray();
+ }
+ else if ( typeof mixed === 'string' ) {
+ // jQuery selector
+ jq = $(mixed);
+ }
+ else if ( mixed instanceof $ ) {
+ // jQuery object (also DataTables instance)
+ jq = mixed;
+ }
+
+ if ( jq ) {
+ return jq.map( function(i) {
+ idx = $.inArray( this, tables );
+ return idx !== -1 ? settings[idx] : null;
+ } ).toArray();
+ }
+ };
+
+
+ /**
+ * DataTables API class - used to control and interface with one or more
+ * DataTables enhanced tables.
+ *
+ * The API class is heavily based on jQuery, presenting a chainable interface
+ * that you can use to interact with tables. Each instance of the API class has
+ * a "context" - i.e. the tables that it will operate on. This could be a single
+ * table, all tables on a page or a sub-set thereof.
+ *
+ * Additionally the API is designed to allow you to easily work with the data in
+ * the tables, retrieving and manipulating it as required. This is done by
+ * presenting the API class as an array like interface. The contents of the
+ * array depend upon the actions requested by each method (for example
+ * `rows().nodes()` will return an array of nodes, while `rows().data()` will
+ * return an array of objects or arrays depending upon your table's
+ * configuration). The API object has a number of array like methods (`push`,
+ * `pop`, `reverse` etc) as well as additional helper methods (`each`, `pluck`,
+ * `unique` etc) to assist your working with the data held in a table.
+ *
+ * Most methods (those which return an Api instance) are chainable, which means
+ * the return from a method call also has all of the methods available that the
+ * top level object had. For example, these two calls are equivalent:
+ *
+ * // Not chained
+ * api.row.add( {...} );
+ * api.draw();
+ *
+ * // Chained
+ * api.row.add( {...} ).draw();
+ *
+ * @class DataTable.Api
+ * @param {array|object|string|jQuery} context DataTable identifier. This is
+ * used to define which DataTables enhanced tables this API will operate on.
+ * Can be one of:
+ *
+ * * `string` - jQuery selector. Any DataTables' matching the given selector
+ * with be found and used.
+ * * `node` - `TABLE` node which has already been formed into a DataTable.
+ * * `jQuery` - A jQuery object of `TABLE` nodes.
+ * * `object` - DataTables settings object
+ * @param {array} [data] Data to initialise the Api instance with.
+ *
+ * @example
+ * // Direct initialisation during DataTables construction
+ * var api = $('#example').DataTable();
+ *
+ * @example
+ * // Initialisation using a DataTables jQuery object
+ * var api = $('#example').dataTable().api();
+ *
+ * @example
+ * // Initialisation as a constructor
+ * var api = new $.fn.DataTable.Api( 'table.dataTable' );
+ */
+ _Api = function ( context, data )
+ {
+ if ( ! (this instanceof _Api) ) {
+ return new _Api( context, data );
+ }
+
+ var settings = [];
+ var ctxSettings = function ( o ) {
+ var a = _toSettings( o );
+ if ( a ) {
+ settings.push.apply( settings, a );
+ }
+ };
+
+ if ( Array.isArray( context ) ) {
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
+ ctxSettings( context[i] );
+ }
+ }
+ else {
+ ctxSettings( context );
+ }
+
+ // Remove duplicates
+ this.context = _unique( settings );
+
+ // Initial data
+ if ( data ) {
+ $.merge( this, data );
+ }
+
+ // selector
+ this.selector = {
+ rows: null,
+ cols: null,
+ opts: null
+ };
+
+ _Api.extend( this, this, __apiStruct );
+ };
+
+ DataTable.Api = _Api;
+
+ // Don't destroy the existing prototype, just extend it. Required for jQuery 2's
+ // isPlainObject.
+ $.extend( _Api.prototype, {
+ any: function ()
+ {
+ return this.count() !== 0;
+ },
+
+
+ concat: __arrayProto.concat,
+
+
+ context: [], // array of table settings objects
+
+
+ count: function ()
+ {
+ return this.flatten().length;
+ },
+
+
+ each: function ( fn )
+ {
+ for ( var i=0, ien=this.length ; i<ien; i++ ) {
+ fn.call( this, this[i], i, this );
+ }
+
+ return this;
+ },
+
+
+ eq: function ( idx )
+ {
+ var ctx = this.context;
+
+ return ctx.length > idx ?
+ new _Api( ctx[idx], this[idx] ) :
+ null;
+ },
+
+
+ filter: function ( fn )
+ {
+ var a = [];
+
+ if ( __arrayProto.filter ) {
+ a = __arrayProto.filter.call( this, fn, this );
+ }
+ else {
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
+ if ( fn.call( this, this[i], i, this ) ) {
+ a.push( this[i] );
+ }
+ }
+ }
+
+ return new _Api( this.context, a );
+ },
+
+
+ flatten: function ()
+ {
+ var a = [];
+ return new _Api( this.context, a.concat.apply( a, this.toArray() ) );
+ },
+
+
+ join: __arrayProto.join,
+
+
+ indexOf: __arrayProto.indexOf || function (obj, start)
+ {
+ for ( var i=(start || 0), ien=this.length ; i<ien ; i++ ) {
+ if ( this[i] === obj ) {
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ iterator: function ( flatten, type, fn, alwaysNew ) {
+ var
+ a = [], ret,
+ i, ien, j, jen,
+ context = this.context,
+ rows, items, item,
+ selector = this.selector;
+
+ // Argument shifting
+ if ( typeof flatten === 'string' ) {
+ alwaysNew = fn;
+ fn = type;
+ type = flatten;
+ flatten = false;
+ }
+
+ for ( i=0, ien=context.length ; i<ien ; i++ ) {
+ var apiInst = new _Api( context[i] );
+
+ if ( type === 'table' ) {
+ ret = fn.call( apiInst, context[i], i );
+
+ if ( ret !== undefined ) {
+ a.push( ret );
+ }
+ }
+ else if ( type === 'columns' || type === 'rows' ) {
+ // this has same length as context - one entry for each table
+ ret = fn.call( apiInst, context[i], this[i], i );
+
+ if ( ret !== undefined ) {
+ a.push( ret );
+ }
+ }
+ else if ( type === 'column' || type === 'column-rows' || type === 'row' || type === 'cell' ) {
+ // columns and rows share the same structure.
+ // 'this' is an array of column indexes for each context
+ items = this[i];
+
+ if ( type === 'column-rows' ) {
+ rows = _selector_row_indexes( context[i], selector.opts );
+ }
+
+ for ( j=0, jen=items.length ; j<jen ; j++ ) {
+ item = items[j];
+
+ if ( type === 'cell' ) {
+ ret = fn.call( apiInst, context[i], item.row, item.column, i, j );
+ }
+ else {
+ ret = fn.call( apiInst, context[i], item, i, j, rows );
+ }
+
+ if ( ret !== undefined ) {
+ a.push( ret );
+ }
+ }
+ }
+ }
+
+ if ( a.length || alwaysNew ) {
+ var api = new _Api( context, flatten ? a.concat.apply( [], a ) : a );
+ var apiSelector = api.selector;
+ apiSelector.rows = selector.rows;
+ apiSelector.cols = selector.cols;
+ apiSelector.opts = selector.opts;
+ return api;
+ }
+ return this;
+ },
+
+
+ lastIndexOf: __arrayProto.lastIndexOf || function (obj, start)
+ {
+ // Bit cheeky...
+ return this.indexOf.apply( this.toArray.reverse(), arguments );
+ },
+
+
+ length: 0,
+
+
+ map: function ( fn )
+ {
+ var a = [];
+
+ if ( __arrayProto.map ) {
+ a = __arrayProto.map.call( this, fn, this );
+ }
+ else {
+ // Compatibility for browsers without EMCA-252-5 (JS 1.6)
+ for ( var i=0, ien=this.length ; i<ien ; i++ ) {
+ a.push( fn.call( this, this[i], i ) );
+ }
+ }
+
+ return new _Api( this.context, a );
+ },
+
+
+ pluck: function ( prop )
+ {
+ let fn = DataTable.util.get(prop);
+
+ return this.map( function ( el ) {
+ return fn(el);
+ } );
+ },
+
+ pop: __arrayProto.pop,
+
+
+ push: __arrayProto.push,
+
+
+ // Does not return an API instance
+ reduce: __arrayProto.reduce || function ( fn, init )
+ {
+ return _fnReduce( this, fn, init, 0, this.length, 1 );
+ },
+
+
+ reduceRight: __arrayProto.reduceRight || function ( fn, init )
+ {
+ return _fnReduce( this, fn, init, this.length-1, -1, -1 );
+ },
+
+
+ reverse: __arrayProto.reverse,
+
+
+ // Object with rows, columns and opts
+ selector: null,
+
+
+ shift: __arrayProto.shift,
+
+
+ slice: function () {
+ return new _Api( this.context, this );
+ },
+
+
+ sort: __arrayProto.sort, // ? name - order?
+
+
+ splice: __arrayProto.splice,
+
+
+ toArray: function ()
+ {
+ return __arrayProto.slice.call( this );
+ },
+
+
+ to$: function ()
+ {
+ return $( this );
+ },
+
+
+ toJQuery: function ()
+ {
+ return $( this );
+ },
+
+
+ unique: function ()
+ {
+ return new _Api( this.context, _unique(this) );
+ },
+
+
+ unshift: __arrayProto.unshift
+ } );
+
+
+ _Api.extend = function ( scope, obj, ext )
+ {
+ // Only extend API instances and static properties of the API
+ if ( ! ext.length || ! obj || ( ! (obj instanceof _Api) && ! obj.__dt_wrapper ) ) {
+ return;
+ }
+
+ var
+ i, ien,
+ struct,
+ methodScoping = function ( scope, fn, struc ) {
+ return function () {
+ var ret = fn.apply( scope, arguments );
+
+ // Method extension
+ _Api.extend( ret, ret, struc.methodExt );
+ return ret;
+ };
+ };
+
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
+ struct = ext[i];
+
+ // Value
+ obj[ struct.name ] = struct.type === 'function' ?
+ methodScoping( scope, struct.val, struct ) :
+ struct.type === 'object' ?
+ {} :
+ struct.val;
+
+ obj[ struct.name ].__dt_wrapper = true;
+
+ // Property extension
+ _Api.extend( scope, obj[ struct.name ], struct.propExt );
+ }
+ };
+
+
+ // @todo - Is there need for an augment function?
+ // _Api.augment = function ( inst, name )
+ // {
+ // // Find src object in the structure from the name
+ // var parts = name.split('.');
+
+ // _Api.extend( inst, obj );
+ // };
+
+
+ // [
+ // {
+ // name: 'data' -- string - Property name
+ // val: function () {}, -- function - Api method (or undefined if just an object
+ // methodExt: [ ... ], -- array - Array of Api object definitions to extend the method result
+ // propExt: [ ... ] -- array - Array of Api object definitions to extend the property
+ // },
+ // {
+ // name: 'row'
+ // val: {},
+ // methodExt: [ ... ],
+ // propExt: [
+ // {
+ // name: 'data'
+ // val: function () {},
+ // methodExt: [ ... ],
+ // propExt: [ ... ]
+ // },
+ // ...
+ // ]
+ // }
+ // ]
+
+ _Api.register = _api_register = function ( name, val )
+ {
+ if ( Array.isArray( name ) ) {
+ for ( var j=0, jen=name.length ; j<jen ; j++ ) {
+ _Api.register( name[j], val );
+ }
+ return;
+ }
+
+ var
+ i, ien,
+ heir = name.split('.'),
+ struct = __apiStruct,
+ key, method;
+
+ var find = function ( src, name ) {
+ for ( var i=0, ien=src.length ; i<ien ; i++ ) {
+ if ( src[i].name === name ) {
+ return src[i];
+ }
+ }
+ return null;
+ };
+
+ for ( i=0, ien=heir.length ; i<ien ; i++ ) {
+ method = heir[i].indexOf('()') !== -1;
+ key = method ?
+ heir[i].replace('()', '') :
+ heir[i];
+
+ var src = find( struct, key );
+ if ( ! src ) {
+ src = {
+ name: key,
+ val: {},
+ methodExt: [],
+ propExt: [],
+ type: 'object'
+ };
+ struct.push( src );
+ }
+
+ if ( i === ien-1 ) {
+ src.val = val;
+ src.type = typeof val === 'function' ?
+ 'function' :
+ $.isPlainObject( val ) ?
+ 'object' :
+ 'other';
+ }
+ else {
+ struct = method ?
+ src.methodExt :
+ src.propExt;
+ }
+ }
+ };
+
+ _Api.registerPlural = _api_registerPlural = function ( pluralName, singularName, val ) {
+ _Api.register( pluralName, val );
+
+ _Api.register( singularName, function () {
+ var ret = val.apply( this, arguments );
+
+ if ( ret === this ) {
+ // Returned item is the API instance that was passed in, return it
+ return this;
+ }
+ else if ( ret instanceof _Api ) {
+ // New API instance returned, want the value from the first item
+ // in the returned array for the singular result.
+ return ret.length ?
+ Array.isArray( ret[0] ) ?
+ new _Api( ret.context, ret[0] ) : // Array results are 'enhanced'
+ ret[0] :
+ undefined;
+ }
+
+ // Non-API return - just fire it back
+ return ret;
+ } );
+ };
+
+
+ /**
+ * Selector for HTML tables. Apply the given selector to the give array of
+ * DataTables settings objects.
+ *
+ * @param {string|integer} [selector] jQuery selector string or integer
+ * @param {array} Array of DataTables settings objects to be filtered
+ * @return {array}
+ * @ignore
+ */
+ var __table_selector = function ( selector, a )
+ {
+ if ( Array.isArray(selector) ) {
+ return $.map( selector, function (item) {
+ return __table_selector(item, a);
+ } );
+ }
+
+ // Integer is used to pick out a table by index
+ if ( typeof selector === 'number' ) {
+ return [ a[ selector ] ];
+ }
+
+ // Perform a jQuery selector on the table nodes
+ var nodes = $.map( a, function (el, i) {
+ return el.nTable;
+ } );
+
+ return $(nodes)
+ .filter( selector )
+ .map( function (i) {
+ // Need to translate back from the table node to the settings
+ var idx = $.inArray( this, nodes );
+ return a[ idx ];
+ } )
+ .toArray();
+ };
+
+
+
+ /**
+ * Context selector for the API's context (i.e. the tables the API instance
+ * refers to.
+ *
+ * @name DataTable.Api#tables
+ * @param {string|integer} [selector] Selector to pick which tables the iterator
+ * should operate on. If not given, all tables in the current context are
+ * used. This can be given as a jQuery selector (for example `':gt(0)'`) to
+ * select multiple tables or as an integer to select a single table.
+ * @returns {DataTable.Api} Returns a new API instance if a selector is given.
+ */
+ _api_register( 'tables()', function ( selector ) {
+ // A new instance is created if there was a selector specified
+ return selector !== undefined && selector !== null ?
+ new _Api( __table_selector( selector, this.context ) ) :
+ this;
+ } );
+
+
+ _api_register( 'table()', function ( selector ) {
+ var tables = this.tables( selector );
+ var ctx = tables.context;
+
+ // Truncate to the first matched table
+ return ctx.length ?
+ new _Api( ctx[0] ) :
+ tables;
+ } );
+
+
+ _api_registerPlural( 'tables().nodes()', 'table().node()' , function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx.nTable;
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'tables().body()', 'table().body()' , function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx.nTBody;
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'tables().header()', 'table().header()' , function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx.nTHead;
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'tables().footer()', 'table().footer()' , function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx.nTFoot;
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'tables().containers()', 'table().container()' , function () {
+ return this.iterator( 'table', function ( ctx ) {
+ return ctx.nTableWrapper;
+ }, 1 );
+ } );
+
+
+
+ /**
+ * Redraw the tables in the current context.
+ */
+ _api_register( 'draw()', function ( paging ) {
+ return this.iterator( 'table', function ( settings ) {
+ if ( paging === 'page' ) {
+ _fnDraw( settings );
+ }
+ else {
+ if ( typeof paging === 'string' ) {
+ paging = paging === 'full-hold' ?
+ false :
+ true;
+ }
+
+ _fnReDraw( settings, paging===false );
+ }
+ } );
+ } );
+
+
+
+ /**
+ * Get the current page index.
+ *
+ * @return {integer} Current page index (zero based)
+ *//**
+ * Set the current page.
+ *
+ * Note that if you attempt to show a page which does not exist, DataTables will
+ * not throw an error, but rather reset the paging.
+ *
+ * @param {integer|string} action The paging action to take. This can be one of:
+ * * `integer` - The page index to jump to
+ * * `string` - An action to take:
+ * * `first` - Jump to first page.
+ * * `next` - Jump to the next page
+ * * `previous` - Jump to previous page
+ * * `last` - Jump to the last page.
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'page()', function ( action ) {
+ if ( action === undefined ) {
+ return this.page.info().page; // not an expensive call
+ }
+
+ // else, have an action to take on all tables
+ return this.iterator( 'table', function ( settings ) {
+ _fnPageChange( settings, action );
+ } );
+ } );
+
+
+ /**
+ * Paging information for the first table in the current context.
+ *
+ * If you require paging information for another table, use the `table()` method
+ * with a suitable selector.
+ *
+ * @return {object} Object with the following properties set:
+ * * `page` - Current page index (zero based - i.e. the first page is `0`)
+ * * `pages` - Total number of pages
+ * * `start` - Display index for the first record shown on the current page
+ * * `end` - Display index for the last record shown on the current page
+ * * `length` - Display length (number of records). Note that generally `start
+ * + length = end`, but this is not always true, for example if there are
+ * only 2 records to show on the final page, with a length of 10.
+ * * `recordsTotal` - Full data set length
+ * * `recordsDisplay` - Data set length once the current filtering criterion
+ * are applied.
+ */
+ _api_register( 'page.info()', function ( action ) {
+ if ( this.context.length === 0 ) {
+ return undefined;
+ }
+
+ var
+ settings = this.context[0],
+ start = settings._iDisplayStart,
+ len = settings.oFeatures.bPaginate ? settings._iDisplayLength : -1,
+ visRecords = settings.fnRecordsDisplay(),
+ all = len === -1;
+
+ return {
+ "page": all ? 0 : Math.floor( start / len ),
+ "pages": all ? 1 : Math.ceil( visRecords / len ),
+ "start": start,
+ "end": settings.fnDisplayEnd(),
+ "length": len,
+ "recordsTotal": settings.fnRecordsTotal(),
+ "recordsDisplay": visRecords,
+ "serverSide": _fnDataSource( settings ) === 'ssp'
+ };
+ } );
+
+
+ /**
+ * Get the current page length.
+ *
+ * @return {integer} Current page length. Note `-1` indicates that all records
+ * are to be shown.
+ *//**
+ * Set the current page length.
+ *
+ * @param {integer} Page length to set. Use `-1` to show all records.
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'page.len()', function ( len ) {
+ // Note that we can't call this function 'length()' because `length`
+ // is a Javascript property of functions which defines how many arguments
+ // the function expects.
+ if ( len === undefined ) {
+ return this.context.length !== 0 ?
+ this.context[0]._iDisplayLength :
+ undefined;
+ }
+
+ // else, set the page length
+ return this.iterator( 'table', function ( settings ) {
+ _fnLengthChange( settings, len );
+ } );
+ } );
+
+
+
+ var __reload = function ( settings, holdPosition, callback ) {
+ // Use the draw event to trigger a callback
+ if ( callback ) {
+ var api = new _Api( settings );
+
+ api.one( 'draw', function () {
+ callback( api.ajax.json() );
+ } );
+ }
+
+ if ( _fnDataSource( settings ) == 'ssp' ) {
+ _fnReDraw( settings, holdPosition );
+ }
+ else {
+ _fnProcessingDisplay( settings, true );
+
+ // Cancel an existing request
+ var xhr = settings.jqXHR;
+ if ( xhr && xhr.readyState !== 4 ) {
+ xhr.abort();
+ }
+
+ // Trigger xhr
+ _fnBuildAjax( settings, [], function( json ) {
+ _fnClearTable( settings );
+
+ var data = _fnAjaxDataSrc( settings, json );
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+ _fnAddData( settings, data[i] );
+ }
+
+ _fnReDraw( settings, holdPosition );
+ _fnProcessingDisplay( settings, false );
+ } );
+ }
+ };
+
+
+ /**
+ * Get the JSON response from the last Ajax request that DataTables made to the
+ * server. Note that this returns the JSON from the first table in the current
+ * context.
+ *
+ * @return {object} JSON received from the server.
+ */
+ _api_register( 'ajax.json()', function () {
+ var ctx = this.context;
+
+ if ( ctx.length > 0 ) {
+ return ctx[0].json;
+ }
+
+ // else return undefined;
+ } );
+
+
+ /**
+ * Get the data submitted in the last Ajax request
+ */
+ _api_register( 'ajax.params()', function () {
+ var ctx = this.context;
+
+ if ( ctx.length > 0 ) {
+ return ctx[0].oAjaxData;
+ }
+
+ // else return undefined;
+ } );
+
+
+ /**
+ * Reload tables from the Ajax data source. Note that this function will
+ * automatically re-draw the table when the remote data has been loaded.
+ *
+ * @param {boolean} [reset=true] Reset (default) or hold the current paging
+ * position. A full re-sort and re-filter is performed when this method is
+ * called, which is why the pagination reset is the default action.
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'ajax.reload()', function ( callback, resetPaging ) {
+ return this.iterator( 'table', function (settings) {
+ __reload( settings, resetPaging===false, callback );
+ } );
+ } );
+
+
+ /**
+ * Get the current Ajax URL. Note that this returns the URL from the first
+ * table in the current context.
+ *
+ * @return {string} Current Ajax source URL
+ *//**
+ * Set the Ajax URL. Note that this will set the URL for all tables in the
+ * current context.
+ *
+ * @param {string} url URL to set.
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'ajax.url()', function ( url ) {
+ var ctx = this.context;
+
+ if ( url === undefined ) {
+ // get
+ if ( ctx.length === 0 ) {
+ return undefined;
+ }
+ ctx = ctx[0];
+
+ return ctx.ajax ?
+ $.isPlainObject( ctx.ajax ) ?
+ ctx.ajax.url :
+ ctx.ajax :
+ ctx.sAjaxSource;
+ }
+
+ // set
+ return this.iterator( 'table', function ( settings ) {
+ if ( $.isPlainObject( settings.ajax ) ) {
+ settings.ajax.url = url;
+ }
+ else {
+ settings.ajax = url;
+ }
+ // No need to consider sAjaxSource here since DataTables gives priority
+ // to `ajax` over `sAjaxSource`. So setting `ajax` here, renders any
+ // value of `sAjaxSource` redundant.
+ } );
+ } );
+
+
+ /**
+ * Load data from the newly set Ajax URL. Note that this method is only
+ * available when `ajax.url()` is used to set a URL. Additionally, this method
+ * has the same effect as calling `ajax.reload()` but is provided for
+ * convenience when setting a new URL. Like `ajax.reload()` it will
+ * automatically redraw the table once the remote data has been loaded.
+ *
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'ajax.url().load()', function ( callback, resetPaging ) {
+ // Same as a reload, but makes sense to present it for easy access after a
+ // url change
+ return this.iterator( 'table', function ( ctx ) {
+ __reload( ctx, resetPaging===false, callback );
+ } );
+ } );
+
+
+
+
+ var _selector_run = function ( type, selector, selectFn, settings, opts )
+ {
+ var
+ out = [], res,
+ a, i, ien, j, jen,
+ selectorType = typeof selector;
+
+ // Can't just check for isArray here, as an API or jQuery instance might be
+ // given with their array like look
+ if ( ! selector || selectorType === 'string' || selectorType === 'function' || selector.length === undefined ) {
+ selector = [ selector ];
+ }
+
+ for ( i=0, ien=selector.length ; i<ien ; i++ ) {
+ // Only split on simple strings - complex expressions will be jQuery selectors
+ a = selector[i] && selector[i].split && ! selector[i].match(/[\[\(:]/) ?
+ selector[i].split(',') :
+ [ selector[i] ];
+
+ for ( j=0, jen=a.length ; j<jen ; j++ ) {
+ res = selectFn( typeof a[j] === 'string' ? (a[j]).trim() : a[j] );
+
+ if ( res && res.length ) {
+ out = out.concat( res );
+ }
+ }
+ }
+
+ // selector extensions
+ var ext = _ext.selector[ type ];
+ if ( ext.length ) {
+ for ( i=0, ien=ext.length ; i<ien ; i++ ) {
+ out = ext[i]( settings, opts, out );
+ }
+ }
+
+ return _unique( out );
+ };
+
+
+ var _selector_opts = function ( opts )
+ {
+ if ( ! opts ) {
+ opts = {};
+ }
+
+ // Backwards compatibility for 1.9- which used the terminology filter rather
+ // than search
+ if ( opts.filter && opts.search === undefined ) {
+ opts.search = opts.filter;
+ }
+
+ return $.extend( {
+ search: 'none',
+ order: 'current',
+ page: 'all'
+ }, opts );
+ };
+
+
+ var _selector_first = function ( inst )
+ {
+ // Reduce the API instance to the first item found
+ for ( var i=0, ien=inst.length ; i<ien ; i++ ) {
+ if ( inst[i].length > 0 ) {
+ // Assign the first element to the first item in the instance
+ // and truncate the instance and context
+ inst[0] = inst[i];
+ inst[0].length = 1;
+ inst.length = 1;
+ inst.context = [ inst.context[i] ];
+
+ return inst;
+ }
+ }
+
+ // Not found - return an empty instance
+ inst.length = 0;
+ return inst;
+ };
+
+
+ var _selector_row_indexes = function ( settings, opts )
+ {
+ var
+ i, ien, tmp, a=[],
+ displayFiltered = settings.aiDisplay,
+ displayMaster = settings.aiDisplayMaster;
+
+ var
+ search = opts.search, // none, applied, removed
+ order = opts.order, // applied, current, index (original - compatibility with 1.9)
+ page = opts.page; // all, current
+
+ if ( _fnDataSource( settings ) == 'ssp' ) {
+ // In server-side processing mode, most options are irrelevant since
+ // rows not shown don't exist and the index order is the applied order
+ // Removed is a special case - for consistency just return an empty
+ // array
+ return search === 'removed' ?
+ [] :
+ _range( 0, displayMaster.length );
+ }
+ else if ( page == 'current' ) {
+ // Current page implies that order=current and filter=applied, since it is
+ // fairly senseless otherwise, regardless of what order and search actually
+ // are
+ for ( i=settings._iDisplayStart, ien=settings.fnDisplayEnd() ; i<ien ; i++ ) {
+ a.push( displayFiltered[i] );
+ }
+ }
+ else if ( order == 'current' || order == 'applied' ) {
+ if ( search == 'none') {
+ a = displayMaster.slice();
+ }
+ else if ( search == 'applied' ) {
+ a = displayFiltered.slice();
+ }
+ else if ( search == 'removed' ) {
+ // O(n+m) solution by creating a hash map
+ var displayFilteredMap = {};
+
+ for ( var i=0, ien=displayFiltered.length ; i<ien ; i++ ) {
+ displayFilteredMap[displayFiltered[i]] = null;
+ }
+
+ a = $.map( displayMaster, function (el) {
+ return ! displayFilteredMap.hasOwnProperty(el) ?
+ el :
+ null;
+ } );
+ }
+ }
+ else if ( order == 'index' || order == 'original' ) {
+ for ( i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ if ( search == 'none' ) {
+ a.push( i );
+ }
+ else { // applied | removed
+ tmp = $.inArray( i, displayFiltered );
+
+ if ((tmp === -1 && search == 'removed') ||
+ (tmp >= 0 && search == 'applied') )
+ {
+ a.push( i );
+ }
+ }
+ }
+ }
+
+ return a;
+ };
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Rows
+ *
+ * {} - no selector - use all available rows
+ * {integer} - row aoData index
+ * {node} - TR node
+ * {string} - jQuery selector to apply to the TR elements
+ * {array} - jQuery array of nodes, or simply an array of TR nodes
+ *
+ */
+ var __row_selector = function ( settings, selector, opts )
+ {
+ var rows;
+ var run = function ( sel ) {
+ var selInt = _intVal( sel );
+ var i, ien;
+ var aoData = settings.aoData;
+
+ // Short cut - selector is a number and no options provided (default is
+ // all records, so no need to check if the index is in there, since it
+ // must be - dev error if the index doesn't exist).
+ if ( selInt !== null && ! opts ) {
+ return [ selInt ];
+ }
+
+ if ( ! rows ) {
+ rows = _selector_row_indexes( settings, opts );
+ }
+
+ if ( selInt !== null && $.inArray( selInt, rows ) !== -1 ) {
+ // Selector - integer
+ return [ selInt ];
+ }
+ else if ( sel === null || sel === undefined || sel === '' ) {
+ // Selector - none
+ return rows;
+ }
+
+ // Selector - function
+ if ( typeof sel === 'function' ) {
+ return $.map( rows, function (idx) {
+ var row = aoData[ idx ];
+ return sel( idx, row._aData, row.nTr ) ? idx : null;
+ } );
+ }
+
+ // Selector - node
+ if ( sel.nodeName ) {
+ var rowIdx = sel._DT_RowIndex; // Property added by DT for fast lookup
+ var cellIdx = sel._DT_CellIndex;
+
+ if ( rowIdx !== undefined ) {
+ // Make sure that the row is actually still present in the table
+ return aoData[ rowIdx ] && aoData[ rowIdx ].nTr === sel ?
+ [ rowIdx ] :
+ [];
+ }
+ else if ( cellIdx ) {
+ return aoData[ cellIdx.row ] && aoData[ cellIdx.row ].nTr === sel.parentNode ?
+ [ cellIdx.row ] :
+ [];
+ }
+ else {
+ var host = $(sel).closest('*[data-dt-row]');
+ return host.length ?
+ [ host.data('dt-row') ] :
+ [];
+ }
+ }
+
+ // ID selector. Want to always be able to select rows by id, regardless
+ // of if the tr element has been created or not, so can't rely upon
+ // jQuery here - hence a custom implementation. This does not match
+ // Sizzle's fast selector or HTML4 - in HTML5 the ID can be anything,
+ // but to select it using a CSS selector engine (like Sizzle or
+ // querySelect) it would need to need to be escaped for some characters.
+ // DataTables simplifies this for row selectors since you can select
+ // only a row. A # indicates an id any anything that follows is the id -
+ // unescaped.
+ if ( typeof sel === 'string' && sel.charAt(0) === '#' ) {
+ // get row index from id
+ var rowObj = settings.aIds[ sel.replace( /^#/, '' ) ];
+ if ( rowObj !== undefined ) {
+ return [ rowObj.idx ];
+ }
+
+ // need to fall through to jQuery in case there is DOM id that
+ // matches
+ }
+
+ // Get nodes in the order from the `rows` array with null values removed
+ var nodes = _removeEmpty(
+ _pluck_order( settings.aoData, rows, 'nTr' )
+ );
+
+ // Selector - jQuery selector string, array of nodes or jQuery object/
+ // As jQuery's .filter() allows jQuery objects to be passed in filter,
+ // it also allows arrays, so this will cope with all three options
+ return $(nodes)
+ .filter( sel )
+ .map( function () {
+ return this._DT_RowIndex;
+ } )
+ .toArray();
+ };
+
+ return _selector_run( 'row', selector, run, settings, opts );
+ };
+
+
+ _api_register( 'rows()', function ( selector, opts ) {
+ // argument shifting
+ if ( selector === undefined ) {
+ selector = '';
+ }
+ else if ( $.isPlainObject( selector ) ) {
+ opts = selector;
+ selector = '';
+ }
+
+ opts = _selector_opts( opts );
+
+ var inst = this.iterator( 'table', function ( settings ) {
+ return __row_selector( settings, selector, opts );
+ }, 1 );
+
+ // Want argument shifting here and in __row_selector?
+ inst.selector.rows = selector;
+ inst.selector.opts = opts;
+
+ return inst;
+ } );
+
+ _api_register( 'rows().nodes()', function () {
+ return this.iterator( 'row', function ( settings, row ) {
+ return settings.aoData[ row ].nTr || undefined;
+ }, 1 );
+ } );
+
+ _api_register( 'rows().data()', function () {
+ return this.iterator( true, 'rows', function ( settings, rows ) {
+ return _pluck_order( settings.aoData, rows, '_aData' );
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'rows().cache()', 'row().cache()', function ( type ) {
+ return this.iterator( 'row', function ( settings, row ) {
+ var r = settings.aoData[ row ];
+ return type === 'search' ? r._aFilterData : r._aSortData;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'rows().invalidate()', 'row().invalidate()', function ( src ) {
+ return this.iterator( 'row', function ( settings, row ) {
+ _fnInvalidate( settings, row, src );
+ } );
+ } );
+
+ _api_registerPlural( 'rows().indexes()', 'row().index()', function () {
+ return this.iterator( 'row', function ( settings, row ) {
+ return row;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'rows().ids()', 'row().id()', function ( hash ) {
+ var a = [];
+ var context = this.context;
+
+ // `iterator` will drop undefined values, but in this case we want them
+ for ( var i=0, ien=context.length ; i<ien ; i++ ) {
+ for ( var j=0, jen=this[i].length ; j<jen ; j++ ) {
+ var id = context[i].rowIdFn( context[i].aoData[ this[i][j] ]._aData );
+ a.push( (hash === true ? '#' : '' )+ id );
+ }
+ }
+
+ return new _Api( context, a );
+ } );
+
+ _api_registerPlural( 'rows().remove()', 'row().remove()', function () {
+ var that = this;
+
+ this.iterator( 'row', function ( settings, row, thatIdx ) {
+ var data = settings.aoData;
+ var rowData = data[ row ];
+ var i, ien, j, jen;
+ var loopRow, loopCells;
+
+ data.splice( row, 1 );
+
+ // Update the cached indexes
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
+ loopRow = data[i];
+ loopCells = loopRow.anCells;
+
+ // Rows
+ if ( loopRow.nTr !== null ) {
+ loopRow.nTr._DT_RowIndex = i;
+ }
+
+ // Cells
+ if ( loopCells !== null ) {
+ for ( j=0, jen=loopCells.length ; j<jen ; j++ ) {
+ loopCells[j]._DT_CellIndex.row = i;
+ }
+ }
+ }
+
+ // Delete from the display arrays
+ _fnDeleteIndex( settings.aiDisplayMaster, row );
+ _fnDeleteIndex( settings.aiDisplay, row );
+ _fnDeleteIndex( that[ thatIdx ], row, false ); // maintain local indexes
+
+ // For server-side processing tables - subtract the deleted row from the count
+ if ( settings._iRecordsDisplay > 0 ) {
+ settings._iRecordsDisplay--;
+ }
+
+ // Check for an 'overflow' they case for displaying the table
+ _fnLengthOverflow( settings );
+
+ // Remove the row's ID reference if there is one
+ var id = settings.rowIdFn( rowData._aData );
+ if ( id !== undefined ) {
+ delete settings.aIds[ id ];
+ }
+ } );
+
+ this.iterator( 'table', function ( settings ) {
+ for ( var i=0, ien=settings.aoData.length ; i<ien ; i++ ) {
+ settings.aoData[i].idx = i;
+ }
+ } );
+
+ return this;
+ } );
+
+
+ _api_register( 'rows.add()', function ( rows ) {
+ var newRows = this.iterator( 'table', function ( settings ) {
+ var row, i, ien;
+ var out = [];
+
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
+ row = rows[i];
+
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
+ out.push( _fnAddTr( settings, row )[0] );
+ }
+ else {
+ out.push( _fnAddData( settings, row ) );
+ }
+ }
+
+ return out;
+ }, 1 );
+
+ // Return an Api.rows() extended instance, so rows().nodes() etc can be used
+ var modRows = this.rows( -1 );
+ modRows.pop();
+ $.merge( modRows, newRows );
+
+ return modRows;
+ } );
+
+
+
+
+
+ /**
+ *
+ */
+ _api_register( 'row()', function ( selector, opts ) {
+ return _selector_first( this.rows( selector, opts ) );
+ } );
+
+
+ _api_register( 'row().data()', function ( data ) {
+ var ctx = this.context;
+
+ if ( data === undefined ) {
+ // Get
+ return ctx.length && this.length ?
+ ctx[0].aoData[ this[0] ]._aData :
+ undefined;
+ }
+
+ // Set
+ var row = ctx[0].aoData[ this[0] ];
+ row._aData = data;
+
+ // If the DOM has an id, and the data source is an array
+ if ( Array.isArray( data ) && row.nTr && row.nTr.id ) {
+ _fnSetObjectDataFn( ctx[0].rowId )( data, row.nTr.id );
+ }
+
+ // Automatically invalidate
+ _fnInvalidate( ctx[0], this[0], 'data' );
+
+ return this;
+ } );
+
+
+ _api_register( 'row().node()', function () {
+ var ctx = this.context;
+
+ return ctx.length && this.length ?
+ ctx[0].aoData[ this[0] ].nTr || null :
+ null;
+ } );
+
+
+ _api_register( 'row.add()', function ( row ) {
+ // Allow a jQuery object to be passed in - only a single row is added from
+ // it though - the first element in the set
+ if ( row instanceof $ && row.length ) {
+ row = row[0];
+ }
+
+ var rows = this.iterator( 'table', function ( settings ) {
+ if ( row.nodeName && row.nodeName.toUpperCase() === 'TR' ) {
+ return _fnAddTr( settings, row )[0];
+ }
+ return _fnAddData( settings, row );
+ } );
+
+ // Return an Api.rows() extended instance, with the newly added row selected
+ return this.row( rows[0] );
+ } );
+
+
+ $(document).on('plugin-init.dt', function (e, context) {
+ var api = new _Api( context );
+
+ const namespace = 'on-plugin-init';
+ const stateSaveParamsEvent = `stateSaveParams.${namespace}`;
+ const destroyEvent = `destroy.${namespace}`;
+
+ api.on( stateSaveParamsEvent, function ( e, settings, d ) {
+ // This could be more compact with the API, but it is a lot faster as a simple
+ // internal loop
+ var idFn = settings.rowIdFn;
+ var data = settings.aoData;
+ var ids = [];
+
+ for (var i=0 ; i<data.length ; i++) {
+ if (data[i]._detailsShow) {
+ ids.push( '#' + idFn(data[i]._aData) );
+ }
+ }
+
+ d.childRows = ids;
+ });
+
+ api.on( destroyEvent, function () {
+ api.off(`${stateSaveParamsEvent} ${destroyEvent}`);
+ });
+
+ var loaded = api.state.loaded();
+
+ if ( loaded && loaded.childRows ) {
+ api
+ .rows( $.map(loaded.childRows, function (id){
+ return id.replace(/:/g, '\\:')
+ }) )
+ .every( function () {
+ _fnCallbackFire( context, null, 'requestChild', [ this ] )
+ });
+ }
+ });
+
+ var __details_add = function ( ctx, row, data, klass )
+ {
+ // Convert to array of TR elements
+ var rows = [];
+ var addRow = function ( r, k ) {
+ // Recursion to allow for arrays of jQuery objects
+ if ( Array.isArray( r ) || r instanceof $ ) {
+ for ( var i=0, ien=r.length ; i<ien ; i++ ) {
+ addRow( r[i], k );
+ }
+ return;
+ }
+
+ // If we get a TR element, then just add it directly - up to the dev
+ // to add the correct number of columns etc
+ if ( r.nodeName && r.nodeName.toLowerCase() === 'tr' ) {
+ rows.push( r );
+ }
+ else {
+ // Otherwise create a row with a wrapper
+ var created = $('<tr><td></td></tr>').addClass( k );
+ $('td', created)
+ .addClass( k )
+ .html( r )
+ [0].colSpan = _fnVisbleColumns( ctx );
+
+ rows.push( created[0] );
+ }
+ };
+
+ addRow( data, klass );
+
+ if ( row._details ) {
+ row._details.detach();
+ }
+
+ row._details = $(rows);
+
+ // If the children were already shown, that state should be retained
+ if ( row._detailsShow ) {
+ row._details.insertAfter( row.nTr );
+ }
+ };
+
+
+ // Make state saving of child row details async to allow them to be batch processed
+ var __details_state = DataTable.util.throttle(
+ function (ctx) {
+ _fnSaveState( ctx[0] )
+ },
+ 500
+ );
+
+
+ var __details_remove = function ( api, idx )
+ {
+ var ctx = api.context;
+
+ if ( ctx.length ) {
+ var row = ctx[0].aoData[ idx !== undefined ? idx : api[0] ];
+
+ if ( row && row._details ) {
+ row._details.remove();
+
+ row._detailsShow = undefined;
+ row._details = undefined;
+ $( row.nTr ).removeClass( 'dt-hasChild' );
+ __details_state( ctx );
+ }
+ }
+ };
+
+
+ var __details_display = function ( api, show ) {
+ var ctx = api.context;
+
+ if ( ctx.length && api.length ) {
+ var row = ctx[0].aoData[ api[0] ];
+
+ if ( row._details ) {
+ row._detailsShow = show;
+
+ if ( show ) {
+ row._details.insertAfter( row.nTr );
+ $( row.nTr ).addClass( 'dt-hasChild' );
+ }
+ else {
+ row._details.detach();
+ $( row.nTr ).removeClass( 'dt-hasChild' );
+ }
+
+ _fnCallbackFire( ctx[0], null, 'childRow', [ show, api.row( api[0] ) ] )
+
+ __details_events( ctx[0] );
+ __details_state( ctx );
+ }
+ }
+ };
+
+
+ var __details_events = function ( settings )
+ {
+ var api = new _Api( settings );
+ var namespace = '.dt.DT_details';
+ var drawEvent = 'draw'+namespace;
+ var colvisEvent = 'column-sizing'+namespace;
+ var destroyEvent = 'destroy'+namespace;
+ var data = settings.aoData;
+
+ api.off( drawEvent +' '+ colvisEvent +' '+ destroyEvent );
+
+ if ( _pluck( data, '_details' ).length > 0 ) {
+ // On each draw, insert the required elements into the document
+ api.on( drawEvent, function ( e, ctx ) {
+ if ( settings !== ctx ) {
+ return;
+ }
+
+ api.rows( {page:'current'} ).eq(0).each( function (idx) {
+ // Internal data grab
+ var row = data[ idx ];
+
+ if ( row._detailsShow ) {
+ row._details.insertAfter( row.nTr );
+ }
+ } );
+ } );
+
+ // Column visibility change - update the colspan
+ api.on( colvisEvent, function ( e, ctx, idx, vis ) {
+ if ( settings !== ctx ) {
+ return;
+ }
+
+ // Update the colspan for the details rows (note, only if it already has
+ // a colspan)
+ var row, visible = _fnVisbleColumns( ctx );
+
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+ row = data[i];
+
+ if ( row._details ) {
+ row._details.children('td[colspan]').attr('colspan', visible );
+ }
+ }
+ } );
+
+ // Table destroyed - nuke any child rows
+ api.on( destroyEvent, function ( e, ctx ) {
+ if ( settings !== ctx ) {
+ return;
+ }
+
+ for ( var i=0, ien=data.length ; i<ien ; i++ ) {
+ if ( data[i]._details ) {
+ __details_remove( api, i );
+ }
+ }
+ } );
+ }
+ };
+
+ // Strings for the method names to help minification
+ var _emp = '';
+ var _child_obj = _emp+'row().child';
+ var _child_mth = _child_obj+'()';
+
+ // data can be:
+ // tr
+ // string
+ // jQuery or array of any of the above
+ _api_register( _child_mth, function ( data, klass ) {
+ var ctx = this.context;
+
+ if ( data === undefined ) {
+ // get
+ return ctx.length && this.length ?
+ ctx[0].aoData[ this[0] ]._details :
+ undefined;
+ }
+ else if ( data === true ) {
+ // show
+ this.child.show();
+ }
+ else if ( data === false ) {
+ // remove
+ __details_remove( this );
+ }
+ else if ( ctx.length && this.length ) {
+ // set
+ __details_add( ctx[0], ctx[0].aoData[ this[0] ], data, klass );
+ }
+
+ return this;
+ } );
+
+
+ _api_register( [
+ _child_obj+'.show()',
+ _child_mth+'.show()' // only when `child()` was called with parameters (without
+ ], function ( show ) { // it returns an object and this method is not executed)
+ __details_display( this, true );
+ return this;
+ } );
+
+
+ _api_register( [
+ _child_obj+'.hide()',
+ _child_mth+'.hide()' // only when `child()` was called with parameters (without
+ ], function () { // it returns an object and this method is not executed)
+ __details_display( this, false );
+ return this;
+ } );
+
+
+ _api_register( [
+ _child_obj+'.remove()',
+ _child_mth+'.remove()' // only when `child()` was called with parameters (without
+ ], function () { // it returns an object and this method is not executed)
+ __details_remove( this );
+ return this;
+ } );
+
+
+ _api_register( _child_obj+'.isShown()', function () {
+ var ctx = this.context;
+
+ if ( ctx.length && this.length ) {
+ // _detailsShown as false or undefined will fall through to return false
+ return ctx[0].aoData[ this[0] ]._detailsShow || false;
+ }
+ return false;
+ } );
+
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Columns
+ *
+ * {integer} - column index (>=0 count from left, <0 count from right)
+ * "{integer}:visIdx" - visible column index (i.e. translate to column index) (>=0 count from left, <0 count from right)
+ * "{integer}:visible" - alias for {integer}:visIdx (>=0 count from left, <0 count from right)
+ * "{string}:name" - column name
+ * "{string}" - jQuery selector on column header nodes
+ *
+ */
+
+ // can be an array of these items, comma separated list, or an array of comma
+ // separated lists
+
+ var __re_column_selector = /^([^:]+):(name|visIdx|visible)$/;
+
+
+ // r1 and r2 are redundant - but it means that the parameters match for the
+ // iterator callback in columns().data()
+ var __columnData = function ( settings, column, r1, r2, rows ) {
+ var a = [];
+ for ( var row=0, ien=rows.length ; row<ien ; row++ ) {
+ a.push( _fnGetCellData( settings, rows[row], column ) );
+ }
+ return a;
+ };
+
+
+ var __column_selector = function ( settings, selector, opts )
+ {
+ var
+ columns = settings.aoColumns,
+ names = _pluck( columns, 'sName' ),
+ nodes = _pluck( columns, 'nTh' );
+
+ var run = function ( s ) {
+ var selInt = _intVal( s );
+
+ // Selector - all
+ if ( s === '' ) {
+ return _range( columns.length );
+ }
+
+ // Selector - index
+ if ( selInt !== null ) {
+ return [ selInt >= 0 ?
+ selInt : // Count from left
+ columns.length + selInt // Count from right (+ because its a negative value)
+ ];
+ }
+
+ // Selector = function
+ if ( typeof s === 'function' ) {
+ var rows = _selector_row_indexes( settings, opts );
+
+ return $.map( columns, function (col, idx) {
+ return s(
+ idx,
+ __columnData( settings, idx, 0, 0, rows ),
+ nodes[ idx ]
+ ) ? idx : null;
+ } );
+ }
+
+ // jQuery or string selector
+ var match = typeof s === 'string' ?
+ s.match( __re_column_selector ) :
+ '';
+
+ if ( match ) {
+ switch( match[2] ) {
+ case 'visIdx':
+ case 'visible':
+ var idx = parseInt( match[1], 10 );
+ // Visible index given, convert to column index
+ if ( idx < 0 ) {
+ // Counting from the right
+ var visColumns = $.map( columns, function (col,i) {
+ return col.bVisible ? i : null;
+ } );
+ return [ visColumns[ visColumns.length + idx ] ];
+ }
+ // Counting from the left
+ return [ _fnVisibleToColumnIndex( settings, idx ) ];
+
+ case 'name':
+ // match by name. `names` is column index complete and in order
+ return $.map( names, function (name, i) {
+ return name === match[1] ? i : null;
+ } );
+
+ default:
+ return [];
+ }
+ }
+
+ // Cell in the table body
+ if ( s.nodeName && s._DT_CellIndex ) {
+ return [ s._DT_CellIndex.column ];
+ }
+
+ // jQuery selector on the TH elements for the columns
+ var jqResult = $( nodes )
+ .filter( s )
+ .map( function () {
+ return $.inArray( this, nodes ); // `nodes` is column index complete and in order
+ } )
+ .toArray();
+
+ if ( jqResult.length || ! s.nodeName ) {
+ return jqResult;
+ }
+
+ // Otherwise a node which might have a `dt-column` data attribute, or be
+ // a child or such an element
+ var host = $(s).closest('*[data-dt-column]');
+ return host.length ?
+ [ host.data('dt-column') ] :
+ [];
+ };
+
+ return _selector_run( 'column', selector, run, settings, opts );
+ };
+
+
+ var __setColumnVis = function ( settings, column, vis ) {
+ var
+ cols = settings.aoColumns,
+ col = cols[ column ],
+ data = settings.aoData,
+ row, cells, i, ien, tr;
+
+ // Get
+ if ( vis === undefined ) {
+ return col.bVisible;
+ }
+
+ // Set
+ // No change
+ if ( col.bVisible === vis ) {
+ return;
+ }
+
+ if ( vis ) {
+ // Insert column
+ // Need to decide if we should use appendChild or insertBefore
+ var insertBefore = $.inArray( true, _pluck(cols, 'bVisible'), column+1 );
+
+ for ( i=0, ien=data.length ; i<ien ; i++ ) {
+ tr = data[i].nTr;
+ cells = data[i].anCells;
+
+ if ( tr ) {
+ // insertBefore can act like appendChild if 2nd arg is null
+ tr.insertBefore( cells[ column ], cells[ insertBefore ] || null );
+ }
+ }
+ }
+ else {
+ // Remove column
+ $( _pluck( settings.aoData, 'anCells', column ) ).detach();
+ }
+
+ // Common actions
+ col.bVisible = vis;
+ };
+
+
+ _api_register( 'columns()', function ( selector, opts ) {
+ // argument shifting
+ if ( selector === undefined ) {
+ selector = '';
+ }
+ else if ( $.isPlainObject( selector ) ) {
+ opts = selector;
+ selector = '';
+ }
+
+ opts = _selector_opts( opts );
+
+ var inst = this.iterator( 'table', function ( settings ) {
+ return __column_selector( settings, selector, opts );
+ }, 1 );
+
+ // Want argument shifting here and in _row_selector?
+ inst.selector.cols = selector;
+ inst.selector.opts = opts;
+
+ return inst;
+ } );
+
+ _api_registerPlural( 'columns().header()', 'column().header()', function ( selector, opts ) {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings.aoColumns[column].nTh;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().footer()', 'column().footer()', function ( selector, opts ) {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings.aoColumns[column].nTf;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().data()', 'column().data()', function () {
+ return this.iterator( 'column-rows', __columnData, 1 );
+ } );
+
+ _api_registerPlural( 'columns().dataSrc()', 'column().dataSrc()', function () {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings.aoColumns[column].mData;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().cache()', 'column().cache()', function ( type ) {
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
+ return _pluck_order( settings.aoData, rows,
+ type === 'search' ? '_aFilterData' : '_aSortData', column
+ );
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().nodes()', 'column().nodes()', function () {
+ return this.iterator( 'column-rows', function ( settings, column, i, j, rows ) {
+ return _pluck_order( settings.aoData, rows, 'anCells', column ) ;
+ }, 1 );
+ } );
+
+ _api_registerPlural( 'columns().visible()', 'column().visible()', function ( vis, calc ) {
+ var that = this;
+ var ret = this.iterator( 'column', function ( settings, column ) {
+ if ( vis === undefined ) {
+ return settings.aoColumns[ column ].bVisible;
+ } // else
+ __setColumnVis( settings, column, vis );
+ } );
+
+ // Group the column visibility changes
+ if ( vis !== undefined ) {
+ this.iterator( 'table', function ( settings ) {
+ // Redraw the header after changes
+ _fnDrawHead( settings, settings.aoHeader );
+ _fnDrawHead( settings, settings.aoFooter );
+
+ // Update colspan for no records display. Child rows and extensions will use their own
+ // listeners to do this - only need to update the empty table item here
+ if ( ! settings.aiDisplay.length ) {
+ $(settings.nTBody).find('td[colspan]').attr('colspan', _fnVisbleColumns(settings));
+ }
+
+ _fnSaveState( settings );
+
+ // Second loop once the first is done for events
+ that.iterator( 'column', function ( settings, column ) {
+ _fnCallbackFire( settings, null, 'column-visibility', [settings, column, vis, calc] );
+ } );
+
+ if ( calc === undefined || calc ) {
+ that.columns.adjust();
+ }
+ });
+ }
+
+ return ret;
+ } );
+
+ _api_registerPlural( 'columns().indexes()', 'column().index()', function ( type ) {
+ return this.iterator( 'column', function ( settings, column ) {
+ return type === 'visible' ?
+ _fnColumnIndexToVisible( settings, column ) :
+ column;
+ }, 1 );
+ } );
+
+ _api_register( 'columns.adjust()', function () {
+ return this.iterator( 'table', function ( settings ) {
+ _fnAdjustColumnSizing( settings );
+ }, 1 );
+ } );
+
+ _api_register( 'column.index()', function ( type, idx ) {
+ if ( this.context.length !== 0 ) {
+ var ctx = this.context[0];
+
+ if ( type === 'fromVisible' || type === 'toData' ) {
+ return _fnVisibleToColumnIndex( ctx, idx );
+ }
+ else if ( type === 'fromData' || type === 'toVisible' ) {
+ return _fnColumnIndexToVisible( ctx, idx );
+ }
+ }
+ } );
+
+ _api_register( 'column()', function ( selector, opts ) {
+ return _selector_first( this.columns( selector, opts ) );
+ } );
+
+ var __cell_selector = function ( settings, selector, opts )
+ {
+ var data = settings.aoData;
+ var rows = _selector_row_indexes( settings, opts );
+ var cells = _removeEmpty( _pluck_order( data, rows, 'anCells' ) );
+ var allCells = $(_flatten( [], cells ));
+ var row;
+ var columns = settings.aoColumns.length;
+ var a, i, ien, j, o, host;
+
+ var run = function ( s ) {
+ var fnSelector = typeof s === 'function';
+
+ if ( s === null || s === undefined || fnSelector ) {
+ // All cells and function selectors
+ a = [];
+
+ for ( i=0, ien=rows.length ; i<ien ; i++ ) {
+ row = rows[i];
+
+ for ( j=0 ; j<columns ; j++ ) {
+ o = {
+ row: row,
+ column: j
+ };
+
+ if ( fnSelector ) {
+ // Selector - function
+ host = data[ row ];
+
+ if ( s( o, _fnGetCellData(settings, row, j), host.anCells ? host.anCells[j] : null ) ) {
+ a.push( o );
+ }
+ }
+ else {
+ // Selector - all
+ a.push( o );
+ }
+ }
+ }
+
+ return a;
+ }
+
+ // Selector - index
+ if ( $.isPlainObject( s ) ) {
+ // Valid cell index and its in the array of selectable rows
+ return s.column !== undefined && s.row !== undefined && $.inArray( s.row, rows ) !== -1 ?
+ [s] :
+ [];
+ }
+
+ // Selector - jQuery filtered cells
+ var jqResult = allCells
+ .filter( s )
+ .map( function (i, el) {
+ return { // use a new object, in case someone changes the values
+ row: el._DT_CellIndex.row,
+ column: el._DT_CellIndex.column
+ };
+ } )
+ .toArray();
+
+ if ( jqResult.length || ! s.nodeName ) {
+ return jqResult;
+ }
+
+ // Otherwise the selector is a node, and there is one last option - the
+ // element might be a child of an element which has dt-row and dt-column
+ // data attributes
+ host = $(s).closest('*[data-dt-row]');
+ return host.length ?
+ [ {
+ row: host.data('dt-row'),
+ column: host.data('dt-column')
+ } ] :
+ [];
+ };
+
+ return _selector_run( 'cell', selector, run, settings, opts );
+ };
+
+
+
+
+ _api_register( 'cells()', function ( rowSelector, columnSelector, opts ) {
+ // Argument shifting
+ if ( $.isPlainObject( rowSelector ) ) {
+ // Indexes
+ if ( rowSelector.row === undefined ) {
+ // Selector options in first parameter
+ opts = rowSelector;
+ rowSelector = null;
+ }
+ else {
+ // Cell index objects in first parameter
+ opts = columnSelector;
+ columnSelector = null;
+ }
+ }
+ if ( $.isPlainObject( columnSelector ) ) {
+ opts = columnSelector;
+ columnSelector = null;
+ }
+
+ // Cell selector
+ if ( columnSelector === null || columnSelector === undefined ) {
+ return this.iterator( 'table', function ( settings ) {
+ return __cell_selector( settings, rowSelector, _selector_opts( opts ) );
+ } );
+ }
+
+ // The default built in options need to apply to row and columns
+ var internalOpts = opts ? {
+ page: opts.page,
+ order: opts.order,
+ search: opts.search
+ } : {};
+
+ // Row + column selector
+ var columns = this.columns( columnSelector, internalOpts );
+ var rows = this.rows( rowSelector, internalOpts );
+ var i, ien, j, jen;
+
+ var cellsNoOpts = this.iterator( 'table', function ( settings, idx ) {
+ var a = [];
+
+ for ( i=0, ien=rows[idx].length ; i<ien ; i++ ) {
+ for ( j=0, jen=columns[idx].length ; j<jen ; j++ ) {
+ a.push( {
+ row: rows[idx][i],
+ column: columns[idx][j]
+ } );
+ }
+ }
+
+ return a;
+ }, 1 );
+
+ // There is currently only one extension which uses a cell selector extension
+ // It is a _major_ performance drag to run this if it isn't needed, so this is
+ // an extension specific check at the moment
+ var cells = opts && opts.selected ?
+ this.cells( cellsNoOpts, opts ) :
+ cellsNoOpts;
+
+ $.extend( cells.selector, {
+ cols: columnSelector,
+ rows: rowSelector,
+ opts: opts
+ } );
+
+ return cells;
+ } );
+
+
+ _api_registerPlural( 'cells().nodes()', 'cell().node()', function () {
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ var data = settings.aoData[ row ];
+
+ return data && data.anCells ?
+ data.anCells[ column ] :
+ undefined;
+ }, 1 );
+ } );
+
+
+ _api_register( 'cells().data()', function () {
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ return _fnGetCellData( settings, row, column );
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'cells().cache()', 'cell().cache()', function ( type ) {
+ type = type === 'search' ? '_aFilterData' : '_aSortData';
+
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ return settings.aoData[ row ][ type ][ column ];
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'cells().render()', 'cell().render()', function ( type ) {
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ return _fnGetCellData( settings, row, column, type );
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'cells().indexes()', 'cell().index()', function () {
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ return {
+ row: row,
+ column: column,
+ columnVisible: _fnColumnIndexToVisible( settings, column )
+ };
+ }, 1 );
+ } );
+
+
+ _api_registerPlural( 'cells().invalidate()', 'cell().invalidate()', function ( src ) {
+ return this.iterator( 'cell', function ( settings, row, column ) {
+ _fnInvalidate( settings, row, src, column );
+ } );
+ } );
+
+
+
+ _api_register( 'cell()', function ( rowSelector, columnSelector, opts ) {
+ return _selector_first( this.cells( rowSelector, columnSelector, opts ) );
+ } );
+
+
+ _api_register( 'cell().data()', function ( data ) {
+ var ctx = this.context;
+ var cell = this[0];
+
+ if ( data === undefined ) {
+ // Get
+ return ctx.length && cell.length ?
+ _fnGetCellData( ctx[0], cell[0].row, cell[0].column ) :
+ undefined;
+ }
+
+ // Set
+ _fnSetCellData( ctx[0], cell[0].row, cell[0].column, data );
+ _fnInvalidate( ctx[0], cell[0].row, 'data', cell[0].column );
+
+ return this;
+ } );
+
+
+
+ /**
+ * Get current ordering (sorting) that has been applied to the table.
+ *
+ * @returns {array} 2D array containing the sorting information for the first
+ * table in the current context. Each element in the parent array represents
+ * a column being sorted upon (i.e. multi-sorting with two columns would have
+ * 2 inner arrays). The inner arrays may have 2 or 3 elements. The first is
+ * the column index that the sorting condition applies to, the second is the
+ * direction of the sort (`desc` or `asc`) and, optionally, the third is the
+ * index of the sorting order from the `column.sorting` initialisation array.
+ *//**
+ * Set the ordering for the table.
+ *
+ * @param {integer} order Column index to sort upon.
+ * @param {string} direction Direction of the sort to be applied (`asc` or `desc`)
+ * @returns {DataTables.Api} this
+ *//**
+ * Set the ordering for the table.
+ *
+ * @param {array} order 1D array of sorting information to be applied.
+ * @param {array} [...] Optional additional sorting conditions
+ * @returns {DataTables.Api} this
+ *//**
+ * Set the ordering for the table.
+ *
+ * @param {array} order 2D array of sorting information to be applied.
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'order()', function ( order, dir ) {
+ var ctx = this.context;
+
+ if ( order === undefined ) {
+ // get
+ return ctx.length !== 0 ?
+ ctx[0].aaSorting :
+ undefined;
+ }
+
+ // set
+ if ( typeof order === 'number' ) {
+ // Simple column / direction passed in
+ order = [ [ order, dir ] ];
+ }
+ else if ( order.length && ! Array.isArray( order[0] ) ) {
+ // Arguments passed in (list of 1D arrays)
+ order = Array.prototype.slice.call( arguments );
+ }
+ // otherwise a 2D array was passed in
+
+ return this.iterator( 'table', function ( settings ) {
+ settings.aaSorting = order.slice();
+ } );
+ } );
+
+
+ /**
+ * Attach a sort listener to an element for a given column
+ *
+ * @param {node|jQuery|string} node Identifier for the element(s) to attach the
+ * listener to. This can take the form of a single DOM node, a jQuery
+ * collection of nodes or a jQuery selector which will identify the node(s).
+ * @param {integer} column the column that a click on this node will sort on
+ * @param {function} [callback] callback function when sort is run
+ * @returns {DataTables.Api} this
+ */
+ _api_register( 'order.listener()', function ( node, column, callback ) {
+ return this.iterator( 'table', function ( settings ) {
+ _fnSortAttachListener( settings, node, column, callback );
+ } );
+ } );
+
+
+ _api_register( 'order.fixed()', function ( set ) {
+ if ( ! set ) {
+ var ctx = this.context;
+ var fixed = ctx.length ?
+ ctx[0].aaSortingFixed :
+ undefined;
+
+ return Array.isArray( fixed ) ?
+ { pre: fixed } :
+ fixed;
+ }
+
+ return this.iterator( 'table', function ( settings ) {
+ settings.aaSortingFixed = $.extend( true, {}, set );
+ } );
+ } );
+
+
+ // Order by the selected column(s)
+ _api_register( [
+ 'columns().order()',
+ 'column().order()'
+ ], function ( dir ) {
+ var that = this;
+
+ return this.iterator( 'table', function ( settings, i ) {
+ var sort = [];
+
+ $.each( that[i], function (j, col) {
+ sort.push( [ col, dir ] );
+ } );
+
+ settings.aaSorting = sort;
+ } );
+ } );
+
+
+
+ _api_register( 'search()', function ( input, regex, smart, caseInsen ) {
+ var ctx = this.context;
+
+ if ( input === undefined ) {
+ // get
+ return ctx.length !== 0 ?
+ ctx[0].oPreviousSearch.sSearch :
+ undefined;
+ }
+
+ // set
+ return this.iterator( 'table', function ( settings ) {
+ if ( ! settings.oFeatures.bFilter ) {
+ return;
+ }
+
+ _fnFilterComplete( settings, $.extend( {}, settings.oPreviousSearch, {
+ "sSearch": input+"",
+ "bRegex": regex === null ? false : regex,
+ "bSmart": smart === null ? true : smart,
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
+ } ), 1 );
+ } );
+ } );
+
+
+ _api_registerPlural(
+ 'columns().search()',
+ 'column().search()',
+ function ( input, regex, smart, caseInsen ) {
+ return this.iterator( 'column', function ( settings, column ) {
+ var preSearch = settings.aoPreSearchCols;
+
+ if ( input === undefined ) {
+ // get
+ return preSearch[ column ].sSearch;
+ }
+
+ // set
+ if ( ! settings.oFeatures.bFilter ) {
+ return;
+ }
+
+ $.extend( preSearch[ column ], {
+ "sSearch": input+"",
+ "bRegex": regex === null ? false : regex,
+ "bSmart": smart === null ? true : smart,
+ "bCaseInsensitive": caseInsen === null ? true : caseInsen
+ } );
+
+ _fnFilterComplete( settings, settings.oPreviousSearch, 1 );
+ } );
+ }
+ );
+
+ /*
+ * State API methods
+ */
+
+ _api_register( 'state()', function () {
+ return this.context.length ?
+ this.context[0].oSavedState :
+ null;
+ } );
+
+
+ _api_register( 'state.clear()', function () {
+ return this.iterator( 'table', function ( settings ) {
+ // Save an empty object
+ settings.fnStateSaveCallback.call( settings.oInstance, settings, {} );
+ } );
+ } );
+
+
+ _api_register( 'state.loaded()', function () {
+ return this.context.length ?
+ this.context[0].oLoadedState :
+ null;
+ } );
+
+
+ _api_register( 'state.save()', function () {
+ return this.iterator( 'table', function ( settings ) {
+ _fnSaveState( settings );
+ } );
+ } );
+
+
+
+ /**
+ * Provide a common method for plug-ins to check the version of DataTables being
+ * used, in order to ensure compatibility.
+ *
+ * @param {string} version Version string to check for, in the format "X.Y.Z".
+ * Note that the formats "X" and "X.Y" are also acceptable.
+ * @returns {boolean} true if this version of DataTables is greater or equal to
+ * the required version, or false if this version of DataTales is not
+ * suitable
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * alert( $.fn.dataTable.versionCheck( '1.9.0' ) );
+ */
+ DataTable.versionCheck = DataTable.fnVersionCheck = function( version )
+ {
+ var aThis = DataTable.version.split('.');
+ var aThat = version.split('.');
+ var iThis, iThat;
+
+ for ( var i=0, iLen=aThat.length ; i<iLen ; i++ ) {
+ iThis = parseInt( aThis[i], 10 ) || 0;
+ iThat = parseInt( aThat[i], 10 ) || 0;
+
+ // Parts are the same, keep comparing
+ if (iThis === iThat) {
+ continue;
+ }
+
+ // Parts are different, return immediately
+ return iThis > iThat;
+ }
+
+ return true;
+ };
+
+
+ /**
+ * Check if a `<table>` node is a DataTable table already or not.
+ *
+ * @param {node|jquery|string} table Table node, jQuery object or jQuery
+ * selector for the table to test. Note that if more than more than one
+ * table is passed on, only the first will be checked
+ * @returns {boolean} true the table given is a DataTable, or false otherwise
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * if ( ! $.fn.DataTable.isDataTable( '#example' ) ) {
+ * $('#example').dataTable();
+ * }
+ */
+ DataTable.isDataTable = DataTable.fnIsDataTable = function ( table )
+ {
+ var t = $(table).get(0);
+ var is = false;
+
+ if ( table instanceof DataTable.Api ) {
+ return true;
+ }
+
+ $.each( DataTable.settings, function (i, o) {
+ var head = o.nScrollHead ? $('table', o.nScrollHead)[0] : null;
+ var foot = o.nScrollFoot ? $('table', o.nScrollFoot)[0] : null;
+
+ if ( o.nTable === t || head === t || foot === t ) {
+ is = true;
+ }
+ } );
+
+ return is;
+ };
+
+
+ /**
+ * Get all DataTable tables that have been initialised - optionally you can
+ * select to get only currently visible tables.
+ *
+ * @param {boolean} [visible=false] Flag to indicate if you want all (default)
+ * or visible tables only.
+ * @returns {array} Array of `table` nodes (not DataTable instances) which are
+ * DataTables
+ * @static
+ * @dtopt API-Static
+ *
+ * @example
+ * $.each( $.fn.dataTable.tables(true), function () {
+ * $(table).DataTable().columns.adjust();
+ * } );
+ */
+ DataTable.tables = DataTable.fnTables = function ( visible )
+ {
+ var api = false;
+
+ if ( $.isPlainObject( visible ) ) {
+ api = visible.api;
+ visible = visible.visible;
+ }
+
+ var a = $.map( DataTable.settings, function (o) {
+ if ( !visible || (visible && $(o.nTable).is(':visible')) ) {
+ return o.nTable;
+ }
+ } );
+
+ return api ?
+ new _Api( a ) :
+ a;
+ };
+
+
+ /**
+ * Convert from camel case parameters to Hungarian notation. This is made public
+ * for the extensions to provide the same ability as DataTables core to accept
+ * either the 1.9 style Hungarian notation, or the 1.10+ style camelCase
+ * parameters.
+ *
+ * @param {object} src The model object which holds all parameters that can be
+ * mapped.
+ * @param {object} user The object to convert from camel case to Hungarian.
+ * @param {boolean} force When set to `true`, properties which already have a
+ * Hungarian value in the `user` object will be overwritten. Otherwise they
+ * won't be.
+ */
+ DataTable.camelToHungarian = _fnCamelToHungarian;
+
+
+
+ /**
+ *
+ */
+ _api_register( '$()', function ( selector, opts ) {
+ var
+ rows = this.rows( opts ).nodes(), // Get all rows
+ jqRows = $(rows);
+
+ return $( [].concat(
+ jqRows.filter( selector ).toArray(),
+ jqRows.find( selector ).toArray()
+ ) );
+ } );
+
+
+ // jQuery functions to operate on the tables
+ $.each( [ 'on', 'one', 'off' ], function (i, key) {
+ _api_register( key+'()', function ( /* event, handler */ ) {
+ var args = Array.prototype.slice.call(arguments);
+
+ // Add the `dt` namespace automatically if it isn't already present
+ args[0] = $.map( args[0].split( /\s/ ), function ( e ) {
+ return ! e.match(/\.dt\b/) ?
+ e+'.dt' :
+ e;
+ } ).join( ' ' );
+
+ var inst = $( this.tables().nodes() );
+ inst[key].apply( inst, args );
+ return this;
+ } );
+ } );
+
+
+ _api_register( 'clear()', function () {
+ return this.iterator( 'table', function ( settings ) {
+ _fnClearTable( settings );
+ } );
+ } );
+
+
+ _api_register( 'settings()', function () {
+ return new _Api( this.context, this.context );
+ } );
+
+
+ _api_register( 'init()', function () {
+ var ctx = this.context;
+ return ctx.length ? ctx[0].oInit : null;
+ } );
+
+
+ _api_register( 'data()', function () {
+ return this.iterator( 'table', function ( settings ) {
+ return _pluck( settings.aoData, '_aData' );
+ } ).flatten();
+ } );
+
+
+ _api_register( 'destroy()', function ( remove ) {
+ remove = remove || false;
+
+ return this.iterator( 'table', function ( settings ) {
+ var classes = settings.oClasses;
+ var table = settings.nTable;
+ var tbody = settings.nTBody;
+ var thead = settings.nTHead;
+ var tfoot = settings.nTFoot;
+ var jqTable = $(table);
+ var jqTbody = $(tbody);
+ var jqWrapper = $(settings.nTableWrapper);
+ var rows = $.map( settings.aoData, function (r) { return r.nTr; } );
+ var i, ien;
+
+ // Flag to note that the table is currently being destroyed - no action
+ // should be taken
+ settings.bDestroying = true;
+
+ // Fire off the destroy callbacks for plug-ins etc
+ _fnCallbackFire( settings, "aoDestroyCallback", "destroy", [settings] );
+
+ // If not being removed from the document, make all columns visible
+ if ( ! remove ) {
+ new _Api( settings ).columns().visible( true );
+ }
+
+ // Blitz all `DT` namespaced events (these are internal events, the
+ // lowercase, `dt` events are user subscribed and they are responsible
+ // for removing them
+ jqWrapper.off('.DT').find(':not(tbody *)').off('.DT');
+ $(window).off('.DT-'+settings.sInstance);
+
+ // When scrolling we had to break the table up - restore it
+ if ( table != thead.parentNode ) {
+ jqTable.children('thead').detach();
+ jqTable.append( thead );
+ }
+
+ if ( tfoot && table != tfoot.parentNode ) {
+ jqTable.children('tfoot').detach();
+ jqTable.append( tfoot );
+ }
+
+ settings.aaSorting = [];
+ settings.aaSortingFixed = [];
+ _fnSortingClasses( settings );
+
+ $( rows ).removeClass( settings.asStripeClasses.join(' ') );
+
+ $('th, td', thead).removeClass( classes.sSortable+' '+
+ classes.sSortableAsc+' '+classes.sSortableDesc+' '+classes.sSortableNone
+ );
+
+ // Add the TR elements back into the table in their original order
+ jqTbody.children().detach();
+ jqTbody.append( rows );
+
+ var orig = settings.nTableWrapper.parentNode;
+
+ // Remove the DataTables generated nodes, events and classes
+ var removedMethod = remove ? 'remove' : 'detach';
+ jqTable[ removedMethod ]();
+ jqWrapper[ removedMethod ]();
+
+ // If we need to reattach the table to the document
+ if ( ! remove && orig ) {
+ // insertBefore acts like appendChild if !arg[1]
+ orig.insertBefore( table, settings.nTableReinsertBefore );
+
+ // Restore the width of the original table - was read from the style property,
+ // so we can restore directly to that
+ jqTable
+ .css( 'width', settings.sDestroyWidth )
+ .removeClass( classes.sTable );
+
+ // If the were originally stripe classes - then we add them back here.
+ // Note this is not fool proof (for example if not all rows had stripe
+ // classes - but it's a good effort without getting carried away
+ ien = settings.asDestroyStripes.length;
+
+ if ( ien ) {
+ jqTbody.children().each( function (i) {
+ $(this).addClass( settings.asDestroyStripes[i % ien] );
+ } );
+ }
+ }
+
+ /* Remove the settings object from the settings array */
+ var idx = $.inArray( settings, DataTable.settings );
+ if ( idx !== -1 ) {
+ DataTable.settings.splice( idx, 1 );
+ }
+ } );
+ } );
+
+
+ // Add the `every()` method for rows, columns and cells in a compact form
+ $.each( [ 'column', 'row', 'cell' ], function ( i, type ) {
+ _api_register( type+'s().every()', function ( fn ) {
+ var opts = this.selector.opts;
+ var api = this;
+
+ return this.iterator( type, function ( settings, arg1, arg2, arg3, arg4 ) {
+ // Rows and columns:
+ // arg1 - index
+ // arg2 - table counter
+ // arg3 - loop counter
+ // arg4 - undefined
+ // Cells:
+ // arg1 - row index
+ // arg2 - column index
+ // arg3 - table counter
+ // arg4 - loop counter
+ fn.call(
+ api[ type ](
+ arg1,
+ type==='cell' ? arg2 : opts,
+ type==='cell' ? opts : undefined
+ ),
+ arg1, arg2, arg3, arg4
+ );
+ } );
+ } );
+ } );
+
+
+ // i18n method for extensions to be able to use the language object from the
+ // DataTable
+ _api_register( 'i18n()', function ( token, def, plural ) {
+ var ctx = this.context[0];
+ var resolved = _fnGetObjectDataFn( token )( ctx.oLanguage );
+
+ if ( resolved === undefined ) {
+ resolved = def;
+ }
+
+ if ( plural !== undefined && $.isPlainObject( resolved ) ) {
+ resolved = resolved[ plural ] !== undefined ?
+ resolved[ plural ] :
+ resolved._;
+ }
+
+ return resolved.replace( '%d', plural ); // nb: plural might be undefined,
+ } );
+ /**
+ * Version string for plug-ins to check compatibility. Allowed format is
+ * `a.b.c-d` where: a:int, b:int, c:int, d:string(dev|beta|alpha). `d` is used
+ * only for non-release builds. See http://semver.org/ for more information.
+ * @member
+ * @type string
+ * @default Version number
+ */
+ DataTable.version = "1.13.1";
+
+ /**
+ * Private data store, containing all of the settings objects that are
+ * created for the tables on a given page.
+ *
+ * Note that the `DataTable.settings` object is aliased to
+ * `jQuery.fn.dataTableExt` through which it may be accessed and
+ * manipulated, or `jQuery.fn.dataTable.settings`.
+ * @member
+ * @type array
+ * @default []
+ * @private
+ */
+ DataTable.settings = [];
+
+ /**
+ * Object models container, for the various models that DataTables has
+ * available to it. These models define the objects that are used to hold
+ * the active state and configuration of the table.
+ * @namespace
+ */
+ DataTable.models = {};
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * search information for the global filter and individual column filters.
+ * @namespace
+ */
+ DataTable.models.oSearch = {
+ /**
+ * Flag to indicate if the filtering should be case insensitive or not
+ * @type boolean
+ * @default true
+ */
+ "bCaseInsensitive": true,
+
+ /**
+ * Applied search term
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sSearch": "",
+
+ /**
+ * Flag to indicate if the search term should be interpreted as a
+ * regular expression (true) or not (false) and therefore and special
+ * regex characters escaped.
+ * @type boolean
+ * @default false
+ */
+ "bRegex": false,
+
+ /**
+ * Flag to indicate if DataTables is to use its smart filtering or not.
+ * @type boolean
+ * @default true
+ */
+ "bSmart": true,
+
+ /**
+ * Flag to indicate if DataTables should only trigger a search when
+ * the return key is pressed.
+ * @type boolean
+ * @default false
+ */
+ "return": false
+ };
+
+
+
+
+ /**
+ * Template object for the way in which DataTables holds information about
+ * each individual row. This is the object format used for the settings
+ * aoData array.
+ * @namespace
+ */
+ DataTable.models.oRow = {
+ /**
+ * TR element for the row
+ * @type node
+ * @default null
+ */
+ "nTr": null,
+
+ /**
+ * Array of TD elements for each row. This is null until the row has been
+ * created.
+ * @type array nodes
+ * @default []
+ */
+ "anCells": null,
+
+ /**
+ * Data object from the original data source for the row. This is either
+ * an array if using the traditional form of DataTables, or an object if
+ * using mData options. The exact type will depend on the passed in
+ * data from the data source, or will be an array if using DOM a data
+ * source.
+ * @type array|object
+ * @default []
+ */
+ "_aData": [],
+
+ /**
+ * Sorting data cache - this array is ostensibly the same length as the
+ * number of columns (although each index is generated only as it is
+ * needed), and holds the data that is used for sorting each column in the
+ * row. We do this cache generation at the start of the sort in order that
+ * the formatting of the sort data need be done only once for each cell
+ * per sort. This array should not be read from or written to by anything
+ * other than the master sorting methods.
+ * @type array
+ * @default null
+ * @private
+ */
+ "_aSortData": null,
+
+ /**
+ * Per cell filtering data cache. As per the sort data cache, used to
+ * increase the performance of the filtering in DataTables
+ * @type array
+ * @default null
+ * @private
+ */
+ "_aFilterData": null,
+
+ /**
+ * Filtering data cache. This is the same as the cell filtering cache, but
+ * in this case a string rather than an array. This is easily computed with
+ * a join on `_aFilterData`, but is provided as a cache so the join isn't
+ * needed on every search (memory traded for performance)
+ * @type array
+ * @default null
+ * @private
+ */
+ "_sFilterRow": null,
+
+ /**
+ * Cache of the class name that DataTables has applied to the row, so we
+ * can quickly look at this variable rather than needing to do a DOM check
+ * on className for the nTr property.
+ * @type string
+ * @default <i>Empty string</i>
+ * @private
+ */
+ "_sRowStripe": "",
+
+ /**
+ * Denote if the original data source was from the DOM, or the data source
+ * object. This is used for invalidating data, so DataTables can
+ * automatically read data from the original source, unless uninstructed
+ * otherwise.
+ * @type string
+ * @default null
+ * @private
+ */
+ "src": null,
+
+ /**
+ * Index in the aoData array. This saves an indexOf lookup when we have the
+ * object, but want to know the index
+ * @type integer
+ * @default -1
+ * @private
+ */
+ "idx": -1
+ };
+
+
+ /**
+ * Template object for the column information object in DataTables. This object
+ * is held in the settings aoColumns array and contains all the information that
+ * DataTables needs about each individual column.
+ *
+ * Note that this object is related to {@link DataTable.defaults.column}
+ * but this one is the internal data store for DataTables's cache of columns.
+ * It should NOT be manipulated outside of DataTables. Any configuration should
+ * be done through the initialisation options.
+ * @namespace
+ */
+ DataTable.models.oColumn = {
+ /**
+ * Column index. This could be worked out on-the-fly with $.inArray, but it
+ * is faster to just hold it as a variable
+ * @type integer
+ * @default null
+ */
+ "idx": null,
+
+ /**
+ * A list of the columns that sorting should occur on when this column
+ * is sorted. That this property is an array allows multi-column sorting
+ * to be defined for a column (for example first name / last name columns
+ * would benefit from this). The values are integers pointing to the
+ * columns to be sorted on (typically it will be a single integer pointing
+ * at itself, but that doesn't need to be the case).
+ * @type array
+ */
+ "aDataSort": null,
+
+ /**
+ * Define the sorting directions that are applied to the column, in sequence
+ * as the column is repeatedly sorted upon - i.e. the first value is used
+ * as the sorting direction when the column if first sorted (clicked on).
+ * Sort it again (click again) and it will move on to the next index.
+ * Repeat until loop.
+ * @type array
+ */
+ "asSorting": null,
+
+ /**
+ * Flag to indicate if the column is searchable, and thus should be included
+ * in the filtering or not.
+ * @type boolean
+ */
+ "bSearchable": null,
+
+ /**
+ * Flag to indicate if the column is sortable or not.
+ * @type boolean
+ */
+ "bSortable": null,
+
+ /**
+ * Flag to indicate if the column is currently visible in the table or not
+ * @type boolean
+ */
+ "bVisible": null,
+
+ /**
+ * Store for manual type assignment using the `column.type` option. This
+ * is held in store so we can manipulate the column's `sType` property.
+ * @type string
+ * @default null
+ * @private
+ */
+ "_sManualType": null,
+
+ /**
+ * Flag to indicate if HTML5 data attributes should be used as the data
+ * source for filtering or sorting. True is either are.
+ * @type boolean
+ * @default false
+ * @private
+ */
+ "_bAttrSrc": false,
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} nTd The TD node that has been created
+ * @param {*} sData The Data for the cell
+ * @param {array|object} oData The data for the whole row
+ * @param {int} iRow The row index for the aoData data store
+ * @default null
+ */
+ "fnCreatedCell": null,
+
+ /**
+ * Function to get data from a cell in a column. You should <b>never</b>
+ * access data directly through _aData internally in DataTables - always use
+ * the method attached to this property. It allows mData to function as
+ * required. This function is automatically assigned by the column
+ * initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {string} sSpecific The specific data type you want to get -
+ * 'display', 'type' 'filter' 'sort'
+ * @returns {*} The data for the cell from the given row's data
+ * @default null
+ */
+ "fnGetData": null,
+
+ /**
+ * Function to set data for a cell in the column. You should <b>never</b>
+ * set the data directly to _aData internally in DataTables - always use
+ * this method. It allows mData to function as required. This function
+ * is automatically assigned by the column initialisation method
+ * @type function
+ * @param {array|object} oData The data array/object for the array
+ * (i.e. aoData[]._aData)
+ * @param {*} sValue Value to set
+ * @default null
+ */
+ "fnSetData": null,
+
+ /**
+ * Property to read the value for the cells in the column from the data
+ * source array / object. If null, then the default content is used, if a
+ * function is given then the return from the function is used.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mData": null,
+
+ /**
+ * Partner property to mData which is used (only when defined) to get
+ * the data - i.e. it is basically the same as mData, but without the
+ * 'set' option, and also the data fed to it is the result from mData.
+ * This is the rendering method to match the data method of mData.
+ * @type function|int|string|null
+ * @default null
+ */
+ "mRender": null,
+
+ /**
+ * Unique header TH/TD element for this column - this is what the sorting
+ * listener is attached to (if sorting is enabled.)
+ * @type node
+ * @default null
+ */
+ "nTh": null,
+
+ /**
+ * Unique footer TH/TD element for this column (if there is one). Not used
+ * in DataTables as such, but can be used for plug-ins to reference the
+ * footer for each column.
+ * @type node
+ * @default null
+ */
+ "nTf": null,
+
+ /**
+ * The class to apply to all TD elements in the table's TBODY for the column
+ * @type string
+ * @default null
+ */
+ "sClass": null,
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * @type string
+ */
+ "sContentPadding": null,
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because mData
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ */
+ "sDefaultContent": null,
+
+ /**
+ * Name for the column, allowing reference to the column by name as well as
+ * by index (needs a lookup to work by name).
+ * @type string
+ */
+ "sName": null,
+
+ /**
+ * Custom sorting data type - defines which of the available plug-ins in
+ * afnSortData the custom sorting will use - if any is defined.
+ * @type string
+ * @default std
+ */
+ "sSortDataType": 'std',
+
+ /**
+ * Class to be applied to the header element when sorting on this column
+ * @type string
+ * @default null
+ */
+ "sSortingClass": null,
+
+ /**
+ * Class to be applied to the header element when sorting on this column -
+ * when jQuery UI theming is used.
+ * @type string
+ * @default null
+ */
+ "sSortingClassJUI": null,
+
+ /**
+ * Title of the column - what is seen in the TH element (nTh).
+ * @type string
+ */
+ "sTitle": null,
+
+ /**
+ * Column sorting and filtering type
+ * @type string
+ * @default null
+ */
+ "sType": null,
+
+ /**
+ * Width of the column
+ * @type string
+ * @default null
+ */
+ "sWidth": null,
+
+ /**
+ * Width of the column when it was first "encountered"
+ * @type string
+ * @default null
+ */
+ "sWidthOrig": null
+ };
+
+
+ /*
+ * Developer note: The properties of the object below are given in Hungarian
+ * notation, that was used as the interface for DataTables prior to v1.10, however
+ * from v1.10 onwards the primary interface is camel case. In order to avoid
+ * breaking backwards compatibility utterly with this change, the Hungarian
+ * version is still, internally the primary interface, but is is not documented
+ * - hence the @name tags in each doc comment. This allows a Javascript function
+ * to create a map from Hungarian notation to camel case (going the other direction
+ * would require each property to be listed, which would add around 3K to the size
+ * of DataTables, while this method is about a 0.5K hit).
+ *
+ * Ultimately this does pave the way for Hungarian notation to be dropped
+ * completely, but that is a massive amount of work and will break current
+ * installs (therefore is on-hold until v2).
+ */
+
+ /**
+ * Initialisation options that can be given to DataTables at initialisation
+ * time.
+ * @namespace
+ */
+ DataTable.defaults = {
+ /**
+ * An array of data to use for the table, passed in at initialisation which
+ * will be used in preference to any data which is already in the DOM. This is
+ * particularly useful for constructing tables purely in Javascript, for
+ * example with a custom Ajax call.
+ * @type array
+ * @default null
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.data
+ *
+ * @example
+ * // Using a 2D array data source
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "data": [
+ * ['Trident', 'Internet Explorer 4.0', 'Win 95+', 4, 'X'],
+ * ['Trident', 'Internet Explorer 5.0', 'Win 95+', 5, 'C'],
+ * ],
+ * "columns": [
+ * { "title": "Engine" },
+ * { "title": "Browser" },
+ * { "title": "Platform" },
+ * { "title": "Version" },
+ * { "title": "Grade" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using an array of objects as a data source (`data`)
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "data": [
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 4.0",
+ * "platform": "Win 95+",
+ * "version": 4,
+ * "grade": "X"
+ * },
+ * {
+ * "engine": "Trident",
+ * "browser": "Internet Explorer 5.0",
+ * "platform": "Win 95+",
+ * "version": 5,
+ * "grade": "C"
+ * }
+ * ],
+ * "columns": [
+ * { "title": "Engine", "data": "engine" },
+ * { "title": "Browser", "data": "browser" },
+ * { "title": "Platform", "data": "platform" },
+ * { "title": "Version", "data": "version" },
+ * { "title": "Grade", "data": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "aaData": null,
+
+
+ /**
+ * If ordering is enabled, then DataTables will perform a first pass sort on
+ * initialisation. You can define which column(s) the sort is performed
+ * upon, and the sorting direction, with this variable. The `sorting` array
+ * should contain an array for each column to be sorted initially containing
+ * the column's index and a direction string ('asc' or 'desc').
+ * @type array
+ * @default [[0,'asc']]
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.order
+ *
+ * @example
+ * // Sort by 3rd column first, and then 4th column
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "order": [[2,'asc'], [3,'desc']]
+ * } );
+ * } );
+ *
+ * // No initial sorting
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "order": []
+ * } );
+ * } );
+ */
+ "aaSorting": [[0,'asc']],
+
+
+ /**
+ * This parameter is basically identical to the `sorting` parameter, but
+ * cannot be overridden by user interaction with the table. What this means
+ * is that you could have a column (visible or hidden) which the sorting
+ * will always be forced on first - any sorting after that (from the user)
+ * will then be performed as required. This can be useful for grouping rows
+ * together.
+ * @type array
+ * @default null
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.orderFixed
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "orderFixed": [[0,'asc']]
+ * } );
+ * } )
+ */
+ "aaSortingFixed": [],
+
+
+ /**
+ * DataTables can be instructed to load data to display in the table from a
+ * Ajax source. This option defines how that Ajax call is made and where to.
+ *
+ * The `ajax` property has three different modes of operation, depending on
+ * how it is defined. These are:
+ *
+ * * `string` - Set the URL from where the data should be loaded from.
+ * * `object` - Define properties for `jQuery.ajax`.
+ * * `function` - Custom data get function
+ *
+ * `string`
+ * --------
+ *
+ * As a string, the `ajax` property simply defines the URL from which
+ * DataTables will load data.
+ *
+ * `object`
+ * --------
+ *
+ * As an object, the parameters in the object are passed to
+ * [jQuery.ajax](http://api.jquery.com/jQuery.ajax/) allowing fine control
+ * of the Ajax request. DataTables has a number of default parameters which
+ * you can override using this option. Please refer to the jQuery
+ * documentation for a full description of the options available, although
+ * the following parameters provide additional options in DataTables or
+ * require special consideration:
+ *
+ * * `data` - As with jQuery, `data` can be provided as an object, but it
+ * can also be used as a function to manipulate the data DataTables sends
+ * to the server. The function takes a single parameter, an object of
+ * parameters with the values that DataTables has readied for sending. An
+ * object may be returned which will be merged into the DataTables
+ * defaults, or you can add the items to the object that was passed in and
+ * not return anything from the function. This supersedes `fnServerParams`
+ * from DataTables 1.9-.
+ *
+ * * `dataSrc` - By default DataTables will look for the property `data` (or
+ * `aaData` for compatibility with DataTables 1.9-) when obtaining data
+ * from an Ajax source or for server-side processing - this parameter
+ * allows that property to be changed. You can use Javascript dotted
+ * object notation to get a data source for multiple levels of nesting, or
+ * it my be used as a function. As a function it takes a single parameter,
+ * the JSON returned from the server, which can be manipulated as
+ * required, with the returned value being that used by DataTables as the
+ * data source for the table. This supersedes `sAjaxDataProp` from
+ * DataTables 1.9-.
+ *
+ * * `success` - Should not be overridden it is used internally in
+ * DataTables. To manipulate / transform the data returned by the server
+ * use `ajax.dataSrc`, or use `ajax` as a function (see below).
+ *
+ * `function`
+ * ----------
+ *
+ * As a function, making the Ajax call is left up to yourself allowing
+ * complete control of the Ajax request. Indeed, if desired, a method other
+ * than Ajax could be used to obtain the required data, such as Web storage
+ * or an AIR database.
+ *
+ * The function is given four parameters and no return is required. The
+ * parameters are:
+ *
+ * 1. _object_ - Data to send to the server
+ * 2. _function_ - Callback function that must be executed when the required
+ * data has been obtained. That data should be passed into the callback
+ * as the only parameter
+ * 3. _object_ - DataTables settings object for the table
+ *
+ * Note that this supersedes `fnServerData` from DataTables 1.9-.
+ *
+ * @type string|object|function
+ * @default null
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.ajax
+ * @since 1.10.0
+ *
+ * @example
+ * // Get JSON data from a file via Ajax.
+ * // Note DataTables expects data in the form `{ data: [ ...data... ] }` by default).
+ * $('#example').dataTable( {
+ * "ajax": "data.json"
+ * } );
+ *
+ * @example
+ * // Get JSON data from a file via Ajax, using `dataSrc` to change
+ * // `data` to `tableData` (i.e. `{ tableData: [ ...data... ] }`)
+ * $('#example').dataTable( {
+ * "ajax": {
+ * "url": "data.json",
+ * "dataSrc": "tableData"
+ * }
+ * } );
+ *
+ * @example
+ * // Get JSON data from a file via Ajax, using `dataSrc` to read data
+ * // from a plain array rather than an array in an object
+ * $('#example').dataTable( {
+ * "ajax": {
+ * "url": "data.json",
+ * "dataSrc": ""
+ * }
+ * } );
+ *
+ * @example
+ * // Manipulate the data returned from the server - add a link to data
+ * // (note this can, should, be done using `render` for the column - this
+ * // is just a simple example of how the data can be manipulated).
+ * $('#example').dataTable( {
+ * "ajax": {
+ * "url": "data.json",
+ * "dataSrc": function ( json ) {
+ * for ( var i=0, ien=json.length ; i<ien ; i++ ) {
+ * json[i][0] = '<a href="/message/'+json[i][0]+'>View message</a>';
+ * }
+ * return json;
+ * }
+ * }
+ * } );
+ *
+ * @example
+ * // Add data to the request
+ * $('#example').dataTable( {
+ * "ajax": {
+ * "url": "data.json",
+ * "data": function ( d ) {
+ * return {
+ * "extra_search": $('#extra').val()
+ * };
+ * }
+ * }
+ * } );
+ *
+ * @example
+ * // Send request as POST
+ * $('#example').dataTable( {
+ * "ajax": {
+ * "url": "data.json",
+ * "type": "POST"
+ * }
+ * } );
+ *
+ * @example
+ * // Get the data from localStorage (could interface with a form for
+ * // adding, editing and removing rows).
+ * $('#example').dataTable( {
+ * "ajax": function (data, callback, settings) {
+ * callback(
+ * JSON.parse( localStorage.getItem('dataTablesData') )
+ * );
+ * }
+ * } );
+ */
+ "ajax": null,
+
+
+ /**
+ * This parameter allows you to readily specify the entries in the length drop
+ * down menu that DataTables shows when pagination is enabled. It can be
+ * either a 1D array of options which will be used for both the displayed
+ * option and the value, or a 2D array which will use the array in the first
+ * position as the value, and the array in the second position as the
+ * displayed options (useful for language strings such as 'All').
+ *
+ * Note that the `pageLength` property will be automatically set to the
+ * first value given in this array, unless `pageLength` is also provided.
+ * @type array
+ * @default [ 10, 25, 50, 100 ]
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.lengthMenu
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]]
+ * } );
+ * } );
+ */
+ "aLengthMenu": [ 10, 25, 50, 100 ],
+
+
+ /**
+ * The `columns` option in the initialisation parameter allows you to define
+ * details about the way individual columns behave. For a full list of
+ * column options that can be set, please see
+ * {@link DataTable.defaults.column}. Note that if you use `columns` to
+ * define your columns, you must have an entry in the array for every single
+ * column that you have in your table (these can be null if you don't which
+ * to specify any options).
+ * @member
+ *
+ * @name DataTable.defaults.column
+ */
+ "aoColumns": null,
+
+ /**
+ * Very similar to `columns`, `columnDefs` allows you to target a specific
+ * column, multiple columns, or all columns, using the `targets` property of
+ * each object in the array. This allows great flexibility when creating
+ * tables, as the `columnDefs` arrays can be of any length, targeting the
+ * columns you specifically want. `columnDefs` may use any of the column
+ * options available: {@link DataTable.defaults.column}, but it _must_
+ * have `targets` defined in each object in the array. Values in the `targets`
+ * array may be:
+ * <ul>
+ * <li>a string - class name will be matched on the TH for the column</li>
+ * <li>0 or a positive integer - column index counting from the left</li>
+ * <li>a negative integer - column index counting from the right</li>
+ * <li>the string "_all" - all columns (i.e. assign a default)</li>
+ * </ul>
+ * @member
+ *
+ * @name DataTable.defaults.columnDefs
+ */
+ "aoColumnDefs": null,
+
+
+ /**
+ * Basically the same as `search`, this parameter defines the individual column
+ * filtering state at initialisation time. The array must be of the same size
+ * as the number of columns, and each element be an object with the parameters
+ * `search` and `escapeRegex` (the latter is optional). 'null' is also
+ * accepted and the default will be used.
+ * @type array
+ * @default []
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.searchCols
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "searchCols": [
+ * null,
+ * { "search": "My filter" },
+ * null,
+ * { "search": "^[0-9]", "escapeRegex": false }
+ * ]
+ * } );
+ * } )
+ */
+ "aoSearchCols": [],
+
+
+ /**
+ * An array of CSS classes that should be applied to displayed rows. This
+ * array may be of any length, and DataTables will apply each class
+ * sequentially, looping when required.
+ * @type array
+ * @default null <i>Will take the values determined by the `oClasses.stripe*`
+ * options</i>
+ *
+ * @dtopt Option
+ * @name DataTable.defaults.stripeClasses
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stripeClasses": [ 'strip1', 'strip2', 'strip3' ]
+ * } );
+ * } )
+ */
+ "asStripeClasses": null,
+
+
+ /**
+ * Enable or disable automatic column width calculation. This can be disabled
+ * as an optimisation (it takes some time to calculate the widths) if the
+ * tables widths are passed in using `columns`.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.autoWidth
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "autoWidth": false
+ * } );
+ * } );
+ */
+ "bAutoWidth": true,
+
+
+ /**
+ * Deferred rendering can provide DataTables with a huge speed boost when you
+ * are using an Ajax or JS data source for the table. This option, when set to
+ * true, will cause DataTables to defer the creation of the table elements for
+ * each row until they are needed for a draw - saving a significant amount of
+ * time.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.deferRender
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "ajax": "sources/arrays.txt",
+ * "deferRender": true
+ * } );
+ * } );
+ */
+ "bDeferRender": false,
+
+
+ /**
+ * Replace a DataTable which matches the given selector and replace it with
+ * one which has the properties of the new initialisation object passed. If no
+ * table matches the selector, then the new DataTable will be constructed as
+ * per normal.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.destroy
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "srollY": "200px",
+ * "paginate": false
+ * } );
+ *
+ * // Some time later....
+ * $('#example').dataTable( {
+ * "filter": false,
+ * "destroy": true
+ * } );
+ * } );
+ */
+ "bDestroy": false,
+
+
+ /**
+ * Enable or disable filtering of data. Filtering in DataTables is "smart" in
+ * that it allows the end user to input multiple words (space separated) and
+ * will match a row containing those words, even if not in the order that was
+ * specified (this allow matching across multiple columns). Note that if you
+ * wish to use filtering in DataTables this must remain 'true' - to remove the
+ * default filtering input box and retain filtering abilities, please use
+ * {@link DataTable.defaults.dom}.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.searching
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "searching": false
+ * } );
+ * } );
+ */
+ "bFilter": true,
+
+
+ /**
+ * Enable or disable the table information display. This shows information
+ * about the data that is currently visible on the page, including information
+ * about filtered data if that action is being performed.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.info
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "info": false
+ * } );
+ * } );
+ */
+ "bInfo": true,
+
+
+ /**
+ * Allows the end user to select the size of a formatted page from a select
+ * menu (sizes are 10, 25, 50 and 100). Requires pagination (`paginate`).
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.lengthChange
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "lengthChange": false
+ * } );
+ * } );
+ */
+ "bLengthChange": true,
+
+
+ /**
+ * Enable or disable pagination.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.paging
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "paging": false
+ * } );
+ * } );
+ */
+ "bPaginate": true,
+
+
+ /**
+ * Enable or disable the display of a 'processing' indicator when the table is
+ * being processed (e.g. a sort). This is particularly useful for tables with
+ * large amounts of data where it can take a noticeable amount of time to sort
+ * the entries.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.processing
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "processing": true
+ * } );
+ * } );
+ */
+ "bProcessing": false,
+
+
+ /**
+ * Retrieve the DataTables object for the given selector. Note that if the
+ * table has already been initialised, this parameter will cause DataTables
+ * to simply return the object that has already been set up - it will not take
+ * account of any changes you might have made to the initialisation object
+ * passed to DataTables (setting this parameter to true is an acknowledgement
+ * that you understand this). `destroy` can be used to reinitialise a table if
+ * you need.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.retrieve
+ *
+ * @example
+ * $(document).ready( function() {
+ * initTable();
+ * tableActions();
+ * } );
+ *
+ * function initTable ()
+ * {
+ * return $('#example').dataTable( {
+ * "scrollY": "200px",
+ * "paginate": false,
+ * "retrieve": true
+ * } );
+ * }
+ *
+ * function tableActions ()
+ * {
+ * var table = initTable();
+ * // perform API operations with oTable
+ * }
+ */
+ "bRetrieve": false,
+
+
+ /**
+ * When vertical (y) scrolling is enabled, DataTables will force the height of
+ * the table's viewport to the given height at all times (useful for layout).
+ * However, this can look odd when filtering data down to a small data set,
+ * and the footer is left "floating" further down. This parameter (when
+ * enabled) will cause DataTables to collapse the table's viewport down when
+ * the result set will fit within the given Y height.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.scrollCollapse
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "scrollY": "200",
+ * "scrollCollapse": true
+ * } );
+ * } );
+ */
+ "bScrollCollapse": false,
+
+
+ /**
+ * Configure DataTables to use server-side processing. Note that the
+ * `ajax` parameter must also be given in order to give DataTables a
+ * source to obtain the required data for each draw.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Features
+ * @dtopt Server-side
+ * @name DataTable.defaults.serverSide
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "serverSide": true,
+ * "ajax": "xhr.php"
+ * } );
+ * } );
+ */
+ "bServerSide": false,
+
+
+ /**
+ * Enable or disable sorting of columns. Sorting of individual columns can be
+ * disabled by the `sortable` option for each column.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.ordering
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "ordering": false
+ * } );
+ * } );
+ */
+ "bSort": true,
+
+
+ /**
+ * Enable or display DataTables' ability to sort multiple columns at the
+ * same time (activated by shift-click by the user).
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.orderMulti
+ *
+ * @example
+ * // Disable multiple column sorting ability
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "orderMulti": false
+ * } );
+ * } );
+ */
+ "bSortMulti": true,
+
+
+ /**
+ * Allows control over whether DataTables should use the top (true) unique
+ * cell that is found for a single column, or the bottom (false - default).
+ * This is useful when using complex headers.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.orderCellsTop
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "orderCellsTop": true
+ * } );
+ * } );
+ */
+ "bSortCellsTop": false,
+
+
+ /**
+ * Enable or disable the addition of the classes `sorting\_1`, `sorting\_2` and
+ * `sorting\_3` to the columns which are currently being sorted on. This is
+ * presented as a feature switch as it can increase processing time (while
+ * classes are removed and added) so for large data sets you might want to
+ * turn this off.
+ * @type boolean
+ * @default true
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.orderClasses
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "orderClasses": false
+ * } );
+ * } );
+ */
+ "bSortClasses": true,
+
+
+ /**
+ * Enable or disable state saving. When enabled HTML5 `localStorage` will be
+ * used to save table display information such as pagination information,
+ * display length, filtering and sorting. As such when the end user reloads
+ * the page the display display will match what thy had previously set up.
+ *
+ * Due to the use of `localStorage` the default state saving is not supported
+ * in IE6 or 7. If state saving is required in those browsers, use
+ * `stateSaveCallback` to provide a storage solution such as cookies.
+ * @type boolean
+ * @default false
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.stateSave
+ *
+ * @example
+ * $(document).ready( function () {
+ * $('#example').dataTable( {
+ * "stateSave": true
+ * } );
+ * } );
+ */
+ "bStateSave": false,
+
+
+ /**
+ * This function is called when a TR element is created (and all TD child
+ * elements have been inserted), or registered if using a DOM source, allowing
+ * manipulation of the TR element (adding classes etc).
+ * @type function
+ * @param {node} row "TR" element for the current row
+ * @param {array} data Raw data array for this row
+ * @param {int} dataIndex The index of this row in the internal aoData array
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.createdRow
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "createdRow": function( row, data, dataIndex ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( data[4] == "A" )
+ * {
+ * $('td:eq(4)', row).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnCreatedRow": null,
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify any aspect you want about the created DOM.
+ * @type function
+ * @param {object} settings DataTables settings object
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.drawCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "drawCallback": function( settings ) {
+ * alert( 'DataTables has redrawn the table' );
+ * }
+ * } );
+ * } );
+ */
+ "fnDrawCallback": null,
+
+
+ /**
+ * Identical to fnHeaderCallback() but for the table footer this function
+ * allows you to modify the table footer on every 'draw' event.
+ * @type function
+ * @param {node} foot "TR" element for the footer
+ * @param {array} data Full table data (as derived from the original HTML)
+ * @param {int} start Index for the current display starting point in the
+ * display array
+ * @param {int} end Index for the current display ending point in the
+ * display array
+ * @param {array int} display Index array to translate the visual position
+ * to the full data array
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.footerCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "footerCallback": function( tfoot, data, start, end, display ) {
+ * tfoot.getElementsByTagName('th')[0].innerHTML = "Starting index is "+start;
+ * }
+ * } );
+ * } )
+ */
+ "fnFooterCallback": null,
+
+
+ /**
+ * When rendering large numbers in the information element for the table
+ * (i.e. "Showing 1 to 10 of 57 entries") DataTables will render large numbers
+ * to have a comma separator for the 'thousands' units (e.g. 1 million is
+ * rendered as "1,000,000") to help readability for the end user. This
+ * function will override the default method DataTables uses.
+ * @type function
+ * @member
+ * @param {int} toFormat number to be formatted
+ * @returns {string} formatted string for DataTables to show the number
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.formatNumber
+ *
+ * @example
+ * // Format a number using a single quote for the separator (note that
+ * // this can also be done with the language.thousands option)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "formatNumber": function ( toFormat ) {
+ * return toFormat.toString().replace(
+ * /\B(?=(\d{3})+(?!\d))/g, "'"
+ * );
+ * };
+ * } );
+ * } );
+ */
+ "fnFormatNumber": function ( toFormat ) {
+ return toFormat.toString().replace(
+ /\B(?=(\d{3})+(?!\d))/g,
+ this.oLanguage.sThousands
+ );
+ },
+
+
+ /**
+ * This function is called on every 'draw' event, and allows you to
+ * dynamically modify the header row. This can be used to calculate and
+ * display useful information about the table.
+ * @type function
+ * @param {node} head "TR" element for the header
+ * @param {array} data Full table data (as derived from the original HTML)
+ * @param {int} start Index for the current display starting point in the
+ * display array
+ * @param {int} end Index for the current display ending point in the
+ * display array
+ * @param {array int} display Index array to translate the visual position
+ * to the full data array
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.headerCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "fheaderCallback": function( head, data, start, end, display ) {
+ * head.getElementsByTagName('th')[0].innerHTML = "Displaying "+(end-start)+" records";
+ * }
+ * } );
+ * } )
+ */
+ "fnHeaderCallback": null,
+
+
+ /**
+ * The information element can be used to convey information about the current
+ * state of the table. Although the internationalisation options presented by
+ * DataTables are quite capable of dealing with most customisations, there may
+ * be times where you wish to customise the string further. This callback
+ * allows you to do exactly that.
+ * @type function
+ * @param {object} oSettings DataTables settings object
+ * @param {int} start Starting position in data for the draw
+ * @param {int} end End position in data for the draw
+ * @param {int} max Total number of rows in the table (regardless of
+ * filtering)
+ * @param {int} total Total number of rows in the data set, after filtering
+ * @param {string} pre The string that DataTables has formatted using it's
+ * own rules
+ * @returns {string} The string to be displayed in the information element.
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.infoCallback
+ *
+ * @example
+ * $('#example').dataTable( {
+ * "infoCallback": function( settings, start, end, max, total, pre ) {
+ * return start +" to "+ end;
+ * }
+ * } );
+ */
+ "fnInfoCallback": null,
+
+
+ /**
+ * Called when the table has been initialised. Normally DataTables will
+ * initialise sequentially and there will be no need for this function,
+ * however, this does not hold true when using external language information
+ * since that is obtained using an async XHR call.
+ * @type function
+ * @param {object} settings DataTables settings object
+ * @param {object} json The JSON object request from the server - only
+ * present if client-side Ajax sourced data is used
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.initComplete
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "initComplete": function(settings, json) {
+ * alert( 'DataTables has finished its initialisation.' );
+ * }
+ * } );
+ * } )
+ */
+ "fnInitComplete": null,
+
+
+ /**
+ * Called at the very start of each table draw and can be used to cancel the
+ * draw by returning false, any other return (including undefined) results in
+ * the full draw occurring).
+ * @type function
+ * @param {object} settings DataTables settings object
+ * @returns {boolean} False will cancel the draw, anything else (including no
+ * return) will allow it to complete.
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.preDrawCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "preDrawCallback": function( settings ) {
+ * if ( $('#test').val() == 1 ) {
+ * return false;
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnPreDrawCallback": null,
+
+
+ /**
+ * This function allows you to 'post process' each row after it have been
+ * generated for each table draw, but before it is rendered on screen. This
+ * function might be used for setting the row class name etc.
+ * @type function
+ * @param {node} row "TR" element for the current row
+ * @param {array} data Raw data array for this row
+ * @param {int} displayIndex The display index for the current table draw
+ * @param {int} displayIndexFull The index of the data in the full list of
+ * rows (after filtering)
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.rowCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "rowCallback": function( row, data, displayIndex, displayIndexFull ) {
+ * // Bold the grade for all 'A' grade browsers
+ * if ( data[4] == "A" ) {
+ * $('td:eq(4)', row).html( '<b>A</b>' );
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "fnRowCallback": null,
+
+
+ /**
+ * __Deprecated__ The functionality provided by this parameter has now been
+ * superseded by that provided through `ajax`, which should be used instead.
+ *
+ * This parameter allows you to override the default function which obtains
+ * the data from the server so something more suitable for your application.
+ * For example you could use POST data, or pull information from a Gears or
+ * AIR database.
+ * @type function
+ * @member
+ * @param {string} source HTTP source to obtain the data from (`ajax`)
+ * @param {array} data A key/value pair object containing the data to send
+ * to the server
+ * @param {function} callback to be called on completion of the data get
+ * process that will draw the data on the page.
+ * @param {object} settings DataTables settings object
+ *
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ * @name DataTable.defaults.serverData
+ *
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
+ */
+ "fnServerData": null,
+
+
+ /**
+ * __Deprecated__ The functionality provided by this parameter has now been
+ * superseded by that provided through `ajax`, which should be used instead.
+ *
+ * It is often useful to send extra data to the server when making an Ajax
+ * request - for example custom filtering information, and this callback
+ * function makes it trivial to send extra information to the server. The
+ * passed in parameter is the data set that has been constructed by
+ * DataTables, and you can add to this or modify it as you require.
+ * @type function
+ * @param {array} data Data array (array of objects which are name/value
+ * pairs) that has been constructed by DataTables and will be sent to the
+ * server. In the case of Ajax sourced data with server-side processing
+ * this will be an empty array, for server-side processing there will be a
+ * significant number of parameters!
+ * @returns {undefined} Ensure that you modify the data array passed in,
+ * as this is passed by reference.
+ *
+ * @dtopt Callbacks
+ * @dtopt Server-side
+ * @name DataTable.defaults.serverParams
+ *
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
+ */
+ "fnServerParams": null,
+
+
+ /**
+ * Load the table state. With this function you can define from where, and how, the
+ * state of a table is loaded. By default DataTables will load from `localStorage`
+ * but you might wish to use a server-side database or cookies.
+ * @type function
+ * @member
+ * @param {object} settings DataTables settings object
+ * @param {object} callback Callback that can be executed when done. It
+ * should be passed the loaded state object.
+ * @return {object} The DataTables state object to be loaded
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.stateLoadCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateLoadCallback": function (settings, callback) {
+ * $.ajax( {
+ * "url": "/state_load",
+ * "dataType": "json",
+ * "success": function (json) {
+ * callback( json );
+ * }
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoadCallback": function ( settings ) {
+ try {
+ return JSON.parse(
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).getItem(
+ 'DataTables_'+settings.sInstance+'_'+location.pathname
+ )
+ );
+ } catch (e) {
+ return {};
+ }
+ },
+
+
+ /**
+ * Callback which allows modification of the saved state prior to loading that state.
+ * This callback is called when the table is loading state from the stored data, but
+ * prior to the settings object being modified by the saved state. Note that for
+ * plug-in authors, you should use the `stateLoadParams` event to load parameters for
+ * a plug-in.
+ * @type function
+ * @param {object} settings DataTables settings object
+ * @param {object} data The state object that is to be loaded
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.stateLoadParams
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never loaded
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateLoadParams": function (settings, data) {
+ * data.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Disallow state loading by returning false
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateLoadParams": function (settings, data) {
+ * return false;
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoadParams": null,
+
+
+ /**
+ * Callback that is called when the state has been loaded from the state saving method
+ * and the DataTables settings object has been modified as a result of the loaded state.
+ * @type function
+ * @param {object} settings DataTables settings object
+ * @param {object} data The state object that was loaded
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.stateLoaded
+ *
+ * @example
+ * // Show an alert with the filtering value that was saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateLoaded": function (settings, data) {
+ * alert( 'Saved filter was: '+data.oSearch.sSearch );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateLoaded": null,
+
+
+ /**
+ * Save the table state. This function allows you to define where and how the state
+ * information for the table is stored By default DataTables will use `localStorage`
+ * but you might wish to use a server-side database or cookies.
+ * @type function
+ * @member
+ * @param {object} settings DataTables settings object
+ * @param {object} data The state object to be saved
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.stateSaveCallback
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateSaveCallback": function (settings, data) {
+ * // Send an Ajax request to the server with the state object
+ * $.ajax( {
+ * "url": "/state_save",
+ * "data": data,
+ * "dataType": "json",
+ * "method": "POST"
+ * "success": function () {}
+ * } );
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSaveCallback": function ( settings, data ) {
+ try {
+ (settings.iStateDuration === -1 ? sessionStorage : localStorage).setItem(
+ 'DataTables_'+settings.sInstance+'_'+location.pathname,
+ JSON.stringify( data )
+ );
+ } catch (e) {}
+ },
+
+
+ /**
+ * Callback which allows modification of the state to be saved. Called when the table
+ * has changed state a new state save is required. This method allows modification of
+ * the state saving object prior to actually doing the save, including addition or
+ * other state properties or modification. Note that for plug-in authors, you should
+ * use the `stateSaveParams` event to save parameters for a plug-in.
+ * @type function
+ * @param {object} settings DataTables settings object
+ * @param {object} data The state object to be saved
+ *
+ * @dtopt Callbacks
+ * @name DataTable.defaults.stateSaveParams
+ *
+ * @example
+ * // Remove a saved filter, so filtering is never saved
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateSave": true,
+ * "stateSaveParams": function (settings, data) {
+ * data.oSearch.sSearch = "";
+ * }
+ * } );
+ * } );
+ */
+ "fnStateSaveParams": null,
+
+
+ /**
+ * Duration for which the saved state information is considered valid. After this period
+ * has elapsed the state will be returned to the default.
+ * Value is given in seconds.
+ * @type int
+ * @default 7200 <i>(2 hours)</i>
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.stateDuration
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "stateDuration": 60*60*24; // 1 day
+ * } );
+ * } )
+ */
+ "iStateDuration": 7200,
+
+
+ /**
+ * When enabled DataTables will not make a request to the server for the first
+ * page draw - rather it will use the data already on the page (no sorting etc
+ * will be applied to it), thus saving on an XHR at load time. `deferLoading`
+ * is used to indicate that deferred loading is required, but it is also used
+ * to tell DataTables how many records there are in the full table (allowing
+ * the information element and pagination to be displayed correctly). In the case
+ * where a filtering is applied to the table on initial load, this can be
+ * indicated by giving the parameter as an array, where the first element is
+ * the number of records available after filtering and the second element is the
+ * number of records without filtering (allowing the table information element
+ * to be shown correctly).
+ * @type int | array
+ * @default null
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.deferLoading
+ *
+ * @example
+ * // 57 records available in the table, no filtering applied
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "serverSide": true,
+ * "ajax": "scripts/server_processing.php",
+ * "deferLoading": 57
+ * } );
+ * } );
+ *
+ * @example
+ * // 57 records after filtering, 100 without filtering (an initial filter applied)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "serverSide": true,
+ * "ajax": "scripts/server_processing.php",
+ * "deferLoading": [ 57, 100 ],
+ * "search": {
+ * "search": "my_filter"
+ * }
+ * } );
+ * } );
+ */
+ "iDeferLoading": null,
+
+
+ /**
+ * Number of rows to display on a single page when using pagination. If
+ * feature enabled (`lengthChange`) then the end user will be able to override
+ * this to a custom setting using a pop-up menu.
+ * @type int
+ * @default 10
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.pageLength
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "pageLength": 50
+ * } );
+ * } )
+ */
+ "iDisplayLength": 10,
+
+
+ /**
+ * Define the starting point for data display when using DataTables with
+ * pagination. Note that this parameter is the number of records, rather than
+ * the page number, so if you have 10 records per page and want to start on
+ * the third page, it should be "20".
+ * @type int
+ * @default 0
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.displayStart
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "displayStart": 20
+ * } );
+ * } )
+ */
+ "iDisplayStart": 0,
+
+
+ /**
+ * By default DataTables allows keyboard navigation of the table (sorting, paging,
+ * and filtering) by adding a `tabindex` attribute to the required elements. This
+ * allows you to tab through the controls and press the enter key to activate them.
+ * The tabindex is default 0, meaning that the tab follows the flow of the document.
+ * You can overrule this using this parameter if you wish. Use a value of -1 to
+ * disable built-in keyboard navigation.
+ * @type int
+ * @default 0
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.tabIndex
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "tabIndex": 1
+ * } );
+ * } );
+ */
+ "iTabIndex": 0,
+
+
+ /**
+ * Classes that DataTables assigns to the various components and features
+ * that it adds to the HTML table. This allows classes to be configured
+ * during initialisation in addition to through the static
+ * {@link DataTable.ext.oStdClasses} object).
+ * @namespace
+ * @name DataTable.defaults.classes
+ */
+ "oClasses": {},
+
+
+ /**
+ * All strings that DataTables uses in the user interface that it creates
+ * are defined in this object, allowing you to modified them individually or
+ * completely replace them all as required.
+ * @namespace
+ * @name DataTable.defaults.language
+ */
+ "oLanguage": {
+ /**
+ * Strings that are used for WAI-ARIA labels and controls only (these are not
+ * actually visible on the page, but will be read by screenreaders, and thus
+ * must be internationalised as well).
+ * @namespace
+ * @name DataTable.defaults.language.aria
+ */
+ "oAria": {
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted ascending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.aria.sortAscending
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "aria": {
+ * "sortAscending": " - click/return to sort ascending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortAscending": ": activate to sort column ascending",
+
+ /**
+ * ARIA label that is added to the table headers when the column may be
+ * sorted descending by activing the column (click or return when focused).
+ * Note that the column header is prefixed to this string.
+ * @type string
+ * @default : activate to sort column ascending
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.aria.sortDescending
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "aria": {
+ * "sortDescending": " - click/return to sort descending"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sSortDescending": ": activate to sort column descending"
+ },
+
+ /**
+ * Pagination string used by DataTables for the built-in pagination
+ * control types.
+ * @namespace
+ * @name DataTable.defaults.language.paginate
+ */
+ "oPaginate": {
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the first page.
+ * @type string
+ * @default First
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.paginate.first
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "paginate": {
+ * "first": "First page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sFirst": "First",
+
+
+ /**
+ * Text to use when using the 'full_numbers' type of pagination for the
+ * button to take the user to the last page.
+ * @type string
+ * @default Last
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.paginate.last
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "paginate": {
+ * "last": "Last page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sLast": "Last",
+
+
+ /**
+ * Text to use for the 'next' pagination button (to take the user to the
+ * next page).
+ * @type string
+ * @default Next
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.paginate.next
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "paginate": {
+ * "next": "Next page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sNext": "Next",
+
+
+ /**
+ * Text to use for the 'previous' pagination button (to take the user to
+ * the previous page).
+ * @type string
+ * @default Previous
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.paginate.previous
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "paginate": {
+ * "previous": "Previous page"
+ * }
+ * }
+ * } );
+ * } );
+ */
+ "sPrevious": "Previous"
+ },
+
+ /**
+ * This string is shown in preference to `zeroRecords` when the table is
+ * empty of data (regardless of filtering). Note that this is an optional
+ * parameter - if it is not given, the value of `zeroRecords` will be used
+ * instead (either the default or given value).
+ * @type string
+ * @default No data available in table
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.emptyTable
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "emptyTable": "No data available in table"
+ * }
+ * } );
+ * } );
+ */
+ "sEmptyTable": "No data available in table",
+
+
+ /**
+ * This string gives information to the end user about the information
+ * that is current on display on the page. The following tokens can be
+ * used in the string and will be dynamically replaced as the table
+ * display updates. This tokens can be placed anywhere in the string, or
+ * removed as needed by the language requires:
+ *
+ * * `\_START\_` - Display index of the first record on the current page
+ * * `\_END\_` - Display index of the last record on the current page
+ * * `\_TOTAL\_` - Number of records in the table after filtering
+ * * `\_MAX\_` - Number of records in the table without filtering
+ * * `\_PAGE\_` - Current page number
+ * * `\_PAGES\_` - Total number of pages of data in the table
+ *
+ * @type string
+ * @default Showing _START_ to _END_ of _TOTAL_ entries
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.info
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "info": "Showing page _PAGE_ of _PAGES_"
+ * }
+ * } );
+ * } );
+ */
+ "sInfo": "Showing _START_ to _END_ of _TOTAL_ entries",
+
+
+ /**
+ * Display information string for when the table is empty. Typically the
+ * format of this string should match `info`.
+ * @type string
+ * @default Showing 0 to 0 of 0 entries
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.infoEmpty
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "infoEmpty": "No entries to show"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoEmpty": "Showing 0 to 0 of 0 entries",
+
+
+ /**
+ * When a user filters the information in a table, this string is appended
+ * to the information (`info`) to give an idea of how strong the filtering
+ * is. The variable _MAX_ is dynamically updated.
+ * @type string
+ * @default (filtered from _MAX_ total entries)
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.infoFiltered
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "infoFiltered": " - filtering from _MAX_ records"
+ * }
+ * } );
+ * } );
+ */
+ "sInfoFiltered": "(filtered from _MAX_ total entries)",
+
+
+ /**
+ * If can be useful to append extra information to the info string at times,
+ * and this variable does exactly that. This information will be appended to
+ * the `info` (`infoEmpty` and `infoFiltered` in whatever combination they are
+ * being used) at all times.
+ * @type string
+ * @default <i>Empty string</i>
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.infoPostFix
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "infoPostFix": "All records shown are derived from real information."
+ * }
+ * } );
+ * } );
+ */
+ "sInfoPostFix": "",
+
+
+ /**
+ * This decimal place operator is a little different from the other
+ * language options since DataTables doesn't output floating point
+ * numbers, so it won't ever use this for display of a number. Rather,
+ * what this parameter does is modify the sort methods of the table so
+ * that numbers which are in a format which has a character other than
+ * a period (`.`) as a decimal place will be sorted numerically.
+ *
+ * Note that numbers with different decimal places cannot be shown in
+ * the same table and still be sortable, the table must be consistent.
+ * However, multiple different tables on the page can use different
+ * decimal place characters.
+ * @type string
+ * @default
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.decimal
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "decimal": ","
+ * "thousands": "."
+ * }
+ * } );
+ * } );
+ */
+ "sDecimal": "",
+
+
+ /**
+ * DataTables has a build in number formatter (`formatNumber`) which is
+ * used to format large numbers that are used in the table information.
+ * By default a comma is used, but this can be trivially changed to any
+ * character you wish with this parameter.
+ * @type string
+ * @default ,
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.thousands
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "thousands": "'"
+ * }
+ * } );
+ * } );
+ */
+ "sThousands": ",",
+
+
+ /**
+ * Detail the action that will be taken when the drop down menu for the
+ * pagination length option is changed. The '_MENU_' variable is replaced
+ * with a default select list of 10, 25, 50 and 100, and can be replaced
+ * with a custom select box if required.
+ * @type string
+ * @default Show _MENU_ entries
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.lengthMenu
+ *
+ * @example
+ * // Language change only
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "lengthMenu": "Display _MENU_ records"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Language and options change
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "lengthMenu": 'Display <select>'+
+ * '<option value="10">10</option>'+
+ * '<option value="20">20</option>'+
+ * '<option value="30">30</option>'+
+ * '<option value="40">40</option>'+
+ * '<option value="50">50</option>'+
+ * '<option value="-1">All</option>'+
+ * '</select> records'
+ * }
+ * } );
+ * } );
+ */
+ "sLengthMenu": "Show _MENU_ entries",
+
+
+ /**
+ * When using Ajax sourced data and during the first draw when DataTables is
+ * gathering the data, this message is shown in an empty row in the table to
+ * indicate to the end user the the data is being loaded. Note that this
+ * parameter is not used when loading data by server-side processing, just
+ * Ajax sourced data with client-side processing.
+ * @type string
+ * @default Loading...
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.loadingRecords
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "loadingRecords": "Please wait - loading..."
+ * }
+ * } );
+ * } );
+ */
+ "sLoadingRecords": "Loading...",
+
+
+ /**
+ * Text which is displayed when the table is processing a user action
+ * (usually a sort command or similar).
+ * @type string
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.processing
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "processing": "DataTables is currently busy"
+ * }
+ * } );
+ * } );
+ */
+ "sProcessing": "",
+
+
+ /**
+ * Details the actions that will be taken when the user types into the
+ * filtering input text box. The variable "_INPUT_", if used in the string,
+ * is replaced with the HTML text box for the filtering input allowing
+ * control over where it appears in the string. If "_INPUT_" is not given
+ * then the input box is appended to the string automatically.
+ * @type string
+ * @default Search:
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.search
+ *
+ * @example
+ * // Input text box will be appended at the end automatically
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "search": "Filter records:"
+ * }
+ * } );
+ * } );
+ *
+ * @example
+ * // Specify where the filter should appear
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "search": "Apply filter _INPUT_ to table"
+ * }
+ * } );
+ * } );
+ */
+ "sSearch": "Search:",
+
+
+ /**
+ * Assign a `placeholder` attribute to the search `input` element
+ * @type string
+ * @default
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.searchPlaceholder
+ */
+ "sSearchPlaceholder": "",
+
+
+ /**
+ * All of the language information can be stored in a file on the
+ * server-side, which DataTables will look up if this parameter is passed.
+ * It must store the URL of the language file, which is in a JSON format,
+ * and the object has the same properties as the oLanguage object in the
+ * initialiser object (i.e. the above parameters). Please refer to one of
+ * the example language files to see how this works in action.
+ * @type string
+ * @default <i>Empty string - i.e. disabled</i>
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.url
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "url": "http://www.sprymedia.co.uk/dataTables/lang.txt"
+ * }
+ * } );
+ * } );
+ */
+ "sUrl": "",
+
+
+ /**
+ * Text shown inside the table records when the is no information to be
+ * displayed after filtering. `emptyTable` is shown when there is simply no
+ * information in the table at all (regardless of filtering).
+ * @type string
+ * @default No matching records found
+ *
+ * @dtopt Language
+ * @name DataTable.defaults.language.zeroRecords
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "language": {
+ * "zeroRecords": "No records to display"
+ * }
+ * } );
+ * } );
+ */
+ "sZeroRecords": "No matching records found"
+ },
+
+
+ /**
+ * This parameter allows you to have define the global filtering state at
+ * initialisation time. As an object the `search` parameter must be
+ * defined, but all other parameters are optional. When `regex` is true,
+ * the search string will be treated as a regular expression, when false
+ * (default) it will be treated as a straight string. When `smart`
+ * DataTables will use it's smart filtering methods (to word match at
+ * any point in the data), when false this will not be done.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.search
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "search": {"search": "Initial search"}
+ * } );
+ * } )
+ */
+ "oSearch": $.extend( {}, DataTable.models.oSearch ),
+
+
+ /**
+ * __Deprecated__ The functionality provided by this parameter has now been
+ * superseded by that provided through `ajax`, which should be used instead.
+ *
+ * By default DataTables will look for the property `data` (or `aaData` for
+ * compatibility with DataTables 1.9-) when obtaining data from an Ajax
+ * source or for server-side processing - this parameter allows that
+ * property to be changed. You can use Javascript dotted object notation to
+ * get a data source for multiple levels of nesting.
+ * @type string
+ * @default data
+ *
+ * @dtopt Options
+ * @dtopt Server-side
+ * @name DataTable.defaults.ajaxDataProp
+ *
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
+ */
+ "sAjaxDataProp": "data",
+
+
+ /**
+ * __Deprecated__ The functionality provided by this parameter has now been
+ * superseded by that provided through `ajax`, which should be used instead.
+ *
+ * You can instruct DataTables to load data from an external
+ * source using this parameter (use aData if you want to pass data in you
+ * already have). Simply provide a url a JSON object can be obtained from.
+ * @type string
+ * @default null
+ *
+ * @dtopt Options
+ * @dtopt Server-side
+ * @name DataTable.defaults.ajaxSource
+ *
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
+ */
+ "sAjaxSource": null,
+
+
+ /**
+ * This initialisation variable allows you to specify exactly where in the
+ * DOM you want DataTables to inject the various controls it adds to the page
+ * (for example you might want the pagination controls at the top of the
+ * table). DIV elements (with or without a custom class) can also be added to
+ * aid styling. The follow syntax is used:
+ * <ul>
+ * <li>The following options are allowed:
+ * <ul>
+ * <li>'l' - Length changing</li>
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * </li>
+ * <li>The following constants are allowed:
+ * <ul>
+ * <li>'H' - jQueryUI theme "header" classes ('fg-toolbar ui-widget-header ui-corner-tl ui-corner-tr ui-helper-clearfix')</li>
+ * <li>'F' - jQueryUI theme "footer" classes ('fg-toolbar ui-widget-header ui-corner-bl ui-corner-br ui-helper-clearfix')</li>
+ * </ul>
+ * </li>
+ * <li>The following syntax is expected:
+ * <ul>
+ * <li>'<' and '>' - div elements</li>
+ * <li>'<"class" and '>' - div with a class</li>
+ * <li>'<"#id" and '>' - div with an ID</li>
+ * </ul>
+ * </li>
+ * <li>Examples:
+ * <ul>
+ * <li>'<"wrapper"flipt>'</li>
+ * <li>'<lf<t>ip>'</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * @type string
+ * @default lfrtip <i>(when `jQueryUI` is false)</i> <b>or</b>
+ * <"H"lfr>t<"F"ip> <i>(when `jQueryUI` is true)</i>
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.dom
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "dom": '<"top"i>rt<"bottom"flp><"clear">'
+ * } );
+ * } );
+ */
+ "sDom": "lfrtip",
+
+
+ /**
+ * Search delay option. This will throttle full table searches that use the
+ * DataTables provided search input element (it does not effect calls to
+ * `dt-api search()`, providing a delay before the search is made.
+ * @type integer
+ * @default 0
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.searchDelay
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "searchDelay": 200
+ * } );
+ * } )
+ */
+ "searchDelay": null,
+
+
+ /**
+ * DataTables features six different built-in options for the buttons to
+ * display for pagination control:
+ *
+ * * `numbers` - Page number buttons only
+ * * `simple` - 'Previous' and 'Next' buttons only
+ * * 'simple_numbers` - 'Previous' and 'Next' buttons, plus page numbers
+ * * `full` - 'First', 'Previous', 'Next' and 'Last' buttons
+ * * `full_numbers` - 'First', 'Previous', 'Next' and 'Last' buttons, plus page numbers
+ * * `first_last_numbers` - 'First' and 'Last' buttons, plus page numbers
+ *
+ * Further methods can be added using {@link DataTable.ext.oPagination}.
+ * @type string
+ * @default simple_numbers
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.pagingType
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "pagingType": "full_numbers"
+ * } );
+ * } )
+ */
+ "sPaginationType": "simple_numbers",
+
+
+ /**
+ * Enable horizontal scrolling. When a table is too wide to fit into a
+ * certain layout, or you have a large number of columns in the table, you
+ * can enable x-scrolling to show the table in a viewport, which can be
+ * scrolled. This property can be `true` which will allow the table to
+ * scroll horizontally when needed, or any CSS unit, or a number (in which
+ * case it will be treated as a pixel measurement). Setting as simply `true`
+ * is recommended.
+ * @type boolean|string
+ * @default <i>blank string - i.e. disabled</i>
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.scrollX
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "scrollX": true,
+ * "scrollCollapse": true
+ * } );
+ * } );
+ */
+ "sScrollX": "",
+
+
+ /**
+ * This property can be used to force a DataTable to use more width than it
+ * might otherwise do when x-scrolling is enabled. For example if you have a
+ * table which requires to be well spaced, this parameter is useful for
+ * "over-sizing" the table, and thus forcing scrolling. This property can by
+ * any CSS unit, or a number (in which case it will be treated as a pixel
+ * measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ *
+ * @dtopt Options
+ * @name DataTable.defaults.scrollXInner
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "scrollX": "100%",
+ * "scrollXInner": "110%"
+ * } );
+ * } );
+ */
+ "sScrollXInner": "",
+
+
+ /**
+ * Enable vertical scrolling. Vertical scrolling will constrain the DataTable
+ * to the given height, and enable scrolling for any data which overflows the
+ * current viewport. This can be used as an alternative to paging to display
+ * a lot of data in a small area (although paging and scrolling can both be
+ * enabled at the same time). This property can be any CSS unit, or a number
+ * (in which case it will be treated as a pixel measurement).
+ * @type string
+ * @default <i>blank string - i.e. disabled</i>
+ *
+ * @dtopt Features
+ * @name DataTable.defaults.scrollY
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "scrollY": "200px",
+ * "paginate": false
+ * } );
+ * } );
+ */
+ "sScrollY": "",
+
+
+ /**
+ * __Deprecated__ The functionality provided by this parameter has now been
+ * superseded by that provided through `ajax`, which should be used instead.
+ *
+ * Set the HTTP method that is used to make the Ajax call for server-side
+ * processing or Ajax sourced data.
+ * @type string
+ * @default GET
+ *
+ * @dtopt Options
+ * @dtopt Server-side
+ * @name DataTable.defaults.serverMethod
+ *
+ * @deprecated 1.10. Please use `ajax` for this functionality now.
+ */
+ "sServerMethod": "GET",
+
+
+ /**
+ * DataTables makes use of renderers when displaying HTML elements for
+ * a table. These renderers can be added or modified by plug-ins to
+ * generate suitable mark-up for a site. For example the Bootstrap
+ * integration plug-in for DataTables uses a paging button renderer to
+ * display pagination buttons in the mark-up required by Bootstrap.
+ *
+ * For further information about the renderers available see
+ * DataTable.ext.renderer
+ * @type string|object
+ * @default null
+ *
+ * @name DataTable.defaults.renderer
+ *
+ */
+ "renderer": null,
+
+
+ /**
+ * Set the data property name that DataTables should use to get a row's id
+ * to set as the `id` property in the node.
+ * @type string
+ * @default DT_RowId
+ *
+ * @name DataTable.defaults.rowId
+ */
+ "rowId": "DT_RowId"
+ };
+
+ _fnHungarianMap( DataTable.defaults );
+
+
+
+ /*
+ * Developer note - See note in model.defaults.js about the use of Hungarian
+ * notation and camel case.
+ */
+
+ /**
+ * Column options that can be given to DataTables at initialisation time.
+ * @namespace
+ */
+ DataTable.defaults.column = {
+ /**
+ * Define which column(s) an order will occur on for this column. This
+ * allows a column's ordering to take multiple columns into account when
+ * doing a sort or use the data from a different column. For example first
+ * name / last name columns make sense to do a multi-column sort over the
+ * two columns.
+ * @type array|int
+ * @default null <i>Takes the value of the column index automatically</i>
+ *
+ * @name DataTable.defaults.column.orderData
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "orderData": [ 0, 1 ], "targets": [ 0 ] },
+ * { "orderData": [ 1, 0 ], "targets": [ 1 ] },
+ * { "orderData": 2, "targets": [ 2 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "orderData": [ 0, 1 ] },
+ * { "orderData": [ 1, 0 ] },
+ * { "orderData": 2 },
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "aDataSort": null,
+ "iDataSort": -1,
+
+
+ /**
+ * You can control the default ordering direction, and even alter the
+ * behaviour of the sort handler (i.e. only allow ascending ordering etc)
+ * using this parameter.
+ * @type array
+ * @default [ 'asc', 'desc' ]
+ *
+ * @name DataTable.defaults.column.orderSequence
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "orderSequence": [ "asc" ], "targets": [ 1 ] },
+ * { "orderSequence": [ "desc", "asc", "asc" ], "targets": [ 2 ] },
+ * { "orderSequence": [ "desc" ], "targets": [ 3 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * null,
+ * { "orderSequence": [ "asc" ] },
+ * { "orderSequence": [ "desc", "asc", "asc" ] },
+ * { "orderSequence": [ "desc" ] },
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "asSorting": [ 'asc', 'desc' ],
+
+
+ /**
+ * Enable or disable filtering on the data in this column.
+ * @type boolean
+ * @default true
+ *
+ * @name DataTable.defaults.column.searchable
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "searchable": false, "targets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "searchable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSearchable": true,
+
+
+ /**
+ * Enable or disable ordering on this column.
+ * @type boolean
+ * @default true
+ *
+ * @name DataTable.defaults.column.orderable
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "orderable": false, "targets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "orderable": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bSortable": true,
+
+
+ /**
+ * Enable or disable the display of this column.
+ * @type boolean
+ * @default true
+ *
+ * @name DataTable.defaults.column.visible
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "visible": false, "targets": [ 0 ] }
+ * ] } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "visible": false },
+ * null,
+ * null,
+ * null,
+ * null
+ * ] } );
+ * } );
+ */
+ "bVisible": true,
+
+
+ /**
+ * Developer definable function that is called whenever a cell is created (Ajax source,
+ * etc) or processed for input (DOM source). This can be used as a compliment to mRender
+ * allowing you to modify the DOM element (add background colour for example) when the
+ * element is available.
+ * @type function
+ * @param {element} td The TD node that has been created
+ * @param {*} cellData The Data for the cell
+ * @param {array|object} rowData The data for the whole row
+ * @param {int} row The row index for the aoData data store
+ * @param {int} col The column index for aoColumns
+ *
+ * @name DataTable.defaults.column.createdCell
+ * @dtopt Columns
+ *
+ * @example
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [3],
+ * "createdCell": function (td, cellData, rowData, row, col) {
+ * if ( cellData == "1.7" ) {
+ * $(td).css('color', 'blue')
+ * }
+ * }
+ * } ]
+ * });
+ * } );
+ */
+ "fnCreatedCell": null,
+
+
+ /**
+ * This parameter has been replaced by `data` in DataTables to ensure naming
+ * consistency. `dataProp` can still be used, as there is backwards
+ * compatibility in DataTables for this option, but it is strongly
+ * recommended that you use `data` in preference to `dataProp`.
+ * @name DataTable.defaults.column.dataProp
+ */
+
+
+ /**
+ * This property can be used to read data from any data source property,
+ * including deeply nested objects / properties. `data` can be given in a
+ * number of different ways which effect its behaviour:
+ *
+ * * `integer` - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).
+ * * `string` - read an object property from the data source. There are
+ * three 'special' options that can be used in the string to alter how
+ * DataTables reads the data from the source object:
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
+ * Javascript to read from nested objects, so to can the options
+ * specified in `data`. For example: `browser.version` or
+ * `browser.name`. If your object parameter name contains a period, use
+ * `\\` to escape it - i.e. `first\\.name`.
+ * * `[]` - Array notation. DataTables can automatically combine data
+ * from and array source, joining the data with the characters provided
+ * between the two brackets. For example: `name[, ]` would provide a
+ * comma-space separated list from the source array. If no characters
+ * are provided between the brackets, the original array source is
+ * returned.
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
+ * execute a function of the name given. For example: `browser()` for a
+ * simple function on the data source, `browser.version()` for a
+ * function in a nested property or even `browser().version` to get an
+ * object property if the function called returns an object. Note that
+ * function notation is recommended for use in `render` rather than
+ * `data` as it is much simpler to use as a renderer.
+ * * `null` - use the original data source for the row rather than plucking
+ * data directly from it. This action has effects on two other
+ * initialisation options:
+ * * `defaultContent` - When null is given as the `data` option and
+ * `defaultContent` is specified for the column, the value defined by
+ * `defaultContent` will be used for the cell.
+ * * `render` - When null is used for the `data` option and the `render`
+ * option is specified for the column, the whole data source for the
+ * row is used for the renderer.
+ * * `function` - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * * Parameters:
+ * * `{array|object}` The data source for the row
+ * * `{string}` The type call data requested - this will be 'set' when
+ * setting data or 'filter', 'display', 'type', 'sort' or undefined
+ * when gathering data. Note that when `undefined` is given for the
+ * type DataTables expects to get the raw data for the object back<
+ * * `{*}` Data to set when the second parameter is 'set'.
+ * * Return:
+ * * The return value from the function is not required when 'set' is
+ * the type of call, but otherwise the return is what will be used
+ * for the data requested.
+ *
+ * Note that `data` is a getter and setter option. If you just require
+ * formatting of data for output, you will likely want to use `render` which
+ * is simply a getter and thus simpler to use.
+ *
+ * Note that prior to DataTables 1.9.2 `data` was called `mDataProp`. The
+ * name change reflects the flexibility of this property and is consistent
+ * with the naming of mRender. If 'mDataProp' is given, then it will still
+ * be used by DataTables, as it automatically maps the old name to the new
+ * if required.
+ *
+ * @type string|int|function|null
+ * @default null <i>Use automatically calculated column index</i>
+ *
+ * @name DataTable.defaults.column.data
+ * @dtopt Columns
+ *
+ * @example
+ * // Read table data from objects
+ * // JSON structure for each row:
+ * // {
+ * // "engine": {value},
+ * // "browser": {value},
+ * // "platform": {value},
+ * // "version": {value},
+ * // "grade": {value}
+ * // }
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "ajaxSource": "sources/objects.txt",
+ * "columns": [
+ * { "data": "engine" },
+ * { "data": "browser" },
+ * { "data": "platform" },
+ * { "data": "version" },
+ * { "data": "grade" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Read information from deeply nested objects
+ * // JSON structure for each row:
+ * // {
+ * // "engine": {value},
+ * // "browser": {value},
+ * // "platform": {
+ * // "inner": {value}
+ * // },
+ * // "details": [
+ * // {value}, {value}
+ * // ]
+ * // }
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "ajaxSource": "sources/deep.txt",
+ * "columns": [
+ * { "data": "engine" },
+ * { "data": "browser" },
+ * { "data": "platform.inner" },
+ * { "data": "details.0" },
+ * { "data": "details.1" }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `data` as a function to provide different information for
+ * // sorting, filtering and display. In this case, currency (price)
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": function ( source, type, val ) {
+ * if (type === 'set') {
+ * source.price = val;
+ * // Store the computed display and filter values for efficiency
+ * source.price_display = val=="" ? "" : "$"+numberFormat(val);
+ * source.price_filter = val=="" ? "" : "$"+numberFormat(val)+" "+val;
+ * return;
+ * }
+ * else if (type === 'display') {
+ * return source.price_display;
+ * }
+ * else if (type === 'filter') {
+ * return source.price_filter;
+ * }
+ * // 'sort', 'type' and undefined all just use the integer
+ * return source.price;
+ * }
+ * } ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using default content
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": null,
+ * "defaultContent": "Click to edit"
+ * } ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using array notation - outputting a list from an array
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": "name[, ]"
+ * } ]
+ * } );
+ * } );
+ *
+ */
+ "mData": null,
+
+
+ /**
+ * This property is the rendering partner to `data` and it is suggested that
+ * when you want to manipulate data for display (including filtering,
+ * sorting etc) without altering the underlying data for the table, use this
+ * property. `render` can be considered to be the the read only companion to
+ * `data` which is read / write (then as such more complex). Like `data`
+ * this option can be given in a number of different ways to effect its
+ * behaviour:
+ *
+ * * `integer` - treated as an array index for the data source. This is the
+ * default that DataTables uses (incrementally increased for each column).
+ * * `string` - read an object property from the data source. There are
+ * three 'special' options that can be used in the string to alter how
+ * DataTables reads the data from the source object:
+ * * `.` - Dotted Javascript notation. Just as you use a `.` in
+ * Javascript to read from nested objects, so to can the options
+ * specified in `data`. For example: `browser.version` or
+ * `browser.name`. If your object parameter name contains a period, use
+ * `\\` to escape it - i.e. `first\\.name`.
+ * * `[]` - Array notation. DataTables can automatically combine data
+ * from and array source, joining the data with the characters provided
+ * between the two brackets. For example: `name[, ]` would provide a
+ * comma-space separated list from the source array. If no characters
+ * are provided between the brackets, the original array source is
+ * returned.
+ * * `()` - Function notation. Adding `()` to the end of a parameter will
+ * execute a function of the name given. For example: `browser()` for a
+ * simple function on the data source, `browser.version()` for a
+ * function in a nested property or even `browser().version` to get an
+ * object property if the function called returns an object.
+ * * `object` - use different data for the different data types requested by
+ * DataTables ('filter', 'display', 'type' or 'sort'). The property names
+ * of the object is the data type the property refers to and the value can
+ * defined using an integer, string or function using the same rules as
+ * `render` normally does. Note that an `_` option _must_ be specified.
+ * This is the default value to use if you haven't specified a value for
+ * the data type requested by DataTables.
+ * * `function` - the function given will be executed whenever DataTables
+ * needs to set or get the data for a cell in the column. The function
+ * takes three parameters:
+ * * Parameters:
+ * * {array|object} The data source for the row (based on `data`)
+ * * {string} The type call data requested - this will be 'filter',
+ * 'display', 'type' or 'sort'.
+ * * {array|object} The full data source for the row (not based on
+ * `data`)
+ * * Return:
+ * * The return value from the function is what will be used for the
+ * data requested.
+ *
+ * @type string|int|function|object|null
+ * @default null Use the data source value.
+ *
+ * @name DataTable.defaults.column.render
+ * @dtopt Columns
+ *
+ * @example
+ * // Create a comma separated list from an array of objects
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "ajaxSource": "sources/deep.txt",
+ * "columns": [
+ * { "data": "engine" },
+ * { "data": "browser" },
+ * {
+ * "data": "platform",
+ * "render": "[, ].name"
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Execute a function to obtain data
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": null, // Use the full data source object for the renderer's source
+ * "render": "browserName()"
+ * } ]
+ * } );
+ * } );
+ *
+ * @example
+ * // As an object, extracting different data for the different types
+ * // This would be used with a data source such as:
+ * // { "phone": 5552368, "phone_filter": "5552368 555-2368", "phone_display": "555-2368" }
+ * // Here the `phone` integer is used for sorting and type detection, while `phone_filter`
+ * // (which has both forms) is used for filtering for if a user inputs either format, while
+ * // the formatted phone number is the one that is shown in the table.
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": null, // Use the full data source object for the renderer's source
+ * "render": {
+ * "_": "phone",
+ * "filter": "phone_filter",
+ * "display": "phone_display"
+ * }
+ * } ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Use as a function to create a link from the data source
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "data": "download_link",
+ * "render": function ( data, type, full ) {
+ * return '<a href="'+data+'">Download</a>';
+ * }
+ * } ]
+ * } );
+ * } );
+ */
+ "mRender": null,
+
+
+ /**
+ * Change the cell type created for the column - either TD cells or TH cells. This
+ * can be useful as TH cells have semantic meaning in the table body, allowing them
+ * to act as a header for a row (you may wish to add scope='row' to the TH elements).
+ * @type string
+ * @default td
+ *
+ * @name DataTable.defaults.column.cellType
+ * @dtopt Columns
+ *
+ * @example
+ * // Make the first column use TH cells
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [ {
+ * "targets": [ 0 ],
+ * "cellType": "th"
+ * } ]
+ * } );
+ * } );
+ */
+ "sCellType": "td",
+
+
+ /**
+ * Class to give to each cell in this column.
+ * @type string
+ * @default <i>Empty string</i>
+ *
+ * @name DataTable.defaults.column.class
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "class": "my_class", "targets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "class": "my_class" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sClass": "",
+
+ /**
+ * When DataTables calculates the column widths to assign to each column,
+ * it finds the longest string in each column and then constructs a
+ * temporary table and reads the widths from that. The problem with this
+ * is that "mmm" is much wider then "iiii", but the latter is a longer
+ * string - thus the calculation can go wrong (doing it properly and putting
+ * it into an DOM object and measuring that is horribly(!) slow). Thus as
+ * a "work around" we provide this option. It will append its value to the
+ * text that is found to be the longest string for the column - i.e. padding.
+ * Generally you shouldn't need this!
+ * @type string
+ * @default <i>Empty string<i>
+ *
+ * @name DataTable.defaults.column.contentPadding
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "contentPadding": "mmm"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sContentPadding": "",
+
+
+ /**
+ * Allows a default value to be given for a column's data, and will be used
+ * whenever a null data source is encountered (this can be because `data`
+ * is set to null, or because the data source itself is null).
+ * @type string
+ * @default null
+ *
+ * @name DataTable.defaults.column.defaultContent
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * {
+ * "data": null,
+ * "defaultContent": "Edit",
+ * "targets": [ -1 ]
+ * }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * null,
+ * null,
+ * null,
+ * {
+ * "data": null,
+ * "defaultContent": "Edit"
+ * }
+ * ]
+ * } );
+ * } );
+ */
+ "sDefaultContent": null,
+
+
+ /**
+ * This parameter is only used in DataTables' server-side processing. It can
+ * be exceptionally useful to know what columns are being displayed on the
+ * client side, and to map these to database fields. When defined, the names
+ * also allow DataTables to reorder information from the server if it comes
+ * back in an unexpected order (i.e. if you switch your columns around on the
+ * client-side, your server-side code does not also need updating).
+ * @type string
+ * @default <i>Empty string</i>
+ *
+ * @name DataTable.defaults.column.name
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "name": "engine", "targets": [ 0 ] },
+ * { "name": "browser", "targets": [ 1 ] },
+ * { "name": "platform", "targets": [ 2 ] },
+ * { "name": "version", "targets": [ 3 ] },
+ * { "name": "grade", "targets": [ 4 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "name": "engine" },
+ * { "name": "browser" },
+ * { "name": "platform" },
+ * { "name": "version" },
+ * { "name": "grade" }
+ * ]
+ * } );
+ * } );
+ */
+ "sName": "",
+
+
+ /**
+ * Defines a data source type for the ordering which can be used to read
+ * real-time information from the table (updating the internally cached
+ * version) prior to ordering. This allows ordering to occur on user
+ * editable elements such as form inputs.
+ * @type string
+ * @default std
+ *
+ * @name DataTable.defaults.column.orderDataType
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "orderDataType": "dom-text", "targets": [ 2, 3 ] },
+ * { "type": "numeric", "targets": [ 3 ] },
+ * { "orderDataType": "dom-select", "targets": [ 4 ] },
+ * { "orderDataType": "dom-checkbox", "targets": [ 5 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * null,
+ * null,
+ * { "orderDataType": "dom-text" },
+ * { "orderDataType": "dom-text", "type": "numeric" },
+ * { "orderDataType": "dom-select" },
+ * { "orderDataType": "dom-checkbox" }
+ * ]
+ * } );
+ * } );
+ */
+ "sSortDataType": "std",
+
+
+ /**
+ * The title of this column.
+ * @type string
+ * @default null <i>Derived from the 'TH' value for this column in the
+ * original HTML table.</i>
+ *
+ * @name DataTable.defaults.column.title
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "title": "My column title", "targets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "title": "My column title" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sTitle": null,
+
+
+ /**
+ * The type allows you to specify how the data for this column will be
+ * ordered. Four types (string, numeric, date and html (which will strip
+ * HTML tags before ordering)) are currently available. Note that only date
+ * formats understood by Javascript's Date() object will be accepted as type
+ * date. For example: "Mar 26, 2008 5:03 PM". May take the values: 'string',
+ * 'numeric', 'date' or 'html' (by default). Further types can be adding
+ * through plug-ins.
+ * @type string
+ * @default null <i>Auto-detected from raw data</i>
+ *
+ * @name DataTable.defaults.column.type
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "type": "html", "targets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "type": "html" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sType": null,
+
+
+ /**
+ * Defining the width of the column, this parameter may take any CSS value
+ * (3em, 20px etc). DataTables applies 'smart' widths to columns which have not
+ * been given a specific width through this interface ensuring that the table
+ * remains readable.
+ * @type string
+ * @default null <i>Automatic</i>
+ *
+ * @name DataTable.defaults.column.width
+ * @dtopt Columns
+ *
+ * @example
+ * // Using `columnDefs`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columnDefs": [
+ * { "width": "20%", "targets": [ 0 ] }
+ * ]
+ * } );
+ * } );
+ *
+ * @example
+ * // Using `columns`
+ * $(document).ready( function() {
+ * $('#example').dataTable( {
+ * "columns": [
+ * { "width": "20%" },
+ * null,
+ * null,
+ * null,
+ * null
+ * ]
+ * } );
+ * } );
+ */
+ "sWidth": null
+ };
+
+ _fnHungarianMap( DataTable.defaults.column );
+
+
+
+ /**
+ * DataTables settings object - this holds all the information needed for a
+ * given table, including configuration, data and current application of the
+ * table options. DataTables does not have a single instance for each DataTable
+ * with the settings attached to that instance, but rather instances of the
+ * DataTable "class" are created on-the-fly as needed (typically by a
+ * $().dataTable() call) and the settings object is then applied to that
+ * instance.
+ *
+ * Note that this object is related to {@link DataTable.defaults} but this
+ * one is the internal data store for DataTables's cache of columns. It should
+ * NOT be manipulated outside of DataTables. Any configuration should be done
+ * through the initialisation options.
+ * @namespace
+ * @todo Really should attach the settings object to individual instances so we
+ * don't need to create new instances on each $().dataTable() call (if the
+ * table already exists). It would also save passing oSettings around and
+ * into every single function. However, this is a very significant
+ * architecture change for DataTables and will almost certainly break
+ * backwards compatibility with older installations. This is something that
+ * will be done in 2.0.
+ */
+ DataTable.models.oSettings = {
+ /**
+ * Primary features of DataTables and their enablement state.
+ * @namespace
+ */
+ "oFeatures": {
+
+ /**
+ * Flag to say if DataTables should automatically try to calculate the
+ * optimum table and columns widths (true) or not (false).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bAutoWidth": null,
+
+ /**
+ * Delay the creation of TR and TD elements until they are actually
+ * needed by a driven page draw. This can give a significant speed
+ * increase for Ajax source and Javascript source data, but makes no
+ * difference at all for DOM and server-side processing tables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bDeferRender": null,
+
+ /**
+ * Enable filtering on the table or not. Note that if this is disabled
+ * then there is no filtering at all on the table, including fnFilter.
+ * To just remove the filtering input use sDom and remove the 'f' option.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bFilter": null,
+
+ /**
+ * Table information element (the 'Showing x of y records' div) enable
+ * flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bInfo": null,
+
+ /**
+ * Present a user control allowing the end user to change the page size
+ * when pagination is enabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bLengthChange": null,
+
+ /**
+ * Pagination enabled or not. Note that if this is disabled then length
+ * changing must also be disabled.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bPaginate": null,
+
+ /**
+ * Processing indicator enable flag whenever DataTables is enacting a
+ * user request - typically an Ajax request for server-side processing.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bProcessing": null,
+
+ /**
+ * Server-side processing enabled flag - when enabled DataTables will
+ * get all data from the server for every draw - there is no filtering,
+ * sorting or paging done on the client-side.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bServerSide": null,
+
+ /**
+ * Sorting enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSort": null,
+
+ /**
+ * Multi-column sorting
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortMulti": null,
+
+ /**
+ * Apply a class to the columns which are being sorted to provide a
+ * visual highlight or not. This can slow things down when enabled since
+ * there is a lot of DOM interaction.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortClasses": null,
+
+ /**
+ * State saving enablement flag.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bStateSave": null
+ },
+
+
+ /**
+ * Scrolling settings for a table.
+ * @namespace
+ */
+ "oScroll": {
+ /**
+ * When the table is shorter in height than sScrollY, collapse the
+ * table container down to the height of the table (when true).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bCollapse": null,
+
+ /**
+ * Width of the scrollbar for the web-browser's platform. Calculated
+ * during table initialisation.
+ * @type int
+ * @default 0
+ */
+ "iBarWidth": 0,
+
+ /**
+ * Viewport width for horizontal scrolling. Horizontal scrolling is
+ * disabled if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sX": null,
+
+ /**
+ * Width to expand the table to when using x-scrolling. Typically you
+ * should not need to use this.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @deprecated
+ */
+ "sXInner": null,
+
+ /**
+ * Viewport height for vertical scrolling. Vertical scrolling is disabled
+ * if an empty string.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sY": null
+ },
+
+ /**
+ * Language information for the table.
+ * @namespace
+ * @extends DataTable.defaults.oLanguage
+ */
+ "oLanguage": {
+ /**
+ * Information callback function. See
+ * {@link DataTable.defaults.fnInfoCallback}
+ * @type function
+ * @default null
+ */
+ "fnInfoCallback": null
+ },
+
+ /**
+ * Browser support parameters
+ * @namespace
+ */
+ "oBrowser": {
+ /**
+ * Indicate if the browser incorrectly calculates width:100% inside a
+ * scrolling element (IE6/7)
+ * @type boolean
+ * @default false
+ */
+ "bScrollOversize": false,
+
+ /**
+ * Determine if the vertical scrollbar is on the right or left of the
+ * scrolling container - needed for rtl language layout, although not
+ * all browsers move the scrollbar (Safari).
+ * @type boolean
+ * @default false
+ */
+ "bScrollbarLeft": false,
+
+ /**
+ * Flag for if `getBoundingClientRect` is fully supported or not
+ * @type boolean
+ * @default false
+ */
+ "bBounding": false,
+
+ /**
+ * Browser scrollbar width
+ * @type integer
+ * @default 0
+ */
+ "barWidth": 0
+ },
+
+
+ "ajax": null,
+
+
+ /**
+ * Array referencing the nodes which are used for the features. The
+ * parameters of this object match what is allowed by sDom - i.e.
+ * <ul>
+ * <li>'l' - Length changing</li>
+ * <li>'f' - Filtering input</li>
+ * <li>'t' - The table!</li>
+ * <li>'i' - Information</li>
+ * <li>'p' - Pagination</li>
+ * <li>'r' - pRocessing</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aanFeatures": [],
+
+ /**
+ * Store data information - see {@link DataTable.models.oRow} for detailed
+ * information.
+ * @type array
+ * @default []
+ */
+ "aoData": [],
+
+ /**
+ * Array of indexes which are in the current display (after filtering etc)
+ * @type array
+ * @default []
+ */
+ "aiDisplay": [],
+
+ /**
+ * Array of indexes for display - no filtering
+ * @type array
+ * @default []
+ */
+ "aiDisplayMaster": [],
+
+ /**
+ * Map of row ids to data indexes
+ * @type object
+ * @default {}
+ */
+ "aIds": {},
+
+ /**
+ * Store information about each column that is in use
+ * @type array
+ * @default []
+ */
+ "aoColumns": [],
+
+ /**
+ * Store information about the table's header
+ * @type array
+ * @default []
+ */
+ "aoHeader": [],
+
+ /**
+ * Store information about the table's footer
+ * @type array
+ * @default []
+ */
+ "aoFooter": [],
+
+ /**
+ * Store the applied global search information in case we want to force a
+ * research or compare the old search to a new one.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @namespace
+ * @extends DataTable.models.oSearch
+ */
+ "oPreviousSearch": {},
+
+ /**
+ * Store the applied search for each column - see
+ * {@link DataTable.models.oSearch} for the format that is used for the
+ * filtering information for each column.
+ * @type array
+ * @default []
+ */
+ "aoPreSearchCols": [],
+
+ /**
+ * Sorting that is applied to the table. Note that the inner arrays are
+ * used in the following manner:
+ * <ul>
+ * <li>Index 0 - column number</li>
+ * <li>Index 1 - current sorting direction</li>
+ * </ul>
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @todo These inner arrays should really be objects
+ */
+ "aaSorting": null,
+
+ /**
+ * Sorting that is always applied to the table (i.e. prefixed in front of
+ * aaSorting).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "aaSortingFixed": [],
+
+ /**
+ * Classes to use for the striping of a table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "asStripeClasses": null,
+
+ /**
+ * If restoring a table - we should restore its striping classes as well
+ * @type array
+ * @default []
+ */
+ "asDestroyStripes": [],
+
+ /**
+ * If restoring a table - we should restore its width
+ * @type int
+ * @default 0
+ */
+ "sDestroyWidth": 0,
+
+ /**
+ * Callback functions array for every time a row is inserted (i.e. on a draw).
+ * @type array
+ * @default []
+ */
+ "aoRowCallback": [],
+
+ /**
+ * Callback functions for the header on each draw.
+ * @type array
+ * @default []
+ */
+ "aoHeaderCallback": [],
+
+ /**
+ * Callback function for the footer on each draw.
+ * @type array
+ * @default []
+ */
+ "aoFooterCallback": [],
+
+ /**
+ * Array of callback functions for draw callback functions
+ * @type array
+ * @default []
+ */
+ "aoDrawCallback": [],
+
+ /**
+ * Array of callback functions for row created function
+ * @type array
+ * @default []
+ */
+ "aoRowCreatedCallback": [],
+
+ /**
+ * Callback functions for just before the table is redrawn. A return of
+ * false will be used to cancel the draw.
+ * @type array
+ * @default []
+ */
+ "aoPreDrawCallback": [],
+
+ /**
+ * Callback functions for when the table has been initialised.
+ * @type array
+ * @default []
+ */
+ "aoInitComplete": [],
+
+
+ /**
+ * Callbacks for modifying the settings to be stored for state saving, prior to
+ * saving state.
+ * @type array
+ * @default []
+ */
+ "aoStateSaveParams": [],
+
+ /**
+ * Callbacks for modifying the settings that have been stored for state saving
+ * prior to using the stored values to restore the state.
+ * @type array
+ * @default []
+ */
+ "aoStateLoadParams": [],
+
+ /**
+ * Callbacks for operating on the settings object once the saved state has been
+ * loaded
+ * @type array
+ * @default []
+ */
+ "aoStateLoaded": [],
+
+ /**
+ * Cache the table ID for quick access
+ * @type string
+ * @default <i>Empty string</i>
+ */
+ "sTableId": "",
+
+ /**
+ * The TABLE node for the main table
+ * @type node
+ * @default null
+ */
+ "nTable": null,
+
+ /**
+ * Permanent ref to the thead element
+ * @type node
+ * @default null
+ */
+ "nTHead": null,
+
+ /**
+ * Permanent ref to the tfoot element - if it exists
+ * @type node
+ * @default null
+ */
+ "nTFoot": null,
+
+ /**
+ * Permanent ref to the tbody element
+ * @type node
+ * @default null
+ */
+ "nTBody": null,
+
+ /**
+ * Cache the wrapper node (contains all DataTables controlled elements)
+ * @type node
+ * @default null
+ */
+ "nTableWrapper": null,
+
+ /**
+ * Indicate if when using server-side processing the loading of data
+ * should be deferred until the second draw.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ * @default false
+ */
+ "bDeferLoading": false,
+
+ /**
+ * Indicate if all required information has been read in
+ * @type boolean
+ * @default false
+ */
+ "bInitialised": false,
+
+ /**
+ * Information about open rows. Each object in the array has the parameters
+ * 'nTr' and 'nParent'
+ * @type array
+ * @default []
+ */
+ "aoOpenRows": [],
+
+ /**
+ * Dictate the positioning of DataTables' control elements - see
+ * {@link DataTable.model.oInit.sDom}.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sDom": null,
+
+ /**
+ * Search delay (in mS)
+ * @type integer
+ * @default null
+ */
+ "searchDelay": null,
+
+ /**
+ * Which type of pagination should be used.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default two_button
+ */
+ "sPaginationType": "two_button",
+
+ /**
+ * The state duration (for `stateSave`) in seconds.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type int
+ * @default 0
+ */
+ "iStateDuration": 0,
+
+ /**
+ * Array of callback functions for state saving. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the JSON string to save that has been thus far created. Returns
+ * a JSON string to be inserted into a json object
+ * (i.e. '"param": [ 0, 1, 2]')</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateSave": [],
+
+ /**
+ * Array of callback functions for state loading. Each array element is an
+ * object with the following parameters:
+ * <ul>
+ * <li>function:fn - function to call. Takes two parameters, oSettings
+ * and the object stored. May return false to cancel state loading</li>
+ * <li>string:sName - name of callback</li>
+ * </ul>
+ * @type array
+ * @default []
+ */
+ "aoStateLoad": [],
+
+ /**
+ * State that was saved. Useful for back reference
+ * @type object
+ * @default null
+ */
+ "oSavedState": null,
+
+ /**
+ * State that was loaded. Useful for back reference
+ * @type object
+ * @default null
+ */
+ "oLoadedState": null,
+
+ /**
+ * Source url for AJAX data for the table.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ * @default null
+ */
+ "sAjaxSource": null,
+
+ /**
+ * Property from a given object from which to read the table data from. This
+ * can be an empty string (when not server-side processing), in which case
+ * it is assumed an an array is given directly.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sAjaxDataProp": null,
+
+ /**
+ * The last jQuery XHR object that was used for server-side data gathering.
+ * This can be used for working with the XHR information in one of the
+ * callbacks
+ * @type object
+ * @default null
+ */
+ "jqXHR": null,
+
+ /**
+ * JSON returned from the server in the last Ajax request
+ * @type object
+ * @default undefined
+ */
+ "json": undefined,
+
+ /**
+ * Data submitted as part of the last Ajax request
+ * @type object
+ * @default undefined
+ */
+ "oAjaxData": undefined,
+
+ /**
+ * Function to get the server-side data.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnServerData": null,
+
+ /**
+ * Functions which are called prior to sending an Ajax request so extra
+ * parameters can easily be sent to the server
+ * @type array
+ * @default []
+ */
+ "aoServerParams": [],
+
+ /**
+ * Send the XHR HTTP method - GET or POST (could be PUT or DELETE if
+ * required).
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type string
+ */
+ "sServerMethod": null,
+
+ /**
+ * Format numbers for display.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type function
+ */
+ "fnFormatNumber": null,
+
+ /**
+ * List of options that can be used for the user selectable length menu.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type array
+ * @default []
+ */
+ "aLengthMenu": null,
+
+ /**
+ * Counter for the draws that the table does. Also used as a tracker for
+ * server-side processing
+ * @type int
+ * @default 0
+ */
+ "iDraw": 0,
+
+ /**
+ * Indicate if a redraw is being done - useful for Ajax
+ * @type boolean
+ * @default false
+ */
+ "bDrawing": false,
+
+ /**
+ * Draw index (iDraw) of the last error when parsing the returned data
+ * @type int
+ * @default -1
+ */
+ "iDrawError": -1,
+
+ /**
+ * Paging display length
+ * @type int
+ * @default 10
+ */
+ "_iDisplayLength": 10,
+
+ /**
+ * Paging start point - aiDisplay index
+ * @type int
+ * @default 0
+ */
+ "_iDisplayStart": 0,
+
+ /**
+ * Server-side processing - number of records in the result set
+ * (i.e. before filtering), Use fnRecordsTotal rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type int
+ * @default 0
+ * @private
+ */
+ "_iRecordsTotal": 0,
+
+ /**
+ * Server-side processing - number of records in the current display set
+ * (i.e. after filtering). Use fnRecordsDisplay rather than
+ * this property to get the value of the number of records, regardless of
+ * the server-side processing setting.
+ * @type boolean
+ * @default 0
+ * @private
+ */
+ "_iRecordsDisplay": 0,
+
+ /**
+ * The classes to use for the table
+ * @type object
+ * @default {}
+ */
+ "oClasses": {},
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if filtering has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bFiltered": false,
+
+ /**
+ * Flag attached to the settings object so you can check in the draw
+ * callback if sorting has been done in the draw. Deprecated in favour of
+ * events.
+ * @type boolean
+ * @default false
+ * @deprecated
+ */
+ "bSorted": false,
+
+ /**
+ * Indicate that if multiple rows are in the header and there is more than
+ * one unique cell per column, if the top one (true) or bottom one (false)
+ * should be used for sorting / title by DataTables.
+ * Note that this parameter will be set by the initialisation routine. To
+ * set a default use {@link DataTable.defaults}.
+ * @type boolean
+ */
+ "bSortCellsTop": null,
+
+ /**
+ * Initialisation object that is used for the table
+ * @type object
+ * @default null
+ */
+ "oInit": null,
+
+ /**
+ * Destroy callback functions - for plug-ins to attach themselves to the
+ * destroy so they can clean up markup and events.
+ * @type array
+ * @default []
+ */
+ "aoDestroyCallback": [],
+
+
+ /**
+ * Get the number of records in the current record set, before filtering
+ * @type function
+ */
+ "fnRecordsTotal": function ()
+ {
+ return _fnDataSource( this ) == 'ssp' ?
+ this._iRecordsTotal * 1 :
+ this.aiDisplayMaster.length;
+ },
+
+ /**
+ * Get the number of records in the current record set, after filtering
+ * @type function
+ */
+ "fnRecordsDisplay": function ()
+ {
+ return _fnDataSource( this ) == 'ssp' ?
+ this._iRecordsDisplay * 1 :
+ this.aiDisplay.length;
+ },
+
+ /**
+ * Get the display end point - aiDisplay index
+ * @type function
+ */
+ "fnDisplayEnd": function ()
+ {
+ var
+ len = this._iDisplayLength,
+ start = this._iDisplayStart,
+ calc = start + len,
+ records = this.aiDisplay.length,
+ features = this.oFeatures,
+ paginate = features.bPaginate;
+
+ if ( features.bServerSide ) {
+ return paginate === false || len === -1 ?
+ start + records :
+ Math.min( start+len, this._iRecordsDisplay );
+ }
+ else {
+ return ! paginate || calc>records || len===-1 ?
+ records :
+ calc;
+ }
+ },
+
+ /**
+ * The DataTables object for this table
+ * @type object
+ * @default null
+ */
+ "oInstance": null,
+
+ /**
+ * Unique identifier for each instance of the DataTables object. If there
+ * is an ID on the table node, then it takes that value, otherwise an
+ * incrementing internal counter is used.
+ * @type string
+ * @default null
+ */
+ "sInstance": null,
+
+ /**
+ * tabindex attribute value that is added to DataTables control elements, allowing
+ * keyboard navigation of the table and its controls.
+ */
+ "iTabIndex": 0,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollHead": null,
+
+ /**
+ * DIV container for the footer scrolling table if scrolling
+ */
+ "nScrollFoot": null,
+
+ /**
+ * Last applied sort
+ * @type array
+ * @default []
+ */
+ "aLastSort": [],
+
+ /**
+ * Stored plug-in instances
+ * @type object
+ * @default {}
+ */
+ "oPlugins": {},
+
+ /**
+ * Function used to get a row's id from the row's data
+ * @type function
+ * @default null
+ */
+ "rowIdFn": null,
+
+ /**
+ * Data location where to store a row's id
+ * @type string
+ * @default null
+ */
+ "rowId": null
+ };
+
+ /**
+ * Extension object for DataTables that is used to provide all extension
+ * options.
+ *
+ * Note that the `DataTable.ext` object is available through
+ * `jQuery.fn.dataTable.ext` where it may be accessed and manipulated. It is
+ * also aliased to `jQuery.fn.dataTableExt` for historic reasons.
+ * @namespace
+ * @extends DataTable.models.ext
+ */
+
+
+ /**
+ * DataTables extensions
+ *
+ * This namespace acts as a collection area for plug-ins that can be used to
+ * extend DataTables capabilities. Indeed many of the build in methods
+ * use this method to provide their own capabilities (sorting methods for
+ * example).
+ *
+ * Note that this namespace is aliased to `jQuery.fn.dataTableExt` for legacy
+ * reasons
+ *
+ * @namespace
+ */
+ DataTable.ext = _ext = {
+ /**
+ * Buttons. For use with the Buttons extension for DataTables. This is
+ * defined here so other extensions can define buttons regardless of load
+ * order. It is _not_ used by DataTables core.
+ *
+ * @type object
+ * @default {}
+ */
+ buttons: {},
+
+
+ /**
+ * Element class names
+ *
+ * @type object
+ * @default {}
+ */
+ classes: {},
+
+
+ /**
+ * DataTables build type (expanded by the download builder)
+ *
+ * @type string
+ */
+ build:"bs5/dt-1.13.1/r-2.4.0/sl-1.5.0",
+
+
+ /**
+ * Error reporting.
+ *
+ * How should DataTables report an error. Can take the value 'alert',
+ * 'throw', 'none' or a function.
+ *
+ * @type string|function
+ * @default alert
+ */
+ errMode: "alert",
+
+
+ /**
+ * Feature plug-ins.
+ *
+ * This is an array of objects which describe the feature plug-ins that are
+ * available to DataTables. These feature plug-ins are then available for
+ * use through the `dom` initialisation option.
+ *
+ * Each feature plug-in is described by an object which must have the
+ * following properties:
+ *
+ * * `fnInit` - function that is used to initialise the plug-in,
+ * * `cFeature` - a character so the feature can be enabled by the `dom`
+ * instillation option. This is case sensitive.
+ *
+ * The `fnInit` function has the following input parameters:
+ *
+ * 1. `{object}` DataTables settings object: see
+ * {@link DataTable.models.oSettings}
+ *
+ * And the following return is expected:
+ *
+ * * {node|null} The element which contains your feature. Note that the
+ * return may also be void if your plug-in does not require to inject any
+ * DOM elements into DataTables control (`dom`) - for example this might
+ * be useful when developing a plug-in which allows table control via
+ * keyboard entry
+ *
+ * @type array
+ *
+ * @example
+ * $.fn.dataTable.ext.features.push( {
+ * "fnInit": function( oSettings ) {
+ * return new TableTools( { "oDTSettings": oSettings } );
+ * },
+ * "cFeature": "T"
+ * } );
+ */
+ feature: [],
+
+
+ /**
+ * Row searching.
+ *
+ * This method of searching is complimentary to the default type based
+ * searching, and a lot more comprehensive as it allows you complete control
+ * over the searching logic. Each element in this array is a function
+ * (parameters described below) that is called for every row in the table,
+ * and your logic decides if it should be included in the searching data set
+ * or not.
+ *
+ * Searching functions have the following input parameters:
+ *
+ * 1. `{object}` DataTables settings object: see
+ * {@link DataTable.models.oSettings}
+ * 2. `{array|object}` Data for the row to be processed (same as the
+ * original format that was passed in as the data source, or an array
+ * from a DOM data source
+ * 3. `{int}` Row index ({@link DataTable.models.oSettings.aoData}), which
+ * can be useful to retrieve the `TR` element if you need DOM interaction.
+ *
+ * And the following return is expected:
+ *
+ * * {boolean} Include the row in the searched result set (true) or not
+ * (false)
+ *
+ * Note that as with the main search ability in DataTables, technically this
+ * is "filtering", since it is subtractive. However, for consistency in
+ * naming we call it searching here.
+ *
+ * @type array
+ * @default []
+ *
+ * @example
+ * // The following example shows custom search being applied to the
+ * // fourth column (i.e. the data[3] index) based on two input values
+ * // from the end-user, matching the data in a certain range.
+ * $.fn.dataTable.ext.search.push(
+ * function( settings, data, dataIndex ) {
+ * var min = document.getElementById('min').value * 1;
+ * var max = document.getElementById('max').value * 1;
+ * var version = data[3] == "-" ? 0 : data[3]*1;
+ *
+ * if ( min == "" && max == "" ) {
+ * return true;
+ * }
+ * else if ( min == "" && version < max ) {
+ * return true;
+ * }
+ * else if ( min < version && "" == max ) {
+ * return true;
+ * }
+ * else if ( min < version && version < max ) {
+ * return true;
+ * }
+ * return false;
+ * }
+ * );
+ */
+ search: [],
+
+
+ /**
+ * Selector extensions
+ *
+ * The `selector` option can be used to extend the options available for the
+ * selector modifier options (`selector-modifier` object data type) that
+ * each of the three built in selector types offer (row, column and cell +
+ * their plural counterparts). For example the Select extension uses this
+ * mechanism to provide an option to select only rows, columns and cells
+ * that have been marked as selected by the end user (`{selected: true}`),
+ * which can be used in conjunction with the existing built in selector
+ * options.
+ *
+ * Each property is an array to which functions can be pushed. The functions
+ * take three attributes:
+ *
+ * * Settings object for the host table
+ * * Options object (`selector-modifier` object type)
+ * * Array of selected item indexes
+ *
+ * The return is an array of the resulting item indexes after the custom
+ * selector has been applied.
+ *
+ * @type object
+ */
+ selector: {
+ cell: [],
+ column: [],
+ row: []
+ },
+
+
+ /**
+ * Internal functions, exposed for used in plug-ins.
+ *
+ * Please note that you should not need to use the internal methods for
+ * anything other than a plug-in (and even then, try to avoid if possible).
+ * The internal function may change between releases.
+ *
+ * @type object
+ * @default {}
+ */
+ internal: {},
+
+
+ /**
+ * Legacy configuration options. Enable and disable legacy options that
+ * are available in DataTables.
+ *
+ * @type object
+ */
+ legacy: {
+ /**
+ * Enable / disable DataTables 1.9 compatible server-side processing
+ * requests
+ *
+ * @type boolean
+ * @default null
+ */
+ ajax: null
+ },
+
+
+ /**
+ * Pagination plug-in methods.
+ *
+ * Each entry in this object is a function and defines which buttons should
+ * be shown by the pagination rendering method that is used for the table:
+ * {@link DataTable.ext.renderer.pageButton}. The renderer addresses how the
+ * buttons are displayed in the document, while the functions here tell it
+ * what buttons to display. This is done by returning an array of button
+ * descriptions (what each button will do).
+ *
+ * Pagination types (the four built in options and any additional plug-in
+ * options defined here) can be used through the `paginationType`
+ * initialisation parameter.
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{int} page` The current page index
+ * 2. `{int} pages` The number of pages in the table
+ *
+ * Each function is expected to return an array where each element of the
+ * array can be one of:
+ *
+ * * `first` - Jump to first page when activated
+ * * `last` - Jump to last page when activated
+ * * `previous` - Show previous page when activated
+ * * `next` - Show next page when activated
+ * * `{int}` - Show page of the index given
+ * * `{array}` - A nested array containing the above elements to add a
+ * containing 'DIV' element (might be useful for styling).
+ *
+ * Note that DataTables v1.9- used this object slightly differently whereby
+ * an object with two functions would be defined for each plug-in. That
+ * ability is still supported by DataTables 1.10+ to provide backwards
+ * compatibility, but this option of use is now decremented and no longer
+ * documented in DataTables 1.10+.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Show previous, next and current page buttons only
+ * $.fn.dataTableExt.oPagination.current = function ( page, pages ) {
+ * return [ 'previous', page, 'next' ];
+ * };
+ */
+ pager: {},
+
+
+ renderer: {
+ pageButton: {},
+ header: {}
+ },
+
+
+ /**
+ * Ordering plug-ins - custom data source
+ *
+ * The extension options for ordering of data available here is complimentary
+ * to the default type based ordering that DataTables typically uses. It
+ * allows much greater control over the the data that is being used to
+ * order a column, but is necessarily therefore more complex.
+ *
+ * This type of ordering is useful if you want to do ordering based on data
+ * live from the DOM (for example the contents of an 'input' element) rather
+ * than just the static string that DataTables knows of.
+ *
+ * The way these plug-ins work is that you create an array of the values you
+ * wish to be ordering for the column in question and then return that
+ * array. The data in the array much be in the index order of the rows in
+ * the table (not the currently ordering order!). Which order data gathering
+ * function is run here depends on the `dt-init columns.orderDataType`
+ * parameter that is used for the column (if any).
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{object}` DataTables settings object: see
+ * {@link DataTable.models.oSettings}
+ * 2. `{int}` Target column index
+ *
+ * Each function is expected to return an array:
+ *
+ * * `{array}` Data for the column to be ordering upon
+ *
+ * @type array
+ *
+ * @example
+ * // Ordering using `input` node values
+ * $.fn.dataTable.ext.order['dom-text'] = function ( settings, col )
+ * {
+ * return this.api().column( col, {order:'index'} ).nodes().map( function ( td, i ) {
+ * return $('input', td).val();
+ * } );
+ * }
+ */
+ order: {},
+
+
+ /**
+ * Type based plug-ins.
+ *
+ * Each column in DataTables has a type assigned to it, either by automatic
+ * detection or by direct assignment using the `type` option for the column.
+ * The type of a column will effect how it is ordering and search (plug-ins
+ * can also make use of the column type if required).
+ *
+ * @namespace
+ */
+ type: {
+ /**
+ * Type detection functions.
+ *
+ * The functions defined in this object are used to automatically detect
+ * a column's type, making initialisation of DataTables super easy, even
+ * when complex data is in the table.
+ *
+ * The functions defined take two parameters:
+ *
+ * 1. `{*}` Data from the column cell to be analysed
+ * 2. `{settings}` DataTables settings object. This can be used to
+ * perform context specific type detection - for example detection
+ * based on language settings such as using a comma for a decimal
+ * place. Generally speaking the options from the settings will not
+ * be required
+ *
+ * Each function is expected to return:
+ *
+ * * `{string|null}` Data type detected, or null if unknown (and thus
+ * pass it on to the other type detection functions.
+ *
+ * @type array
+ *
+ * @example
+ * // Currency type detection plug-in:
+ * $.fn.dataTable.ext.type.detect.push(
+ * function ( data, settings ) {
+ * // Check the numeric part
+ * if ( ! data.substring(1).match(/[0-9]/) ) {
+ * return null;
+ * }
+ *
+ * // Check prefixed by currency
+ * if ( data.charAt(0) == '$' || data.charAt(0) == '£' ) {
+ * return 'currency';
+ * }
+ * return null;
+ * }
+ * );
+ */
+ detect: [],
+
+
+ /**
+ * Type based search formatting.
+ *
+ * The type based searching functions can be used to pre-format the
+ * data to be search on. For example, it can be used to strip HTML
+ * tags or to de-format telephone numbers for numeric only searching.
+ *
+ * Note that is a search is not defined for a column of a given type,
+ * no search formatting will be performed.
+ *
+ * Pre-processing of searching data plug-ins - When you assign the sType
+ * for a column (or have it automatically detected for you by DataTables
+ * or a type detection plug-in), you will typically be using this for
+ * custom sorting, but it can also be used to provide custom searching
+ * by allowing you to pre-processing the data and returning the data in
+ * the format that should be searched upon. This is done by adding
+ * functions this object with a parameter name which matches the sType
+ * for that target column. This is the corollary of <i>afnSortData</i>
+ * for searching data.
+ *
+ * The functions defined take a single parameter:
+ *
+ * 1. `{*}` Data from the column cell to be prepared for searching
+ *
+ * Each function is expected to return:
+ *
+ * * `{string|null}` Formatted string that will be used for the searching.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * $.fn.dataTable.ext.type.search['title-numeric'] = function ( d ) {
+ * return d.replace(/\n/g," ").replace( /<.*?>/g, "" );
+ * }
+ */
+ search: {},
+
+
+ /**
+ * Type based ordering.
+ *
+ * The column type tells DataTables what ordering to apply to the table
+ * when a column is sorted upon. The order for each type that is defined,
+ * is defined by the functions available in this object.
+ *
+ * Each ordering option can be described by three properties added to
+ * this object:
+ *
+ * * `{type}-pre` - Pre-formatting function
+ * * `{type}-asc` - Ascending order function
+ * * `{type}-desc` - Descending order function
+ *
+ * All three can be used together, only `{type}-pre` or only
+ * `{type}-asc` and `{type}-desc` together. It is generally recommended
+ * that only `{type}-pre` is used, as this provides the optimal
+ * implementation in terms of speed, although the others are provided
+ * for compatibility with existing Javascript sort functions.
+ *
+ * `{type}-pre`: Functions defined take a single parameter:
+ *
+ * 1. `{*}` Data from the column cell to be prepared for ordering
+ *
+ * And return:
+ *
+ * * `{*}` Data to be sorted upon
+ *
+ * `{type}-asc` and `{type}-desc`: Functions are typical Javascript sort
+ * functions, taking two parameters:
+ *
+ * 1. `{*}` Data to compare to the second parameter
+ * 2. `{*}` Data to compare to the first parameter
+ *
+ * And returning:
+ *
+ * * `{*}` Ordering match: <0 if first parameter should be sorted lower
+ * than the second parameter, ===0 if the two parameters are equal and
+ * >0 if the first parameter should be sorted height than the second
+ * parameter.
+ *
+ * @type object
+ * @default {}
+ *
+ * @example
+ * // Numeric ordering of formatted numbers with a pre-formatter
+ * $.extend( $.fn.dataTable.ext.type.order, {
+ * "string-pre": function(x) {
+ * a = (a === "-" || a === "") ? 0 : a.replace( /[^\d\-\.]/g, "" );
+ * return parseFloat( a );
+ * }
+ * } );
+ *
+ * @example
+ * // Case-sensitive string ordering, with no pre-formatting method
+ * $.extend( $.fn.dataTable.ext.order, {
+ * "string-case-asc": function(x,y) {
+ * return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ * },
+ * "string-case-desc": function(x,y) {
+ * return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ * }
+ * } );
+ */
+ order: {}
+ },
+
+ /**
+ * Unique DataTables instance counter
+ *
+ * @type int
+ * @private
+ */
+ _unique: 0,
+
+
+ //
+ // Depreciated
+ // The following properties are retained for backwards compatibility only.
+ // The should not be used in new projects and will be removed in a future
+ // version
+ //
+
+ /**
+ * Version check function.
+ * @type function
+ * @depreciated Since 1.10
+ */
+ fnVersionCheck: DataTable.fnVersionCheck,
+
+
+ /**
+ * Index for what 'this' index API functions should use
+ * @type int
+ * @deprecated Since v1.10
+ */
+ iApiIndex: 0,
+
+
+ /**
+ * jQuery UI class container
+ * @type object
+ * @deprecated Since v1.10
+ */
+ oJUIClasses: {},
+
+
+ /**
+ * Software version
+ * @type string
+ * @deprecated Since v1.10
+ */
+ sVersion: DataTable.version
+ };
+
+
+ //
+ // Backwards compatibility. Alias to pre 1.10 Hungarian notation counter parts
+ //
+ $.extend( _ext, {
+ afnFiltering: _ext.search,
+ aTypes: _ext.type.detect,
+ ofnSearch: _ext.type.search,
+ oSort: _ext.type.order,
+ afnSortData: _ext.order,
+ aoFeatures: _ext.feature,
+ oApi: _ext.internal,
+ oStdClasses: _ext.classes,
+ oPagination: _ext.pager
+ } );
+
+
+ $.extend( DataTable.ext.classes, {
+ "sTable": "dataTable",
+ "sNoFooter": "no-footer",
+
+ /* Paging buttons */
+ "sPageButton": "paginate_button",
+ "sPageButtonActive": "current",
+ "sPageButtonDisabled": "disabled",
+
+ /* Striping classes */
+ "sStripeOdd": "odd",
+ "sStripeEven": "even",
+
+ /* Empty row */
+ "sRowEmpty": "dataTables_empty",
+
+ /* Features */
+ "sWrapper": "dataTables_wrapper",
+ "sFilter": "dataTables_filter",
+ "sInfo": "dataTables_info",
+ "sPaging": "dataTables_paginate paging_", /* Note that the type is postfixed */
+ "sLength": "dataTables_length",
+ "sProcessing": "dataTables_processing",
+
+ /* Sorting */
+ "sSortAsc": "sorting_asc",
+ "sSortDesc": "sorting_desc",
+ "sSortable": "sorting", /* Sortable in both directions */
+ "sSortableAsc": "sorting_desc_disabled",
+ "sSortableDesc": "sorting_asc_disabled",
+ "sSortableNone": "sorting_disabled",
+ "sSortColumn": "sorting_", /* Note that an int is postfixed for the sorting order */
+
+ /* Filtering */
+ "sFilterInput": "",
+
+ /* Page length */
+ "sLengthSelect": "",
+
+ /* Scrolling */
+ "sScrollWrapper": "dataTables_scroll",
+ "sScrollHead": "dataTables_scrollHead",
+ "sScrollHeadInner": "dataTables_scrollHeadInner",
+ "sScrollBody": "dataTables_scrollBody",
+ "sScrollFoot": "dataTables_scrollFoot",
+ "sScrollFootInner": "dataTables_scrollFootInner",
+
+ /* Misc */
+ "sHeaderTH": "",
+ "sFooterTH": "",
+
+ // Deprecated
+ "sSortJUIAsc": "",
+ "sSortJUIDesc": "",
+ "sSortJUI": "",
+ "sSortJUIAscAllowed": "",
+ "sSortJUIDescAllowed": "",
+ "sSortJUIWrapper": "",
+ "sSortIcon": "",
+ "sJUIHeader": "",
+ "sJUIFooter": ""
+ } );
+
+
+ var extPagination = DataTable.ext.pager;
+
+ function _numbers ( page, pages ) {
+ var
+ numbers = [],
+ buttons = extPagination.numbers_length,
+ half = Math.floor( buttons / 2 ),
+ i = 1;
+
+ if ( pages <= buttons ) {
+ numbers = _range( 0, pages );
+ }
+ else if ( page <= half ) {
+ numbers = _range( 0, buttons-2 );
+ numbers.push( 'ellipsis' );
+ numbers.push( pages-1 );
+ }
+ else if ( page >= pages - 1 - half ) {
+ numbers = _range( pages-(buttons-2), pages );
+ numbers.splice( 0, 0, 'ellipsis' ); // no unshift in ie6
+ numbers.splice( 0, 0, 0 );
+ }
+ else {
+ numbers = _range( page-half+2, page+half-1 );
+ numbers.push( 'ellipsis' );
+ numbers.push( pages-1 );
+ numbers.splice( 0, 0, 'ellipsis' );
+ numbers.splice( 0, 0, 0 );
+ }
+
+ numbers.DT_el = 'span';
+ return numbers;
+ }
+
+
+ $.extend( extPagination, {
+ simple: function ( page, pages ) {
+ return [ 'previous', 'next' ];
+ },
+
+ full: function ( page, pages ) {
+ return [ 'first', 'previous', 'next', 'last' ];
+ },
+
+ numbers: function ( page, pages ) {
+ return [ _numbers(page, pages) ];
+ },
+
+ simple_numbers: function ( page, pages ) {
+ return [ 'previous', _numbers(page, pages), 'next' ];
+ },
+
+ full_numbers: function ( page, pages ) {
+ return [ 'first', 'previous', _numbers(page, pages), 'next', 'last' ];
+ },
+
+ first_last_numbers: function (page, pages) {
+ return ['first', _numbers(page, pages), 'last'];
+ },
+
+ // For testing and plug-ins to use
+ _numbers: _numbers,
+
+ // Number of number buttons (including ellipsis) to show. _Must be odd!_
+ numbers_length: 7
+ } );
+
+
+ $.extend( true, DataTable.ext.renderer, {
+ pageButton: {
+ _: function ( settings, host, idx, buttons, page, pages ) {
+ var classes = settings.oClasses;
+ var lang = settings.oLanguage.oPaginate;
+ var aria = settings.oLanguage.oAria.paginate || {};
+ var btnDisplay, btnClass;
+
+ var attach = function( container, buttons ) {
+ var i, ien, node, button, tabIndex;
+ var disabledClass = classes.sPageButtonDisabled;
+ var clickHandler = function ( e ) {
+ _fnPageChange( settings, e.data.action, true );
+ };
+
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
+ button = buttons[i];
+
+ if ( Array.isArray( button ) ) {
+ var inner = $( '<'+(button.DT_el || 'div')+'/>' )
+ .appendTo( container );
+ attach( inner, button );
+ }
+ else {
+ btnDisplay = null;
+ btnClass = button;
+ tabIndex = settings.iTabIndex;
+
+ switch ( button ) {
+ case 'ellipsis':
+ container.append('<span class="ellipsis">…</span>');
+ break;
+
+ case 'first':
+ btnDisplay = lang.sFirst;
+
+ if ( page === 0 ) {
+ tabIndex = -1;
+ btnClass += ' ' + disabledClass;
+ }
+ break;
+
+ case 'previous':
+ btnDisplay = lang.sPrevious;
+
+ if ( page === 0 ) {
+ tabIndex = -1;
+ btnClass += ' ' + disabledClass;
+ }
+ break;
+
+ case 'next':
+ btnDisplay = lang.sNext;
+
+ if ( pages === 0 || page === pages-1 ) {
+ tabIndex = -1;
+ btnClass += ' ' + disabledClass;
+ }
+ break;
+
+ case 'last':
+ btnDisplay = lang.sLast;
+
+ if ( pages === 0 || page === pages-1 ) {
+ tabIndex = -1;
+ btnClass += ' ' + disabledClass;
+ }
+ break;
+
+ default:
+ btnDisplay = settings.fnFormatNumber( button + 1 );
+ btnClass = page === button ?
+ classes.sPageButtonActive : '';
+ break;
+ }
+
+ if ( btnDisplay !== null ) {
+ node = $('<a>', {
+ 'class': classes.sPageButton+' '+btnClass,
+ 'aria-controls': settings.sTableId,
+ 'aria-label': aria[ button ],
+ 'data-dt-idx': button,
+ 'tabindex': tabIndex,
+ 'id': idx === 0 && typeof button === 'string' ?
+ settings.sTableId +'_'+ button :
+ null
+ } )
+ .html( btnDisplay )
+ .appendTo( container );
+
+ _fnBindAction(
+ node, {action: button}, clickHandler
+ );
+ }
+ }
+ }
+ };
+
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame. Try / catch the error. Not good for
+ // accessibility, but neither are frames.
+ var activeEl;
+
+ try {
+ // Because this approach is destroying and recreating the paging
+ // elements, focus is lost on the select button which is bad for
+ // accessibility. So we want to restore focus once the draw has
+ // completed
+ activeEl = $(host).find(document.activeElement).data('dt-idx');
+ }
+ catch (e) {}
+
+ attach( $(host).empty(), buttons );
+
+ if ( activeEl !== undefined ) {
+ $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
+ }
+ }
+ }
+ } );
+
+
+
+ // Built in type detection. See model.ext.aTypes for information about
+ // what is required from this methods.
+ $.extend( DataTable.ext.type.detect, [
+ // Plain numbers - first since V8 detects some plain numbers as dates
+ // e.g. Date.parse('55') (but not all, e.g. Date.parse('22')...).
+ function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _isNumber( d, decimal ) ? 'num'+decimal : null;
+ },
+
+ // Dates (only those recognised by the browser's Date.parse)
+ function ( d, settings )
+ {
+ // V8 tries _very_ hard to make a string passed into `Date.parse()`
+ // valid, so we need to use a regex to restrict date formats. Use a
+ // plug-in for anything other than ISO8601 style strings
+ if ( d && !(d instanceof Date) && ! _re_date.test(d) ) {
+ return null;
+ }
+ var parsed = Date.parse(d);
+ return (parsed !== null && !isNaN(parsed)) || _empty(d) ? 'date' : null;
+ },
+
+ // Formatted numbers
+ function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _isNumber( d, decimal, true ) ? 'num-fmt'+decimal : null;
+ },
+
+ // HTML numeric
+ function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _htmlNumeric( d, decimal ) ? 'html-num'+decimal : null;
+ },
+
+ // HTML numeric, formatted
+ function ( d, settings )
+ {
+ var decimal = settings.oLanguage.sDecimal;
+ return _htmlNumeric( d, decimal, true ) ? 'html-num-fmt'+decimal : null;
+ },
+
+ // HTML (this is strict checking - there must be html)
+ function ( d, settings )
+ {
+ return _empty( d ) || (typeof d === 'string' && d.indexOf('<') !== -1) ?
+ 'html' : null;
+ }
+ ] );
+
+
+
+ // Filter formatting functions. See model.ext.ofnSearch for information about
+ // what is required from these methods.
+ //
+ // Note that additional search methods are added for the html numbers and
+ // html formatted numbers by `_addNumericSort()` when we know what the decimal
+ // place is
+
+
+ $.extend( DataTable.ext.type.search, {
+ html: function ( data ) {
+ return _empty(data) ?
+ data :
+ typeof data === 'string' ?
+ data
+ .replace( _re_new_lines, " " )
+ .replace( _re_html, "" ) :
+ '';
+ },
+
+ string: function ( data ) {
+ return _empty(data) ?
+ data :
+ typeof data === 'string' ?
+ data.replace( _re_new_lines, " " ) :
+ data;
+ }
+ } );
+
+
+
+ var __numericReplace = function ( d, decimalPlace, re1, re2 ) {
+ if ( d !== 0 && (!d || d === '-') ) {
+ return -Infinity;
+ }
+
+ // If a decimal place other than `.` is used, it needs to be given to the
+ // function so we can detect it and replace with a `.` which is the only
+ // decimal place Javascript recognises - it is not locale aware.
+ if ( decimalPlace ) {
+ d = _numToDecimal( d, decimalPlace );
+ }
+
+ if ( d.replace ) {
+ if ( re1 ) {
+ d = d.replace( re1, '' );
+ }
+
+ if ( re2 ) {
+ d = d.replace( re2, '' );
+ }
+ }
+
+ return d * 1;
+ };
+
+
+ // Add the numeric 'deformatting' functions for sorting and search. This is done
+ // in a function to provide an easy ability for the language options to add
+ // additional methods if a non-period decimal place is used.
+ function _addNumericSort ( decimalPlace ) {
+ $.each(
+ {
+ // Plain numbers
+ "num": function ( d ) {
+ return __numericReplace( d, decimalPlace );
+ },
+
+ // Formatted numbers
+ "num-fmt": function ( d ) {
+ return __numericReplace( d, decimalPlace, _re_formatted_numeric );
+ },
+
+ // HTML numeric
+ "html-num": function ( d ) {
+ return __numericReplace( d, decimalPlace, _re_html );
+ },
+
+ // HTML numeric, formatted
+ "html-num-fmt": function ( d ) {
+ return __numericReplace( d, decimalPlace, _re_html, _re_formatted_numeric );
+ }
+ },
+ function ( key, fn ) {
+ // Add the ordering method
+ _ext.type.order[ key+decimalPlace+'-pre' ] = fn;
+
+ // For HTML types add a search formatter that will strip the HTML
+ if ( key.match(/^html\-/) ) {
+ _ext.type.search[ key+decimalPlace ] = _ext.type.search.html;
+ }
+ }
+ );
+ }
+
+
+ // Default sort methods
+ $.extend( _ext.type.order, {
+ // Dates
+ "date-pre": function ( d ) {
+ var ts = Date.parse( d );
+ return isNaN(ts) ? -Infinity : ts;
+ },
+
+ // html
+ "html-pre": function ( a ) {
+ return _empty(a) ?
+ '' :
+ a.replace ?
+ a.replace( /<.*?>/g, "" ).toLowerCase() :
+ a+'';
+ },
+
+ // string
+ "string-pre": function ( a ) {
+ // This is a little complex, but faster than always calling toString,
+ // http://jsperf.com/tostring-v-check
+ return _empty(a) ?
+ '' :
+ typeof a === 'string' ?
+ a.toLowerCase() :
+ ! a.toString ?
+ '' :
+ a.toString();
+ },
+
+ // string-asc and -desc are retained only for compatibility with the old
+ // sort methods
+ "string-asc": function ( x, y ) {
+ return ((x < y) ? -1 : ((x > y) ? 1 : 0));
+ },
+
+ "string-desc": function ( x, y ) {
+ return ((x < y) ? 1 : ((x > y) ? -1 : 0));
+ }
+ } );
+
+
+ // Numeric sorting types - order doesn't matter here
+ _addNumericSort( '' );
+
+
+ $.extend( true, DataTable.ext.renderer, {
+ header: {
+ _: function ( settings, cell, column, classes ) {
+ // No additional mark-up required
+ // Attach a sort listener to update on sort - note that using the
+ // `DT` namespace will allow the event to be removed automatically
+ // on destroy, while the `dt` namespaced event is the one we are
+ // listening for
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
+ if ( settings !== ctx ) { // need to check this this is the host
+ return; // table, not a nested one
+ }
+
+ var colIdx = column.idx;
+
+ cell
+ .removeClass(
+ classes.sSortAsc +' '+
+ classes.sSortDesc
+ )
+ .addClass( columns[ colIdx ] == 'asc' ?
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
+ classes.sSortDesc :
+ column.sSortingClass
+ );
+ } );
+ },
+
+ jqueryui: function ( settings, cell, column, classes ) {
+ $('<div/>')
+ .addClass( classes.sSortJUIWrapper )
+ .append( cell.contents() )
+ .append( $('<span/>')
+ .addClass( classes.sSortIcon+' '+column.sSortingClassJUI )
+ )
+ .appendTo( cell );
+
+ // Attach a sort listener to update on sort
+ $(settings.nTable).on( 'order.dt.DT', function ( e, ctx, sorting, columns ) {
+ if ( settings !== ctx ) {
+ return;
+ }
+
+ var colIdx = column.idx;
+
+ cell
+ .removeClass( classes.sSortAsc +" "+classes.sSortDesc )
+ .addClass( columns[ colIdx ] == 'asc' ?
+ classes.sSortAsc : columns[ colIdx ] == 'desc' ?
+ classes.sSortDesc :
+ column.sSortingClass
+ );
+
+ cell
+ .find( 'span.'+classes.sSortIcon )
+ .removeClass(
+ classes.sSortJUIAsc +" "+
+ classes.sSortJUIDesc +" "+
+ classes.sSortJUI +" "+
+ classes.sSortJUIAscAllowed +" "+
+ classes.sSortJUIDescAllowed
+ )
+ .addClass( columns[ colIdx ] == 'asc' ?
+ classes.sSortJUIAsc : columns[ colIdx ] == 'desc' ?
+ classes.sSortJUIDesc :
+ column.sSortingClassJUI
+ );
+ } );
+ }
+ }
+ } );
+
+ /*
+ * Public helper functions. These aren't used internally by DataTables, or
+ * called by any of the options passed into DataTables, but they can be used
+ * externally by developers working with DataTables. They are helper functions
+ * to make working with DataTables a little bit easier.
+ */
+
+ var __htmlEscapeEntities = function ( d ) {
+ if (Array.isArray(d)) {
+ d = d.join(',');
+ }
+
+ return typeof d === 'string' ?
+ d
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>')
+ .replace(/"/g, '"') :
+ d;
+ };
+
+ // Common logic for moment, luxon or a date action
+ function __mld( dt, momentFn, luxonFn, dateFn, arg1 ) {
+ if (window.moment) {
+ return dt[momentFn]( arg1 );
+ }
+ else if (window.luxon) {
+ return dt[luxonFn]( arg1 );
+ }
+
+ return dateFn ? dt[dateFn]( arg1 ) : dt;
+ }
+
+
+ var __mlWarning = false;
+ function __mldObj (d, format, locale) {
+ var dt;
+
+ if (window.moment) {
+ dt = window.moment.utc( d, format, locale, true );
+
+ if (! dt.isValid()) {
+ return null;
+ }
+ }
+ else if (window.luxon) {
+ dt = format && typeof d === 'string'
+ ? window.luxon.DateTime.fromFormat( d, format )
+ : window.luxon.DateTime.fromISO( d );
+
+ if (! dt.isValid) {
+ return null;
+ }
+
+ dt.setLocale(locale);
+ }
+ else if (! format) {
+ // No format given, must be ISO
+ dt = new Date(d);
+ }
+ else {
+ if (! __mlWarning) {
+ alert('DataTables warning: Formatted date without Moment.js or Luxon - https://datatables.net/tn/17');
+ }
+
+ __mlWarning = true;
+ }
+
+ return dt;
+ }
+
+ // Wrapper for date, datetime and time which all operate the same way with the exception of
+ // the output string for auto locale support
+ function __mlHelper (localeString) {
+ return function ( from, to, locale, def ) {
+ // Luxon and Moment support
+ // Argument shifting
+ if ( arguments.length === 0 ) {
+ locale = 'en';
+ to = null; // means toLocaleString
+ from = null; // means iso8601
+ }
+ else if ( arguments.length === 1 ) {
+ locale = 'en';
+ to = from;
+ from = null;
+ }
+ else if ( arguments.length === 2 ) {
+ locale = to;
+ to = from;
+ from = null;
+ }
+
+ var typeName = 'datetime-' + to;
+
+ // Add type detection and sorting specific to this date format - we need to be able to identify
+ // date type columns as such, rather than as numbers in extensions. Hence the need for this.
+ if (! DataTable.ext.type.order[typeName]) {
+ // The renderer will give the value to type detect as the type!
+ DataTable.ext.type.detect.unshift(function (d) {
+ return d === typeName ? typeName : false;
+ });
+
+ // The renderer gives us Moment, Luxon or Date obects for the sorting, all of which have a
+ // `valueOf` which gives milliseconds epoch
+ DataTable.ext.type.order[typeName + '-asc'] = function (a, b) {
+ var x = a.valueOf();
+ var y = b.valueOf();
+
+ return x === y
+ ? 0
+ : x < y
+ ? -1
+ : 1;
+ }
+
+ DataTable.ext.type.order[typeName + '-desc'] = function (a, b) {
+ var x = a.valueOf();
+ var y = b.valueOf();
+
+ return x === y
+ ? 0
+ : x > y
+ ? -1
+ : 1;
+ }
+ }
+
+ return function ( d, type ) {
+ // Allow for a default value
+ if (d === null || d === undefined) {
+ if (def === '--now') {
+ // We treat everything as UTC further down, so no changes are
+ // made, as such need to get the local date / time as if it were
+ // UTC
+ var local = new Date();
+ d = new Date( Date.UTC(
+ local.getFullYear(), local.getMonth(), local.getDate(),
+ local.getHours(), local.getMinutes(), local.getSeconds()
+ ) );
+ }
+ else {
+ d = '';
+ }
+ }
+
+ if (type === 'type') {
+ // Typing uses the type name for fast matching
+ return typeName;
+ }
+
+ if (d === '') {
+ return type !== 'sort'
+ ? ''
+ : __mldObj('0000-01-01 00:00:00', null, locale);
+ }
+
+ // Shortcut. If `from` and `to` are the same, we are using the renderer to
+ // format for ordering, not display - its already in the display format.
+ if ( to !== null && from === to && type !== 'sort' && type !== 'type' && ! (d instanceof Date) ) {
+ return d;
+ }
+
+ var dt = __mldObj(d, from, locale);
+
+ if (dt === null) {
+ return d;
+ }
+
+ if (type === 'sort') {
+ return dt;
+ }
+
+ var formatted = to === null
+ ? __mld(dt, 'toDate', 'toJSDate', '')[localeString]()
+ : __mld(dt, 'format', 'toFormat', 'toISOString', to);
+
+ // XSS protection
+ return type === 'display' ?
+ __htmlEscapeEntities( formatted ) :
+ formatted;
+ };
+ }
+ }
+
+ // Based on locale, determine standard number formatting
+ // Fallback for legacy browsers is US English
+ var __thousands = ',';
+ var __decimal = '.';
+
+ if (Intl) {
+ try {
+ var num = new Intl.NumberFormat().formatToParts(100000.1);
+
+ for (var i=0 ; i<num.length ; i++) {
+ if (num[i].type === 'group') {
+ __thousands = num[i].value;
+ }
+ else if (num[i].type === 'decimal') {
+ __decimal = num[i].value;
+ }
+ }
+ }
+ catch (e) {
+ // noop
+ }
+ }
+
+ // Formatted date time detection - use by declaring the formats you are going to use
+ DataTable.datetime = function ( format, locale ) {
+ var typeName = 'datetime-detect-' + format;
+
+ if (! locale) {
+ locale = 'en';
+ }
+
+ if (! DataTable.ext.type.order[typeName]) {
+ DataTable.ext.type.detect.unshift(function (d) {
+ var dt = __mldObj(d, format, locale);
+ return d === '' || dt ? typeName : false;
+ });
+
+ DataTable.ext.type.order[typeName + '-pre'] = function (d) {
+ return __mldObj(d, format, locale) || 0;
+ }
+ }
+ }
+
+ /**
+ * Helpers for `columns.render`.
+ *
+ * The options defined here can be used with the `columns.render` initialisation
+ * option to provide a display renderer. The following functions are defined:
+ *
+ * * `number` - Will format numeric data (defined by `columns.data`) for
+ * display, retaining the original unformatted data for sorting and filtering.
+ * It takes 5 parameters:
+ * * `string` - Thousands grouping separator
+ * * `string` - Decimal point indicator
+ * * `integer` - Number of decimal points to show
+ * * `string` (optional) - Prefix.
+ * * `string` (optional) - Postfix (/suffix).
+ * * `text` - Escape HTML to help prevent XSS attacks. It has no optional
+ * parameters.
+ *
+ * @example
+ * // Column definition using the number renderer
+ * {
+ * data: "salary",
+ * render: $.fn.dataTable.render.number( '\'', '.', 0, '$' )
+ * }
+ *
+ * @namespace
+ */
+ DataTable.render = {
+ date: __mlHelper('toLocaleDateString'),
+ datetime: __mlHelper('toLocaleString'),
+ time: __mlHelper('toLocaleTimeString'),
+ number: function ( thousands, decimal, precision, prefix, postfix ) {
+ // Auto locale detection
+ if (thousands === null || thousands === undefined) {
+ thousands = __thousands;
+ }
+
+ if (decimal === null || decimal === undefined) {
+ decimal = __decimal;
+ }
+
+ return {
+ display: function ( d ) {
+ if ( typeof d !== 'number' && typeof d !== 'string' ) {
+ return d;
+ }
+
+ if (d === '' || d === null) {
+ return d;
+ }
+
+ var negative = d < 0 ? '-' : '';
+ var flo = parseFloat( d );
+
+ // If NaN then there isn't much formatting that we can do - just
+ // return immediately, escaping any HTML (this was supposed to
+ // be a number after all)
+ if ( isNaN( flo ) ) {
+ return __htmlEscapeEntities( d );
+ }
+
+ flo = flo.toFixed( precision );
+ d = Math.abs( flo );
+
+ var intPart = parseInt( d, 10 );
+ var floatPart = precision ?
+ decimal+(d - intPart).toFixed( precision ).substring( 2 ):
+ '';
+
+ // If zero, then can't have a negative prefix
+ if (intPart === 0 && parseFloat(floatPart) === 0) {
+ negative = '';
+ }
+
+ return negative + (prefix||'') +
+ intPart.toString().replace(
+ /\B(?=(\d{3})+(?!\d))/g, thousands
+ ) +
+ floatPart +
+ (postfix||'');
+ }
+ };
+ },
+
+ text: function () {
+ return {
+ display: __htmlEscapeEntities,
+ filter: __htmlEscapeEntities
+ };
+ }
+ };
+
+
+ /*
+ * This is really a good bit rubbish this method of exposing the internal methods
+ * publicly... - To be fixed in 2.0 using methods on the prototype
+ */
+
+
+ /**
+ * Create a wrapper function for exporting an internal functions to an external API.
+ * @param {string} fn API function name
+ * @returns {function} wrapped function
+ * @memberof DataTable#internal
+ */
+ function _fnExternApiFunc (fn)
+ {
+ return function() {
+ var args = [_fnSettingsFromNode( this[DataTable.ext.iApiIndex] )].concat(
+ Array.prototype.slice.call(arguments)
+ );
+ return DataTable.ext.internal[fn].apply( this, args );
+ };
+ }
+
+
+ /**
+ * Reference to internal functions for use by plug-in developers. Note that
+ * these methods are references to internal functions and are considered to be
+ * private. If you use these methods, be aware that they are liable to change
+ * between versions.
+ * @namespace
+ */
+ $.extend( DataTable.ext.internal, {
+ _fnExternApiFunc: _fnExternApiFunc,
+ _fnBuildAjax: _fnBuildAjax,
+ _fnAjaxUpdate: _fnAjaxUpdate,
+ _fnAjaxParameters: _fnAjaxParameters,
+ _fnAjaxUpdateDraw: _fnAjaxUpdateDraw,
+ _fnAjaxDataSrc: _fnAjaxDataSrc,
+ _fnAddColumn: _fnAddColumn,
+ _fnColumnOptions: _fnColumnOptions,
+ _fnAdjustColumnSizing: _fnAdjustColumnSizing,
+ _fnVisibleToColumnIndex: _fnVisibleToColumnIndex,
+ _fnColumnIndexToVisible: _fnColumnIndexToVisible,
+ _fnVisbleColumns: _fnVisbleColumns,
+ _fnGetColumns: _fnGetColumns,
+ _fnColumnTypes: _fnColumnTypes,
+ _fnApplyColumnDefs: _fnApplyColumnDefs,
+ _fnHungarianMap: _fnHungarianMap,
+ _fnCamelToHungarian: _fnCamelToHungarian,
+ _fnLanguageCompat: _fnLanguageCompat,
+ _fnBrowserDetect: _fnBrowserDetect,
+ _fnAddData: _fnAddData,
+ _fnAddTr: _fnAddTr,
+ _fnNodeToDataIndex: _fnNodeToDataIndex,
+ _fnNodeToColumnIndex: _fnNodeToColumnIndex,
+ _fnGetCellData: _fnGetCellData,
+ _fnSetCellData: _fnSetCellData,
+ _fnSplitObjNotation: _fnSplitObjNotation,
+ _fnGetObjectDataFn: _fnGetObjectDataFn,
+ _fnSetObjectDataFn: _fnSetObjectDataFn,
+ _fnGetDataMaster: _fnGetDataMaster,
+ _fnClearTable: _fnClearTable,
+ _fnDeleteIndex: _fnDeleteIndex,
+ _fnInvalidate: _fnInvalidate,
+ _fnGetRowElements: _fnGetRowElements,
+ _fnCreateTr: _fnCreateTr,
+ _fnBuildHead: _fnBuildHead,
+ _fnDrawHead: _fnDrawHead,
+ _fnDraw: _fnDraw,
+ _fnReDraw: _fnReDraw,
+ _fnAddOptionsHtml: _fnAddOptionsHtml,
+ _fnDetectHeader: _fnDetectHeader,
+ _fnGetUniqueThs: _fnGetUniqueThs,
+ _fnFeatureHtmlFilter: _fnFeatureHtmlFilter,
+ _fnFilterComplete: _fnFilterComplete,
+ _fnFilterCustom: _fnFilterCustom,
+ _fnFilterColumn: _fnFilterColumn,
+ _fnFilter: _fnFilter,
+ _fnFilterCreateSearch: _fnFilterCreateSearch,
+ _fnEscapeRegex: _fnEscapeRegex,
+ _fnFilterData: _fnFilterData,
+ _fnFeatureHtmlInfo: _fnFeatureHtmlInfo,
+ _fnUpdateInfo: _fnUpdateInfo,
+ _fnInfoMacros: _fnInfoMacros,
+ _fnInitialise: _fnInitialise,
+ _fnInitComplete: _fnInitComplete,
+ _fnLengthChange: _fnLengthChange,
+ _fnFeatureHtmlLength: _fnFeatureHtmlLength,
+ _fnFeatureHtmlPaginate: _fnFeatureHtmlPaginate,
+ _fnPageChange: _fnPageChange,
+ _fnFeatureHtmlProcessing: _fnFeatureHtmlProcessing,
+ _fnProcessingDisplay: _fnProcessingDisplay,
+ _fnFeatureHtmlTable: _fnFeatureHtmlTable,
+ _fnScrollDraw: _fnScrollDraw,
+ _fnApplyToChildren: _fnApplyToChildren,
+ _fnCalculateColumnWidths: _fnCalculateColumnWidths,
+ _fnThrottle: _fnThrottle,
+ _fnConvertToWidth: _fnConvertToWidth,
+ _fnGetWidestNode: _fnGetWidestNode,
+ _fnGetMaxLenString: _fnGetMaxLenString,
+ _fnStringToCss: _fnStringToCss,
+ _fnSortFlatten: _fnSortFlatten,
+ _fnSort: _fnSort,
+ _fnSortAria: _fnSortAria,
+ _fnSortListener: _fnSortListener,
+ _fnSortAttachListener: _fnSortAttachListener,
+ _fnSortingClasses: _fnSortingClasses,
+ _fnSortData: _fnSortData,
+ _fnSaveState: _fnSaveState,
+ _fnLoadState: _fnLoadState,
+ _fnImplementState: _fnImplementState,
+ _fnSettingsFromNode: _fnSettingsFromNode,
+ _fnLog: _fnLog,
+ _fnMap: _fnMap,
+ _fnBindAction: _fnBindAction,
+ _fnCallbackReg: _fnCallbackReg,
+ _fnCallbackFire: _fnCallbackFire,
+ _fnLengthOverflow: _fnLengthOverflow,
+ _fnRenderer: _fnRenderer,
+ _fnDataSource: _fnDataSource,
+ _fnRowAttributes: _fnRowAttributes,
+ _fnExtend: _fnExtend,
+ _fnCalculateEnd: function () {} // Used by a lot of plug-ins, but redundant
+ // in 1.10, so this dead-end function is
+ // added to prevent errors
+ } );
+
+
+ // jQuery access
+ $.fn.dataTable = DataTable;
+
+ // Provide access to the host jQuery object (circular reference)
+ DataTable.$ = $;
+
+ // Legacy aliases
+ $.fn.dataTableSettings = DataTable.settings;
+ $.fn.dataTableExt = DataTable.ext;
+
+ // With a capital `D` we return a DataTables API instance rather than a
+ // jQuery object
+ $.fn.DataTable = function ( opts ) {
+ return $(this).dataTable( opts ).api();
+ };
+
+ // All properties that are available to $.fn.dataTable should also be
+ // available on $.fn.DataTable
+ $.each( DataTable, function ( prop, val ) {
+ $.fn.DataTable[ prop ] = val;
+ } );
+
+ return DataTable;
+}));
+
+
+/*! DataTables Bootstrap 5 integration
+ * 2020 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+/**
+ * DataTables integration for Bootstrap 5. This requires Bootstrap 5 and
+ * DataTables 1.10 or newer.
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
+ * for further information.
+ */
+
+/* Set the defaults for DataTables initialisation */
+$.extend( true, DataTable.defaults, {
+ dom:
+ "<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
+ "<'row dt-row'<'col-sm-12'tr>>" +
+ "<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
+ renderer: 'bootstrap'
+} );
+
+
+/* Default class modification */
+$.extend( DataTable.ext.classes, {
+ sWrapper: "dataTables_wrapper dt-bootstrap5",
+ sFilterInput: "form-control form-control-sm",
+ sLengthSelect: "form-select form-select-sm",
+ sProcessing: "dataTables_processing card",
+ sPageButton: "paginate_button page-item"
+} );
+
+
+/* Bootstrap paging button renderer */
+DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, buttons, page, pages ) {
+ var api = new DataTable.Api( settings );
+ var classes = settings.oClasses;
+ var lang = settings.oLanguage.oPaginate;
+ var aria = settings.oLanguage.oAria.paginate || {};
+ var btnDisplay, btnClass;
+
+ var attach = function( container, buttons ) {
+ var i, ien, node, button;
+ var clickHandler = function ( e ) {
+ e.preventDefault();
+ if ( !$(e.currentTarget).hasClass('disabled') && api.page() != e.data.action ) {
+ api.page( e.data.action ).draw( 'page' );
+ }
+ };
+
+ for ( i=0, ien=buttons.length ; i<ien ; i++ ) {
+ button = buttons[i];
+
+ if ( Array.isArray( button ) ) {
+ attach( container, button );
+ }
+ else {
+ btnDisplay = '';
+ btnClass = '';
+
+ switch ( button ) {
+ case 'ellipsis':
+ btnDisplay = '…';
+ btnClass = 'disabled';
+ break;
+
+ case 'first':
+ btnDisplay = lang.sFirst;
+ btnClass = button + (page > 0 ?
+ '' : ' disabled');
+ break;
+
+ case 'previous':
+ btnDisplay = lang.sPrevious;
+ btnClass = button + (page > 0 ?
+ '' : ' disabled');
+ break;
+
+ case 'next':
+ btnDisplay = lang.sNext;
+ btnClass = button + (page < pages-1 ?
+ '' : ' disabled');
+ break;
+
+ case 'last':
+ btnDisplay = lang.sLast;
+ btnClass = button + (page < pages-1 ?
+ '' : ' disabled');
+ break;
+
+ default:
+ btnDisplay = button + 1;
+ btnClass = page === button ?
+ 'active' : '';
+ break;
+ }
+
+ if ( btnDisplay ) {
+ node = $('<li>', {
+ 'class': classes.sPageButton+' '+btnClass,
+ 'id': idx === 0 && typeof button === 'string' ?
+ settings.sTableId +'_'+ button :
+ null
+ } )
+ .append( $('<a>', {
+ 'href': '#',
+ 'aria-controls': settings.sTableId,
+ 'aria-label': aria[ button ],
+ 'data-dt-idx': button,
+ 'tabindex': settings.iTabIndex,
+ 'class': 'page-link'
+ } )
+ .html( btnDisplay )
+ )
+ .appendTo( container );
+
+ settings.oApi._fnBindAction(
+ node, {action: button}, clickHandler
+ );
+ }
+ }
+ }
+ };
+
+ var hostEl = $(host);
+ // IE9 throws an 'unknown error' if document.activeElement is used
+ // inside an iframe or frame.
+ var activeEl;
+
+ try {
+ // Because this approach is destroying and recreating the paging
+ // elements, focus is lost on the select button which is bad for
+ // accessibility. So we want to restore focus once the draw has
+ // completed
+ activeEl = hostEl.find(document.activeElement).data('dt-idx');
+ }
+ catch (e) {}
+
+ var paginationEl = hostEl.children('ul.pagination');
+
+ if (paginationEl.length) {
+ paginationEl.empty();
+ }
+ else {
+ paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination');
+ }
+
+ attach(
+ paginationEl,
+ buttons
+ );
+
+ if ( activeEl !== undefined ) {
+ hostEl.find('[data-dt-idx='+activeEl+']').trigger('focus');
+ }
+};
+
+
+return DataTable;
+}));
+
+
+/*! Responsive 2.4.0
+ * 2014-2022 SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+/**
+ * @summary Responsive
+ * @description Responsive tables plug-in for DataTables
+ * @version 2.4.0
+ * @author SpryMedia Ltd (www.sprymedia.co.uk)
+ * @contact www.sprymedia.co.uk/contact
+ * @copyright SpryMedia Ltd.
+ *
+ * This source file is free software, available under the following license:
+ * MIT license - http://datatables.net/license/mit
+ *
+ * This source file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the license files for details.
+ *
+ * For details please refer to: http://www.datatables.net
+ */
+
+/**
+ * Responsive is a plug-in for the DataTables library that makes use of
+ * DataTables' ability to change the visibility of columns, changing the
+ * visibility of columns so the displayed columns fit into the table container.
+ * The end result is that complex tables will be dynamically adjusted to fit
+ * into the viewport, be it on a desktop, tablet or mobile browser.
+ *
+ * Responsive for DataTables has two modes of operation, which can used
+ * individually or combined:
+ *
+ * * Class name based control - columns assigned class names that match the
+ * breakpoint logic can be shown / hidden as required for each breakpoint.
+ * * Automatic control - columns are automatically hidden when there is no
+ * room left to display them. Columns removed from the right.
+ *
+ * In additional to column visibility control, Responsive also has built into
+ * options to use DataTables' child row display to show / hide the information
+ * from the table that has been hidden. There are also two modes of operation
+ * for this child row display:
+ *
+ * * Inline - when the control element that the user can use to show / hide
+ * child rows is displayed inside the first column of the table.
+ * * Column - where a whole column is dedicated to be the show / hide control.
+ *
+ * Initialisation of Responsive is performed by:
+ *
+ * * Adding the class `responsive` or `dt-responsive` to the table. In this case
+ * Responsive will automatically be initialised with the default configuration
+ * options when the DataTable is created.
+ * * Using the `responsive` option in the DataTables configuration options. This
+ * can also be used to specify the configuration options, or simply set to
+ * `true` to use the defaults.
+ *
+ * @class
+ * @param {object} settings DataTables settings object for the host table
+ * @param {object} [opts] Configuration options
+ * @requires jQuery 1.7+
+ * @requires DataTables 1.10.3+
+ *
+ * @example
+ * $('#example').DataTable( {
+ * responsive: true
+ * } );
+ * } );
+ */
+var Responsive = function ( settings, opts ) {
+ // Sanity check that we are using DataTables 1.10 or newer
+ if ( ! DataTable.versionCheck || ! DataTable.versionCheck( '1.10.10' ) ) {
+ throw 'DataTables Responsive requires DataTables 1.10.10 or newer';
+ }
+
+ this.s = {
+ childNodeStore: {},
+ columns: [],
+ current: [],
+ dt: new DataTable.Api( settings )
+ };
+
+ // Check if responsive has already been initialised on this table
+ if ( this.s.dt.settings()[0].responsive ) {
+ return;
+ }
+
+ // details is an object, but for simplicity the user can give it as a string
+ // or a boolean
+ if ( opts && typeof opts.details === 'string' ) {
+ opts.details = { type: opts.details };
+ }
+ else if ( opts && opts.details === false ) {
+ opts.details = { type: false };
+ }
+ else if ( opts && opts.details === true ) {
+ opts.details = { type: 'inline' };
+ }
+
+ this.c = $.extend( true, {}, Responsive.defaults, DataTable.defaults.responsive, opts );
+ settings.responsive = this;
+ this._constructor();
+};
+
+$.extend( Responsive.prototype, {
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Constructor
+ */
+
+ /**
+ * Initialise the Responsive instance
+ *
+ * @private
+ */
+ _constructor: function ()
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var dtPrivateSettings = dt.settings()[0];
+ var oldWindowWidth = $(window).innerWidth();
+
+ dt.settings()[0]._responsive = this;
+
+ // Use DataTables' throttle function to avoid processor thrashing on
+ // resize
+ $(window).on( 'resize.dtr orientationchange.dtr', DataTable.util.throttle( function () {
+ // iOS has a bug whereby resize can fire when only scrolling
+ // See: http://stackoverflow.com/questions/8898412
+ var width = $(window).innerWidth();
+
+ if ( width !== oldWindowWidth ) {
+ that._resize();
+ oldWindowWidth = width;
+ }
+ } ) );
+
+ // DataTables doesn't currently trigger an event when a row is added, so
+ // we need to hook into its private API to enforce the hidden rows when
+ // new data is added
+ dtPrivateSettings.oApi._fnCallbackReg( dtPrivateSettings, 'aoRowCreatedCallback', function (tr, data, idx) {
+ if ( $.inArray( false, that.s.current ) !== -1 ) {
+ $('>td, >th', tr).each( function ( i ) {
+ var idx = dt.column.index( 'toData', i );
+
+ if ( that.s.current[idx] === false ) {
+ $(this).css('display', 'none');
+ }
+ } );
+ }
+ } );
+
+ // Destroy event handler
+ dt.on( 'destroy.dtr', function () {
+ dt.off( '.dtr' );
+ $( dt.table().body() ).off( '.dtr' );
+ $(window).off( 'resize.dtr orientationchange.dtr' );
+ dt.cells('.dtr-control').nodes().to$().removeClass('dtr-control');
+
+ // Restore the columns that we've hidden
+ $.each( that.s.current, function ( i, val ) {
+ if ( val === false ) {
+ that._setColumnVis( i, true );
+ }
+ } );
+ } );
+
+ // Reorder the breakpoints array here in case they have been added out
+ // of order
+ this.c.breakpoints.sort( function (a, b) {
+ return a.width < b.width ? 1 :
+ a.width > b.width ? -1 : 0;
+ } );
+
+ this._classLogic();
+ this._resizeAuto();
+
+ // Details handler
+ var details = this.c.details;
+
+ if ( details.type !== false ) {
+ that._detailsInit();
+
+ // DataTables will trigger this event on every column it shows and
+ // hides individually
+ dt.on( 'column-visibility.dtr', function () {
+ // Use a small debounce to allow multiple columns to be set together
+ if ( that._timer ) {
+ clearTimeout( that._timer );
+ }
+
+ that._timer = setTimeout( function () {
+ that._timer = null;
+
+ that._classLogic();
+ that._resizeAuto();
+ that._resize(true);
+
+ that._redrawChildren();
+ }, 100 );
+ } );
+
+ // Redraw the details box on each draw which will happen if the data
+ // has changed. This is used until DataTables implements a native
+ // `updated` event for rows
+ dt.on( 'draw.dtr', function () {
+ that._redrawChildren();
+ } );
+
+ $(dt.table().node()).addClass( 'dtr-'+details.type );
+ }
+
+ dt.on( 'column-reorder.dtr', function (e, settings, details) {
+ that._classLogic();
+ that._resizeAuto();
+ that._resize(true);
+ } );
+
+ // Change in column sizes means we need to calc
+ dt.on( 'column-sizing.dtr', function () {
+ that._resizeAuto();
+ that._resize();
+ });
+
+ // DT2 let's us tell it if we are hiding columns
+ dt.on( 'column-calc.dt', function (e, d) {
+ var curr = that.s.current;
+
+ for (var i=0 ; i<curr.length ; i++) {
+ var idx = d.visible.indexOf(i);
+
+ if (curr[i] === false && idx >= 0) {
+ d.visible.splice(idx, 1);
+ }
+ }
+ } );
+
+ // On Ajax reload we want to reopen any child rows which are displayed
+ // by responsive
+ dt.on( 'preXhr.dtr', function () {
+ var rowIds = [];
+ dt.rows().every( function () {
+ if ( this.child.isShown() ) {
+ rowIds.push( this.id(true) );
+ }
+ } );
+
+ dt.one( 'draw.dtr', function () {
+ that._resizeAuto();
+ that._resize();
+
+ dt.rows( rowIds ).every( function () {
+ that._detailsDisplay( this, false );
+ } );
+ } );
+ });
+
+ dt
+ .on( 'draw.dtr', function () {
+ that._controlClass();
+ })
+ .on( 'init.dtr', function (e, settings, details) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ that._resizeAuto();
+ that._resize();
+
+ // If columns were hidden, then DataTables needs to adjust the
+ // column sizing
+ if ( $.inArray( false, that.s.current ) ) {
+ dt.columns.adjust();
+ }
+ } );
+
+ // First pass - draw the table for the current viewport size
+ this._resize();
+ },
+
+
+ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Private methods
+ */
+
+ /**
+ * Get and store nodes from a cell - use for node moving renderers
+ *
+ * @param {*} dt DT instance
+ * @param {*} row Row index
+ * @param {*} col Column index
+ */
+ _childNodes: function( dt, row, col ) {
+ var name = row+'-'+col;
+
+ if ( this.s.childNodeStore[ name ] ) {
+ return this.s.childNodeStore[ name ];
+ }
+
+ // https://jsperf.com/childnodes-array-slice-vs-loop
+ var nodes = [];
+ var children = dt.cell( row, col ).node().childNodes;
+ for ( var i=0, ien=children.length ; i<ien ; i++ ) {
+ nodes.push( children[i] );
+ }
+
+ this.s.childNodeStore[ name ] = nodes;
+
+ return nodes;
+ },
+
+ /**
+ * Restore nodes from the cache to a table cell
+ *
+ * @param {*} dt DT instance
+ * @param {*} row Row index
+ * @param {*} col Column index
+ */
+ _childNodesRestore: function( dt, row, col ) {
+ var name = row+'-'+col;
+
+ if ( ! this.s.childNodeStore[ name ] ) {
+ return;
+ }
+
+ var node = dt.cell( row, col ).node();
+ var store = this.s.childNodeStore[ name ];
+ var parent = store[0].parentNode;
+ var parentChildren = parent.childNodes;
+ var a = [];
+
+ for ( var i=0, ien=parentChildren.length ; i<ien ; i++ ) {
+ a.push( parentChildren[i] );
+ }
+
+ for ( var j=0, jen=a.length ; j<jen ; j++ ) {
+ node.appendChild( a[j] );
+ }
+
+ this.s.childNodeStore[ name ] = undefined;
+ },
+
+ /**
+ * Calculate the visibility for the columns in a table for a given
+ * breakpoint. The result is pre-determined based on the class logic if
+ * class names are used to control all columns, but the width of the table
+ * is also used if there are columns which are to be automatically shown
+ * and hidden.
+ *
+ * @param {string} breakpoint Breakpoint name to use for the calculation
+ * @return {array} Array of boolean values initiating the visibility of each
+ * column.
+ * @private
+ */
+ _columnsVisiblity: function ( breakpoint )
+ {
+ var dt = this.s.dt;
+ var columns = this.s.columns;
+ var i, ien;
+
+ // Create an array that defines the column ordering based first on the
+ // column's priority, and secondly the column index. This allows the
+ // columns to be removed from the right if the priority matches
+ var order = columns
+ .map( function ( col, idx ) {
+ return {
+ columnIdx: idx,
+ priority: col.priority
+ };
+ } )
+ .sort( function ( a, b ) {
+ if ( a.priority !== b.priority ) {
+ return a.priority - b.priority;
+ }
+ return a.columnIdx - b.columnIdx;
+ } );
+
+ // Class logic - determine which columns are in this breakpoint based
+ // on the classes. If no class control (i.e. `auto`) then `-` is used
+ // to indicate this to the rest of the function
+ var display = $.map( columns, function ( col, i ) {
+ if ( dt.column(i).visible() === false ) {
+ return 'not-visible';
+ }
+ return col.auto && col.minWidth === null ?
+ false :
+ col.auto === true ?
+ '-' :
+ $.inArray( breakpoint, col.includeIn ) !== -1;
+ } );
+
+ // Auto column control - first pass: how much width is taken by the
+ // ones that must be included from the non-auto columns
+ var requiredWidth = 0;
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
+ if ( display[i] === true ) {
+ requiredWidth += columns[i].minWidth;
+ }
+ }
+
+ // Second pass, use up any remaining width for other columns. For
+ // scrolling tables we need to subtract the width of the scrollbar. It
+ // may not be requires which makes this sub-optimal, but it would
+ // require another full redraw to make complete use of those extra few
+ // pixels
+ var scrolling = dt.settings()[0].oScroll;
+ var bar = scrolling.sY || scrolling.sX ? scrolling.iBarWidth : 0;
+ var widthAvailable = dt.table().container().offsetWidth - bar;
+ var usedWidth = widthAvailable - requiredWidth;
+
+ // Control column needs to always be included. This makes it sub-
+ // optimal in terms of using the available with, but to stop layout
+ // thrashing or overflow. Also we need to account for the control column
+ // width first so we know how much width is available for the other
+ // columns, since the control column might not be the first one shown
+ for ( i=0, ien=display.length ; i<ien ; i++ ) {
+ if ( columns[i].control ) {
+ usedWidth -= columns[i].minWidth;
+ }
+ }
+
+ // Allow columns to be shown (counting by priority and then right to
+ // left) until we run out of room
+ var empty = false;
+ for ( i=0, ien=order.length ; i<ien ; i++ ) {
+ var colIdx = order[i].columnIdx;
+
+ if ( display[colIdx] === '-' && ! columns[colIdx].control && columns[colIdx].minWidth ) {
+ // Once we've found a column that won't fit we don't let any
+ // others display either, or columns might disappear in the
+ // middle of the table
+ if ( empty || usedWidth - columns[colIdx].minWidth < 0 ) {
+ empty = true;
+ display[colIdx] = false;
+ }
+ else {
+ display[colIdx] = true;
+ }
+
+ usedWidth -= columns[colIdx].minWidth;
+ }
+ }
+
+ // Determine if the 'control' column should be shown (if there is one).
+ // This is the case when there is a hidden column (that is not the
+ // control column). The two loops look inefficient here, but they are
+ // trivial and will fly through. We need to know the outcome from the
+ // first , before the action in the second can be taken
+ var showControl = false;
+
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ if ( ! columns[i].control && ! columns[i].never && display[i] === false ) {
+ showControl = true;
+ break;
+ }
+ }
+
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ if ( columns[i].control ) {
+ display[i] = showControl;
+ }
+
+ // Replace not visible string with false from the control column detection above
+ if ( display[i] === 'not-visible' ) {
+ display[i] = false;
+ }
+ }
+
+ // Finally we need to make sure that there is at least one column that
+ // is visible
+ if ( $.inArray( true, display ) === -1 ) {
+ display[0] = true;
+ }
+
+ return display;
+ },
+
+
+ /**
+ * Create the internal `columns` array with information about the columns
+ * for the table. This includes determining which breakpoints the column
+ * will appear in, based upon class names in the column, which makes up the
+ * vast majority of this method.
+ *
+ * @private
+ */
+ _classLogic: function ()
+ {
+ var that = this;
+ var calc = {};
+ var breakpoints = this.c.breakpoints;
+ var dt = this.s.dt;
+ var columns = dt.columns().eq(0).map( function (i) {
+ var column = this.column(i);
+ var className = column.header().className;
+ var priority = dt.settings()[0].aoColumns[i].responsivePriority;
+ var dataPriority = column.header().getAttribute('data-priority');
+
+ if ( priority === undefined ) {
+ priority = dataPriority === undefined || dataPriority === null?
+ 10000 :
+ dataPriority * 1;
+ }
+
+ return {
+ className: className,
+ includeIn: [],
+ auto: false,
+ control: false,
+ never: className.match(/\b(dtr\-)?never\b/) ? true : false,
+ priority: priority
+ };
+ } );
+
+ // Simply add a breakpoint to `includeIn` array, ensuring that there are
+ // no duplicates
+ var add = function ( colIdx, name ) {
+ var includeIn = columns[ colIdx ].includeIn;
+
+ if ( $.inArray( name, includeIn ) === -1 ) {
+ includeIn.push( name );
+ }
+ };
+
+ var column = function ( colIdx, name, operator, matched ) {
+ var size, i, ien;
+
+ if ( ! operator ) {
+ columns[ colIdx ].includeIn.push( name );
+ }
+ else if ( operator === 'max-' ) {
+ // Add this breakpoint and all smaller
+ size = that._find( name ).width;
+
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
+ if ( breakpoints[i].width <= size ) {
+ add( colIdx, breakpoints[i].name );
+ }
+ }
+ }
+ else if ( operator === 'min-' ) {
+ // Add this breakpoint and all larger
+ size = that._find( name ).width;
+
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
+ if ( breakpoints[i].width >= size ) {
+ add( colIdx, breakpoints[i].name );
+ }
+ }
+ }
+ else if ( operator === 'not-' ) {
+ // Add all but this breakpoint
+ for ( i=0, ien=breakpoints.length ; i<ien ; i++ ) {
+ if ( breakpoints[i].name.indexOf( matched ) === -1 ) {
+ add( colIdx, breakpoints[i].name );
+ }
+ }
+ }
+ };
+
+ // Loop over each column and determine if it has a responsive control
+ // class
+ columns.each( function ( col, i ) {
+ var classNames = col.className.split(' ');
+ var hasClass = false;
+
+ // Split the class name up so multiple rules can be applied if needed
+ for ( var k=0, ken=classNames.length ; k<ken ; k++ ) {
+ var className = classNames[k].trim();
+
+ if ( className === 'all' || className === 'dtr-all' ) {
+ // Include in all
+ hasClass = true;
+ col.includeIn = $.map( breakpoints, function (a) {
+ return a.name;
+ } );
+ return;
+ }
+ else if ( className === 'none' || className === 'dtr-none' || col.never ) {
+ // Include in none (default) and no auto
+ hasClass = true;
+ return;
+ }
+ else if ( className === 'control' || className === 'dtr-control' ) {
+ // Special column that is only visible, when one of the other
+ // columns is hidden. This is used for the details control
+ hasClass = true;
+ col.control = true;
+ return;
+ }
+
+ $.each( breakpoints, function ( j, breakpoint ) {
+ // Does this column have a class that matches this breakpoint?
+ var brokenPoint = breakpoint.name.split('-');
+ var re = new RegExp( '(min\\-|max\\-|not\\-)?('+brokenPoint[0]+')(\\-[_a-zA-Z0-9])?' );
+ var match = className.match( re );
+
+ if ( match ) {
+ hasClass = true;
+
+ if ( match[2] === brokenPoint[0] && match[3] === '-'+brokenPoint[1] ) {
+ // Class name matches breakpoint name fully
+ column( i, breakpoint.name, match[1], match[2]+match[3] );
+ }
+ else if ( match[2] === brokenPoint[0] && ! match[3] ) {
+ // Class name matched primary breakpoint name with no qualifier
+ column( i, breakpoint.name, match[1], match[2] );
+ }
+ }
+ } );
+ }
+
+ // If there was no control class, then automatic sizing is used
+ if ( ! hasClass ) {
+ col.auto = true;
+ }
+ } );
+
+ this.s.columns = columns;
+ },
+
+ /**
+ * Update the cells to show the correct control class / button
+ * @private
+ */
+ _controlClass: function ()
+ {
+ if ( this.c.details.type === 'inline' ) {
+ var dt = this.s.dt;
+ var columnsVis = this.s.current;
+ var firstVisible = $.inArray(true, columnsVis);
+
+ // Remove from any cells which shouldn't have it
+ dt.cells(
+ null,
+ function(idx) {
+ return idx !== firstVisible;
+ },
+ {page: 'current'}
+ )
+ .nodes()
+ .to$()
+ .filter('.dtr-control')
+ .removeClass('dtr-control');
+
+ dt.cells(null, firstVisible, {page: 'current'})
+ .nodes()
+ .to$()
+ .addClass('dtr-control');
+ }
+ },
+
+ /**
+ * Show the details for the child row
+ *
+ * @param {DataTables.Api} row API instance for the row
+ * @param {boolean} update Update flag
+ * @private
+ */
+ _detailsDisplay: function ( row, update )
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var details = this.c.details;
+
+ if ( details && details.type !== false ) {
+ var renderer = typeof details.renderer === 'string'
+ ? Responsive.renderer[details.renderer]()
+ : details.renderer;
+
+ var res = details.display( row, update, function () {
+ return renderer.call(
+ that, dt, row[0], that._detailsObj(row[0])
+ );
+ } );
+
+ if ( res === true || res === false ) {
+ $(dt.table().node()).triggerHandler( 'responsive-display.dt', [dt, row, res, update] );
+ }
+ }
+ },
+
+
+ /**
+ * Initialisation for the details handler
+ *
+ * @private
+ */
+ _detailsInit: function ()
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var details = this.c.details;
+
+ // The inline type always uses the first child as the target
+ if ( details.type === 'inline' ) {
+ details.target = 'td.dtr-control, th.dtr-control';
+ }
+
+ // Keyboard accessibility
+ dt.on( 'draw.dtr', function () {
+ that._tabIndexes();
+ } );
+ that._tabIndexes(); // Initial draw has already happened
+
+ $( dt.table().body() ).on( 'keyup.dtr', 'td, th', function (e) {
+ if ( e.keyCode === 13 && $(this).data('dtr-keyboard') ) {
+ $(this).click();
+ }
+ } );
+
+ // type.target can be a string jQuery selector or a column index
+ var target = details.target;
+ var selector = typeof target === 'string' ? target : 'td, th';
+
+ if ( target !== undefined || target !== null ) {
+ // Click handler to show / hide the details rows when they are available
+ $( dt.table().body() )
+ .on( 'click.dtr mousedown.dtr mouseup.dtr', selector, function (e) {
+ // If the table is not collapsed (i.e. there is no hidden columns)
+ // then take no action
+ if ( ! $(dt.table().node()).hasClass('collapsed' ) ) {
+ return;
+ }
+
+ // Check that the row is actually a DataTable's controlled node
+ if ( $.inArray( $(this).closest('tr').get(0), dt.rows().nodes().toArray() ) === -1 ) {
+ return;
+ }
+
+ // For column index, we determine if we should act or not in the
+ // handler - otherwise it is already okay
+ if ( typeof target === 'number' ) {
+ var targetIdx = target < 0 ?
+ dt.columns().eq(0).length + target :
+ target;
+
+ if ( dt.cell( this ).index().column !== targetIdx ) {
+ return;
+ }
+ }
+
+ // $().closest() includes itself in its check
+ var row = dt.row( $(this).closest('tr') );
+
+ // Check event type to do an action
+ if ( e.type === 'click' ) {
+ // The renderer is given as a function so the caller can execute it
+ // only when they need (i.e. if hiding there is no point is running
+ // the renderer)
+ that._detailsDisplay( row, false );
+ }
+ else if ( e.type === 'mousedown' ) {
+ // For mouse users, prevent the focus ring from showing
+ $(this).css('outline', 'none');
+ }
+ else if ( e.type === 'mouseup' ) {
+ // And then re-allow at the end of the click
+ $(this).trigger('blur').css('outline', '');
+ }
+ } );
+ }
+ },
+
+
+ /**
+ * Get the details to pass to a renderer for a row
+ * @param {int} rowIdx Row index
+ * @private
+ */
+ _detailsObj: function ( rowIdx )
+ {
+ var that = this;
+ var dt = this.s.dt;
+
+ return $.map( this.s.columns, function( col, i ) {
+ // Never and control columns should not be passed to the renderer
+ if ( col.never || col.control ) {
+ return;
+ }
+
+ var dtCol = dt.settings()[0].aoColumns[ i ];
+
+ return {
+ className: dtCol.sClass,
+ columnIndex: i,
+ data: dt.cell( rowIdx, i ).render( that.c.orthogonal ),
+ hidden: dt.column( i ).visible() && !that.s.current[ i ],
+ rowIndex: rowIdx,
+ title: dtCol.sTitle !== null ?
+ dtCol.sTitle :
+ $(dt.column(i).header()).text()
+ };
+ } );
+ },
+
+
+ /**
+ * Find a breakpoint object from a name
+ *
+ * @param {string} name Breakpoint name to find
+ * @return {object} Breakpoint description object
+ * @private
+ */
+ _find: function ( name )
+ {
+ var breakpoints = this.c.breakpoints;
+
+ for ( var i=0, ien=breakpoints.length ; i<ien ; i++ ) {
+ if ( breakpoints[i].name === name ) {
+ return breakpoints[i];
+ }
+ }
+ },
+
+
+ /**
+ * Re-create the contents of the child rows as the display has changed in
+ * some way.
+ *
+ * @private
+ */
+ _redrawChildren: function ()
+ {
+ var that = this;
+ var dt = this.s.dt;
+
+ dt.rows( {page: 'current'} ).iterator( 'row', function ( settings, idx ) {
+ var row = dt.row( idx );
+
+ that._detailsDisplay( dt.row( idx ), true );
+ } );
+ },
+
+
+ /**
+ * Alter the table display for a resized viewport. This involves first
+ * determining what breakpoint the window currently is in, getting the
+ * column visibilities to apply and then setting them.
+ *
+ * @param {boolean} forceRedraw Force a redraw
+ * @private
+ */
+ _resize: function (forceRedraw)
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var width = $(window).innerWidth();
+ var breakpoints = this.c.breakpoints;
+ var breakpoint = breakpoints[0].name;
+ var columns = this.s.columns;
+ var i, ien;
+ var oldVis = this.s.current.slice();
+
+ // Determine what breakpoint we are currently at
+ for ( i=breakpoints.length-1 ; i>=0 ; i-- ) {
+ if ( width <= breakpoints[i].width ) {
+ breakpoint = breakpoints[i].name;
+ break;
+ }
+ }
+
+ // Show the columns for that break point
+ var columnsVis = this._columnsVisiblity( breakpoint );
+ this.s.current = columnsVis;
+
+ // Set the class before the column visibility is changed so event
+ // listeners know what the state is. Need to determine if there are
+ // any columns that are not visible but can be shown
+ var collapsedClass = false;
+
+ for ( i=0, ien=columns.length ; i<ien ; i++ ) {
+ if ( columnsVis[i] === false && ! columns[i].never && ! columns[i].control && ! dt.column(i).visible() === false ) {
+ collapsedClass = true;
+ break;
+ }
+ }
+
+ $( dt.table().node() ).toggleClass( 'collapsed', collapsedClass );
+
+ var changed = false;
+ var visible = 0;
+
+ dt.columns().eq(0).each( function ( colIdx, i ) {
+ if ( columnsVis[i] === true ) {
+ visible++;
+ }
+
+ if ( forceRedraw || columnsVis[i] !== oldVis[i] ) {
+ changed = true;
+ that._setColumnVis( colIdx, columnsVis[i] );
+ }
+ } );
+
+ // Always need to update the display, regardless of if it has changed or not, so nodes
+ // can be re-inserted for listHiddenNodes
+ this._redrawChildren();
+
+ if ( changed ) {
+ // Inform listeners of the change
+ $(dt.table().node()).trigger( 'responsive-resize.dt', [dt, this.s.current] );
+
+ // If no records, update the "No records" display element
+ if ( dt.page.info().recordsDisplay === 0 ) {
+ $('td', dt.table().body()).eq(0).attr('colspan', visible);
+ }
+ }
+
+ that._controlClass();
+ },
+
+
+ /**
+ * Determine the width of each column in the table so the auto column hiding
+ * has that information to work with. This method is never going to be 100%
+ * perfect since column widths can change slightly per page, but without
+ * seriously compromising performance this is quite effective.
+ *
+ * @private
+ */
+ _resizeAuto: function ()
+ {
+ var dt = this.s.dt;
+ var columns = this.s.columns;
+ var that = this;
+
+ // Are we allowed to do auto sizing?
+ if ( ! this.c.auto ) {
+ return;
+ }
+
+ // Are there any columns that actually need auto-sizing, or do they all
+ // have classes defined
+ if ( $.inArray( true, $.map( columns, function (c) { return c.auto; } ) ) === -1 ) {
+ return;
+ }
+
+ // Need to restore all children. They will be reinstated by a re-render
+ if ( ! $.isEmptyObject( this.s.childNodeStore ) ) {
+ $.each( this.s.childNodeStore, function ( key ) {
+ var idx = key.split('-');
+
+ that._childNodesRestore( dt, idx[0]*1, idx[1]*1 );
+ } );
+ }
+
+ // Clone the table with the current data in it
+ var tableWidth = dt.table().node().offsetWidth;
+ var columnWidths = dt.columns;
+ var clonedTable = dt.table().node().cloneNode( false );
+ var clonedHeader = $( dt.table().header().cloneNode( false ) ).appendTo( clonedTable );
+ var clonedBody = $( dt.table().body() ).clone( false, false ).empty().appendTo( clonedTable ); // use jQuery because of IE8
+
+ clonedTable.style.width = 'auto';
+
+ // Header
+ var headerCells = dt.columns()
+ .header()
+ .filter( function (idx) {
+ return dt.column(idx).visible();
+ } )
+ .to$()
+ .clone( false )
+ .css( 'display', 'table-cell' )
+ .css( 'width', 'auto' )
+ .css( 'min-width', 0 );
+
+ // Body rows - we don't need to take account of DataTables' column
+ // visibility since we implement our own here (hence the `display` set)
+ $(clonedBody)
+ .append( $(dt.rows( { page: 'current' } ).nodes()).clone( false ) )
+ .find( 'th, td' ).css( 'display', '' );
+
+ // Footer
+ var footer = dt.table().footer();
+ if ( footer ) {
+ var clonedFooter = $( footer.cloneNode( false ) ).appendTo( clonedTable );
+ var footerCells = dt.columns()
+ .footer()
+ .filter( function (idx) {
+ return dt.column(idx).visible();
+ } )
+ .to$()
+ .clone( false )
+ .css( 'display', 'table-cell' );
+
+ $('<tr/>')
+ .append( footerCells )
+ .appendTo( clonedFooter );
+ }
+
+ $('<tr/>')
+ .append( headerCells )
+ .appendTo( clonedHeader );
+
+ // In the inline case extra padding is applied to the first column to
+ // give space for the show / hide icon. We need to use this in the
+ // calculation
+ if ( this.c.details.type === 'inline' ) {
+ $(clonedTable).addClass( 'dtr-inline collapsed' );
+ }
+
+ // It is unsafe to insert elements with the same name into the DOM
+ // multiple times. For example, cloning and inserting a checked radio
+ // clears the chcecked state of the original radio.
+ $( clonedTable ).find( '[name]' ).removeAttr( 'name' );
+
+ // A position absolute table would take the table out of the flow of
+ // our container element, bypassing the height and width (Scroller)
+ $( clonedTable ).css( 'position', 'relative' )
+
+ var inserted = $('<div/>')
+ .css( {
+ width: 1,
+ height: 1,
+ overflow: 'hidden',
+ clear: 'both'
+ } )
+ .append( clonedTable );
+
+ inserted.insertBefore( dt.table().node() );
+
+ // The cloned header now contains the smallest that each column can be
+ headerCells.each( function (i) {
+ var idx = dt.column.index( 'fromVisible', i );
+ columns[ idx ].minWidth = this.offsetWidth || 0;
+ } );
+
+ inserted.remove();
+ },
+
+ /**
+ * Get the state of the current hidden columns - controlled by Responsive only
+ */
+ _responsiveOnlyHidden: function ()
+ {
+ var dt = this.s.dt;
+
+ return $.map( this.s.current, function (v, i) {
+ // If the column is hidden by DataTables then it can't be hidden by
+ // Responsive!
+ if ( dt.column(i).visible() === false ) {
+ return true;
+ }
+ return v;
+ } );
+ },
+
+ /**
+ * Set a column's visibility.
+ *
+ * We don't use DataTables' column visibility controls in order to ensure
+ * that column visibility can Responsive can no-exist. Since only IE8+ is
+ * supported (and all evergreen browsers of course) the control of the
+ * display attribute works well.
+ *
+ * @param {integer} col Column index
+ * @param {boolean} showHide Show or hide (true or false)
+ * @private
+ */
+ _setColumnVis: function ( col, showHide )
+ {
+ var that = this;
+ var dt = this.s.dt;
+ var display = showHide ? '' : 'none'; // empty string will remove the attr
+
+ $( dt.column( col ).header() )
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ $( dt.column( col ).footer() )
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ dt.column( col ).nodes().to$()
+ .css( 'display', display )
+ .toggleClass('dtr-hidden', !showHide);
+
+ // If the are child nodes stored, we might need to reinsert them
+ if ( ! $.isEmptyObject( this.s.childNodeStore ) ) {
+ dt.cells( null, col ).indexes().each( function (idx) {
+ that._childNodesRestore( dt, idx.row, idx.column );
+ } );
+ }
+ },
+
+
+ /**
+ * Update the cell tab indexes for keyboard accessibility. This is called on
+ * every table draw - that is potentially inefficient, but also the least
+ * complex option given that column visibility can change on the fly. Its a
+ * shame user-focus was removed from CSS 3 UI, as it would have solved this
+ * issue with a single CSS statement.
+ *
+ * @private
+ */
+ _tabIndexes: function ()
+ {
+ var dt = this.s.dt;
+ var cells = dt.cells( { page: 'current' } ).nodes().to$();
+ var ctx = dt.settings()[0];
+ var target = this.c.details.target;
+
+ cells.filter( '[data-dtr-keyboard]' ).removeData( '[data-dtr-keyboard]' );
+
+ if ( typeof target === 'number' ) {
+ dt.cells( null, target, { page: 'current' } ).nodes().to$()
+ .attr( 'tabIndex', ctx.iTabIndex )
+ .data( 'dtr-keyboard', 1 );
+ }
+ else {
+ // This is a bit of a hack - we need to limit the selected nodes to just
+ // those of this table
+ if ( target === 'td:first-child, th:first-child' ) {
+ target = '>td:first-child, >th:first-child';
+ }
+
+ $( target, dt.rows( { page: 'current' } ).nodes() )
+ .attr( 'tabIndex', ctx.iTabIndex )
+ .data( 'dtr-keyboard', 1 );
+ }
+ }
+} );
+
+
+/**
+ * List of default breakpoints. Each item in the array is an object with two
+ * properties:
+ *
+ * * `name` - the breakpoint name.
+ * * `width` - the breakpoint width
+ *
+ * @name Responsive.breakpoints
+ * @static
+ */
+Responsive.breakpoints = [
+ { name: 'desktop', width: Infinity },
+ { name: 'tablet-l', width: 1024 },
+ { name: 'tablet-p', width: 768 },
+ { name: 'mobile-l', width: 480 },
+ { name: 'mobile-p', width: 320 }
+];
+
+
+/**
+ * Display methods - functions which define how the hidden data should be shown
+ * in the table.
+ *
+ * @namespace
+ * @name Responsive.defaults
+ * @static
+ */
+Responsive.display = {
+ childRow: function ( row, update, render ) {
+ if ( update ) {
+ if ( $(row.node()).hasClass('parent') ) {
+ row.child( render(), 'child' ).show();
+
+ return true;
+ }
+ }
+ else {
+ if ( ! row.child.isShown() ) {
+ row.child( render(), 'child' ).show();
+ $( row.node() ).addClass( 'parent' );
+
+ return true;
+ }
+ else {
+ row.child( false );
+ $( row.node() ).removeClass( 'parent' );
+
+ return false;
+ }
+ }
+ },
+
+ childRowImmediate: function ( row, update, render ) {
+ if ( (! update && row.child.isShown()) || ! row.responsive.hasHidden() ) {
+ // User interaction and the row is show, or nothing to show
+ row.child( false );
+ $( row.node() ).removeClass( 'parent' );
+
+ return false;
+ }
+ else {
+ // Display
+ row.child( render(), 'child' ).show();
+ $( row.node() ).addClass( 'parent' );
+
+ return true;
+ }
+ },
+
+ // This is a wrapper so the modal options for Bootstrap and jQuery UI can
+ // have options passed into them. This specific one doesn't need to be a
+ // function but it is for consistency in the `modal` name
+ modal: function ( options ) {
+ return function ( row, update, render ) {
+ if ( ! update ) {
+ // Show a modal
+ var close = function () {
+ modal.remove(); // will tidy events for us
+ $(document).off( 'keypress.dtr' );
+ };
+
+ var modal = $('<div class="dtr-modal"/>')
+ .append( $('<div class="dtr-modal-display"/>')
+ .append( $('<div class="dtr-modal-content"/>')
+ .append( render() )
+ )
+ .append( $('<div class="dtr-modal-close">×</div>' )
+ .click( function () {
+ close();
+ } )
+ )
+ )
+ .append( $('<div class="dtr-modal-background"/>')
+ .click( function () {
+ close();
+ } )
+ )
+ .appendTo( 'body' );
+
+ $(document).on( 'keyup.dtr', function (e) {
+ if ( e.keyCode === 27 ) {
+ e.stopPropagation();
+
+ close();
+ }
+ } );
+ }
+ else {
+ $('div.dtr-modal-content')
+ .empty()
+ .append( render() );
+ }
+
+ if ( options && options.header ) {
+ $('div.dtr-modal-content').prepend(
+ '<h2>'+options.header( row )+'</h2>'
+ );
+ }
+ };
+ }
+};
+
+
+/**
+ * Display methods - functions which define how the hidden data should be shown
+ * in the table.
+ *
+ * @namespace
+ * @name Responsive.defaults
+ * @static
+ */
+Responsive.renderer = {
+ listHiddenNodes: function () {
+ return function ( api, rowIdx, columns ) {
+ var that = this;
+ var ul = $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>');
+ var found = false;
+
+ var data = $.each( columns, function ( i, col ) {
+ if ( col.hidden ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ $(
+ '<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
+ '<span class="dtr-title">'+
+ col.title+
+ '</span> '+
+ '</li>'
+ )
+ .append( $('<span class="dtr-data"/>').append( that._childNodes( api, col.rowIndex, col.columnIndex ) ) )// api.cell( col.rowIndex, col.columnIndex ).node().childNodes ) )
+ .appendTo( ul );
+
+ found = true;
+ }
+ } );
+
+ return found ?
+ ul :
+ false;
+ };
+ },
+
+ listHidden: function () {
+ return function ( api, rowIdx, columns ) {
+ var data = $.map( columns, function ( col ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ return col.hidden ?
+ '<li '+klass+' data-dtr-index="'+col.columnIndex+'" data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
+ '<span class="dtr-title">'+
+ col.title+
+ '</span> '+
+ '<span class="dtr-data">'+
+ col.data+
+ '</span>'+
+ '</li>' :
+ '';
+ } ).join('');
+
+ return data ?
+ $('<ul data-dtr-index="'+rowIdx+'" class="dtr-details"/>').append( data ) :
+ false;
+ }
+ },
+
+ tableAll: function ( options ) {
+ options = $.extend( {
+ tableClass: ''
+ }, options );
+
+ return function ( api, rowIdx, columns ) {
+ var data = $.map( columns, function ( col ) {
+ var klass = col.className ?
+ 'class="'+ col.className +'"' :
+ '';
+
+ return '<tr '+klass+' data-dt-row="'+col.rowIndex+'" data-dt-column="'+col.columnIndex+'">'+
+ '<td>'+col.title+':'+'</td> '+
+ '<td>'+col.data+'</td>'+
+ '</tr>';
+ } ).join('');
+
+ return $('<table class="'+options.tableClass+' dtr-details" width="100%"/>').append( data );
+ }
+ }
+};
+
+/**
+ * Responsive default settings for initialisation
+ *
+ * @namespace
+ * @name Responsive.defaults
+ * @static
+ */
+Responsive.defaults = {
+ /**
+ * List of breakpoints for the instance. Note that this means that each
+ * instance can have its own breakpoints. Additionally, the breakpoints
+ * cannot be changed once an instance has been creased.
+ *
+ * @type {Array}
+ * @default Takes the value of `Responsive.breakpoints`
+ */
+ breakpoints: Responsive.breakpoints,
+
+ /**
+ * Enable / disable auto hiding calculations. It can help to increase
+ * performance slightly if you disable this option, but all columns would
+ * need to have breakpoint classes assigned to them
+ *
+ * @type {Boolean}
+ * @default `true`
+ */
+ auto: true,
+
+ /**
+ * Details control. If given as a string value, the `type` property of the
+ * default object is set to that value, and the defaults used for the rest
+ * of the object - this is for ease of implementation.
+ *
+ * The object consists of the following properties:
+ *
+ * * `display` - A function that is used to show and hide the hidden details
+ * * `renderer` - function that is called for display of the child row data.
+ * The default function will show the data from the hidden columns
+ * * `target` - Used as the selector for what objects to attach the child
+ * open / close to
+ * * `type` - `false` to disable the details display, `inline` or `column`
+ * for the two control types
+ *
+ * @type {Object|string}
+ */
+ details: {
+ display: Responsive.display.childRow,
+
+ renderer: Responsive.renderer.listHidden(),
+
+ target: 0,
+
+ type: 'inline'
+ },
+
+ /**
+ * Orthogonal data request option. This is used to define the data type
+ * requested when Responsive gets the data to show in the child row.
+ *
+ * @type {String}
+ */
+ orthogonal: 'display'
+};
+
+
+/*
+ * API
+ */
+var Api = $.fn.dataTable.Api;
+
+// Doesn't do anything - work around for a bug in DT... Not documented
+Api.register( 'responsive()', function () {
+ return this;
+} );
+
+Api.register( 'responsive.index()', function ( li ) {
+ li = $(li);
+
+ return {
+ column: li.data('dtr-index'),
+ row: li.parent().data('dtr-index')
+ };
+} );
+
+Api.register( 'responsive.rebuild()', function () {
+ return this.iterator( 'table', function ( ctx ) {
+ if ( ctx._responsive ) {
+ ctx._responsive._classLogic();
+ }
+ } );
+} );
+
+Api.register( 'responsive.recalc()', function () {
+ return this.iterator( 'table', function ( ctx ) {
+ if ( ctx._responsive ) {
+ ctx._responsive._resizeAuto();
+ ctx._responsive._resize();
+ }
+ } );
+} );
+
+Api.register( 'responsive.hasHidden()', function () {
+ var ctx = this.context[0];
+
+ return ctx._responsive ?
+ $.inArray( false, ctx._responsive._responsiveOnlyHidden() ) !== -1 :
+ false;
+} );
+
+Api.registerPlural( 'columns().responsiveHidden()', 'column().responsiveHidden()', function () {
+ return this.iterator( 'column', function ( settings, column ) {
+ return settings._responsive ?
+ settings._responsive._responsiveOnlyHidden()[ column ] :
+ false;
+ }, 1 );
+} );
+
+
+/**
+ * Version information
+ *
+ * @name Responsive.version
+ * @static
+ */
+Responsive.version = '2.4.0';
+
+
+$.fn.dataTable.Responsive = Responsive;
+$.fn.DataTable.Responsive = Responsive;
+
+// Attach a listener to the document which listens for DataTables initialisation
+// events so we can automatically initialise
+$(document).on( 'preInit.dt.dtr', function (e, settings, json) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ if ( $(settings.nTable).hasClass( 'responsive' ) ||
+ $(settings.nTable).hasClass( 'dt-responsive' ) ||
+ settings.oInit.responsive ||
+ DataTable.defaults.responsive
+ ) {
+ var init = settings.oInit.responsive;
+
+ if ( init !== false ) {
+ new Responsive( settings, $.isPlainObject( init ) ? init : {} );
+ }
+ }
+} );
+
+
+return DataTable;
+}));
+
+
+/*! Bootstrap 5 integration for DataTables' Responsive
+ * © SpryMedia Ltd - datatables.net/license
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net-bs5', 'datatables.net-responsive'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net-bs5')(root, $);
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net-responsive')(root, $);
+ }
+
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+var _display = DataTable.Responsive.display;
+var _original = _display.modal;
+var _modal = $(
+ '<div class="modal fade dtr-bs-modal" role="dialog">'+
+ '<div class="modal-dialog" role="document">'+
+ '<div class="modal-content">'+
+ '<div class="modal-header">'+
+ '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>'+
+ '</div>'+
+ '<div class="modal-body"/>'+
+ '</div>'+
+ '</div>'+
+ '</div>'
+);
+var modal;
+
+// Note this could be undefined at the time of initialisation - the
+// DataTable.Responsive.bootstrap function can be used to set a different
+// bootstrap object
+var _bs = window.bootstrap;
+
+DataTable.Responsive.bootstrap = function (bs) {
+ _bs = bs;
+}
+
+_display.modal = function ( options ) {
+ if (! modal) {
+ modal = new _bs.Modal(_modal[0]);
+ }
+
+ return function ( row, update, render ) {
+ if ( ! $.fn.modal ) {
+ _original( row, update, render );
+ }
+ else {
+ if ( ! update ) {
+ if ( options && options.header ) {
+ var header = _modal.find('div.modal-header');
+ var button = header.find('button').detach();
+
+ header
+ .empty()
+ .append( '<h4 class="modal-title">'+options.header( row )+'</h4>' )
+ .append( button );
+ }
+
+ _modal.find( 'div.modal-body' )
+ .empty()
+ .append( render() );
+
+ _modal
+ .appendTo( 'body' )
+ .modal();
+
+ modal.show();
+ }
+ }
+ };
+};
+
+
+return DataTable;
+}));
+
+
+/*! Select for DataTables 1.5.0
+ * 2015-2021 SpryMedia Ltd - datatables.net/license/mit
+ */
+
+(function( factory ){
+ if ( typeof define === 'function' && define.amd ) {
+ // AMD
+ define( ['jquery', 'datatables.net'], function ( $ ) {
+ return factory( $, window, document );
+ } );
+ }
+ else if ( typeof exports === 'object' ) {
+ // CommonJS
+ module.exports = function (root, $) {
+ if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
+ root = window;
+ }
+
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
+ }
+
+
+ return factory( $, root, root.document );
+ };
+ }
+ else {
+ // Browser
+ factory( jQuery, window, document );
+ }
+}(function( $, window, document, undefined ) {
+'use strict';
+var DataTable = $.fn.dataTable;
+
+
+
+// Version information for debugger
+DataTable.select = {};
+
+DataTable.select.version = '1.5.0';
+
+DataTable.select.init = function ( dt ) {
+ var ctx = dt.settings()[0];
+
+ if (ctx._select) {
+ return;
+ }
+
+ var savedSelected = dt.state.loaded();
+
+ var selectAndSave = function(e, settings, data) {
+ if(data === null || data.select === undefined) {
+ return;
+ }
+
+ // Clear any currently selected rows, before restoring state
+ // None will be selected on first initialisation
+ if (dt.rows({selected: true}).any()) {
+ dt.rows().deselect();
+ }
+ if (data.select.rows !== undefined) {
+ dt.rows(data.select.rows).select();
+ }
+
+ if (dt.columns({selected: true}).any()) {
+ dt.columns().deselect();
+ }
+ if (data.select.columns !== undefined) {
+ dt.columns(data.select.columns).select();
+ }
+
+ if (dt.cells({selected: true}).any()) {
+ dt.cells().deselect();
+ }
+ if (data.select.cells !== undefined) {
+ for(var i = 0; i < data.select.cells.length; i++) {
+ dt.cell(data.select.cells[i].row, data.select.cells[i].column).select();
+ }
+ }
+ dt.state.save();
+ }
+
+ dt.one('init', function() {
+ dt.on('stateSaveParams', function(e, settings, data) {
+ data.select = {};
+ data.select.rows = dt.rows({selected:true}).ids(true).toArray();
+ data.select.columns = dt.columns({selected:true})[0];
+ data.select.cells = dt.cells({selected:true})[0].map(function(coords) {
+ return {row: dt.row(coords.row).id(true), column: coords.column}
+ });
+ })
+
+ selectAndSave(undefined, undefined, savedSelected)
+ dt.on('stateLoaded stateLoadParams', selectAndSave)
+ })
+
+ var init = ctx.oInit.select;
+ var defaults = DataTable.defaults.select;
+ var opts = init === undefined ?
+ defaults :
+ init;
+
+ // Set defaults
+ var items = 'row';
+ var style = 'api';
+ var blurable = false;
+ var toggleable = true;
+ var info = true;
+ var selector = 'td, th';
+ var className = 'selected';
+ var setStyle = false;
+
+ ctx._select = {};
+
+ // Initialisation customisations
+ if ( opts === true ) {
+ style = 'os';
+ setStyle = true;
+ }
+ else if ( typeof opts === 'string' ) {
+ style = opts;
+ setStyle = true;
+ }
+ else if ( $.isPlainObject( opts ) ) {
+ if ( opts.blurable !== undefined ) {
+ blurable = opts.blurable;
+ }
+
+ if ( opts.toggleable !== undefined ) {
+ toggleable = opts.toggleable;
+ }
+
+ if ( opts.info !== undefined ) {
+ info = opts.info;
+ }
+
+ if ( opts.items !== undefined ) {
+ items = opts.items;
+ }
+
+ if ( opts.style !== undefined ) {
+ style = opts.style;
+ setStyle = true;
+ }
+ else {
+ style = 'os';
+ setStyle = true;
+ }
+
+ if ( opts.selector !== undefined ) {
+ selector = opts.selector;
+ }
+
+ if ( opts.className !== undefined ) {
+ className = opts.className;
+ }
+ }
+
+ dt.select.selector( selector );
+ dt.select.items( items );
+ dt.select.style( style );
+ dt.select.blurable( blurable );
+ dt.select.toggleable( toggleable );
+ dt.select.info( info );
+ ctx._select.className = className;
+
+
+ // Sort table based on selected rows. Requires Select Datatables extension
+ $.fn.dataTable.ext.order['select-checkbox'] = function ( settings, col ) {
+ return this.api().column( col, {order: 'index'} ).nodes().map( function ( td ) {
+ if ( settings._select.items === 'row' ) {
+ return $( td ).parent().hasClass( settings._select.className );
+ } else if ( settings._select.items === 'cell' ) {
+ return $( td ).hasClass( settings._select.className );
+ }
+ return false;
+ });
+ };
+
+ // If the init options haven't enabled select, but there is a selectable
+ // class name, then enable
+ if ( ! setStyle && $( dt.table().node() ).hasClass( 'selectable' ) ) {
+ dt.select.style( 'os' );
+ }
+};
+
+/*
+
+Select is a collection of API methods, event handlers, event emitters and
+buttons (for the `Buttons` extension) for DataTables. It provides the following
+features, with an overview of how they are implemented:
+
+## Selection of rows, columns and cells. Whether an item is selected or not is
+ stored in:
+
+* rows: a `_select_selected` property which contains a boolean value of the
+ DataTables' `aoData` object for each row
+* columns: a `_select_selected` property which contains a boolean value of the
+ DataTables' `aoColumns` object for each column
+* cells: a `_selected_cells` property which contains an array of boolean values
+ of the `aoData` object for each row. The array is the same length as the
+ columns array, with each element of it representing a cell.
+
+This method of using boolean flags allows Select to operate when nodes have not
+been created for rows / cells (DataTables' defer rendering feature).
+
+## API methods
+
+A range of API methods are available for triggering selection and de-selection
+of rows. Methods are also available to configure the selection events that can
+be triggered by an end user (such as which items are to be selected). To a large
+extent, these of API methods *is* Select. It is basically a collection of helper
+functions that can be used to select items in a DataTable.
+
+Configuration of select is held in the object `_select` which is attached to the
+DataTables settings object on initialisation. Select being available on a table
+is not optional when Select is loaded, but its default is for selection only to
+be available via the API - so the end user wouldn't be able to select rows
+without additional configuration.
+
+The `_select` object contains the following properties:
+
+```
+{
+ items:string - Can be `rows`, `columns` or `cells`. Defines what item
+ will be selected if the user is allowed to activate row
+ selection using the mouse.
+ style:string - Can be `none`, `single`, `multi` or `os`. Defines the
+ interaction style when selecting items
+ blurable:boolean - If row selection can be cleared by clicking outside of
+ the table
+ toggleable:boolean - If row selection can be cancelled by repeated clicking
+ on the row
+ info:boolean - If the selection summary should be shown in the table
+ information elements
+}
+```
+
+In addition to the API methods, Select also extends the DataTables selector
+options for rows, columns and cells adding a `selected` option to the selector
+options object, allowing the developer to select only selected items or
+unselected items.
+
+## Mouse selection of items
+
+Clicking on items can be used to select items. This is done by a simple event
+handler that will select the items using the API methods.
+
+ */
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Local functions
+ */
+
+/**
+ * Add one or more cells to the selection when shift clicking in OS selection
+ * style cell selection.
+ *
+ * Cell range is more complicated than row and column as we want to select
+ * in the visible grid rather than by index in sequence. For example, if you
+ * click first in cell 1-1 and then shift click in 2-2 - cells 1-2 and 2-1
+ * should also be selected (and not 1-3, 1-4. etc)
+ *
+ * @param {DataTable.Api} dt DataTable
+ * @param {object} idx Cell index to select to
+ * @param {object} last Cell index to select from
+ * @private
+ */
+function cellRange( dt, idx, last )
+{
+ var indexes;
+ var columnIndexes;
+ var rowIndexes;
+ var selectColumns = function ( start, end ) {
+ if ( start > end ) {
+ var tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ var record = false;
+ return dt.columns( ':visible' ).indexes().filter( function (i) {
+ if ( i === start ) {
+ record = true;
+ }
+
+ if ( i === end ) { // not else if, as start might === end
+ record = false;
+ return true;
+ }
+
+ return record;
+ } );
+ };
+
+ var selectRows = function ( start, end ) {
+ var indexes = dt.rows( { search: 'applied' } ).indexes();
+
+ // Which comes first - might need to swap
+ if ( indexes.indexOf( start ) > indexes.indexOf( end ) ) {
+ var tmp = end;
+ end = start;
+ start = tmp;
+ }
+
+ var record = false;
+ return indexes.filter( function (i) {
+ if ( i === start ) {
+ record = true;
+ }
+
+ if ( i === end ) {
+ record = false;
+ return true;
+ }
+
+ return record;
+ } );
+ };
+
+ if ( ! dt.cells( { selected: true } ).any() && ! last ) {
+ // select from the top left cell to this one
+ columnIndexes = selectColumns( 0, idx.column );
+ rowIndexes = selectRows( 0 , idx.row );
+ }
+ else {
+ // Get column indexes between old and new
+ columnIndexes = selectColumns( last.column, idx.column );
+ rowIndexes = selectRows( last.row , idx.row );
+ }
+
+ indexes = dt.cells( rowIndexes, columnIndexes ).flatten();
+
+ if ( ! dt.cells( idx, { selected: true } ).any() ) {
+ // Select range
+ dt.cells( indexes ).select();
+ }
+ else {
+ // Deselect range
+ dt.cells( indexes ).deselect();
+ }
+}
+
+/**
+ * Disable mouse selection by removing the selectors
+ *
+ * @param {DataTable.Api} dt DataTable to remove events from
+ * @private
+ */
+function disableMouseSelection( dt )
+{
+ var ctx = dt.settings()[0];
+ var selector = ctx._select.selector;
+
+ $( dt.table().container() )
+ .off( 'mousedown.dtSelect', selector )
+ .off( 'mouseup.dtSelect', selector )
+ .off( 'click.dtSelect', selector );
+
+ $('body').off( 'click.dtSelect' + _safeId(dt.table().node()) );
+}
+
+/**
+ * Attach mouse listeners to the table to allow mouse selection of items
+ *
+ * @param {DataTable.Api} dt DataTable to remove events from
+ * @private
+ */
+function enableMouseSelection ( dt )
+{
+ var container = $( dt.table().container() );
+ var ctx = dt.settings()[0];
+ var selector = ctx._select.selector;
+ var matchSelection;
+
+ container
+ .on( 'mousedown.dtSelect', selector, function(e) {
+ // Disallow text selection for shift clicking on the table so multi
+ // element selection doesn't look terrible!
+ if ( e.shiftKey || e.metaKey || e.ctrlKey ) {
+ container
+ .css( '-moz-user-select', 'none' )
+ .one('selectstart.dtSelect', selector, function () {
+ return false;
+ } );
+ }
+
+ if ( window.getSelection ) {
+ matchSelection = window.getSelection();
+ }
+ } )
+ .on( 'mouseup.dtSelect', selector, function() {
+ // Allow text selection to occur again, Mozilla style (tested in FF
+ // 35.0.1 - still required)
+ container.css( '-moz-user-select', '' );
+ } )
+ .on( 'click.dtSelect', selector, function ( e ) {
+ var items = dt.select.items();
+ var idx;
+
+ // If text was selected (click and drag), then we shouldn't change
+ // the row's selected state
+ if ( matchSelection ) {
+ var selection = window.getSelection();
+
+ // If the element that contains the selection is not in the table, we can ignore it
+ // This can happen if the developer selects text from the click event
+ if ( ! selection.anchorNode || $(selection.anchorNode).closest('table')[0] === dt.table().node() ) {
+ if ( selection !== matchSelection ) {
+ return;
+ }
+ }
+ }
+
+ var ctx = dt.settings()[0];
+ var wrapperClass = dt.settings()[0].oClasses.sWrapper.trim().replace(/ +/g, '.');
+
+ // Ignore clicks inside a sub-table
+ if ( $(e.target).closest('div.'+wrapperClass)[0] != dt.table().container() ) {
+ return;
+ }
+
+ var cell = dt.cell( $(e.target).closest('td, th') );
+
+ // Check the cell actually belongs to the host DataTable (so child
+ // rows, etc, are ignored)
+ if ( ! cell.any() ) {
+ return;
+ }
+
+ var event = $.Event('user-select.dt');
+ eventTrigger( dt, event, [ items, cell, e ] );
+
+ if ( event.isDefaultPrevented() ) {
+ return;
+ }
+
+ var cellIndex = cell.index();
+ if ( items === 'row' ) {
+ idx = cellIndex.row;
+ typeSelect( e, dt, ctx, 'row', idx );
+ }
+ else if ( items === 'column' ) {
+ idx = cell.index().column;
+ typeSelect( e, dt, ctx, 'column', idx );
+ }
+ else if ( items === 'cell' ) {
+ idx = cell.index();
+ typeSelect( e, dt, ctx, 'cell', idx );
+ }
+
+ ctx._select_lastCell = cellIndex;
+ } );
+
+ // Blurable
+ $('body').on( 'click.dtSelect' + _safeId(dt.table().node()), function ( e ) {
+ if ( ctx._select.blurable ) {
+ // If the click was inside the DataTables container, don't blur
+ if ( $(e.target).parents().filter( dt.table().container() ).length ) {
+ return;
+ }
+
+ // Ignore elements which have been removed from the DOM (i.e. paging
+ // buttons)
+ if ( $(e.target).parents('html').length === 0 ) {
+ return;
+ }
+
+ // Don't blur in Editor form
+ if ( $(e.target).parents('div.DTE').length ) {
+ return;
+ }
+
+ var event = $.Event('select-blur.dt');
+ eventTrigger( dt, event, [ e.target, e ] );
+
+ if ( event.isDefaultPrevented() ) {
+ return;
+ }
+
+ clear( ctx, true );
+ }
+ } );
+}
+
+/**
+ * Trigger an event on a DataTable
+ *
+ * @param {DataTable.Api} api DataTable to trigger events on
+ * @param {boolean} selected true if selected, false if deselected
+ * @param {string} type Item type acting on
+ * @param {boolean} any Require that there are values before
+ * triggering
+ * @private
+ */
+function eventTrigger ( api, type, args, any )
+{
+ if ( any && ! api.flatten().length ) {
+ return;
+ }
+
+ if ( typeof type === 'string' ) {
+ type = type +'.dt';
+ }
+
+ args.unshift( api );
+
+ $(api.table().node()).trigger( type, args );
+}
+
+/**
+ * Update the information element of the DataTable showing information about the
+ * items selected. This is done by adding tags to the existing text
+ *
+ * @param {DataTable.Api} api DataTable to update
+ * @private
+ */
+function info ( api )
+{
+ var ctx = api.settings()[0];
+
+ if ( ! ctx._select.info || ! ctx.aanFeatures.i ) {
+ return;
+ }
+
+ if ( api.select.style() === 'api' ) {
+ return;
+ }
+
+ var rows = api.rows( { selected: true } ).flatten().length;
+ var columns = api.columns( { selected: true } ).flatten().length;
+ var cells = api.cells( { selected: true } ).flatten().length;
+
+ var add = function ( el, name, num ) {
+ el.append( $('<span class="select-item"/>').append( api.i18n(
+ 'select.'+name+'s',
+ { _: '%d '+name+'s selected', 0: '', 1: '1 '+name+' selected' },
+ num
+ ) ) );
+ };
+
+ // Internal knowledge of DataTables to loop over all information elements
+ $.each( ctx.aanFeatures.i, function ( i, el ) {
+ el = $(el);
+
+ var output = $('<span class="select-info"/>');
+ add( output, 'row', rows );
+ add( output, 'column', columns );
+ add( output, 'cell', cells );
+
+ var exisiting = el.children('span.select-info');
+ if ( exisiting.length ) {
+ exisiting.remove();
+ }
+
+ if ( output.text() !== '' ) {
+ el.append( output );
+ }
+ } );
+}
+
+/**
+ * Initialisation of a new table. Attach event handlers and callbacks to allow
+ * Select to operate correctly.
+ *
+ * This will occur _after_ the initial DataTables initialisation, although
+ * before Ajax data is rendered, if there is ajax data
+ *
+ * @param {DataTable.settings} ctx Settings object to operate on
+ * @private
+ */
+function init ( ctx ) {
+ var api = new DataTable.Api( ctx );
+ ctx._select_init = true;
+
+ // Row callback so that classes can be added to rows and cells if the item
+ // was selected before the element was created. This will happen with the
+ // `deferRender` option enabled.
+ //
+ // This method of attaching to `aoRowCreatedCallback` is a hack until
+ // DataTables has proper events for row manipulation If you are reviewing
+ // this code to create your own plug-ins, please do not do this!
+ ctx.aoRowCreatedCallback.push( {
+ fn: function ( row, data, index ) {
+ var i, ien;
+ var d = ctx.aoData[ index ];
+
+ // Row
+ if ( d._select_selected ) {
+ $( row ).addClass( ctx._select.className );
+ }
+
+ // Cells and columns - if separated out, we would need to do two
+ // loops, so it makes sense to combine them into a single one
+ for ( i=0, ien=ctx.aoColumns.length ; i<ien ; i++ ) {
+ if ( ctx.aoColumns[i]._select_selected || (d._selected_cells && d._selected_cells[i]) ) {
+ $(d.anCells[i]).addClass( ctx._select.className );
+ }
+ }
+ },
+ sName: 'select-deferRender'
+ } );
+
+ // On Ajax reload we want to reselect all rows which are currently selected,
+ // if there is an rowId (i.e. a unique value to identify each row with)
+ api.on( 'preXhr.dt.dtSelect', function (e, settings) {
+ if (settings !== api.settings()[0]) {
+ // Not triggered by our DataTable!
+ return;
+ }
+
+ // note that column selection doesn't need to be cached and then
+ // reselected, as they are already selected
+ var rows = api.rows( { selected: true } ).ids( true ).filter( function ( d ) {
+ return d !== undefined;
+ } );
+
+ var cells = api.cells( { selected: true } ).eq(0).map( function ( cellIdx ) {
+ var id = api.row( cellIdx.row ).id( true );
+ return id ?
+ { row: id, column: cellIdx.column } :
+ undefined;
+ } ).filter( function ( d ) {
+ return d !== undefined;
+ } );
+
+ // On the next draw, reselect the currently selected items
+ api.one( 'draw.dt.dtSelect', function () {
+ api.rows( rows ).select();
+
+ // `cells` is not a cell index selector, so it needs a loop
+ if ( cells.any() ) {
+ cells.each( function ( id ) {
+ api.cells( id.row, id.column ).select();
+ } );
+ }
+ } );
+ } );
+
+ // Update the table information element with selected item summary
+ api.on( 'draw.dtSelect.dt select.dtSelect.dt deselect.dtSelect.dt info.dt', function () {
+ info( api );
+ api.state.save();
+ } );
+
+ // Clean up and release
+ api.on( 'destroy.dtSelect', function () {
+ api.rows({selected: true}).deselect();
+
+ disableMouseSelection( api );
+ api.off( '.dtSelect' );
+ $('body').off('.dtSelect' + _safeId(api.table().node()));
+ } );
+}
+
+/**
+ * Add one or more items (rows or columns) to the selection when shift clicking
+ * in OS selection style
+ *
+ * @param {DataTable.Api} dt DataTable
+ * @param {string} type Row or column range selector
+ * @param {object} idx Item index to select to
+ * @param {object} last Item index to select from
+ * @private
+ */
+function rowColumnRange( dt, type, idx, last )
+{
+ // Add a range of rows from the last selected row to this one
+ var indexes = dt[type+'s']( { search: 'applied' } ).indexes();
+ var idx1 = $.inArray( last, indexes );
+ var idx2 = $.inArray( idx, indexes );
+
+ if ( ! dt[type+'s']( { selected: true } ).any() && idx1 === -1 ) {
+ // select from top to here - slightly odd, but both Windows and Mac OS
+ // do this
+ indexes.splice( $.inArray( idx, indexes )+1, indexes.length );
+ }
+ else {
+ // reverse so we can shift click 'up' as well as down
+ if ( idx1 > idx2 ) {
+ var tmp = idx2;
+ idx2 = idx1;
+ idx1 = tmp;
+ }
+
+ indexes.splice( idx2+1, indexes.length );
+ indexes.splice( 0, idx1 );
+ }
+
+ if ( ! dt[type]( idx, { selected: true } ).any() ) {
+ // Select range
+ dt[type+'s']( indexes ).select();
+ }
+ else {
+ // Deselect range - need to keep the clicked on row selected
+ indexes.splice( $.inArray( idx, indexes ), 1 );
+ dt[type+'s']( indexes ).deselect();
+ }
+}
+
+/**
+ * Clear all selected items
+ *
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
+ * @param {boolean} [force=false] Force the de-selection to happen, regardless
+ * of selection style
+ * @private
+ */
+function clear( ctx, force )
+{
+ if ( force || ctx._select.style === 'single' ) {
+ var api = new DataTable.Api( ctx );
+
+ api.rows( { selected: true } ).deselect();
+ api.columns( { selected: true } ).deselect();
+ api.cells( { selected: true } ).deselect();
+ }
+}
+
+/**
+ * Select items based on the current configuration for style and items.
+ *
+ * @param {object} e Mouse event object
+ * @param {DataTables.Api} dt DataTable
+ * @param {DataTable.settings} ctx Settings object of the host DataTable
+ * @param {string} type Items to select
+ * @param {int|object} idx Index of the item to select
+ * @private
+ */
+function typeSelect ( e, dt, ctx, type, idx )
+{
+ var style = dt.select.style();
+ var toggleable = dt.select.toggleable();
+ var isSelected = dt[type]( idx, { selected: true } ).any();
+
+ if ( isSelected && ! toggleable ) {
+ return;
+ }
+
+ if ( style === 'os' ) {
+ if ( e.ctrlKey || e.metaKey ) {
+ // Add or remove from the selection
+ dt[type]( idx ).select( ! isSelected );
+ }
+ else if ( e.shiftKey ) {
+ if ( type === 'cell' ) {
+ cellRange( dt, idx, ctx._select_lastCell || null );
+ }
+ else {
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
+ ctx._select_lastCell[type] :
+ null
+ );
+ }
+ }
+ else {
+ // No cmd or shift click - deselect if selected, or select
+ // this row only
+ var selected = dt[type+'s']( { selected: true } );
+
+ if ( isSelected && selected.flatten().length === 1 ) {
+ dt[type]( idx ).deselect();
+ }
+ else {
+ selected.deselect();
+ dt[type]( idx ).select();
+ }
+ }
+ } else if ( style == 'multi+shift' ) {
+ if ( e.shiftKey ) {
+ if ( type === 'cell' ) {
+ cellRange( dt, idx, ctx._select_lastCell || null );
+ }
+ else {
+ rowColumnRange( dt, type, idx, ctx._select_lastCell ?
+ ctx._select_lastCell[type] :
+ null
+ );
+ }
+ }
+ else {
+ dt[ type ]( idx ).select( ! isSelected );
+ }
+ }
+ else {
+ dt[ type ]( idx ).select( ! isSelected );
+ }
+}
+
+function _safeId( node ) {
+ return node.id.replace(/[^a-zA-Z0-9\-\_]/g, '-');
+}
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables selectors
+ */
+
+// row and column are basically identical just assigned to different properties
+// and checking a different array, so we can dynamically create the functions to
+// reduce the code size
+$.each( [
+ { type: 'row', prop: 'aoData' },
+ { type: 'column', prop: 'aoColumns' }
+], function ( i, o ) {
+ DataTable.ext.selector[ o.type ].push( function ( settings, opts, indexes ) {
+ var selected = opts.selected;
+ var data;
+ var out = [];
+
+ if ( selected !== true && selected !== false ) {
+ return indexes;
+ }
+
+ for ( var i=0, ien=indexes.length ; i<ien ; i++ ) {
+ data = settings[ o.prop ][ indexes[i] ];
+
+ if ( (selected === true && data._select_selected === true) ||
+ (selected === false && ! data._select_selected )
+ ) {
+ out.push( indexes[i] );
+ }
+ }
+
+ return out;
+ } );
+} );
+
+DataTable.ext.selector.cell.push( function ( settings, opts, cells ) {
+ var selected = opts.selected;
+ var rowData;
+ var out = [];
+
+ if ( selected === undefined ) {
+ return cells;
+ }
+
+ for ( var i=0, ien=cells.length ; i<ien ; i++ ) {
+ rowData = settings.aoData[ cells[i].row ];
+
+ if ( (selected === true && rowData._selected_cells && rowData._selected_cells[ cells[i].column ] === true) ||
+ (selected === false && ( ! rowData._selected_cells || ! rowData._selected_cells[ cells[i].column ] ) )
+ ) {
+ out.push( cells[i] );
+ }
+ }
+
+ return out;
+} );
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * DataTables API
+ *
+ * For complete documentation, please refer to the docs/api directory or the
+ * DataTables site
+ */
+
+// Local variables to improve compression
+var apiRegister = DataTable.Api.register;
+var apiRegisterPlural = DataTable.Api.registerPlural;
+
+apiRegister( 'select()', function () {
+ return this.iterator( 'table', function ( ctx ) {
+ DataTable.select.init( new DataTable.Api( ctx ) );
+ } );
+} );
+
+apiRegister( 'select.blurable()', function ( flag ) {
+ if ( flag === undefined ) {
+ return this.context[0]._select.blurable;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ ctx._select.blurable = flag;
+ } );
+} );
+
+apiRegister( 'select.toggleable()', function ( flag ) {
+ if ( flag === undefined ) {
+ return this.context[0]._select.toggleable;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ ctx._select.toggleable = flag;
+ } );
+} );
+
+apiRegister( 'select.info()', function ( flag ) {
+ if ( flag === undefined ) {
+ return this.context[0]._select.info;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ ctx._select.info = flag;
+ } );
+} );
+
+apiRegister( 'select.items()', function ( items ) {
+ if ( items === undefined ) {
+ return this.context[0]._select.items;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ ctx._select.items = items;
+
+ eventTrigger( new DataTable.Api( ctx ), 'selectItems', [ items ] );
+ } );
+} );
+
+// Takes effect from the _next_ selection. None disables future selection, but
+// does not clear the current selection. Use the `deselect` methods for that
+apiRegister( 'select.style()', function ( style ) {
+ if ( style === undefined ) {
+ return this.context[0]._select.style;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ if ( ! ctx._select ) {
+ DataTable.select.init( new DataTable.Api(ctx) );
+ }
+
+ if ( ! ctx._select_init ) {
+ init(ctx);
+ }
+
+ ctx._select.style = style;
+
+ // Add / remove mouse event handlers. They aren't required when only
+ // API selection is available
+ var dt = new DataTable.Api( ctx );
+ disableMouseSelection( dt );
+
+ if ( style !== 'api' ) {
+ enableMouseSelection( dt );
+ }
+
+ eventTrigger( new DataTable.Api( ctx ), 'selectStyle', [ style ] );
+ } );
+} );
+
+apiRegister( 'select.selector()', function ( selector ) {
+ if ( selector === undefined ) {
+ return this.context[0]._select.selector;
+ }
+
+ return this.iterator( 'table', function ( ctx ) {
+ disableMouseSelection( new DataTable.Api( ctx ) );
+
+ ctx._select.selector = selector;
+
+ if ( ctx._select.style !== 'api' ) {
+ enableMouseSelection( new DataTable.Api( ctx ) );
+ }
+ } );
+} );
+
+
+
+apiRegisterPlural( 'rows().select()', 'row().select()', function ( select ) {
+ var api = this;
+
+ if ( select === false ) {
+ return this.deselect();
+ }
+
+ this.iterator( 'row', function ( ctx, idx ) {
+ clear( ctx );
+
+ ctx.aoData[ idx ]._select_selected = true;
+ $( ctx.aoData[ idx ].nTr ).addClass( ctx._select.className );
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'select', [ 'row', api[i] ], true );
+ } );
+
+ return this;
+} );
+
+apiRegister( 'row().selected()', function () {
+ var ctx = this.context[0];
+
+ if (
+ ctx &&
+ this.length &&
+ ctx.aoData[this[0]] &&
+ ctx.aoData[this[0]]._select_selected
+ ) {
+ return true;
+ }
+
+ return false;
+} );
+
+apiRegisterPlural( 'columns().select()', 'column().select()', function ( select ) {
+ var api = this;
+
+ if ( select === false ) {
+ return this.deselect();
+ }
+
+ this.iterator( 'column', function ( ctx, idx ) {
+ clear( ctx );
+
+ ctx.aoColumns[ idx ]._select_selected = true;
+
+ var column = new DataTable.Api( ctx ).column( idx );
+
+ $( column.header() ).addClass( ctx._select.className );
+ $( column.footer() ).addClass( ctx._select.className );
+
+ column.nodes().to$().addClass( ctx._select.className );
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'select', [ 'column', api[i] ], true );
+ } );
+
+ return this;
+} );
+
+apiRegister( 'column().selected()', function () {
+ var ctx = this.context[0];
+
+ if (
+ ctx &&
+ this.length &&
+ ctx.aoColumns[this[0]] &&
+ ctx.aoColumns[this[0]]._select_selected
+ ) {
+ return true;
+ }
+
+ return false;
+} );
+
+apiRegisterPlural( 'cells().select()', 'cell().select()', function ( select ) {
+ var api = this;
+
+ if ( select === false ) {
+ return this.deselect();
+ }
+
+ this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
+ clear( ctx );
+
+ var data = ctx.aoData[ rowIdx ];
+
+ if ( data._selected_cells === undefined ) {
+ data._selected_cells = [];
+ }
+
+ data._selected_cells[ colIdx ] = true;
+
+ if ( data.anCells ) {
+ $( data.anCells[ colIdx ] ).addClass( ctx._select.className );
+ }
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'select', [ 'cell', api.cells(api[i]).indexes().toArray() ], true );
+ } );
+
+ return this;
+} );
+
+apiRegister( 'cell().selected()', function () {
+ var ctx = this.context[0];
+
+ if (ctx && this.length) {
+ var row = ctx.aoData[this[0][0].row];
+
+ if (row && row._selected_cells && row._selected_cells[this[0][0].column]) {
+ return true;
+ }
+ }
+
+ return false;
+} );
+
+
+apiRegisterPlural( 'rows().deselect()', 'row().deselect()', function () {
+ var api = this;
+
+ this.iterator( 'row', function ( ctx, idx ) {
+ ctx.aoData[ idx ]._select_selected = false;
+ ctx._select_lastCell = null;
+ $( ctx.aoData[ idx ].nTr ).removeClass( ctx._select.className );
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'deselect', [ 'row', api[i] ], true );
+ } );
+
+ return this;
+} );
+
+apiRegisterPlural( 'columns().deselect()', 'column().deselect()', function () {
+ var api = this;
+
+ this.iterator( 'column', function ( ctx, idx ) {
+ ctx.aoColumns[ idx ]._select_selected = false;
+
+ var api = new DataTable.Api( ctx );
+ var column = api.column( idx );
+
+ $( column.header() ).removeClass( ctx._select.className );
+ $( column.footer() ).removeClass( ctx._select.className );
+
+ // Need to loop over each cell, rather than just using
+ // `column().nodes()` as cells which are individually selected should
+ // not have the `selected` class removed from them
+ api.cells( null, idx ).indexes().each( function (cellIdx) {
+ var data = ctx.aoData[ cellIdx.row ];
+ var cellSelected = data._selected_cells;
+
+ if ( data.anCells && (! cellSelected || ! cellSelected[ cellIdx.column ]) ) {
+ $( data.anCells[ cellIdx.column ] ).removeClass( ctx._select.className );
+ }
+ } );
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'deselect', [ 'column', api[i] ], true );
+ } );
+
+ return this;
+} );
+
+apiRegisterPlural( 'cells().deselect()', 'cell().deselect()', function () {
+ var api = this;
+
+ this.iterator( 'cell', function ( ctx, rowIdx, colIdx ) {
+ var data = ctx.aoData[ rowIdx ];
+
+ if(data._selected_cells !== undefined) {
+ data._selected_cells[ colIdx ] = false;
+ }
+
+ // Remove class only if the cells exist, and the cell is not column
+ // selected, in which case the class should remain (since it is selected
+ // in the column)
+ if ( data.anCells && ! ctx.aoColumns[ colIdx ]._select_selected ) {
+ $( data.anCells[ colIdx ] ).removeClass( ctx._select.className );
+ }
+ } );
+
+ this.iterator( 'table', function ( ctx, i ) {
+ eventTrigger( api, 'deselect', [ 'cell', api[i] ], true );
+ } );
+
+ return this;
+} );
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Buttons
+ */
+function i18n( label, def ) {
+ return function (dt) {
+ return dt.i18n( 'buttons.'+label, def );
+ };
+}
+
+// Common events with suitable namespaces
+function namespacedEvents ( config ) {
+ var unique = config._eventNamespace;
+
+ return 'draw.dt.DT'+unique+' select.dt.DT'+unique+' deselect.dt.DT'+unique;
+}
+
+function enabled ( dt, config ) {
+ if ( $.inArray( 'rows', config.limitTo ) !== -1 && dt.rows( { selected: true } ).any() ) {
+ return true;
+ }
+
+ if ( $.inArray( 'columns', config.limitTo ) !== -1 && dt.columns( { selected: true } ).any() ) {
+ return true;
+ }
+
+ if ( $.inArray( 'cells', config.limitTo ) !== -1 && dt.cells( { selected: true } ).any() ) {
+ return true;
+ }
+
+ return false;
+}
+
+var _buttonNamespace = 0;
+
+$.extend( DataTable.ext.buttons, {
+ selected: {
+ text: i18n( 'selected', 'Selected' ),
+ className: 'buttons-selected',
+ limitTo: [ 'rows', 'columns', 'cells' ],
+ init: function ( dt, node, config ) {
+ var that = this;
+ config._eventNamespace = '.select'+(_buttonNamespace++);
+
+ // .DT namespace listeners are removed by DataTables automatically
+ // on table destroy
+ dt.on( namespacedEvents(config), function () {
+ that.enable( enabled(dt, config) );
+ } );
+
+ this.disable();
+ },
+ destroy: function ( dt, node, config ) {
+ dt.off( config._eventNamespace );
+ }
+ },
+ selectedSingle: {
+ text: i18n( 'selectedSingle', 'Selected single' ),
+ className: 'buttons-selected-single',
+ init: function ( dt, node, config ) {
+ var that = this;
+ config._eventNamespace = '.select'+(_buttonNamespace++);
+
+ dt.on( namespacedEvents(config), function () {
+ var count = dt.rows( { selected: true } ).flatten().length +
+ dt.columns( { selected: true } ).flatten().length +
+ dt.cells( { selected: true } ).flatten().length;
+
+ that.enable( count === 1 );
+ } );
+
+ this.disable();
+ },
+ destroy: function ( dt, node, config ) {
+ dt.off( config._eventNamespace );
+ }
+ },
+ selectAll: {
+ text: i18n( 'selectAll', 'Select all' ),
+ className: 'buttons-select-all',
+ action: function () {
+ var items = this.select.items();
+ this[ items+'s' ]().select();
+ }
+ },
+ selectNone: {
+ text: i18n( 'selectNone', 'Deselect all' ),
+ className: 'buttons-select-none',
+ action: function () {
+ clear( this.settings()[0], true );
+ },
+ init: function ( dt, node, config ) {
+ var that = this;
+ config._eventNamespace = '.select'+(_buttonNamespace++);
+
+ dt.on( namespacedEvents(config), function () {
+ var count = dt.rows( { selected: true } ).flatten().length +
+ dt.columns( { selected: true } ).flatten().length +
+ dt.cells( { selected: true } ).flatten().length;
+
+ that.enable( count > 0 );
+ } );
+
+ this.disable();
+ },
+ destroy: function ( dt, node, config ) {
+ dt.off( config._eventNamespace );
+ }
+ }
+} );
+
+$.each( [ 'Row', 'Column', 'Cell' ], function ( i, item ) {
+ var lc = item.toLowerCase();
+
+ DataTable.ext.buttons[ 'select'+item+'s' ] = {
+ text: i18n( 'select'+item+'s', 'Select '+lc+'s' ),
+ className: 'buttons-select-'+lc+'s',
+ action: function () {
+ this.select.items( lc );
+ },
+ init: function ( dt ) {
+ var that = this;
+
+ dt.on( 'selectItems.dt.DT', function ( e, ctx, items ) {
+ that.active( items === lc );
+ } );
+ }
+ };
+} );
+
+
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Initialisation
+ */
+
+// DataTables creation - check if select has been defined in the options. Note
+// this required that the table be in the document! If it isn't then something
+// needs to trigger this method unfortunately. The next major release of
+// DataTables will rework the events and address this.
+$(document).on( 'preInit.dt.dtSelect', function (e, ctx) {
+ if ( e.namespace !== 'dt' ) {
+ return;
+ }
+
+ DataTable.select.init( new DataTable.Api( ctx ) );
+} );
+
+
+return DataTable;
+}));
+
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/005-notifications.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/005-notifications.min.js
new file mode 100644
index 0000000..7837ea5
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/005-notifications.min.js
@@ -0,0 +1 @@
+!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(h,b,d){var f,e,g={content:{message:"object"==typeof b?b.message:b,title:b.title?b.title:"",icon:b.icon?b.icon:"",url:b.url?b.url:"#",target:b.target?b.target:"-"}};d=a.extend(!0,{},g,d),this.settings=a.extend(!0,{},c,d),this._defaults=c,"-"===this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),!this.settings.allow_duplicates&&(this.settings.allow_duplicates||(f=this,e=!1,a('[data-notify="container"]').each(function(k,c){var b=a(c),d=b.find('[data-notify="title"]').text().trim(),g=b.find('[data-notify="message"]').html().trim(),h=d===a("<div>"+f.settings.content.title+"</div>").html().trim(),i=g===a("<div>"+f.settings.content.message+"</div>").html().trim(),j=b.hasClass("alert-"+f.settings.type);return h&&i&&j&&(e=!0),!e}),e))||this.init()}var c={element:"body",position:null,type:"info",allow_dismiss:!0,allow_duplicates:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:'<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="btn-close" data-notify="dismiss"></button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'};String.format=function(){for(var b=arguments[0],a=1;a<arguments.length;a++)b=b.replace(RegExp("\\{"+(a-1)+"\\}","gm"),arguments[a]);return b},a.extend(b.prototype,{init:function(){var a=this;this.buildNotify(),this.settings.content.icon&&this.setIcon(),"#"!=this.settings.content.url&&this.styleURL(),this.styleDismiss(),this.placement(),this.bind(),this.notify={$ele:this.$ele,update:function(e,f){var b={};for(var c in"string"==typeof e?b[e]=f:b=e,b)switch(c){case"type":this.$ele.removeClass("alert-"+a.settings.type),this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass("progress-bar-"+a.settings.type),a.settings.type=b[c],this.$ele.addClass("alert-"+b[c]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+b[c]);break;case"icon":var d=this.$ele.find('[data-notify="icon"]');"class"===a.settings.icon_type.toLowerCase()?d.removeClass(a.settings.content.icon).addClass(b[c]):(d.is("img")||d.find("img"),d.attr("src",b[c]));break;case"progress":var g=a.settings.delay-a.settings.delay*(b[c]/100);this.$ele.data("notify-delay",g),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",b[c]).css("width",b[c]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",b[c]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",b[c]);break;default:this.$ele.find('[data-notify="'+c+'"]').html(b[c])}var h=this.$ele.outerHeight()+parseInt(a.settings.spacing)+parseInt(a.settings.offset.y);a.reposition(h)},close:function(){a.close()}}},buildNotify:function(){var b=this.settings.content;this.$ele=a(String.format(this.settings.template,this.settings.type,b.title,b.message,b.url,b.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(!(this.settings.delay<=0)||this.settings.showProgressbar)&&this.settings.showProgressbar||this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"===this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('<img src="'+this.settings.content.icon+'" alt="Notify Icon" />')},styleDismiss:function(){this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:0,position:"absolute",top:0,width:"100%",zIndex:this.settings.z_index+1})},placement:function(){var d=this,b=this.settings.offset.y,c={display:"inline-block",margin:"0px auto",position:this.settings.position?this.settings.position:"body"===this.settings.element?"fixed":"absolute",transition:"all .5s ease-in-out",zIndex:this.settings.z_index},e=!1,f=this.settings;switch(a('[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])').each(function(){b=Math.max(b,parseInt(a(this).css(f.placement.from))+parseInt(a(this).outerHeight())+parseInt(f.spacing))}),!0===this.settings.newest_on_top&&(b=this.settings.offset.y),c[this.settings.placement.from]=b+"px",this.settings.placement.align){case"left":case"right":c[this.settings.placement.align]=this.settings.offset.x+"px";break;case"center":c.left=0,c.right=0}this.$ele.css(c).addClass(this.settings.animate.enter),a.each(Array("webkit-","moz-","o-","ms-",""),function(b,a){d.$ele[0].style[a+"AnimationIterationCount"]=1}),a(this.settings.element).append(this.$ele),!0===this.settings.newest_on_top&&(b=parseInt(b)+parseInt(this.settings.spacing)+this.$ele.outerHeight(),this.reposition(b)),a.isFunction(d.settings.onShow)&&d.settings.onShow.call(this.$ele),this.$ele.one(this.animations.start,function(){e=!0}).one(this.animations.end,function(){d.$ele.removeClass(d.settings.animate.enter),a.isFunction(d.settings.onShown)&&d.settings.onShown.call(this)}),setTimeout(function(){e||a.isFunction(d.settings.onShown)&&d.settings.onShown.call(this)},600)},bind:function(){var b=this;if(this.$ele.find('[data-notify="dismiss"]').on("click",function(){b.close()}),this.$ele.mouseover(function(){a(this).data("data-hover","true")}).mouseout(function(){a(this).data("data-hover","false")}),this.$ele.data("data-hover","false"),this.settings.delay>0){b.$ele.data("notify-delay",b.settings.delay);var c=setInterval(function(){var a=parseInt(b.$ele.data("notify-delay"))-b.settings.timer;if("false"===b.$ele.data("data-hover")&&"pause"===b.settings.mouse_over||"pause"!=b.settings.mouse_over){var d=(b.settings.delay-a)/b.settings.delay*100;b.$ele.data("notify-delay",a),b.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",d).css("width",d+"%")}a<= -b.settings.timer&&(clearInterval(c),b.close())},b.settings.timer)}},close:function(){var b=this,c=parseInt(this.$ele.css(this.settings.placement.from)),d=!1;this.$ele.attr("data-closing","true").addClass(this.settings.animate.exit),b.reposition(c),a.isFunction(b.settings.onClose)&&b.settings.onClose.call(this.$ele),this.$ele.one(this.animations.start,function(){d=!0}).one(this.animations.end,function(){a(this).remove(),a.isFunction(b.settings.onClosed)&&b.settings.onClosed.call(this)}),setTimeout(function(){d||(b.$ele.remove(),b.settings.onClosed&&b.settings.onClosed(b.$ele))},600)},reposition:function(d){var e=this,b='[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])',c=this.$ele.nextAll(b);!0===this.settings.newest_on_top&&(c=this.$ele.prevAll(b)),c.each(function(){a(this).css(e.settings.placement.from,d),d=parseInt(d)+parseInt(e.settings.spacing)+a(this).outerHeight()})}}),a.notify=function(a,c){return new b(this,a,c).notify},a.notifyDefaults=function(b){return c=a.extend(!0,{},c,b)},a.notifyClose=function(b){"warning"===b&&(b="danger"),void 0===b||"all"===b?a("[data-notify]").find('[data-notify="dismiss"]').trigger("click"):"success"===b||"info"===b||"warning"===b||"danger"===b?a(".alert-"+b+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):b?a(b+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):a('[data-notify-position="'+b+'"]').find('[data-notify="dismiss"]').trigger("click")},a.notifyCloseExcept=function(b){"warning"===b&&(b="danger"),"success"===b||"info"===b||"warning"===b||"danger"===b?a("[data-notify]").not(".alert-"+b).find('[data-notify="dismiss"]').trigger("click"):a("[data-notify]").not(b).find('[data-notify="dismiss"]').trigger("click")}})
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/007-formcache.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/006-formcache.min.js
similarity index 100%
rename from mailcow/src/mailcow-dockerized/data/web/js/build/007-formcache.min.js
rename to mailcow/src/mailcow-dockerized/data/web/js/build/006-formcache.min.js
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/006-notifications.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/006-notifications.min.js
deleted file mode 100644
index 01e7f30..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/006-notifications.min.js
+++ /dev/null
@@ -1 +0,0 @@
-!function(t){"function"==typeof define&&define.amd?define(["jquery"],t):t("object"==typeof exports?require("jquery"):jQuery)}(function(t){function s(s){var e=!1;return t('[data-notify="container"]').each(function(i,n){var a=t(n),o=a.find('[data-notify="title"]').text().trim(),r=a.find('[data-notify="message"]').html().trim(),l=o===t("<div>"+s.settings.content.title+"</div>").html().trim(),d=r===t("<div>"+s.settings.content.message+"</div>").html().trim(),g=a.hasClass("alert-"+s.settings.type);return l&&d&&g&&(e=!0),!e}),e}function e(e,n,a){var o={content:{message:"object"==typeof n?n.message:n,title:n.title?n.title:"",icon:n.icon?n.icon:"",url:n.url?n.url:"#",target:n.target?n.target:"-"}};a=t.extend(!0,{},o,a),this.settings=t.extend(!0,{},i,a),this._defaults=i,"-"===this.settings.content.target&&(this.settings.content.target=this.settings.url_target),this.animations={start:"webkitAnimationStart oanimationstart MSAnimationStart animationstart",end:"webkitAnimationEnd oanimationend MSAnimationEnd animationend"},"number"==typeof this.settings.offset&&(this.settings.offset={x:this.settings.offset,y:this.settings.offset}),(this.settings.allow_duplicates||!this.settings.allow_duplicates&&!s(this))&&this.init()}var i={element:"body",position:null,type:"info",allow_dismiss:!0,allow_duplicates:!0,newest_on_top:!1,showProgressbar:!1,placement:{from:"top",align:"right"},offset:20,spacing:10,z_index:1031,delay:5e3,timer:1e3,url_target:"_blank",mouse_over:null,animate:{enter:"animated fadeInDown",exit:"animated fadeOutUp"},onShow:null,onShown:null,onClose:null,onClosed:null,icon_type:"class",template:'<div data-notify="container" class="col-xs-11 col-sm-4 alert alert-{0}" role="alert"><button type="button" aria-hidden="true" class="close" data-notify="dismiss">×</button><span data-notify="icon"></span> <span data-notify="title">{1}</span> <span data-notify="message">{2}</span><div class="progress" data-notify="progressbar"><div class="progress-bar progress-bar-{0}" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%;"></div></div><a href="{3}" target="{4}" data-notify="url"></a></div>'};String.format=function(){for(var t=arguments[0],s=1;s<arguments.length;s++)t=t.replace(RegExp("\\{"+(s-1)+"\\}","gm"),arguments[s]);return t},t.extend(e.prototype,{init:function(){var t=this;this.buildNotify(),this.settings.content.icon&&this.setIcon(),"#"!=this.settings.content.url&&this.styleURL(),this.styleDismiss(),this.placement(),this.bind(),this.notify={$ele:this.$ele,update:function(s,e){var i={};"string"==typeof s?i[s]=e:i=s;for(var n in i)switch(n){case"type":this.$ele.removeClass("alert-"+t.settings.type),this.$ele.find('[data-notify="progressbar"] > .progress-bar').removeClass("progress-bar-"+t.settings.type),t.settings.type=i[n],this.$ele.addClass("alert-"+i[n]).find('[data-notify="progressbar"] > .progress-bar').addClass("progress-bar-"+i[n]);break;case"icon":var a=this.$ele.find('[data-notify="icon"]');"class"===t.settings.icon_type.toLowerCase()?a.removeClass(t.settings.content.icon).addClass(i[n]):(a.is("img")||a.find("img"),a.attr("src",i[n]));break;case"progress":var o=t.settings.delay-t.settings.delay*(i[n]/100);this.$ele.data("notify-delay",o),this.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i[n]).css("width",i[n]+"%");break;case"url":this.$ele.find('[data-notify="url"]').attr("href",i[n]);break;case"target":this.$ele.find('[data-notify="url"]').attr("target",i[n]);break;default:this.$ele.find('[data-notify="'+n+'"]').html(i[n])}var r=this.$ele.outerHeight()+parseInt(t.settings.spacing)+parseInt(t.settings.offset.y);t.reposition(r)},close:function(){t.close()}}},buildNotify:function(){var s=this.settings.content;this.$ele=t(String.format(this.settings.template,this.settings.type,s.title,s.message,s.url,s.target)),this.$ele.attr("data-notify-position",this.settings.placement.from+"-"+this.settings.placement.align),this.settings.allow_dismiss||this.$ele.find('[data-notify="dismiss"]').css("display","none"),(this.settings.delay<=0&&!this.settings.showProgressbar||!this.settings.showProgressbar)&&this.$ele.find('[data-notify="progressbar"]').remove()},setIcon:function(){"class"===this.settings.icon_type.toLowerCase()?this.$ele.find('[data-notify="icon"]').addClass(this.settings.content.icon):this.$ele.find('[data-notify="icon"]').is("img")?this.$ele.find('[data-notify="icon"]').attr("src",this.settings.content.icon):this.$ele.find('[data-notify="icon"]').append('<img src="'+this.settings.content.icon+'" alt="Notify Icon" />')},styleDismiss:function(){this.$ele.find('[data-notify="dismiss"]').css({position:"absolute",right:"10px",top:"5px",zIndex:this.settings.z_index+2})},styleURL:function(){this.$ele.find('[data-notify="url"]').css({backgroundImage:"url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)",height:"100%",left:0,position:"absolute",top:0,width:"100%",zIndex:this.settings.z_index+1})},placement:function(){var s=this,e=this.settings.offset.y,i={display:"inline-block",margin:"0px auto",position:this.settings.position?this.settings.position:"body"===this.settings.element?"fixed":"absolute",transition:"all .5s ease-in-out",zIndex:this.settings.z_index},n=!1,a=this.settings;switch(t('[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])').each(function(){e=Math.max(e,parseInt(t(this).css(a.placement.from))+parseInt(t(this).outerHeight())+parseInt(a.spacing))}),this.settings.newest_on_top===!0&&(e=this.settings.offset.y),i[this.settings.placement.from]=e+"px",this.settings.placement.align){case"left":case"right":i[this.settings.placement.align]=this.settings.offset.x+"px";break;case"center":i.left=0,i.right=0}this.$ele.css(i).addClass(this.settings.animate.enter),t.each(Array("webkit-","moz-","o-","ms-",""),function(t,e){s.$ele[0].style[e+"AnimationIterationCount"]=1}),t(this.settings.element).append(this.$ele),this.settings.newest_on_top===!0&&(e=parseInt(e)+parseInt(this.settings.spacing)+this.$ele.outerHeight(),this.reposition(e)),t.isFunction(s.settings.onShow)&&s.settings.onShow.call(this.$ele),this.$ele.one(this.animations.start,function(){n=!0}).one(this.animations.end,function(){s.$ele.removeClass(s.settings.animate.enter),t.isFunction(s.settings.onShown)&&s.settings.onShown.call(this)}),setTimeout(function(){n||t.isFunction(s.settings.onShown)&&s.settings.onShown.call(this)},600)},bind:function(){var s=this;if(this.$ele.find('[data-notify="dismiss"]').on("click",function(){s.close()}),this.$ele.mouseover(function(){t(this).data("data-hover","true")}).mouseout(function(){t(this).data("data-hover","false")}),this.$ele.data("data-hover","false"),this.settings.delay>0){s.$ele.data("notify-delay",s.settings.delay);var e=setInterval(function(){var t=parseInt(s.$ele.data("notify-delay"))-s.settings.timer;if("false"===s.$ele.data("data-hover")&&"pause"===s.settings.mouse_over||"pause"!=s.settings.mouse_over){var i=(s.settings.delay-t)/s.settings.delay*100;s.$ele.data("notify-delay",t),s.$ele.find('[data-notify="progressbar"] > div').attr("aria-valuenow",i).css("width",i+"%")}t<=-s.settings.timer&&(clearInterval(e),s.close())},s.settings.timer)}},close:function(){var s=this,e=parseInt(this.$ele.css(this.settings.placement.from)),i=!1;this.$ele.attr("data-closing","true").addClass(this.settings.animate.exit),s.reposition(e),t.isFunction(s.settings.onClose)&&s.settings.onClose.call(this.$ele),this.$ele.one(this.animations.start,function(){i=!0}).one(this.animations.end,function(){t(this).remove(),t.isFunction(s.settings.onClosed)&&s.settings.onClosed.call(this)}),setTimeout(function(){i||(s.$ele.remove(),s.settings.onClosed&&s.settings.onClosed(s.$ele))},600)},reposition:function(s){var e=this,i='[data-notify-position="'+this.settings.placement.from+"-"+this.settings.placement.align+'"]:not([data-closing="true"])',n=this.$ele.nextAll(i);this.settings.newest_on_top===!0&&(n=this.$ele.prevAll(i)),n.each(function(){t(this).css(e.settings.placement.from,s),s=parseInt(s)+parseInt(e.settings.spacing)+t(this).outerHeight()})}}),t.notify=function(t,s){var i=new e(this,t,s);return i.notify},t.notifyDefaults=function(s){return i=t.extend(!0,{},i,s)},t.notifyClose=function(s){"warning"===s&&(s="danger"),"undefined"==typeof s||"all"===s?t("[data-notify]").find('[data-notify="dismiss"]').trigger("click"):"success"===s||"info"===s||"warning"===s||"danger"===s?t(".alert-"+s+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):s?t(s+"[data-notify]").find('[data-notify="dismiss"]').trigger("click"):t('[data-notify-position="'+s+'"]').find('[data-notify="dismiss"]').trigger("click")},t.notifyCloseExcept=function(s){"warning"===s&&(s="danger"),"success"===s||"info"===s||"warning"===s||"danger"===s?t("[data-notify]").not(".alert-"+s).find('[data-notify="dismiss"]').trigger("click"):t("[data-notify]").not(s).find('[data-notify="dismiss"]').trigger("click")}});
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/007-chart.js b/mailcow/src/mailcow-dockerized/data/web/js/build/007-chart.js
new file mode 100644
index 0000000..5899061
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/007-chart.js
@@ -0,0 +1,13269 @@
+/*!
+ * Chart.js v3.7.1
+ * https://www.chartjs.org
+ * (c) 2022 Chart.js Contributors
+ * Released under the MIT License
+ */
+(function (global, factory) {
+typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
+typeof define === 'function' && define.amd ? define(factory) :
+(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Chart = factory());
+})(this, (function () { 'use strict';
+
+function fontString(pixelSize, fontStyle, fontFamily) {
+ return fontStyle + ' ' + pixelSize + 'px ' + fontFamily;
+}
+const requestAnimFrame = (function() {
+ if (typeof window === 'undefined') {
+ return function(callback) {
+ return callback();
+ };
+ }
+ return window.requestAnimationFrame;
+}());
+function throttled(fn, thisArg, updateFn) {
+ const updateArgs = updateFn || ((args) => Array.prototype.slice.call(args));
+ let ticking = false;
+ let args = [];
+ return function(...rest) {
+ args = updateArgs(rest);
+ if (!ticking) {
+ ticking = true;
+ requestAnimFrame.call(window, () => {
+ ticking = false;
+ fn.apply(thisArg, args);
+ });
+ }
+ };
+}
+function debounce(fn, delay) {
+ let timeout;
+ return function(...args) {
+ if (delay) {
+ clearTimeout(timeout);
+ timeout = setTimeout(fn, delay, args);
+ } else {
+ fn.apply(this, args);
+ }
+ return delay;
+ };
+}
+const _toLeftRightCenter = (align) => align === 'start' ? 'left' : align === 'end' ? 'right' : 'center';
+const _alignStartEnd = (align, start, end) => align === 'start' ? start : align === 'end' ? end : (start + end) / 2;
+const _textX = (align, left, right, rtl) => {
+ const check = rtl ? 'left' : 'right';
+ return align === check ? right : align === 'center' ? (left + right) / 2 : left;
+};
+
+class Animator {
+ constructor() {
+ this._request = null;
+ this._charts = new Map();
+ this._running = false;
+ this._lastDate = undefined;
+ }
+ _notify(chart, anims, date, type) {
+ const callbacks = anims.listeners[type];
+ const numSteps = anims.duration;
+ callbacks.forEach(fn => fn({
+ chart,
+ initial: anims.initial,
+ numSteps,
+ currentStep: Math.min(date - anims.start, numSteps)
+ }));
+ }
+ _refresh() {
+ if (this._request) {
+ return;
+ }
+ this._running = true;
+ this._request = requestAnimFrame.call(window, () => {
+ this._update();
+ this._request = null;
+ if (this._running) {
+ this._refresh();
+ }
+ });
+ }
+ _update(date = Date.now()) {
+ let remaining = 0;
+ this._charts.forEach((anims, chart) => {
+ if (!anims.running || !anims.items.length) {
+ return;
+ }
+ const items = anims.items;
+ let i = items.length - 1;
+ let draw = false;
+ let item;
+ for (; i >= 0; --i) {
+ item = items[i];
+ if (item._active) {
+ if (item._total > anims.duration) {
+ anims.duration = item._total;
+ }
+ item.tick(date);
+ draw = true;
+ } else {
+ items[i] = items[items.length - 1];
+ items.pop();
+ }
+ }
+ if (draw) {
+ chart.draw();
+ this._notify(chart, anims, date, 'progress');
+ }
+ if (!items.length) {
+ anims.running = false;
+ this._notify(chart, anims, date, 'complete');
+ anims.initial = false;
+ }
+ remaining += items.length;
+ });
+ this._lastDate = date;
+ if (remaining === 0) {
+ this._running = false;
+ }
+ }
+ _getAnims(chart) {
+ const charts = this._charts;
+ let anims = charts.get(chart);
+ if (!anims) {
+ anims = {
+ running: false,
+ initial: true,
+ items: [],
+ listeners: {
+ complete: [],
+ progress: []
+ }
+ };
+ charts.set(chart, anims);
+ }
+ return anims;
+ }
+ listen(chart, event, cb) {
+ this._getAnims(chart).listeners[event].push(cb);
+ }
+ add(chart, items) {
+ if (!items || !items.length) {
+ return;
+ }
+ this._getAnims(chart).items.push(...items);
+ }
+ has(chart) {
+ return this._getAnims(chart).items.length > 0;
+ }
+ start(chart) {
+ const anims = this._charts.get(chart);
+ if (!anims) {
+ return;
+ }
+ anims.running = true;
+ anims.start = Date.now();
+ anims.duration = anims.items.reduce((acc, cur) => Math.max(acc, cur._duration), 0);
+ this._refresh();
+ }
+ running(chart) {
+ if (!this._running) {
+ return false;
+ }
+ const anims = this._charts.get(chart);
+ if (!anims || !anims.running || !anims.items.length) {
+ return false;
+ }
+ return true;
+ }
+ stop(chart) {
+ const anims = this._charts.get(chart);
+ if (!anims || !anims.items.length) {
+ return;
+ }
+ const items = anims.items;
+ let i = items.length - 1;
+ for (; i >= 0; --i) {
+ items[i].cancel();
+ }
+ anims.items = [];
+ this._notify(chart, anims, Date.now(), 'complete');
+ }
+ remove(chart) {
+ return this._charts.delete(chart);
+ }
+}
+var animator = new Animator();
+
+/*!
+ * @kurkle/color v0.1.9
+ * https://github.com/kurkle/color#readme
+ * (c) 2020 Jukka Kurkela
+ * Released under the MIT License
+ */
+const map$1 = {0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, A: 10, B: 11, C: 12, D: 13, E: 14, F: 15, a: 10, b: 11, c: 12, d: 13, e: 14, f: 15};
+const hex = '0123456789ABCDEF';
+const h1 = (b) => hex[b & 0xF];
+const h2 = (b) => hex[(b & 0xF0) >> 4] + hex[b & 0xF];
+const eq = (b) => (((b & 0xF0) >> 4) === (b & 0xF));
+function isShort(v) {
+ return eq(v.r) && eq(v.g) && eq(v.b) && eq(v.a);
+}
+function hexParse(str) {
+ var len = str.length;
+ var ret;
+ if (str[0] === '#') {
+ if (len === 4 || len === 5) {
+ ret = {
+ r: 255 & map$1[str[1]] * 17,
+ g: 255 & map$1[str[2]] * 17,
+ b: 255 & map$1[str[3]] * 17,
+ a: len === 5 ? map$1[str[4]] * 17 : 255
+ };
+ } else if (len === 7 || len === 9) {
+ ret = {
+ r: map$1[str[1]] << 4 | map$1[str[2]],
+ g: map$1[str[3]] << 4 | map$1[str[4]],
+ b: map$1[str[5]] << 4 | map$1[str[6]],
+ a: len === 9 ? (map$1[str[7]] << 4 | map$1[str[8]]) : 255
+ };
+ }
+ }
+ return ret;
+}
+function hexString(v) {
+ var f = isShort(v) ? h1 : h2;
+ return v
+ ? '#' + f(v.r) + f(v.g) + f(v.b) + (v.a < 255 ? f(v.a) : '')
+ : v;
+}
+function round(v) {
+ return v + 0.5 | 0;
+}
+const lim = (v, l, h) => Math.max(Math.min(v, h), l);
+function p2b(v) {
+ return lim(round(v * 2.55), 0, 255);
+}
+function n2b(v) {
+ return lim(round(v * 255), 0, 255);
+}
+function b2n(v) {
+ return lim(round(v / 2.55) / 100, 0, 1);
+}
+function n2p(v) {
+ return lim(round(v * 100), 0, 100);
+}
+const RGB_RE = /^rgba?\(\s*([-+.\d]+)(%)?[\s,]+([-+.e\d]+)(%)?[\s,]+([-+.e\d]+)(%)?(?:[\s,/]+([-+.e\d]+)(%)?)?\s*\)$/;
+function rgbParse(str) {
+ const m = RGB_RE.exec(str);
+ let a = 255;
+ let r, g, b;
+ if (!m) {
+ return;
+ }
+ if (m[7] !== r) {
+ const v = +m[7];
+ a = 255 & (m[8] ? p2b(v) : v * 255);
+ }
+ r = +m[1];
+ g = +m[3];
+ b = +m[5];
+ r = 255 & (m[2] ? p2b(r) : r);
+ g = 255 & (m[4] ? p2b(g) : g);
+ b = 255 & (m[6] ? p2b(b) : b);
+ return {
+ r: r,
+ g: g,
+ b: b,
+ a: a
+ };
+}
+function rgbString(v) {
+ return v && (
+ v.a < 255
+ ? `rgba(${v.r}, ${v.g}, ${v.b}, ${b2n(v.a)})`
+ : `rgb(${v.r}, ${v.g}, ${v.b})`
+ );
+}
+const HUE_RE = /^(hsla?|hwb|hsv)\(\s*([-+.e\d]+)(?:deg)?[\s,]+([-+.e\d]+)%[\s,]+([-+.e\d]+)%(?:[\s,]+([-+.e\d]+)(%)?)?\s*\)$/;
+function hsl2rgbn(h, s, l) {
+ const a = s * Math.min(l, 1 - l);
+ const f = (n, k = (n + h / 30) % 12) => l - a * Math.max(Math.min(k - 3, 9 - k, 1), -1);
+ return [f(0), f(8), f(4)];
+}
+function hsv2rgbn(h, s, v) {
+ const f = (n, k = (n + h / 60) % 6) => v - v * s * Math.max(Math.min(k, 4 - k, 1), 0);
+ return [f(5), f(3), f(1)];
+}
+function hwb2rgbn(h, w, b) {
+ const rgb = hsl2rgbn(h, 1, 0.5);
+ let i;
+ if (w + b > 1) {
+ i = 1 / (w + b);
+ w *= i;
+ b *= i;
+ }
+ for (i = 0; i < 3; i++) {
+ rgb[i] *= 1 - w - b;
+ rgb[i] += w;
+ }
+ return rgb;
+}
+function rgb2hsl(v) {
+ const range = 255;
+ const r = v.r / range;
+ const g = v.g / range;
+ const b = v.b / range;
+ const max = Math.max(r, g, b);
+ const min = Math.min(r, g, b);
+ const l = (max + min) / 2;
+ let h, s, d;
+ if (max !== min) {
+ d = max - min;
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+ h = max === r
+ ? ((g - b) / d) + (g < b ? 6 : 0)
+ : max === g
+ ? (b - r) / d + 2
+ : (r - g) / d + 4;
+ h = h * 60 + 0.5;
+ }
+ return [h | 0, s || 0, l];
+}
+function calln(f, a, b, c) {
+ return (
+ Array.isArray(a)
+ ? f(a[0], a[1], a[2])
+ : f(a, b, c)
+ ).map(n2b);
+}
+function hsl2rgb(h, s, l) {
+ return calln(hsl2rgbn, h, s, l);
+}
+function hwb2rgb(h, w, b) {
+ return calln(hwb2rgbn, h, w, b);
+}
+function hsv2rgb(h, s, v) {
+ return calln(hsv2rgbn, h, s, v);
+}
+function hue(h) {
+ return (h % 360 + 360) % 360;
+}
+function hueParse(str) {
+ const m = HUE_RE.exec(str);
+ let a = 255;
+ let v;
+ if (!m) {
+ return;
+ }
+ if (m[5] !== v) {
+ a = m[6] ? p2b(+m[5]) : n2b(+m[5]);
+ }
+ const h = hue(+m[2]);
+ const p1 = +m[3] / 100;
+ const p2 = +m[4] / 100;
+ if (m[1] === 'hwb') {
+ v = hwb2rgb(h, p1, p2);
+ } else if (m[1] === 'hsv') {
+ v = hsv2rgb(h, p1, p2);
+ } else {
+ v = hsl2rgb(h, p1, p2);
+ }
+ return {
+ r: v[0],
+ g: v[1],
+ b: v[2],
+ a: a
+ };
+}
+function rotate(v, deg) {
+ var h = rgb2hsl(v);
+ h[0] = hue(h[0] + deg);
+ h = hsl2rgb(h);
+ v.r = h[0];
+ v.g = h[1];
+ v.b = h[2];
+}
+function hslString(v) {
+ if (!v) {
+ return;
+ }
+ const a = rgb2hsl(v);
+ const h = a[0];
+ const s = n2p(a[1]);
+ const l = n2p(a[2]);
+ return v.a < 255
+ ? `hsla(${h}, ${s}%, ${l}%, ${b2n(v.a)})`
+ : `hsl(${h}, ${s}%, ${l}%)`;
+}
+const map$1$1 = {
+ x: 'dark',
+ Z: 'light',
+ Y: 're',
+ X: 'blu',
+ W: 'gr',
+ V: 'medium',
+ U: 'slate',
+ A: 'ee',
+ T: 'ol',
+ S: 'or',
+ B: 'ra',
+ C: 'lateg',
+ D: 'ights',
+ R: 'in',
+ Q: 'turquois',
+ E: 'hi',
+ P: 'ro',
+ O: 'al',
+ N: 'le',
+ M: 'de',
+ L: 'yello',
+ F: 'en',
+ K: 'ch',
+ G: 'arks',
+ H: 'ea',
+ I: 'ightg',
+ J: 'wh'
+};
+const names = {
+ OiceXe: 'f0f8ff',
+ antiquewEte: 'faebd7',
+ aqua: 'ffff',
+ aquamarRe: '7fffd4',
+ azuY: 'f0ffff',
+ beige: 'f5f5dc',
+ bisque: 'ffe4c4',
+ black: '0',
+ blanKedOmond: 'ffebcd',
+ Xe: 'ff',
+ XeviTet: '8a2be2',
+ bPwn: 'a52a2a',
+ burlywood: 'deb887',
+ caMtXe: '5f9ea0',
+ KartYuse: '7fff00',
+ KocTate: 'd2691e',
+ cSO: 'ff7f50',
+ cSnflowerXe: '6495ed',
+ cSnsilk: 'fff8dc',
+ crimson: 'dc143c',
+ cyan: 'ffff',
+ xXe: '8b',
+ xcyan: '8b8b',
+ xgTMnPd: 'b8860b',
+ xWay: 'a9a9a9',
+ xgYF: '6400',
+ xgYy: 'a9a9a9',
+ xkhaki: 'bdb76b',
+ xmagFta: '8b008b',
+ xTivegYF: '556b2f',
+ xSange: 'ff8c00',
+ xScEd: '9932cc',
+ xYd: '8b0000',
+ xsOmon: 'e9967a',
+ xsHgYF: '8fbc8f',
+ xUXe: '483d8b',
+ xUWay: '2f4f4f',
+ xUgYy: '2f4f4f',
+ xQe: 'ced1',
+ xviTet: '9400d3',
+ dAppRk: 'ff1493',
+ dApskyXe: 'bfff',
+ dimWay: '696969',
+ dimgYy: '696969',
+ dodgerXe: '1e90ff',
+ fiYbrick: 'b22222',
+ flSOwEte: 'fffaf0',
+ foYstWAn: '228b22',
+ fuKsia: 'ff00ff',
+ gaRsbSo: 'dcdcdc',
+ ghostwEte: 'f8f8ff',
+ gTd: 'ffd700',
+ gTMnPd: 'daa520',
+ Way: '808080',
+ gYF: '8000',
+ gYFLw: 'adff2f',
+ gYy: '808080',
+ honeyMw: 'f0fff0',
+ hotpRk: 'ff69b4',
+ RdianYd: 'cd5c5c',
+ Rdigo: '4b0082',
+ ivSy: 'fffff0',
+ khaki: 'f0e68c',
+ lavFMr: 'e6e6fa',
+ lavFMrXsh: 'fff0f5',
+ lawngYF: '7cfc00',
+ NmoncEffon: 'fffacd',
+ ZXe: 'add8e6',
+ ZcSO: 'f08080',
+ Zcyan: 'e0ffff',
+ ZgTMnPdLw: 'fafad2',
+ ZWay: 'd3d3d3',
+ ZgYF: '90ee90',
+ ZgYy: 'd3d3d3',
+ ZpRk: 'ffb6c1',
+ ZsOmon: 'ffa07a',
+ ZsHgYF: '20b2aa',
+ ZskyXe: '87cefa',
+ ZUWay: '778899',
+ ZUgYy: '778899',
+ ZstAlXe: 'b0c4de',
+ ZLw: 'ffffe0',
+ lime: 'ff00',
+ limegYF: '32cd32',
+ lRF: 'faf0e6',
+ magFta: 'ff00ff',
+ maPon: '800000',
+ VaquamarRe: '66cdaa',
+ VXe: 'cd',
+ VScEd: 'ba55d3',
+ VpurpN: '9370db',
+ VsHgYF: '3cb371',
+ VUXe: '7b68ee',
+ VsprRggYF: 'fa9a',
+ VQe: '48d1cc',
+ VviTetYd: 'c71585',
+ midnightXe: '191970',
+ mRtcYam: 'f5fffa',
+ mistyPse: 'ffe4e1',
+ moccasR: 'ffe4b5',
+ navajowEte: 'ffdead',
+ navy: '80',
+ Tdlace: 'fdf5e6',
+ Tive: '808000',
+ TivedBb: '6b8e23',
+ Sange: 'ffa500',
+ SangeYd: 'ff4500',
+ ScEd: 'da70d6',
+ pOegTMnPd: 'eee8aa',
+ pOegYF: '98fb98',
+ pOeQe: 'afeeee',
+ pOeviTetYd: 'db7093',
+ papayawEp: 'ffefd5',
+ pHKpuff: 'ffdab9',
+ peru: 'cd853f',
+ pRk: 'ffc0cb',
+ plum: 'dda0dd',
+ powMrXe: 'b0e0e6',
+ purpN: '800080',
+ YbeccapurpN: '663399',
+ Yd: 'ff0000',
+ Psybrown: 'bc8f8f',
+ PyOXe: '4169e1',
+ saddNbPwn: '8b4513',
+ sOmon: 'fa8072',
+ sandybPwn: 'f4a460',
+ sHgYF: '2e8b57',
+ sHshell: 'fff5ee',
+ siFna: 'a0522d',
+ silver: 'c0c0c0',
+ skyXe: '87ceeb',
+ UXe: '6a5acd',
+ UWay: '708090',
+ UgYy: '708090',
+ snow: 'fffafa',
+ sprRggYF: 'ff7f',
+ stAlXe: '4682b4',
+ tan: 'd2b48c',
+ teO: '8080',
+ tEstN: 'd8bfd8',
+ tomato: 'ff6347',
+ Qe: '40e0d0',
+ viTet: 'ee82ee',
+ JHt: 'f5deb3',
+ wEte: 'ffffff',
+ wEtesmoke: 'f5f5f5',
+ Lw: 'ffff00',
+ LwgYF: '9acd32'
+};
+function unpack() {
+ const unpacked = {};
+ const keys = Object.keys(names);
+ const tkeys = Object.keys(map$1$1);
+ let i, j, k, ok, nk;
+ for (i = 0; i < keys.length; i++) {
+ ok = nk = keys[i];
+ for (j = 0; j < tkeys.length; j++) {
+ k = tkeys[j];
+ nk = nk.replace(k, map$1$1[k]);
+ }
+ k = parseInt(names[ok], 16);
+ unpacked[nk] = [k >> 16 & 0xFF, k >> 8 & 0xFF, k & 0xFF];
+ }
+ return unpacked;
+}
+let names$1;
+function nameParse(str) {
+ if (!names$1) {
+ names$1 = unpack();
+ names$1.transparent = [0, 0, 0, 0];
+ }
+ const a = names$1[str.toLowerCase()];
+ return a && {
+ r: a[0],
+ g: a[1],
+ b: a[2],
+ a: a.length === 4 ? a[3] : 255
+ };
+}
+function modHSL(v, i, ratio) {
+ if (v) {
+ let tmp = rgb2hsl(v);
+ tmp[i] = Math.max(0, Math.min(tmp[i] + tmp[i] * ratio, i === 0 ? 360 : 1));
+ tmp = hsl2rgb(tmp);
+ v.r = tmp[0];
+ v.g = tmp[1];
+ v.b = tmp[2];
+ }
+}
+function clone$1(v, proto) {
+ return v ? Object.assign(proto || {}, v) : v;
+}
+function fromObject(input) {
+ var v = {r: 0, g: 0, b: 0, a: 255};
+ if (Array.isArray(input)) {
+ if (input.length >= 3) {
+ v = {r: input[0], g: input[1], b: input[2], a: 255};
+ if (input.length > 3) {
+ v.a = n2b(input[3]);
+ }
+ }
+ } else {
+ v = clone$1(input, {r: 0, g: 0, b: 0, a: 1});
+ v.a = n2b(v.a);
+ }
+ return v;
+}
+function functionParse(str) {
+ if (str.charAt(0) === 'r') {
+ return rgbParse(str);
+ }
+ return hueParse(str);
+}
+class Color {
+ constructor(input) {
+ if (input instanceof Color) {
+ return input;
+ }
+ const type = typeof input;
+ let v;
+ if (type === 'object') {
+ v = fromObject(input);
+ } else if (type === 'string') {
+ v = hexParse(input) || nameParse(input) || functionParse(input);
+ }
+ this._rgb = v;
+ this._valid = !!v;
+ }
+ get valid() {
+ return this._valid;
+ }
+ get rgb() {
+ var v = clone$1(this._rgb);
+ if (v) {
+ v.a = b2n(v.a);
+ }
+ return v;
+ }
+ set rgb(obj) {
+ this._rgb = fromObject(obj);
+ }
+ rgbString() {
+ return this._valid ? rgbString(this._rgb) : this._rgb;
+ }
+ hexString() {
+ return this._valid ? hexString(this._rgb) : this._rgb;
+ }
+ hslString() {
+ return this._valid ? hslString(this._rgb) : this._rgb;
+ }
+ mix(color, weight) {
+ const me = this;
+ if (color) {
+ const c1 = me.rgb;
+ const c2 = color.rgb;
+ let w2;
+ const p = weight === w2 ? 0.5 : weight;
+ const w = 2 * p - 1;
+ const a = c1.a - c2.a;
+ const w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
+ w2 = 1 - w1;
+ c1.r = 0xFF & w1 * c1.r + w2 * c2.r + 0.5;
+ c1.g = 0xFF & w1 * c1.g + w2 * c2.g + 0.5;
+ c1.b = 0xFF & w1 * c1.b + w2 * c2.b + 0.5;
+ c1.a = p * c1.a + (1 - p) * c2.a;
+ me.rgb = c1;
+ }
+ return me;
+ }
+ clone() {
+ return new Color(this.rgb);
+ }
+ alpha(a) {
+ this._rgb.a = n2b(a);
+ return this;
+ }
+ clearer(ratio) {
+ const rgb = this._rgb;
+ rgb.a *= 1 - ratio;
+ return this;
+ }
+ greyscale() {
+ const rgb = this._rgb;
+ const val = round(rgb.r * 0.3 + rgb.g * 0.59 + rgb.b * 0.11);
+ rgb.r = rgb.g = rgb.b = val;
+ return this;
+ }
+ opaquer(ratio) {
+ const rgb = this._rgb;
+ rgb.a *= 1 + ratio;
+ return this;
+ }
+ negate() {
+ const v = this._rgb;
+ v.r = 255 - v.r;
+ v.g = 255 - v.g;
+ v.b = 255 - v.b;
+ return this;
+ }
+ lighten(ratio) {
+ modHSL(this._rgb, 2, ratio);
+ return this;
+ }
+ darken(ratio) {
+ modHSL(this._rgb, 2, -ratio);
+ return this;
+ }
+ saturate(ratio) {
+ modHSL(this._rgb, 1, ratio);
+ return this;
+ }
+ desaturate(ratio) {
+ modHSL(this._rgb, 1, -ratio);
+ return this;
+ }
+ rotate(deg) {
+ rotate(this._rgb, deg);
+ return this;
+ }
+}
+function index_esm(input) {
+ return new Color(input);
+}
+
+const isPatternOrGradient = (value) => value instanceof CanvasGradient || value instanceof CanvasPattern;
+function color(value) {
+ return isPatternOrGradient(value) ? value : index_esm(value);
+}
+function getHoverColor(value) {
+ return isPatternOrGradient(value)
+ ? value
+ : index_esm(value).saturate(0.5).darken(0.1).hexString();
+}
+
+function noop() {}
+const uid = (function() {
+ let id = 0;
+ return function() {
+ return id++;
+ };
+}());
+function isNullOrUndef(value) {
+ return value === null || typeof value === 'undefined';
+}
+function isArray(value) {
+ if (Array.isArray && Array.isArray(value)) {
+ return true;
+ }
+ const type = Object.prototype.toString.call(value);
+ if (type.substr(0, 7) === '[object' && type.substr(-6) === 'Array]') {
+ return true;
+ }
+ return false;
+}
+function isObject(value) {
+ return value !== null && Object.prototype.toString.call(value) === '[object Object]';
+}
+const isNumberFinite = (value) => (typeof value === 'number' || value instanceof Number) && isFinite(+value);
+function finiteOrDefault(value, defaultValue) {
+ return isNumberFinite(value) ? value : defaultValue;
+}
+function valueOrDefault(value, defaultValue) {
+ return typeof value === 'undefined' ? defaultValue : value;
+}
+const toPercentage = (value, dimension) =>
+ typeof value === 'string' && value.endsWith('%') ?
+ parseFloat(value) / 100
+ : value / dimension;
+const toDimension = (value, dimension) =>
+ typeof value === 'string' && value.endsWith('%') ?
+ parseFloat(value) / 100 * dimension
+ : +value;
+function callback(fn, args, thisArg) {
+ if (fn && typeof fn.call === 'function') {
+ return fn.apply(thisArg, args);
+ }
+}
+function each(loopable, fn, thisArg, reverse) {
+ let i, len, keys;
+ if (isArray(loopable)) {
+ len = loopable.length;
+ if (reverse) {
+ for (i = len - 1; i >= 0; i--) {
+ fn.call(thisArg, loopable[i], i);
+ }
+ } else {
+ for (i = 0; i < len; i++) {
+ fn.call(thisArg, loopable[i], i);
+ }
+ }
+ } else if (isObject(loopable)) {
+ keys = Object.keys(loopable);
+ len = keys.length;
+ for (i = 0; i < len; i++) {
+ fn.call(thisArg, loopable[keys[i]], keys[i]);
+ }
+ }
+}
+function _elementsEqual(a0, a1) {
+ let i, ilen, v0, v1;
+ if (!a0 || !a1 || a0.length !== a1.length) {
+ return false;
+ }
+ for (i = 0, ilen = a0.length; i < ilen; ++i) {
+ v0 = a0[i];
+ v1 = a1[i];
+ if (v0.datasetIndex !== v1.datasetIndex || v0.index !== v1.index) {
+ return false;
+ }
+ }
+ return true;
+}
+function clone(source) {
+ if (isArray(source)) {
+ return source.map(clone);
+ }
+ if (isObject(source)) {
+ const target = Object.create(null);
+ const keys = Object.keys(source);
+ const klen = keys.length;
+ let k = 0;
+ for (; k < klen; ++k) {
+ target[keys[k]] = clone(source[keys[k]]);
+ }
+ return target;
+ }
+ return source;
+}
+function isValidKey(key) {
+ return ['__proto__', 'prototype', 'constructor'].indexOf(key) === -1;
+}
+function _merger(key, target, source, options) {
+ if (!isValidKey(key)) {
+ return;
+ }
+ const tval = target[key];
+ const sval = source[key];
+ if (isObject(tval) && isObject(sval)) {
+ merge(tval, sval, options);
+ } else {
+ target[key] = clone(sval);
+ }
+}
+function merge(target, source, options) {
+ const sources = isArray(source) ? source : [source];
+ const ilen = sources.length;
+ if (!isObject(target)) {
+ return target;
+ }
+ options = options || {};
+ const merger = options.merger || _merger;
+ for (let i = 0; i < ilen; ++i) {
+ source = sources[i];
+ if (!isObject(source)) {
+ continue;
+ }
+ const keys = Object.keys(source);
+ for (let k = 0, klen = keys.length; k < klen; ++k) {
+ merger(keys[k], target, source, options);
+ }
+ }
+ return target;
+}
+function mergeIf(target, source) {
+ return merge(target, source, {merger: _mergerIf});
+}
+function _mergerIf(key, target, source) {
+ if (!isValidKey(key)) {
+ return;
+ }
+ const tval = target[key];
+ const sval = source[key];
+ if (isObject(tval) && isObject(sval)) {
+ mergeIf(tval, sval);
+ } else if (!Object.prototype.hasOwnProperty.call(target, key)) {
+ target[key] = clone(sval);
+ }
+}
+function _deprecated(scope, value, previous, current) {
+ if (value !== undefined) {
+ console.warn(scope + ': "' + previous +
+ '" is deprecated. Please use "' + current + '" instead');
+ }
+}
+const emptyString = '';
+const dot = '.';
+function indexOfDotOrLength(key, start) {
+ const idx = key.indexOf(dot, start);
+ return idx === -1 ? key.length : idx;
+}
+function resolveObjectKey(obj, key) {
+ if (key === emptyString) {
+ return obj;
+ }
+ let pos = 0;
+ let idx = indexOfDotOrLength(key, pos);
+ while (obj && idx > pos) {
+ obj = obj[key.substr(pos, idx - pos)];
+ pos = idx + 1;
+ idx = indexOfDotOrLength(key, pos);
+ }
+ return obj;
+}
+function _capitalize(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
+const defined = (value) => typeof value !== 'undefined';
+const isFunction = (value) => typeof value === 'function';
+const setsEqual = (a, b) => {
+ if (a.size !== b.size) {
+ return false;
+ }
+ for (const item of a) {
+ if (!b.has(item)) {
+ return false;
+ }
+ }
+ return true;
+};
+function _isClickEvent(e) {
+ return e.type === 'mouseup' || e.type === 'click' || e.type === 'contextmenu';
+}
+
+const overrides = Object.create(null);
+const descriptors = Object.create(null);
+function getScope$1(node, key) {
+ if (!key) {
+ return node;
+ }
+ const keys = key.split('.');
+ for (let i = 0, n = keys.length; i < n; ++i) {
+ const k = keys[i];
+ node = node[k] || (node[k] = Object.create(null));
+ }
+ return node;
+}
+function set(root, scope, values) {
+ if (typeof scope === 'string') {
+ return merge(getScope$1(root, scope), values);
+ }
+ return merge(getScope$1(root, ''), scope);
+}
+class Defaults {
+ constructor(_descriptors) {
+ this.animation = undefined;
+ this.backgroundColor = 'rgba(0,0,0,0.1)';
+ this.borderColor = 'rgba(0,0,0,0.1)';
+ this.color = '#666';
+ this.datasets = {};
+ this.devicePixelRatio = (context) => context.chart.platform.getDevicePixelRatio();
+ this.elements = {};
+ this.events = [
+ 'mousemove',
+ 'mouseout',
+ 'click',
+ 'touchstart',
+ 'touchmove'
+ ];
+ this.font = {
+ family: "'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",
+ size: 12,
+ style: 'normal',
+ lineHeight: 1.2,
+ weight: null
+ };
+ this.hover = {};
+ this.hoverBackgroundColor = (ctx, options) => getHoverColor(options.backgroundColor);
+ this.hoverBorderColor = (ctx, options) => getHoverColor(options.borderColor);
+ this.hoverColor = (ctx, options) => getHoverColor(options.color);
+ this.indexAxis = 'x';
+ this.interaction = {
+ mode: 'nearest',
+ intersect: true
+ };
+ this.maintainAspectRatio = true;
+ this.onHover = null;
+ this.onClick = null;
+ this.parsing = true;
+ this.plugins = {};
+ this.responsive = true;
+ this.scale = undefined;
+ this.scales = {};
+ this.showLine = true;
+ this.drawActiveElementsOnTop = true;
+ this.describe(_descriptors);
+ }
+ set(scope, values) {
+ return set(this, scope, values);
+ }
+ get(scope) {
+ return getScope$1(this, scope);
+ }
+ describe(scope, values) {
+ return set(descriptors, scope, values);
+ }
+ override(scope, values) {
+ return set(overrides, scope, values);
+ }
+ route(scope, name, targetScope, targetName) {
+ const scopeObject = getScope$1(this, scope);
+ const targetScopeObject = getScope$1(this, targetScope);
+ const privateName = '_' + name;
+ Object.defineProperties(scopeObject, {
+ [privateName]: {
+ value: scopeObject[name],
+ writable: true
+ },
+ [name]: {
+ enumerable: true,
+ get() {
+ const local = this[privateName];
+ const target = targetScopeObject[targetName];
+ if (isObject(local)) {
+ return Object.assign({}, target, local);
+ }
+ return valueOrDefault(local, target);
+ },
+ set(value) {
+ this[privateName] = value;
+ }
+ }
+ });
+ }
+}
+var defaults = new Defaults({
+ _scriptable: (name) => !name.startsWith('on'),
+ _indexable: (name) => name !== 'events',
+ hover: {
+ _fallback: 'interaction'
+ },
+ interaction: {
+ _scriptable: false,
+ _indexable: false,
+ }
+});
+
+const PI = Math.PI;
+const TAU = 2 * PI;
+const PITAU = TAU + PI;
+const INFINITY = Number.POSITIVE_INFINITY;
+const RAD_PER_DEG = PI / 180;
+const HALF_PI = PI / 2;
+const QUARTER_PI = PI / 4;
+const TWO_THIRDS_PI = PI * 2 / 3;
+const log10 = Math.log10;
+const sign = Math.sign;
+function niceNum(range) {
+ const roundedRange = Math.round(range);
+ range = almostEquals(range, roundedRange, range / 1000) ? roundedRange : range;
+ const niceRange = Math.pow(10, Math.floor(log10(range)));
+ const fraction = range / niceRange;
+ const niceFraction = fraction <= 1 ? 1 : fraction <= 2 ? 2 : fraction <= 5 ? 5 : 10;
+ return niceFraction * niceRange;
+}
+function _factorize(value) {
+ const result = [];
+ const sqrt = Math.sqrt(value);
+ let i;
+ for (i = 1; i < sqrt; i++) {
+ if (value % i === 0) {
+ result.push(i);
+ result.push(value / i);
+ }
+ }
+ if (sqrt === (sqrt | 0)) {
+ result.push(sqrt);
+ }
+ result.sort((a, b) => a - b).pop();
+ return result;
+}
+function isNumber(n) {
+ return !isNaN(parseFloat(n)) && isFinite(n);
+}
+function almostEquals(x, y, epsilon) {
+ return Math.abs(x - y) < epsilon;
+}
+function almostWhole(x, epsilon) {
+ const rounded = Math.round(x);
+ return ((rounded - epsilon) <= x) && ((rounded + epsilon) >= x);
+}
+function _setMinAndMaxByKey(array, target, property) {
+ let i, ilen, value;
+ for (i = 0, ilen = array.length; i < ilen; i++) {
+ value = array[i][property];
+ if (!isNaN(value)) {
+ target.min = Math.min(target.min, value);
+ target.max = Math.max(target.max, value);
+ }
+ }
+}
+function toRadians(degrees) {
+ return degrees * (PI / 180);
+}
+function toDegrees(radians) {
+ return radians * (180 / PI);
+}
+function _decimalPlaces(x) {
+ if (!isNumberFinite(x)) {
+ return;
+ }
+ let e = 1;
+ let p = 0;
+ while (Math.round(x * e) / e !== x) {
+ e *= 10;
+ p++;
+ }
+ return p;
+}
+function getAngleFromPoint(centrePoint, anglePoint) {
+ const distanceFromXCenter = anglePoint.x - centrePoint.x;
+ const distanceFromYCenter = anglePoint.y - centrePoint.y;
+ const radialDistanceFromCenter = Math.sqrt(distanceFromXCenter * distanceFromXCenter + distanceFromYCenter * distanceFromYCenter);
+ let angle = Math.atan2(distanceFromYCenter, distanceFromXCenter);
+ if (angle < (-0.5 * PI)) {
+ angle += TAU;
+ }
+ return {
+ angle,
+ distance: radialDistanceFromCenter
+ };
+}
+function distanceBetweenPoints(pt1, pt2) {
+ return Math.sqrt(Math.pow(pt2.x - pt1.x, 2) + Math.pow(pt2.y - pt1.y, 2));
+}
+function _angleDiff(a, b) {
+ return (a - b + PITAU) % TAU - PI;
+}
+function _normalizeAngle(a) {
+ return (a % TAU + TAU) % TAU;
+}
+function _angleBetween(angle, start, end, sameAngleIsFullCircle) {
+ const a = _normalizeAngle(angle);
+ const s = _normalizeAngle(start);
+ const e = _normalizeAngle(end);
+ const angleToStart = _normalizeAngle(s - a);
+ const angleToEnd = _normalizeAngle(e - a);
+ const startToAngle = _normalizeAngle(a - s);
+ const endToAngle = _normalizeAngle(a - e);
+ return a === s || a === e || (sameAngleIsFullCircle && s === e)
+ || (angleToStart > angleToEnd && startToAngle < endToAngle);
+}
+function _limitValue(value, min, max) {
+ return Math.max(min, Math.min(max, value));
+}
+function _int16Range(value) {
+ return _limitValue(value, -32768, 32767);
+}
+function _isBetween(value, start, end, epsilon = 1e-6) {
+ return value >= Math.min(start, end) - epsilon && value <= Math.max(start, end) + epsilon;
+}
+
+function toFontString(font) {
+ if (!font || isNullOrUndef(font.size) || isNullOrUndef(font.family)) {
+ return null;
+ }
+ return (font.style ? font.style + ' ' : '')
+ + (font.weight ? font.weight + ' ' : '')
+ + font.size + 'px '
+ + font.family;
+}
+function _measureText(ctx, data, gc, longest, string) {
+ let textWidth = data[string];
+ if (!textWidth) {
+ textWidth = data[string] = ctx.measureText(string).width;
+ gc.push(string);
+ }
+ if (textWidth > longest) {
+ longest = textWidth;
+ }
+ return longest;
+}
+function _longestText(ctx, font, arrayOfThings, cache) {
+ cache = cache || {};
+ let data = cache.data = cache.data || {};
+ let gc = cache.garbageCollect = cache.garbageCollect || [];
+ if (cache.font !== font) {
+ data = cache.data = {};
+ gc = cache.garbageCollect = [];
+ cache.font = font;
+ }
+ ctx.save();
+ ctx.font = font;
+ let longest = 0;
+ const ilen = arrayOfThings.length;
+ let i, j, jlen, thing, nestedThing;
+ for (i = 0; i < ilen; i++) {
+ thing = arrayOfThings[i];
+ if (thing !== undefined && thing !== null && isArray(thing) !== true) {
+ longest = _measureText(ctx, data, gc, longest, thing);
+ } else if (isArray(thing)) {
+ for (j = 0, jlen = thing.length; j < jlen; j++) {
+ nestedThing = thing[j];
+ if (nestedThing !== undefined && nestedThing !== null && !isArray(nestedThing)) {
+ longest = _measureText(ctx, data, gc, longest, nestedThing);
+ }
+ }
+ }
+ }
+ ctx.restore();
+ const gcLen = gc.length / 2;
+ if (gcLen > arrayOfThings.length) {
+ for (i = 0; i < gcLen; i++) {
+ delete data[gc[i]];
+ }
+ gc.splice(0, gcLen);
+ }
+ return longest;
+}
+function _alignPixel(chart, pixel, width) {
+ const devicePixelRatio = chart.currentDevicePixelRatio;
+ const halfWidth = width !== 0 ? Math.max(width / 2, 0.5) : 0;
+ return Math.round((pixel - halfWidth) * devicePixelRatio) / devicePixelRatio + halfWidth;
+}
+function clearCanvas(canvas, ctx) {
+ ctx = ctx || canvas.getContext('2d');
+ ctx.save();
+ ctx.resetTransform();
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ ctx.restore();
+}
+function drawPoint(ctx, options, x, y) {
+ let type, xOffset, yOffset, size, cornerRadius;
+ const style = options.pointStyle;
+ const rotation = options.rotation;
+ const radius = options.radius;
+ let rad = (rotation || 0) * RAD_PER_DEG;
+ if (style && typeof style === 'object') {
+ type = style.toString();
+ if (type === '[object HTMLImageElement]' || type === '[object HTMLCanvasElement]') {
+ ctx.save();
+ ctx.translate(x, y);
+ ctx.rotate(rad);
+ ctx.drawImage(style, -style.width / 2, -style.height / 2, style.width, style.height);
+ ctx.restore();
+ return;
+ }
+ }
+ if (isNaN(radius) || radius <= 0) {
+ return;
+ }
+ ctx.beginPath();
+ switch (style) {
+ default:
+ ctx.arc(x, y, radius, 0, TAU);
+ ctx.closePath();
+ break;
+ case 'triangle':
+ ctx.moveTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+ rad += TWO_THIRDS_PI;
+ ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+ rad += TWO_THIRDS_PI;
+ ctx.lineTo(x + Math.sin(rad) * radius, y - Math.cos(rad) * radius);
+ ctx.closePath();
+ break;
+ case 'rectRounded':
+ cornerRadius = radius * 0.516;
+ size = radius - cornerRadius;
+ xOffset = Math.cos(rad + QUARTER_PI) * size;
+ yOffset = Math.sin(rad + QUARTER_PI) * size;
+ ctx.arc(x - xOffset, y - yOffset, cornerRadius, rad - PI, rad - HALF_PI);
+ ctx.arc(x + yOffset, y - xOffset, cornerRadius, rad - HALF_PI, rad);
+ ctx.arc(x + xOffset, y + yOffset, cornerRadius, rad, rad + HALF_PI);
+ ctx.arc(x - yOffset, y + xOffset, cornerRadius, rad + HALF_PI, rad + PI);
+ ctx.closePath();
+ break;
+ case 'rect':
+ if (!rotation) {
+ size = Math.SQRT1_2 * radius;
+ ctx.rect(x - size, y - size, 2 * size, 2 * size);
+ break;
+ }
+ rad += QUARTER_PI;
+ case 'rectRot':
+ xOffset = Math.cos(rad) * radius;
+ yOffset = Math.sin(rad) * radius;
+ ctx.moveTo(x - xOffset, y - yOffset);
+ ctx.lineTo(x + yOffset, y - xOffset);
+ ctx.lineTo(x + xOffset, y + yOffset);
+ ctx.lineTo(x - yOffset, y + xOffset);
+ ctx.closePath();
+ break;
+ case 'crossRot':
+ rad += QUARTER_PI;
+ case 'cross':
+ xOffset = Math.cos(rad) * radius;
+ yOffset = Math.sin(rad) * radius;
+ ctx.moveTo(x - xOffset, y - yOffset);
+ ctx.lineTo(x + xOffset, y + yOffset);
+ ctx.moveTo(x + yOffset, y - xOffset);
+ ctx.lineTo(x - yOffset, y + xOffset);
+ break;
+ case 'star':
+ xOffset = Math.cos(rad) * radius;
+ yOffset = Math.sin(rad) * radius;
+ ctx.moveTo(x - xOffset, y - yOffset);
+ ctx.lineTo(x + xOffset, y + yOffset);
+ ctx.moveTo(x + yOffset, y - xOffset);
+ ctx.lineTo(x - yOffset, y + xOffset);
+ rad += QUARTER_PI;
+ xOffset = Math.cos(rad) * radius;
+ yOffset = Math.sin(rad) * radius;
+ ctx.moveTo(x - xOffset, y - yOffset);
+ ctx.lineTo(x + xOffset, y + yOffset);
+ ctx.moveTo(x + yOffset, y - xOffset);
+ ctx.lineTo(x - yOffset, y + xOffset);
+ break;
+ case 'line':
+ xOffset = Math.cos(rad) * radius;
+ yOffset = Math.sin(rad) * radius;
+ ctx.moveTo(x - xOffset, y - yOffset);
+ ctx.lineTo(x + xOffset, y + yOffset);
+ break;
+ case 'dash':
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + Math.cos(rad) * radius, y + Math.sin(rad) * radius);
+ break;
+ }
+ ctx.fill();
+ if (options.borderWidth > 0) {
+ ctx.stroke();
+ }
+}
+function _isPointInArea(point, area, margin) {
+ margin = margin || 0.5;
+ return !area || (point && point.x > area.left - margin && point.x < area.right + margin &&
+ point.y > area.top - margin && point.y < area.bottom + margin);
+}
+function clipArea(ctx, area) {
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(area.left, area.top, area.right - area.left, area.bottom - area.top);
+ ctx.clip();
+}
+function unclipArea(ctx) {
+ ctx.restore();
+}
+function _steppedLineTo(ctx, previous, target, flip, mode) {
+ if (!previous) {
+ return ctx.lineTo(target.x, target.y);
+ }
+ if (mode === 'middle') {
+ const midpoint = (previous.x + target.x) / 2.0;
+ ctx.lineTo(midpoint, previous.y);
+ ctx.lineTo(midpoint, target.y);
+ } else if (mode === 'after' !== !!flip) {
+ ctx.lineTo(previous.x, target.y);
+ } else {
+ ctx.lineTo(target.x, previous.y);
+ }
+ ctx.lineTo(target.x, target.y);
+}
+function _bezierCurveTo(ctx, previous, target, flip) {
+ if (!previous) {
+ return ctx.lineTo(target.x, target.y);
+ }
+ ctx.bezierCurveTo(
+ flip ? previous.cp1x : previous.cp2x,
+ flip ? previous.cp1y : previous.cp2y,
+ flip ? target.cp2x : target.cp1x,
+ flip ? target.cp2y : target.cp1y,
+ target.x,
+ target.y);
+}
+function renderText(ctx, text, x, y, font, opts = {}) {
+ const lines = isArray(text) ? text : [text];
+ const stroke = opts.strokeWidth > 0 && opts.strokeColor !== '';
+ let i, line;
+ ctx.save();
+ ctx.font = font.string;
+ setRenderOpts(ctx, opts);
+ for (i = 0; i < lines.length; ++i) {
+ line = lines[i];
+ if (stroke) {
+ if (opts.strokeColor) {
+ ctx.strokeStyle = opts.strokeColor;
+ }
+ if (!isNullOrUndef(opts.strokeWidth)) {
+ ctx.lineWidth = opts.strokeWidth;
+ }
+ ctx.strokeText(line, x, y, opts.maxWidth);
+ }
+ ctx.fillText(line, x, y, opts.maxWidth);
+ decorateText(ctx, x, y, line, opts);
+ y += font.lineHeight;
+ }
+ ctx.restore();
+}
+function setRenderOpts(ctx, opts) {
+ if (opts.translation) {
+ ctx.translate(opts.translation[0], opts.translation[1]);
+ }
+ if (!isNullOrUndef(opts.rotation)) {
+ ctx.rotate(opts.rotation);
+ }
+ if (opts.color) {
+ ctx.fillStyle = opts.color;
+ }
+ if (opts.textAlign) {
+ ctx.textAlign = opts.textAlign;
+ }
+ if (opts.textBaseline) {
+ ctx.textBaseline = opts.textBaseline;
+ }
+}
+function decorateText(ctx, x, y, line, opts) {
+ if (opts.strikethrough || opts.underline) {
+ const metrics = ctx.measureText(line);
+ const left = x - metrics.actualBoundingBoxLeft;
+ const right = x + metrics.actualBoundingBoxRight;
+ const top = y - metrics.actualBoundingBoxAscent;
+ const bottom = y + metrics.actualBoundingBoxDescent;
+ const yDecoration = opts.strikethrough ? (top + bottom) / 2 : bottom;
+ ctx.strokeStyle = ctx.fillStyle;
+ ctx.beginPath();
+ ctx.lineWidth = opts.decorationWidth || 2;
+ ctx.moveTo(left, yDecoration);
+ ctx.lineTo(right, yDecoration);
+ ctx.stroke();
+ }
+}
+function addRoundedRectPath(ctx, rect) {
+ const {x, y, w, h, radius} = rect;
+ ctx.arc(x + radius.topLeft, y + radius.topLeft, radius.topLeft, -HALF_PI, PI, true);
+ ctx.lineTo(x, y + h - radius.bottomLeft);
+ ctx.arc(x + radius.bottomLeft, y + h - radius.bottomLeft, radius.bottomLeft, PI, HALF_PI, true);
+ ctx.lineTo(x + w - radius.bottomRight, y + h);
+ ctx.arc(x + w - radius.bottomRight, y + h - radius.bottomRight, radius.bottomRight, HALF_PI, 0, true);
+ ctx.lineTo(x + w, y + radius.topRight);
+ ctx.arc(x + w - radius.topRight, y + radius.topRight, radius.topRight, 0, -HALF_PI, true);
+ ctx.lineTo(x + radius.topLeft, y);
+}
+
+function _lookup(table, value, cmp) {
+ cmp = cmp || ((index) => table[index] < value);
+ let hi = table.length - 1;
+ let lo = 0;
+ let mid;
+ while (hi - lo > 1) {
+ mid = (lo + hi) >> 1;
+ if (cmp(mid)) {
+ lo = mid;
+ } else {
+ hi = mid;
+ }
+ }
+ return {lo, hi};
+}
+const _lookupByKey = (table, key, value) =>
+ _lookup(table, value, index => table[index][key] < value);
+const _rlookupByKey = (table, key, value) =>
+ _lookup(table, value, index => table[index][key] >= value);
+function _filterBetween(values, min, max) {
+ let start = 0;
+ let end = values.length;
+ while (start < end && values[start] < min) {
+ start++;
+ }
+ while (end > start && values[end - 1] > max) {
+ end--;
+ }
+ return start > 0 || end < values.length
+ ? values.slice(start, end)
+ : values;
+}
+const arrayEvents = ['push', 'pop', 'shift', 'splice', 'unshift'];
+function listenArrayEvents(array, listener) {
+ if (array._chartjs) {
+ array._chartjs.listeners.push(listener);
+ return;
+ }
+ Object.defineProperty(array, '_chartjs', {
+ configurable: true,
+ enumerable: false,
+ value: {
+ listeners: [listener]
+ }
+ });
+ arrayEvents.forEach((key) => {
+ const method = '_onData' + _capitalize(key);
+ const base = array[key];
+ Object.defineProperty(array, key, {
+ configurable: true,
+ enumerable: false,
+ value(...args) {
+ const res = base.apply(this, args);
+ array._chartjs.listeners.forEach((object) => {
+ if (typeof object[method] === 'function') {
+ object[method](...args);
+ }
+ });
+ return res;
+ }
+ });
+ });
+}
+function unlistenArrayEvents(array, listener) {
+ const stub = array._chartjs;
+ if (!stub) {
+ return;
+ }
+ const listeners = stub.listeners;
+ const index = listeners.indexOf(listener);
+ if (index !== -1) {
+ listeners.splice(index, 1);
+ }
+ if (listeners.length > 0) {
+ return;
+ }
+ arrayEvents.forEach((key) => {
+ delete array[key];
+ });
+ delete array._chartjs;
+}
+function _arrayUnique(items) {
+ const set = new Set();
+ let i, ilen;
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
+ set.add(items[i]);
+ }
+ if (set.size === ilen) {
+ return items;
+ }
+ return Array.from(set);
+}
+
+function _isDomSupported() {
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
+}
+function _getParentNode(domNode) {
+ let parent = domNode.parentNode;
+ if (parent && parent.toString() === '[object ShadowRoot]') {
+ parent = parent.host;
+ }
+ return parent;
+}
+function parseMaxStyle(styleValue, node, parentProperty) {
+ let valueInPixels;
+ if (typeof styleValue === 'string') {
+ valueInPixels = parseInt(styleValue, 10);
+ if (styleValue.indexOf('%') !== -1) {
+ valueInPixels = valueInPixels / 100 * node.parentNode[parentProperty];
+ }
+ } else {
+ valueInPixels = styleValue;
+ }
+ return valueInPixels;
+}
+const getComputedStyle = (element) => window.getComputedStyle(element, null);
+function getStyle(el, property) {
+ return getComputedStyle(el).getPropertyValue(property);
+}
+const positions = ['top', 'right', 'bottom', 'left'];
+function getPositionedStyle(styles, style, suffix) {
+ const result = {};
+ suffix = suffix ? '-' + suffix : '';
+ for (let i = 0; i < 4; i++) {
+ const pos = positions[i];
+ result[pos] = parseFloat(styles[style + '-' + pos + suffix]) || 0;
+ }
+ result.width = result.left + result.right;
+ result.height = result.top + result.bottom;
+ return result;
+}
+const useOffsetPos = (x, y, target) => (x > 0 || y > 0) && (!target || !target.shadowRoot);
+function getCanvasPosition(evt, canvas) {
+ const e = evt.native || evt;
+ const touches = e.touches;
+ const source = touches && touches.length ? touches[0] : e;
+ const {offsetX, offsetY} = source;
+ let box = false;
+ let x, y;
+ if (useOffsetPos(offsetX, offsetY, e.target)) {
+ x = offsetX;
+ y = offsetY;
+ } else {
+ const rect = canvas.getBoundingClientRect();
+ x = source.clientX - rect.left;
+ y = source.clientY - rect.top;
+ box = true;
+ }
+ return {x, y, box};
+}
+function getRelativePosition$1(evt, chart) {
+ const {canvas, currentDevicePixelRatio} = chart;
+ const style = getComputedStyle(canvas);
+ const borderBox = style.boxSizing === 'border-box';
+ const paddings = getPositionedStyle(style, 'padding');
+ const borders = getPositionedStyle(style, 'border', 'width');
+ const {x, y, box} = getCanvasPosition(evt, canvas);
+ const xOffset = paddings.left + (box && borders.left);
+ const yOffset = paddings.top + (box && borders.top);
+ let {width, height} = chart;
+ if (borderBox) {
+ width -= paddings.width + borders.width;
+ height -= paddings.height + borders.height;
+ }
+ return {
+ x: Math.round((x - xOffset) / width * canvas.width / currentDevicePixelRatio),
+ y: Math.round((y - yOffset) / height * canvas.height / currentDevicePixelRatio)
+ };
+}
+function getContainerSize(canvas, width, height) {
+ let maxWidth, maxHeight;
+ if (width === undefined || height === undefined) {
+ const container = _getParentNode(canvas);
+ if (!container) {
+ width = canvas.clientWidth;
+ height = canvas.clientHeight;
+ } else {
+ const rect = container.getBoundingClientRect();
+ const containerStyle = getComputedStyle(container);
+ const containerBorder = getPositionedStyle(containerStyle, 'border', 'width');
+ const containerPadding = getPositionedStyle(containerStyle, 'padding');
+ width = rect.width - containerPadding.width - containerBorder.width;
+ height = rect.height - containerPadding.height - containerBorder.height;
+ maxWidth = parseMaxStyle(containerStyle.maxWidth, container, 'clientWidth');
+ maxHeight = parseMaxStyle(containerStyle.maxHeight, container, 'clientHeight');
+ }
+ }
+ return {
+ width,
+ height,
+ maxWidth: maxWidth || INFINITY,
+ maxHeight: maxHeight || INFINITY
+ };
+}
+const round1 = v => Math.round(v * 10) / 10;
+function getMaximumSize(canvas, bbWidth, bbHeight, aspectRatio) {
+ const style = getComputedStyle(canvas);
+ const margins = getPositionedStyle(style, 'margin');
+ const maxWidth = parseMaxStyle(style.maxWidth, canvas, 'clientWidth') || INFINITY;
+ const maxHeight = parseMaxStyle(style.maxHeight, canvas, 'clientHeight') || INFINITY;
+ const containerSize = getContainerSize(canvas, bbWidth, bbHeight);
+ let {width, height} = containerSize;
+ if (style.boxSizing === 'content-box') {
+ const borders = getPositionedStyle(style, 'border', 'width');
+ const paddings = getPositionedStyle(style, 'padding');
+ width -= paddings.width + borders.width;
+ height -= paddings.height + borders.height;
+ }
+ width = Math.max(0, width - margins.width);
+ height = Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height - margins.height);
+ width = round1(Math.min(width, maxWidth, containerSize.maxWidth));
+ height = round1(Math.min(height, maxHeight, containerSize.maxHeight));
+ if (width && !height) {
+ height = round1(width / 2);
+ }
+ return {
+ width,
+ height
+ };
+}
+function retinaScale(chart, forceRatio, forceStyle) {
+ const pixelRatio = forceRatio || 1;
+ const deviceHeight = Math.floor(chart.height * pixelRatio);
+ const deviceWidth = Math.floor(chart.width * pixelRatio);
+ chart.height = deviceHeight / pixelRatio;
+ chart.width = deviceWidth / pixelRatio;
+ const canvas = chart.canvas;
+ if (canvas.style && (forceStyle || (!canvas.style.height && !canvas.style.width))) {
+ canvas.style.height = `${chart.height}px`;
+ canvas.style.width = `${chart.width}px`;
+ }
+ if (chart.currentDevicePixelRatio !== pixelRatio
+ || canvas.height !== deviceHeight
+ || canvas.width !== deviceWidth) {
+ chart.currentDevicePixelRatio = pixelRatio;
+ canvas.height = deviceHeight;
+ canvas.width = deviceWidth;
+ chart.ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
+ return true;
+ }
+ return false;
+}
+const supportsEventListenerOptions = (function() {
+ let passiveSupported = false;
+ try {
+ const options = {
+ get passive() {
+ passiveSupported = true;
+ return false;
+ }
+ };
+ window.addEventListener('test', null, options);
+ window.removeEventListener('test', null, options);
+ } catch (e) {
+ }
+ return passiveSupported;
+}());
+function readUsedSize(element, property) {
+ const value = getStyle(element, property);
+ const matches = value && value.match(/^(\d+)(\.\d+)?px$/);
+ return matches ? +matches[1] : undefined;
+}
+
+function getRelativePosition(e, chart) {
+ if ('native' in e) {
+ return {
+ x: e.x,
+ y: e.y
+ };
+ }
+ return getRelativePosition$1(e, chart);
+}
+function evaluateAllVisibleItems(chart, handler) {
+ const metasets = chart.getSortedVisibleDatasetMetas();
+ let index, data, element;
+ for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
+ ({index, data} = metasets[i]);
+ for (let j = 0, jlen = data.length; j < jlen; ++j) {
+ element = data[j];
+ if (!element.skip) {
+ handler(element, index, j);
+ }
+ }
+ }
+}
+function binarySearch(metaset, axis, value, intersect) {
+ const {controller, data, _sorted} = metaset;
+ const iScale = controller._cachedMeta.iScale;
+ if (iScale && axis === iScale.axis && axis !== 'r' && _sorted && data.length) {
+ const lookupMethod = iScale._reversePixels ? _rlookupByKey : _lookupByKey;
+ if (!intersect) {
+ return lookupMethod(data, axis, value);
+ } else if (controller._sharedOptions) {
+ const el = data[0];
+ const range = typeof el.getRange === 'function' && el.getRange(axis);
+ if (range) {
+ const start = lookupMethod(data, axis, value - range);
+ const end = lookupMethod(data, axis, value + range);
+ return {lo: start.lo, hi: end.hi};
+ }
+ }
+ }
+ return {lo: 0, hi: data.length - 1};
+}
+function optimizedEvaluateItems(chart, axis, position, handler, intersect) {
+ const metasets = chart.getSortedVisibleDatasetMetas();
+ const value = position[axis];
+ for (let i = 0, ilen = metasets.length; i < ilen; ++i) {
+ const {index, data} = metasets[i];
+ const {lo, hi} = binarySearch(metasets[i], axis, value, intersect);
+ for (let j = lo; j <= hi; ++j) {
+ const element = data[j];
+ if (!element.skip) {
+ handler(element, index, j);
+ }
+ }
+ }
+}
+function getDistanceMetricForAxis(axis) {
+ const useX = axis.indexOf('x') !== -1;
+ const useY = axis.indexOf('y') !== -1;
+ return function(pt1, pt2) {
+ const deltaX = useX ? Math.abs(pt1.x - pt2.x) : 0;
+ const deltaY = useY ? Math.abs(pt1.y - pt2.y) : 0;
+ return Math.sqrt(Math.pow(deltaX, 2) + Math.pow(deltaY, 2));
+ };
+}
+function getIntersectItems(chart, position, axis, useFinalPosition) {
+ const items = [];
+ if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {
+ return items;
+ }
+ const evaluationFunc = function(element, datasetIndex, index) {
+ if (element.inRange(position.x, position.y, useFinalPosition)) {
+ items.push({element, datasetIndex, index});
+ }
+ };
+ optimizedEvaluateItems(chart, axis, position, evaluationFunc, true);
+ return items;
+}
+function getNearestRadialItems(chart, position, axis, useFinalPosition) {
+ let items = [];
+ function evaluationFunc(element, datasetIndex, index) {
+ const {startAngle, endAngle} = element.getProps(['startAngle', 'endAngle'], useFinalPosition);
+ const {angle} = getAngleFromPoint(element, {x: position.x, y: position.y});
+ if (_angleBetween(angle, startAngle, endAngle)) {
+ items.push({element, datasetIndex, index});
+ }
+ }
+ optimizedEvaluateItems(chart, axis, position, evaluationFunc);
+ return items;
+}
+function getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition) {
+ let items = [];
+ const distanceMetric = getDistanceMetricForAxis(axis);
+ let minDistance = Number.POSITIVE_INFINITY;
+ function evaluationFunc(element, datasetIndex, index) {
+ const inRange = element.inRange(position.x, position.y, useFinalPosition);
+ if (intersect && !inRange) {
+ return;
+ }
+ const center = element.getCenterPoint(useFinalPosition);
+ const pointInArea = _isPointInArea(center, chart.chartArea, chart._minPadding);
+ if (!pointInArea && !inRange) {
+ return;
+ }
+ const distance = distanceMetric(position, center);
+ if (distance < minDistance) {
+ items = [{element, datasetIndex, index}];
+ minDistance = distance;
+ } else if (distance === minDistance) {
+ items.push({element, datasetIndex, index});
+ }
+ }
+ optimizedEvaluateItems(chart, axis, position, evaluationFunc);
+ return items;
+}
+function getNearestItems(chart, position, axis, intersect, useFinalPosition) {
+ if (!_isPointInArea(position, chart.chartArea, chart._minPadding)) {
+ return [];
+ }
+ return axis === 'r' && !intersect
+ ? getNearestRadialItems(chart, position, axis, useFinalPosition)
+ : getNearestCartesianItems(chart, position, axis, intersect, useFinalPosition);
+}
+function getAxisItems(chart, e, options, useFinalPosition) {
+ const position = getRelativePosition(e, chart);
+ const items = [];
+ const axis = options.axis;
+ const rangeMethod = axis === 'x' ? 'inXRange' : 'inYRange';
+ let intersectsItem = false;
+ evaluateAllVisibleItems(chart, (element, datasetIndex, index) => {
+ if (element[rangeMethod](position[axis], useFinalPosition)) {
+ items.push({element, datasetIndex, index});
+ }
+ if (element.inRange(position.x, position.y, useFinalPosition)) {
+ intersectsItem = true;
+ }
+ });
+ if (options.intersect && !intersectsItem) {
+ return [];
+ }
+ return items;
+}
+var Interaction = {
+ modes: {
+ index(chart, e, options, useFinalPosition) {
+ const position = getRelativePosition(e, chart);
+ const axis = options.axis || 'x';
+ const items = options.intersect
+ ? getIntersectItems(chart, position, axis, useFinalPosition)
+ : getNearestItems(chart, position, axis, false, useFinalPosition);
+ const elements = [];
+ if (!items.length) {
+ return [];
+ }
+ chart.getSortedVisibleDatasetMetas().forEach((meta) => {
+ const index = items[0].index;
+ const element = meta.data[index];
+ if (element && !element.skip) {
+ elements.push({element, datasetIndex: meta.index, index});
+ }
+ });
+ return elements;
+ },
+ dataset(chart, e, options, useFinalPosition) {
+ const position = getRelativePosition(e, chart);
+ const axis = options.axis || 'xy';
+ let items = options.intersect
+ ? getIntersectItems(chart, position, axis, useFinalPosition) :
+ getNearestItems(chart, position, axis, false, useFinalPosition);
+ if (items.length > 0) {
+ const datasetIndex = items[0].datasetIndex;
+ const data = chart.getDatasetMeta(datasetIndex).data;
+ items = [];
+ for (let i = 0; i < data.length; ++i) {
+ items.push({element: data[i], datasetIndex, index: i});
+ }
+ }
+ return items;
+ },
+ point(chart, e, options, useFinalPosition) {
+ const position = getRelativePosition(e, chart);
+ const axis = options.axis || 'xy';
+ return getIntersectItems(chart, position, axis, useFinalPosition);
+ },
+ nearest(chart, e, options, useFinalPosition) {
+ const position = getRelativePosition(e, chart);
+ const axis = options.axis || 'xy';
+ return getNearestItems(chart, position, axis, options.intersect, useFinalPosition);
+ },
+ x(chart, e, options, useFinalPosition) {
+ return getAxisItems(chart, e, {axis: 'x', intersect: options.intersect}, useFinalPosition);
+ },
+ y(chart, e, options, useFinalPosition) {
+ return getAxisItems(chart, e, {axis: 'y', intersect: options.intersect}, useFinalPosition);
+ }
+ }
+};
+
+const LINE_HEIGHT = new RegExp(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);
+const FONT_STYLE = new RegExp(/^(normal|italic|initial|inherit|unset|(oblique( -?[0-9]?[0-9]deg)?))$/);
+function toLineHeight(value, size) {
+ const matches = ('' + value).match(LINE_HEIGHT);
+ if (!matches || matches[1] === 'normal') {
+ return size * 1.2;
+ }
+ value = +matches[2];
+ switch (matches[3]) {
+ case 'px':
+ return value;
+ case '%':
+ value /= 100;
+ break;
+ }
+ return size * value;
+}
+const numberOrZero = v => +v || 0;
+function _readValueToProps(value, props) {
+ const ret = {};
+ const objProps = isObject(props);
+ const keys = objProps ? Object.keys(props) : props;
+ const read = isObject(value)
+ ? objProps
+ ? prop => valueOrDefault(value[prop], value[props[prop]])
+ : prop => value[prop]
+ : () => value;
+ for (const prop of keys) {
+ ret[prop] = numberOrZero(read(prop));
+ }
+ return ret;
+}
+function toTRBL(value) {
+ return _readValueToProps(value, {top: 'y', right: 'x', bottom: 'y', left: 'x'});
+}
+function toTRBLCorners(value) {
+ return _readValueToProps(value, ['topLeft', 'topRight', 'bottomLeft', 'bottomRight']);
+}
+function toPadding(value) {
+ const obj = toTRBL(value);
+ obj.width = obj.left + obj.right;
+ obj.height = obj.top + obj.bottom;
+ return obj;
+}
+function toFont(options, fallback) {
+ options = options || {};
+ fallback = fallback || defaults.font;
+ let size = valueOrDefault(options.size, fallback.size);
+ if (typeof size === 'string') {
+ size = parseInt(size, 10);
+ }
+ let style = valueOrDefault(options.style, fallback.style);
+ if (style && !('' + style).match(FONT_STYLE)) {
+ console.warn('Invalid font style specified: "' + style + '"');
+ style = '';
+ }
+ const font = {
+ family: valueOrDefault(options.family, fallback.family),
+ lineHeight: toLineHeight(valueOrDefault(options.lineHeight, fallback.lineHeight), size),
+ size,
+ style,
+ weight: valueOrDefault(options.weight, fallback.weight),
+ string: ''
+ };
+ font.string = toFontString(font);
+ return font;
+}
+function resolve(inputs, context, index, info) {
+ let cacheable = true;
+ let i, ilen, value;
+ for (i = 0, ilen = inputs.length; i < ilen; ++i) {
+ value = inputs[i];
+ if (value === undefined) {
+ continue;
+ }
+ if (context !== undefined && typeof value === 'function') {
+ value = value(context);
+ cacheable = false;
+ }
+ if (index !== undefined && isArray(value)) {
+ value = value[index % value.length];
+ cacheable = false;
+ }
+ if (value !== undefined) {
+ if (info && !cacheable) {
+ info.cacheable = false;
+ }
+ return value;
+ }
+ }
+}
+function _addGrace(minmax, grace, beginAtZero) {
+ const {min, max} = minmax;
+ const change = toDimension(grace, (max - min) / 2);
+ const keepZero = (value, add) => beginAtZero && value === 0 ? 0 : value + add;
+ return {
+ min: keepZero(min, -Math.abs(change)),
+ max: keepZero(max, change)
+ };
+}
+function createContext(parentContext, context) {
+ return Object.assign(Object.create(parentContext), context);
+}
+
+const STATIC_POSITIONS = ['left', 'top', 'right', 'bottom'];
+function filterByPosition(array, position) {
+ return array.filter(v => v.pos === position);
+}
+function filterDynamicPositionByAxis(array, axis) {
+ return array.filter(v => STATIC_POSITIONS.indexOf(v.pos) === -1 && v.box.axis === axis);
+}
+function sortByWeight(array, reverse) {
+ return array.sort((a, b) => {
+ const v0 = reverse ? b : a;
+ const v1 = reverse ? a : b;
+ return v0.weight === v1.weight ?
+ v0.index - v1.index :
+ v0.weight - v1.weight;
+ });
+}
+function wrapBoxes(boxes) {
+ const layoutBoxes = [];
+ let i, ilen, box, pos, stack, stackWeight;
+ for (i = 0, ilen = (boxes || []).length; i < ilen; ++i) {
+ box = boxes[i];
+ ({position: pos, options: {stack, stackWeight = 1}} = box);
+ layoutBoxes.push({
+ index: i,
+ box,
+ pos,
+ horizontal: box.isHorizontal(),
+ weight: box.weight,
+ stack: stack && (pos + stack),
+ stackWeight
+ });
+ }
+ return layoutBoxes;
+}
+function buildStacks(layouts) {
+ const stacks = {};
+ for (const wrap of layouts) {
+ const {stack, pos, stackWeight} = wrap;
+ if (!stack || !STATIC_POSITIONS.includes(pos)) {
+ continue;
+ }
+ const _stack = stacks[stack] || (stacks[stack] = {count: 0, placed: 0, weight: 0, size: 0});
+ _stack.count++;
+ _stack.weight += stackWeight;
+ }
+ return stacks;
+}
+function setLayoutDims(layouts, params) {
+ const stacks = buildStacks(layouts);
+ const {vBoxMaxWidth, hBoxMaxHeight} = params;
+ let i, ilen, layout;
+ for (i = 0, ilen = layouts.length; i < ilen; ++i) {
+ layout = layouts[i];
+ const {fullSize} = layout.box;
+ const stack = stacks[layout.stack];
+ const factor = stack && layout.stackWeight / stack.weight;
+ if (layout.horizontal) {
+ layout.width = factor ? factor * vBoxMaxWidth : fullSize && params.availableWidth;
+ layout.height = hBoxMaxHeight;
+ } else {
+ layout.width = vBoxMaxWidth;
+ layout.height = factor ? factor * hBoxMaxHeight : fullSize && params.availableHeight;
+ }
+ }
+ return stacks;
+}
+function buildLayoutBoxes(boxes) {
+ const layoutBoxes = wrapBoxes(boxes);
+ const fullSize = sortByWeight(layoutBoxes.filter(wrap => wrap.box.fullSize), true);
+ const left = sortByWeight(filterByPosition(layoutBoxes, 'left'), true);
+ const right = sortByWeight(filterByPosition(layoutBoxes, 'right'));
+ const top = sortByWeight(filterByPosition(layoutBoxes, 'top'), true);
+ const bottom = sortByWeight(filterByPosition(layoutBoxes, 'bottom'));
+ const centerHorizontal = filterDynamicPositionByAxis(layoutBoxes, 'x');
+ const centerVertical = filterDynamicPositionByAxis(layoutBoxes, 'y');
+ return {
+ fullSize,
+ leftAndTop: left.concat(top),
+ rightAndBottom: right.concat(centerVertical).concat(bottom).concat(centerHorizontal),
+ chartArea: filterByPosition(layoutBoxes, 'chartArea'),
+ vertical: left.concat(right).concat(centerVertical),
+ horizontal: top.concat(bottom).concat(centerHorizontal)
+ };
+}
+function getCombinedMax(maxPadding, chartArea, a, b) {
+ return Math.max(maxPadding[a], chartArea[a]) + Math.max(maxPadding[b], chartArea[b]);
+}
+function updateMaxPadding(maxPadding, boxPadding) {
+ maxPadding.top = Math.max(maxPadding.top, boxPadding.top);
+ maxPadding.left = Math.max(maxPadding.left, boxPadding.left);
+ maxPadding.bottom = Math.max(maxPadding.bottom, boxPadding.bottom);
+ maxPadding.right = Math.max(maxPadding.right, boxPadding.right);
+}
+function updateDims(chartArea, params, layout, stacks) {
+ const {pos, box} = layout;
+ const maxPadding = chartArea.maxPadding;
+ if (!isObject(pos)) {
+ if (layout.size) {
+ chartArea[pos] -= layout.size;
+ }
+ const stack = stacks[layout.stack] || {size: 0, count: 1};
+ stack.size = Math.max(stack.size, layout.horizontal ? box.height : box.width);
+ layout.size = stack.size / stack.count;
+ chartArea[pos] += layout.size;
+ }
+ if (box.getPadding) {
+ updateMaxPadding(maxPadding, box.getPadding());
+ }
+ const newWidth = Math.max(0, params.outerWidth - getCombinedMax(maxPadding, chartArea, 'left', 'right'));
+ const newHeight = Math.max(0, params.outerHeight - getCombinedMax(maxPadding, chartArea, 'top', 'bottom'));
+ const widthChanged = newWidth !== chartArea.w;
+ const heightChanged = newHeight !== chartArea.h;
+ chartArea.w = newWidth;
+ chartArea.h = newHeight;
+ return layout.horizontal
+ ? {same: widthChanged, other: heightChanged}
+ : {same: heightChanged, other: widthChanged};
+}
+function handleMaxPadding(chartArea) {
+ const maxPadding = chartArea.maxPadding;
+ function updatePos(pos) {
+ const change = Math.max(maxPadding[pos] - chartArea[pos], 0);
+ chartArea[pos] += change;
+ return change;
+ }
+ chartArea.y += updatePos('top');
+ chartArea.x += updatePos('left');
+ updatePos('right');
+ updatePos('bottom');
+}
+function getMargins(horizontal, chartArea) {
+ const maxPadding = chartArea.maxPadding;
+ function marginForPositions(positions) {
+ const margin = {left: 0, top: 0, right: 0, bottom: 0};
+ positions.forEach((pos) => {
+ margin[pos] = Math.max(chartArea[pos], maxPadding[pos]);
+ });
+ return margin;
+ }
+ return horizontal
+ ? marginForPositions(['left', 'right'])
+ : marginForPositions(['top', 'bottom']);
+}
+function fitBoxes(boxes, chartArea, params, stacks) {
+ const refitBoxes = [];
+ let i, ilen, layout, box, refit, changed;
+ for (i = 0, ilen = boxes.length, refit = 0; i < ilen; ++i) {
+ layout = boxes[i];
+ box = layout.box;
+ box.update(
+ layout.width || chartArea.w,
+ layout.height || chartArea.h,
+ getMargins(layout.horizontal, chartArea)
+ );
+ const {same, other} = updateDims(chartArea, params, layout, stacks);
+ refit |= same && refitBoxes.length;
+ changed = changed || other;
+ if (!box.fullSize) {
+ refitBoxes.push(layout);
+ }
+ }
+ return refit && fitBoxes(refitBoxes, chartArea, params, stacks) || changed;
+}
+function setBoxDims(box, left, top, width, height) {
+ box.top = top;
+ box.left = left;
+ box.right = left + width;
+ box.bottom = top + height;
+ box.width = width;
+ box.height = height;
+}
+function placeBoxes(boxes, chartArea, params, stacks) {
+ const userPadding = params.padding;
+ let {x, y} = chartArea;
+ for (const layout of boxes) {
+ const box = layout.box;
+ const stack = stacks[layout.stack] || {count: 1, placed: 0, weight: 1};
+ const weight = (layout.stackWeight / stack.weight) || 1;
+ if (layout.horizontal) {
+ const width = chartArea.w * weight;
+ const height = stack.size || box.height;
+ if (defined(stack.start)) {
+ y = stack.start;
+ }
+ if (box.fullSize) {
+ setBoxDims(box, userPadding.left, y, params.outerWidth - userPadding.right - userPadding.left, height);
+ } else {
+ setBoxDims(box, chartArea.left + stack.placed, y, width, height);
+ }
+ stack.start = y;
+ stack.placed += width;
+ y = box.bottom;
+ } else {
+ const height = chartArea.h * weight;
+ const width = stack.size || box.width;
+ if (defined(stack.start)) {
+ x = stack.start;
+ }
+ if (box.fullSize) {
+ setBoxDims(box, x, userPadding.top, width, params.outerHeight - userPadding.bottom - userPadding.top);
+ } else {
+ setBoxDims(box, x, chartArea.top + stack.placed, width, height);
+ }
+ stack.start = x;
+ stack.placed += height;
+ x = box.right;
+ }
+ }
+ chartArea.x = x;
+ chartArea.y = y;
+}
+defaults.set('layout', {
+ autoPadding: true,
+ padding: {
+ top: 0,
+ right: 0,
+ bottom: 0,
+ left: 0
+ }
+});
+var layouts = {
+ addBox(chart, item) {
+ if (!chart.boxes) {
+ chart.boxes = [];
+ }
+ item.fullSize = item.fullSize || false;
+ item.position = item.position || 'top';
+ item.weight = item.weight || 0;
+ item._layers = item._layers || function() {
+ return [{
+ z: 0,
+ draw(chartArea) {
+ item.draw(chartArea);
+ }
+ }];
+ };
+ chart.boxes.push(item);
+ },
+ removeBox(chart, layoutItem) {
+ const index = chart.boxes ? chart.boxes.indexOf(layoutItem) : -1;
+ if (index !== -1) {
+ chart.boxes.splice(index, 1);
+ }
+ },
+ configure(chart, item, options) {
+ item.fullSize = options.fullSize;
+ item.position = options.position;
+ item.weight = options.weight;
+ },
+ update(chart, width, height, minPadding) {
+ if (!chart) {
+ return;
+ }
+ const padding = toPadding(chart.options.layout.padding);
+ const availableWidth = Math.max(width - padding.width, 0);
+ const availableHeight = Math.max(height - padding.height, 0);
+ const boxes = buildLayoutBoxes(chart.boxes);
+ const verticalBoxes = boxes.vertical;
+ const horizontalBoxes = boxes.horizontal;
+ each(chart.boxes, box => {
+ if (typeof box.beforeLayout === 'function') {
+ box.beforeLayout();
+ }
+ });
+ const visibleVerticalBoxCount = verticalBoxes.reduce((total, wrap) =>
+ wrap.box.options && wrap.box.options.display === false ? total : total + 1, 0) || 1;
+ const params = Object.freeze({
+ outerWidth: width,
+ outerHeight: height,
+ padding,
+ availableWidth,
+ availableHeight,
+ vBoxMaxWidth: availableWidth / 2 / visibleVerticalBoxCount,
+ hBoxMaxHeight: availableHeight / 2
+ });
+ const maxPadding = Object.assign({}, padding);
+ updateMaxPadding(maxPadding, toPadding(minPadding));
+ const chartArea = Object.assign({
+ maxPadding,
+ w: availableWidth,
+ h: availableHeight,
+ x: padding.left,
+ y: padding.top
+ }, padding);
+ const stacks = setLayoutDims(verticalBoxes.concat(horizontalBoxes), params);
+ fitBoxes(boxes.fullSize, chartArea, params, stacks);
+ fitBoxes(verticalBoxes, chartArea, params, stacks);
+ if (fitBoxes(horizontalBoxes, chartArea, params, stacks)) {
+ fitBoxes(verticalBoxes, chartArea, params, stacks);
+ }
+ handleMaxPadding(chartArea);
+ placeBoxes(boxes.leftAndTop, chartArea, params, stacks);
+ chartArea.x += chartArea.w;
+ chartArea.y += chartArea.h;
+ placeBoxes(boxes.rightAndBottom, chartArea, params, stacks);
+ chart.chartArea = {
+ left: chartArea.left,
+ top: chartArea.top,
+ right: chartArea.left + chartArea.w,
+ bottom: chartArea.top + chartArea.h,
+ height: chartArea.h,
+ width: chartArea.w,
+ };
+ each(boxes.chartArea, (layout) => {
+ const box = layout.box;
+ Object.assign(box, chart.chartArea);
+ box.update(chartArea.w, chartArea.h, {left: 0, top: 0, right: 0, bottom: 0});
+ });
+ }
+};
+
+function _createResolver(scopes, prefixes = [''], rootScopes = scopes, fallback, getTarget = () => scopes[0]) {
+ if (!defined(fallback)) {
+ fallback = _resolve('_fallback', scopes);
+ }
+ const cache = {
+ [Symbol.toStringTag]: 'Object',
+ _cacheable: true,
+ _scopes: scopes,
+ _rootScopes: rootScopes,
+ _fallback: fallback,
+ _getTarget: getTarget,
+ override: (scope) => _createResolver([scope, ...scopes], prefixes, rootScopes, fallback),
+ };
+ return new Proxy(cache, {
+ deleteProperty(target, prop) {
+ delete target[prop];
+ delete target._keys;
+ delete scopes[0][prop];
+ return true;
+ },
+ get(target, prop) {
+ return _cached(target, prop,
+ () => _resolveWithPrefixes(prop, prefixes, scopes, target));
+ },
+ getOwnPropertyDescriptor(target, prop) {
+ return Reflect.getOwnPropertyDescriptor(target._scopes[0], prop);
+ },
+ getPrototypeOf() {
+ return Reflect.getPrototypeOf(scopes[0]);
+ },
+ has(target, prop) {
+ return getKeysFromAllScopes(target).includes(prop);
+ },
+ ownKeys(target) {
+ return getKeysFromAllScopes(target);
+ },
+ set(target, prop, value) {
+ const storage = target._storage || (target._storage = getTarget());
+ target[prop] = storage[prop] = value;
+ delete target._keys;
+ return true;
+ }
+ });
+}
+function _attachContext(proxy, context, subProxy, descriptorDefaults) {
+ const cache = {
+ _cacheable: false,
+ _proxy: proxy,
+ _context: context,
+ _subProxy: subProxy,
+ _stack: new Set(),
+ _descriptors: _descriptors(proxy, descriptorDefaults),
+ setContext: (ctx) => _attachContext(proxy, ctx, subProxy, descriptorDefaults),
+ override: (scope) => _attachContext(proxy.override(scope), context, subProxy, descriptorDefaults)
+ };
+ return new Proxy(cache, {
+ deleteProperty(target, prop) {
+ delete target[prop];
+ delete proxy[prop];
+ return true;
+ },
+ get(target, prop, receiver) {
+ return _cached(target, prop,
+ () => _resolveWithContext(target, prop, receiver));
+ },
+ getOwnPropertyDescriptor(target, prop) {
+ return target._descriptors.allKeys
+ ? Reflect.has(proxy, prop) ? {enumerable: true, configurable: true} : undefined
+ : Reflect.getOwnPropertyDescriptor(proxy, prop);
+ },
+ getPrototypeOf() {
+ return Reflect.getPrototypeOf(proxy);
+ },
+ has(target, prop) {
+ return Reflect.has(proxy, prop);
+ },
+ ownKeys() {
+ return Reflect.ownKeys(proxy);
+ },
+ set(target, prop, value) {
+ proxy[prop] = value;
+ delete target[prop];
+ return true;
+ }
+ });
+}
+function _descriptors(proxy, defaults = {scriptable: true, indexable: true}) {
+ const {_scriptable = defaults.scriptable, _indexable = defaults.indexable, _allKeys = defaults.allKeys} = proxy;
+ return {
+ allKeys: _allKeys,
+ scriptable: _scriptable,
+ indexable: _indexable,
+ isScriptable: isFunction(_scriptable) ? _scriptable : () => _scriptable,
+ isIndexable: isFunction(_indexable) ? _indexable : () => _indexable
+ };
+}
+const readKey = (prefix, name) => prefix ? prefix + _capitalize(name) : name;
+const needsSubResolver = (prop, value) => isObject(value) && prop !== 'adapters' &&
+ (Object.getPrototypeOf(value) === null || value.constructor === Object);
+function _cached(target, prop, resolve) {
+ if (Object.prototype.hasOwnProperty.call(target, prop)) {
+ return target[prop];
+ }
+ const value = resolve();
+ target[prop] = value;
+ return value;
+}
+function _resolveWithContext(target, prop, receiver) {
+ const {_proxy, _context, _subProxy, _descriptors: descriptors} = target;
+ let value = _proxy[prop];
+ if (isFunction(value) && descriptors.isScriptable(prop)) {
+ value = _resolveScriptable(prop, value, target, receiver);
+ }
+ if (isArray(value) && value.length) {
+ value = _resolveArray(prop, value, target, descriptors.isIndexable);
+ }
+ if (needsSubResolver(prop, value)) {
+ value = _attachContext(value, _context, _subProxy && _subProxy[prop], descriptors);
+ }
+ return value;
+}
+function _resolveScriptable(prop, value, target, receiver) {
+ const {_proxy, _context, _subProxy, _stack} = target;
+ if (_stack.has(prop)) {
+ throw new Error('Recursion detected: ' + Array.from(_stack).join('->') + '->' + prop);
+ }
+ _stack.add(prop);
+ value = value(_context, _subProxy || receiver);
+ _stack.delete(prop);
+ if (needsSubResolver(prop, value)) {
+ value = createSubResolver(_proxy._scopes, _proxy, prop, value);
+ }
+ return value;
+}
+function _resolveArray(prop, value, target, isIndexable) {
+ const {_proxy, _context, _subProxy, _descriptors: descriptors} = target;
+ if (defined(_context.index) && isIndexable(prop)) {
+ value = value[_context.index % value.length];
+ } else if (isObject(value[0])) {
+ const arr = value;
+ const scopes = _proxy._scopes.filter(s => s !== arr);
+ value = [];
+ for (const item of arr) {
+ const resolver = createSubResolver(scopes, _proxy, prop, item);
+ value.push(_attachContext(resolver, _context, _subProxy && _subProxy[prop], descriptors));
+ }
+ }
+ return value;
+}
+function resolveFallback(fallback, prop, value) {
+ return isFunction(fallback) ? fallback(prop, value) : fallback;
+}
+const getScope = (key, parent) => key === true ? parent
+ : typeof key === 'string' ? resolveObjectKey(parent, key) : undefined;
+function addScopes(set, parentScopes, key, parentFallback, value) {
+ for (const parent of parentScopes) {
+ const scope = getScope(key, parent);
+ if (scope) {
+ set.add(scope);
+ const fallback = resolveFallback(scope._fallback, key, value);
+ if (defined(fallback) && fallback !== key && fallback !== parentFallback) {
+ return fallback;
+ }
+ } else if (scope === false && defined(parentFallback) && key !== parentFallback) {
+ return null;
+ }
+ }
+ return false;
+}
+function createSubResolver(parentScopes, resolver, prop, value) {
+ const rootScopes = resolver._rootScopes;
+ const fallback = resolveFallback(resolver._fallback, prop, value);
+ const allScopes = [...parentScopes, ...rootScopes];
+ const set = new Set();
+ set.add(value);
+ let key = addScopesFromKey(set, allScopes, prop, fallback || prop, value);
+ if (key === null) {
+ return false;
+ }
+ if (defined(fallback) && fallback !== prop) {
+ key = addScopesFromKey(set, allScopes, fallback, key, value);
+ if (key === null) {
+ return false;
+ }
+ }
+ return _createResolver(Array.from(set), [''], rootScopes, fallback,
+ () => subGetTarget(resolver, prop, value));
+}
+function addScopesFromKey(set, allScopes, key, fallback, item) {
+ while (key) {
+ key = addScopes(set, allScopes, key, fallback, item);
+ }
+ return key;
+}
+function subGetTarget(resolver, prop, value) {
+ const parent = resolver._getTarget();
+ if (!(prop in parent)) {
+ parent[prop] = {};
+ }
+ const target = parent[prop];
+ if (isArray(target) && isObject(value)) {
+ return value;
+ }
+ return target;
+}
+function _resolveWithPrefixes(prop, prefixes, scopes, proxy) {
+ let value;
+ for (const prefix of prefixes) {
+ value = _resolve(readKey(prefix, prop), scopes);
+ if (defined(value)) {
+ return needsSubResolver(prop, value)
+ ? createSubResolver(scopes, proxy, prop, value)
+ : value;
+ }
+ }
+}
+function _resolve(key, scopes) {
+ for (const scope of scopes) {
+ if (!scope) {
+ continue;
+ }
+ const value = scope[key];
+ if (defined(value)) {
+ return value;
+ }
+ }
+}
+function getKeysFromAllScopes(target) {
+ let keys = target._keys;
+ if (!keys) {
+ keys = target._keys = resolveKeysFromAllScopes(target._scopes);
+ }
+ return keys;
+}
+function resolveKeysFromAllScopes(scopes) {
+ const set = new Set();
+ for (const scope of scopes) {
+ for (const key of Object.keys(scope).filter(k => !k.startsWith('_'))) {
+ set.add(key);
+ }
+ }
+ return Array.from(set);
+}
+
+const EPSILON = Number.EPSILON || 1e-14;
+const getPoint = (points, i) => i < points.length && !points[i].skip && points[i];
+const getValueAxis = (indexAxis) => indexAxis === 'x' ? 'y' : 'x';
+function splineCurve(firstPoint, middlePoint, afterPoint, t) {
+ const previous = firstPoint.skip ? middlePoint : firstPoint;
+ const current = middlePoint;
+ const next = afterPoint.skip ? middlePoint : afterPoint;
+ const d01 = distanceBetweenPoints(current, previous);
+ const d12 = distanceBetweenPoints(next, current);
+ let s01 = d01 / (d01 + d12);
+ let s12 = d12 / (d01 + d12);
+ s01 = isNaN(s01) ? 0 : s01;
+ s12 = isNaN(s12) ? 0 : s12;
+ const fa = t * s01;
+ const fb = t * s12;
+ return {
+ previous: {
+ x: current.x - fa * (next.x - previous.x),
+ y: current.y - fa * (next.y - previous.y)
+ },
+ next: {
+ x: current.x + fb * (next.x - previous.x),
+ y: current.y + fb * (next.y - previous.y)
+ }
+ };
+}
+function monotoneAdjust(points, deltaK, mK) {
+ const pointsLen = points.length;
+ let alphaK, betaK, tauK, squaredMagnitude, pointCurrent;
+ let pointAfter = getPoint(points, 0);
+ for (let i = 0; i < pointsLen - 1; ++i) {
+ pointCurrent = pointAfter;
+ pointAfter = getPoint(points, i + 1);
+ if (!pointCurrent || !pointAfter) {
+ continue;
+ }
+ if (almostEquals(deltaK[i], 0, EPSILON)) {
+ mK[i] = mK[i + 1] = 0;
+ continue;
+ }
+ alphaK = mK[i] / deltaK[i];
+ betaK = mK[i + 1] / deltaK[i];
+ squaredMagnitude = Math.pow(alphaK, 2) + Math.pow(betaK, 2);
+ if (squaredMagnitude <= 9) {
+ continue;
+ }
+ tauK = 3 / Math.sqrt(squaredMagnitude);
+ mK[i] = alphaK * tauK * deltaK[i];
+ mK[i + 1] = betaK * tauK * deltaK[i];
+ }
+}
+function monotoneCompute(points, mK, indexAxis = 'x') {
+ const valueAxis = getValueAxis(indexAxis);
+ const pointsLen = points.length;
+ let delta, pointBefore, pointCurrent;
+ let pointAfter = getPoint(points, 0);
+ for (let i = 0; i < pointsLen; ++i) {
+ pointBefore = pointCurrent;
+ pointCurrent = pointAfter;
+ pointAfter = getPoint(points, i + 1);
+ if (!pointCurrent) {
+ continue;
+ }
+ const iPixel = pointCurrent[indexAxis];
+ const vPixel = pointCurrent[valueAxis];
+ if (pointBefore) {
+ delta = (iPixel - pointBefore[indexAxis]) / 3;
+ pointCurrent[`cp1${indexAxis}`] = iPixel - delta;
+ pointCurrent[`cp1${valueAxis}`] = vPixel - delta * mK[i];
+ }
+ if (pointAfter) {
+ delta = (pointAfter[indexAxis] - iPixel) / 3;
+ pointCurrent[`cp2${indexAxis}`] = iPixel + delta;
+ pointCurrent[`cp2${valueAxis}`] = vPixel + delta * mK[i];
+ }
+ }
+}
+function splineCurveMonotone(points, indexAxis = 'x') {
+ const valueAxis = getValueAxis(indexAxis);
+ const pointsLen = points.length;
+ const deltaK = Array(pointsLen).fill(0);
+ const mK = Array(pointsLen);
+ let i, pointBefore, pointCurrent;
+ let pointAfter = getPoint(points, 0);
+ for (i = 0; i < pointsLen; ++i) {
+ pointBefore = pointCurrent;
+ pointCurrent = pointAfter;
+ pointAfter = getPoint(points, i + 1);
+ if (!pointCurrent) {
+ continue;
+ }
+ if (pointAfter) {
+ const slopeDelta = pointAfter[indexAxis] - pointCurrent[indexAxis];
+ deltaK[i] = slopeDelta !== 0 ? (pointAfter[valueAxis] - pointCurrent[valueAxis]) / slopeDelta : 0;
+ }
+ mK[i] = !pointBefore ? deltaK[i]
+ : !pointAfter ? deltaK[i - 1]
+ : (sign(deltaK[i - 1]) !== sign(deltaK[i])) ? 0
+ : (deltaK[i - 1] + deltaK[i]) / 2;
+ }
+ monotoneAdjust(points, deltaK, mK);
+ monotoneCompute(points, mK, indexAxis);
+}
+function capControlPoint(pt, min, max) {
+ return Math.max(Math.min(pt, max), min);
+}
+function capBezierPoints(points, area) {
+ let i, ilen, point, inArea, inAreaPrev;
+ let inAreaNext = _isPointInArea(points[0], area);
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
+ inAreaPrev = inArea;
+ inArea = inAreaNext;
+ inAreaNext = i < ilen - 1 && _isPointInArea(points[i + 1], area);
+ if (!inArea) {
+ continue;
+ }
+ point = points[i];
+ if (inAreaPrev) {
+ point.cp1x = capControlPoint(point.cp1x, area.left, area.right);
+ point.cp1y = capControlPoint(point.cp1y, area.top, area.bottom);
+ }
+ if (inAreaNext) {
+ point.cp2x = capControlPoint(point.cp2x, area.left, area.right);
+ point.cp2y = capControlPoint(point.cp2y, area.top, area.bottom);
+ }
+ }
+}
+function _updateBezierControlPoints(points, options, area, loop, indexAxis) {
+ let i, ilen, point, controlPoints;
+ if (options.spanGaps) {
+ points = points.filter((pt) => !pt.skip);
+ }
+ if (options.cubicInterpolationMode === 'monotone') {
+ splineCurveMonotone(points, indexAxis);
+ } else {
+ let prev = loop ? points[points.length - 1] : points[0];
+ for (i = 0, ilen = points.length; i < ilen; ++i) {
+ point = points[i];
+ controlPoints = splineCurve(
+ prev,
+ point,
+ points[Math.min(i + 1, ilen - (loop ? 0 : 1)) % ilen],
+ options.tension
+ );
+ point.cp1x = controlPoints.previous.x;
+ point.cp1y = controlPoints.previous.y;
+ point.cp2x = controlPoints.next.x;
+ point.cp2y = controlPoints.next.y;
+ prev = point;
+ }
+ }
+ if (options.capBezierPoints) {
+ capBezierPoints(points, area);
+ }
+}
+
+const atEdge = (t) => t === 0 || t === 1;
+const elasticIn = (t, s, p) => -(Math.pow(2, 10 * (t -= 1)) * Math.sin((t - s) * TAU / p));
+const elasticOut = (t, s, p) => Math.pow(2, -10 * t) * Math.sin((t - s) * TAU / p) + 1;
+const effects = {
+ linear: t => t,
+ easeInQuad: t => t * t,
+ easeOutQuad: t => -t * (t - 2),
+ easeInOutQuad: t => ((t /= 0.5) < 1)
+ ? 0.5 * t * t
+ : -0.5 * ((--t) * (t - 2) - 1),
+ easeInCubic: t => t * t * t,
+ easeOutCubic: t => (t -= 1) * t * t + 1,
+ easeInOutCubic: t => ((t /= 0.5) < 1)
+ ? 0.5 * t * t * t
+ : 0.5 * ((t -= 2) * t * t + 2),
+ easeInQuart: t => t * t * t * t,
+ easeOutQuart: t => -((t -= 1) * t * t * t - 1),
+ easeInOutQuart: t => ((t /= 0.5) < 1)
+ ? 0.5 * t * t * t * t
+ : -0.5 * ((t -= 2) * t * t * t - 2),
+ easeInQuint: t => t * t * t * t * t,
+ easeOutQuint: t => (t -= 1) * t * t * t * t + 1,
+ easeInOutQuint: t => ((t /= 0.5) < 1)
+ ? 0.5 * t * t * t * t * t
+ : 0.5 * ((t -= 2) * t * t * t * t + 2),
+ easeInSine: t => -Math.cos(t * HALF_PI) + 1,
+ easeOutSine: t => Math.sin(t * HALF_PI),
+ easeInOutSine: t => -0.5 * (Math.cos(PI * t) - 1),
+ easeInExpo: t => (t === 0) ? 0 : Math.pow(2, 10 * (t - 1)),
+ easeOutExpo: t => (t === 1) ? 1 : -Math.pow(2, -10 * t) + 1,
+ easeInOutExpo: t => atEdge(t) ? t : t < 0.5
+ ? 0.5 * Math.pow(2, 10 * (t * 2 - 1))
+ : 0.5 * (-Math.pow(2, -10 * (t * 2 - 1)) + 2),
+ easeInCirc: t => (t >= 1) ? t : -(Math.sqrt(1 - t * t) - 1),
+ easeOutCirc: t => Math.sqrt(1 - (t -= 1) * t),
+ easeInOutCirc: t => ((t /= 0.5) < 1)
+ ? -0.5 * (Math.sqrt(1 - t * t) - 1)
+ : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1),
+ easeInElastic: t => atEdge(t) ? t : elasticIn(t, 0.075, 0.3),
+ easeOutElastic: t => atEdge(t) ? t : elasticOut(t, 0.075, 0.3),
+ easeInOutElastic(t) {
+ const s = 0.1125;
+ const p = 0.45;
+ return atEdge(t) ? t :
+ t < 0.5
+ ? 0.5 * elasticIn(t * 2, s, p)
+ : 0.5 + 0.5 * elasticOut(t * 2 - 1, s, p);
+ },
+ easeInBack(t) {
+ const s = 1.70158;
+ return t * t * ((s + 1) * t - s);
+ },
+ easeOutBack(t) {
+ const s = 1.70158;
+ return (t -= 1) * t * ((s + 1) * t + s) + 1;
+ },
+ easeInOutBack(t) {
+ let s = 1.70158;
+ if ((t /= 0.5) < 1) {
+ return 0.5 * (t * t * (((s *= (1.525)) + 1) * t - s));
+ }
+ return 0.5 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2);
+ },
+ easeInBounce: t => 1 - effects.easeOutBounce(1 - t),
+ easeOutBounce(t) {
+ const m = 7.5625;
+ const d = 2.75;
+ if (t < (1 / d)) {
+ return m * t * t;
+ }
+ if (t < (2 / d)) {
+ return m * (t -= (1.5 / d)) * t + 0.75;
+ }
+ if (t < (2.5 / d)) {
+ return m * (t -= (2.25 / d)) * t + 0.9375;
+ }
+ return m * (t -= (2.625 / d)) * t + 0.984375;
+ },
+ easeInOutBounce: t => (t < 0.5)
+ ? effects.easeInBounce(t * 2) * 0.5
+ : effects.easeOutBounce(t * 2 - 1) * 0.5 + 0.5,
+};
+
+function _pointInLine(p1, p2, t, mode) {
+ return {
+ x: p1.x + t * (p2.x - p1.x),
+ y: p1.y + t * (p2.y - p1.y)
+ };
+}
+function _steppedInterpolation(p1, p2, t, mode) {
+ return {
+ x: p1.x + t * (p2.x - p1.x),
+ y: mode === 'middle' ? t < 0.5 ? p1.y : p2.y
+ : mode === 'after' ? t < 1 ? p1.y : p2.y
+ : t > 0 ? p2.y : p1.y
+ };
+}
+function _bezierInterpolation(p1, p2, t, mode) {
+ const cp1 = {x: p1.cp2x, y: p1.cp2y};
+ const cp2 = {x: p2.cp1x, y: p2.cp1y};
+ const a = _pointInLine(p1, cp1, t);
+ const b = _pointInLine(cp1, cp2, t);
+ const c = _pointInLine(cp2, p2, t);
+ const d = _pointInLine(a, b, t);
+ const e = _pointInLine(b, c, t);
+ return _pointInLine(d, e, t);
+}
+
+const intlCache = new Map();
+function getNumberFormat(locale, options) {
+ options = options || {};
+ const cacheKey = locale + JSON.stringify(options);
+ let formatter = intlCache.get(cacheKey);
+ if (!formatter) {
+ formatter = new Intl.NumberFormat(locale, options);
+ intlCache.set(cacheKey, formatter);
+ }
+ return formatter;
+}
+function formatNumber(num, locale, options) {
+ return getNumberFormat(locale, options).format(num);
+}
+
+const getRightToLeftAdapter = function(rectX, width) {
+ return {
+ x(x) {
+ return rectX + rectX + width - x;
+ },
+ setWidth(w) {
+ width = w;
+ },
+ textAlign(align) {
+ if (align === 'center') {
+ return align;
+ }
+ return align === 'right' ? 'left' : 'right';
+ },
+ xPlus(x, value) {
+ return x - value;
+ },
+ leftForLtr(x, itemWidth) {
+ return x - itemWidth;
+ },
+ };
+};
+const getLeftToRightAdapter = function() {
+ return {
+ x(x) {
+ return x;
+ },
+ setWidth(w) {
+ },
+ textAlign(align) {
+ return align;
+ },
+ xPlus(x, value) {
+ return x + value;
+ },
+ leftForLtr(x, _itemWidth) {
+ return x;
+ },
+ };
+};
+function getRtlAdapter(rtl, rectX, width) {
+ return rtl ? getRightToLeftAdapter(rectX, width) : getLeftToRightAdapter();
+}
+function overrideTextDirection(ctx, direction) {
+ let style, original;
+ if (direction === 'ltr' || direction === 'rtl') {
+ style = ctx.canvas.style;
+ original = [
+ style.getPropertyValue('direction'),
+ style.getPropertyPriority('direction'),
+ ];
+ style.setProperty('direction', direction, 'important');
+ ctx.prevTextDirection = original;
+ }
+}
+function restoreTextDirection(ctx, original) {
+ if (original !== undefined) {
+ delete ctx.prevTextDirection;
+ ctx.canvas.style.setProperty('direction', original[0], original[1]);
+ }
+}
+
+function propertyFn(property) {
+ if (property === 'angle') {
+ return {
+ between: _angleBetween,
+ compare: _angleDiff,
+ normalize: _normalizeAngle,
+ };
+ }
+ return {
+ between: _isBetween,
+ compare: (a, b) => a - b,
+ normalize: x => x
+ };
+}
+function normalizeSegment({start, end, count, loop, style}) {
+ return {
+ start: start % count,
+ end: end % count,
+ loop: loop && (end - start + 1) % count === 0,
+ style
+ };
+}
+function getSegment(segment, points, bounds) {
+ const {property, start: startBound, end: endBound} = bounds;
+ const {between, normalize} = propertyFn(property);
+ const count = points.length;
+ let {start, end, loop} = segment;
+ let i, ilen;
+ if (loop) {
+ start += count;
+ end += count;
+ for (i = 0, ilen = count; i < ilen; ++i) {
+ if (!between(normalize(points[start % count][property]), startBound, endBound)) {
+ break;
+ }
+ start--;
+ end--;
+ }
+ start %= count;
+ end %= count;
+ }
+ if (end < start) {
+ end += count;
+ }
+ return {start, end, loop, style: segment.style};
+}
+function _boundSegment(segment, points, bounds) {
+ if (!bounds) {
+ return [segment];
+ }
+ const {property, start: startBound, end: endBound} = bounds;
+ const count = points.length;
+ const {compare, between, normalize} = propertyFn(property);
+ const {start, end, loop, style} = getSegment(segment, points, bounds);
+ const result = [];
+ let inside = false;
+ let subStart = null;
+ let value, point, prevValue;
+ const startIsBefore = () => between(startBound, prevValue, value) && compare(startBound, prevValue) !== 0;
+ const endIsBefore = () => compare(endBound, value) === 0 || between(endBound, prevValue, value);
+ const shouldStart = () => inside || startIsBefore();
+ const shouldStop = () => !inside || endIsBefore();
+ for (let i = start, prev = start; i <= end; ++i) {
+ point = points[i % count];
+ if (point.skip) {
+ continue;
+ }
+ value = normalize(point[property]);
+ if (value === prevValue) {
+ continue;
+ }
+ inside = between(value, startBound, endBound);
+ if (subStart === null && shouldStart()) {
+ subStart = compare(value, startBound) === 0 ? i : prev;
+ }
+ if (subStart !== null && shouldStop()) {
+ result.push(normalizeSegment({start: subStart, end: i, loop, count, style}));
+ subStart = null;
+ }
+ prev = i;
+ prevValue = value;
+ }
+ if (subStart !== null) {
+ result.push(normalizeSegment({start: subStart, end, loop, count, style}));
+ }
+ return result;
+}
+function _boundSegments(line, bounds) {
+ const result = [];
+ const segments = line.segments;
+ for (let i = 0; i < segments.length; i++) {
+ const sub = _boundSegment(segments[i], line.points, bounds);
+ if (sub.length) {
+ result.push(...sub);
+ }
+ }
+ return result;
+}
+function findStartAndEnd(points, count, loop, spanGaps) {
+ let start = 0;
+ let end = count - 1;
+ if (loop && !spanGaps) {
+ while (start < count && !points[start].skip) {
+ start++;
+ }
+ }
+ while (start < count && points[start].skip) {
+ start++;
+ }
+ start %= count;
+ if (loop) {
+ end += start;
+ }
+ while (end > start && points[end % count].skip) {
+ end--;
+ }
+ end %= count;
+ return {start, end};
+}
+function solidSegments(points, start, max, loop) {
+ const count = points.length;
+ const result = [];
+ let last = start;
+ let prev = points[start];
+ let end;
+ for (end = start + 1; end <= max; ++end) {
+ const cur = points[end % count];
+ if (cur.skip || cur.stop) {
+ if (!prev.skip) {
+ loop = false;
+ result.push({start: start % count, end: (end - 1) % count, loop});
+ start = last = cur.stop ? end : null;
+ }
+ } else {
+ last = end;
+ if (prev.skip) {
+ start = end;
+ }
+ }
+ prev = cur;
+ }
+ if (last !== null) {
+ result.push({start: start % count, end: last % count, loop});
+ }
+ return result;
+}
+function _computeSegments(line, segmentOptions) {
+ const points = line.points;
+ const spanGaps = line.options.spanGaps;
+ const count = points.length;
+ if (!count) {
+ return [];
+ }
+ const loop = !!line._loop;
+ const {start, end} = findStartAndEnd(points, count, loop, spanGaps);
+ if (spanGaps === true) {
+ return splitByStyles(line, [{start, end, loop}], points, segmentOptions);
+ }
+ const max = end < start ? end + count : end;
+ const completeLoop = !!line._fullLoop && start === 0 && end === count - 1;
+ return splitByStyles(line, solidSegments(points, start, max, completeLoop), points, segmentOptions);
+}
+function splitByStyles(line, segments, points, segmentOptions) {
+ if (!segmentOptions || !segmentOptions.setContext || !points) {
+ return segments;
+ }
+ return doSplitByStyles(line, segments, points, segmentOptions);
+}
+function doSplitByStyles(line, segments, points, segmentOptions) {
+ const chartContext = line._chart.getContext();
+ const baseStyle = readStyle(line.options);
+ const {_datasetIndex: datasetIndex, options: {spanGaps}} = line;
+ const count = points.length;
+ const result = [];
+ let prevStyle = baseStyle;
+ let start = segments[0].start;
+ let i = start;
+ function addStyle(s, e, l, st) {
+ const dir = spanGaps ? -1 : 1;
+ if (s === e) {
+ return;
+ }
+ s += count;
+ while (points[s % count].skip) {
+ s -= dir;
+ }
+ while (points[e % count].skip) {
+ e += dir;
+ }
+ if (s % count !== e % count) {
+ result.push({start: s % count, end: e % count, loop: l, style: st});
+ prevStyle = st;
+ start = e % count;
+ }
+ }
+ for (const segment of segments) {
+ start = spanGaps ? start : segment.start;
+ let prev = points[start % count];
+ let style;
+ for (i = start + 1; i <= segment.end; i++) {
+ const pt = points[i % count];
+ style = readStyle(segmentOptions.setContext(createContext(chartContext, {
+ type: 'segment',
+ p0: prev,
+ p1: pt,
+ p0DataIndex: (i - 1) % count,
+ p1DataIndex: i % count,
+ datasetIndex
+ })));
+ if (styleChanged(style, prevStyle)) {
+ addStyle(start, i - 1, segment.loop, prevStyle);
+ }
+ prev = pt;
+ prevStyle = style;
+ }
+ if (start < i - 1) {
+ addStyle(start, i - 1, segment.loop, prevStyle);
+ }
+ }
+ return result;
+}
+function readStyle(options) {
+ return {
+ backgroundColor: options.backgroundColor,
+ borderCapStyle: options.borderCapStyle,
+ borderDash: options.borderDash,
+ borderDashOffset: options.borderDashOffset,
+ borderJoinStyle: options.borderJoinStyle,
+ borderWidth: options.borderWidth,
+ borderColor: options.borderColor
+ };
+}
+function styleChanged(style, prevStyle) {
+ return prevStyle && JSON.stringify(style) !== JSON.stringify(prevStyle);
+}
+
+var helpers = /*#__PURE__*/Object.freeze({
+__proto__: null,
+easingEffects: effects,
+color: color,
+getHoverColor: getHoverColor,
+noop: noop,
+uid: uid,
+isNullOrUndef: isNullOrUndef,
+isArray: isArray,
+isObject: isObject,
+isFinite: isNumberFinite,
+finiteOrDefault: finiteOrDefault,
+valueOrDefault: valueOrDefault,
+toPercentage: toPercentage,
+toDimension: toDimension,
+callback: callback,
+each: each,
+_elementsEqual: _elementsEqual,
+clone: clone,
+_merger: _merger,
+merge: merge,
+mergeIf: mergeIf,
+_mergerIf: _mergerIf,
+_deprecated: _deprecated,
+resolveObjectKey: resolveObjectKey,
+_capitalize: _capitalize,
+defined: defined,
+isFunction: isFunction,
+setsEqual: setsEqual,
+_isClickEvent: _isClickEvent,
+toFontString: toFontString,
+_measureText: _measureText,
+_longestText: _longestText,
+_alignPixel: _alignPixel,
+clearCanvas: clearCanvas,
+drawPoint: drawPoint,
+_isPointInArea: _isPointInArea,
+clipArea: clipArea,
+unclipArea: unclipArea,
+_steppedLineTo: _steppedLineTo,
+_bezierCurveTo: _bezierCurveTo,
+renderText: renderText,
+addRoundedRectPath: addRoundedRectPath,
+_lookup: _lookup,
+_lookupByKey: _lookupByKey,
+_rlookupByKey: _rlookupByKey,
+_filterBetween: _filterBetween,
+listenArrayEvents: listenArrayEvents,
+unlistenArrayEvents: unlistenArrayEvents,
+_arrayUnique: _arrayUnique,
+_createResolver: _createResolver,
+_attachContext: _attachContext,
+_descriptors: _descriptors,
+splineCurve: splineCurve,
+splineCurveMonotone: splineCurveMonotone,
+_updateBezierControlPoints: _updateBezierControlPoints,
+_isDomSupported: _isDomSupported,
+_getParentNode: _getParentNode,
+getStyle: getStyle,
+getRelativePosition: getRelativePosition$1,
+getMaximumSize: getMaximumSize,
+retinaScale: retinaScale,
+supportsEventListenerOptions: supportsEventListenerOptions,
+readUsedSize: readUsedSize,
+fontString: fontString,
+requestAnimFrame: requestAnimFrame,
+throttled: throttled,
+debounce: debounce,
+_toLeftRightCenter: _toLeftRightCenter,
+_alignStartEnd: _alignStartEnd,
+_textX: _textX,
+_pointInLine: _pointInLine,
+_steppedInterpolation: _steppedInterpolation,
+_bezierInterpolation: _bezierInterpolation,
+formatNumber: formatNumber,
+toLineHeight: toLineHeight,
+_readValueToProps: _readValueToProps,
+toTRBL: toTRBL,
+toTRBLCorners: toTRBLCorners,
+toPadding: toPadding,
+toFont: toFont,
+resolve: resolve,
+_addGrace: _addGrace,
+createContext: createContext,
+PI: PI,
+TAU: TAU,
+PITAU: PITAU,
+INFINITY: INFINITY,
+RAD_PER_DEG: RAD_PER_DEG,
+HALF_PI: HALF_PI,
+QUARTER_PI: QUARTER_PI,
+TWO_THIRDS_PI: TWO_THIRDS_PI,
+log10: log10,
+sign: sign,
+niceNum: niceNum,
+_factorize: _factorize,
+isNumber: isNumber,
+almostEquals: almostEquals,
+almostWhole: almostWhole,
+_setMinAndMaxByKey: _setMinAndMaxByKey,
+toRadians: toRadians,
+toDegrees: toDegrees,
+_decimalPlaces: _decimalPlaces,
+getAngleFromPoint: getAngleFromPoint,
+distanceBetweenPoints: distanceBetweenPoints,
+_angleDiff: _angleDiff,
+_normalizeAngle: _normalizeAngle,
+_angleBetween: _angleBetween,
+_limitValue: _limitValue,
+_int16Range: _int16Range,
+_isBetween: _isBetween,
+getRtlAdapter: getRtlAdapter,
+overrideTextDirection: overrideTextDirection,
+restoreTextDirection: restoreTextDirection,
+_boundSegment: _boundSegment,
+_boundSegments: _boundSegments,
+_computeSegments: _computeSegments
+});
+
+class BasePlatform {
+ acquireContext(canvas, aspectRatio) {}
+ releaseContext(context) {
+ return false;
+ }
+ addEventListener(chart, type, listener) {}
+ removeEventListener(chart, type, listener) {}
+ getDevicePixelRatio() {
+ return 1;
+ }
+ getMaximumSize(element, width, height, aspectRatio) {
+ width = Math.max(0, width || element.width);
+ height = height || element.height;
+ return {
+ width,
+ height: Math.max(0, aspectRatio ? Math.floor(width / aspectRatio) : height)
+ };
+ }
+ isAttached(canvas) {
+ return true;
+ }
+ updateConfig(config) {
+ }
+}
+
+class BasicPlatform extends BasePlatform {
+ acquireContext(item) {
+ return item && item.getContext && item.getContext('2d') || null;
+ }
+ updateConfig(config) {
+ config.options.animation = false;
+ }
+}
+
+const EXPANDO_KEY = '$chartjs';
+const EVENT_TYPES = {
+ touchstart: 'mousedown',
+ touchmove: 'mousemove',
+ touchend: 'mouseup',
+ pointerenter: 'mouseenter',
+ pointerdown: 'mousedown',
+ pointermove: 'mousemove',
+ pointerup: 'mouseup',
+ pointerleave: 'mouseout',
+ pointerout: 'mouseout'
+};
+const isNullOrEmpty = value => value === null || value === '';
+function initCanvas(canvas, aspectRatio) {
+ const style = canvas.style;
+ const renderHeight = canvas.getAttribute('height');
+ const renderWidth = canvas.getAttribute('width');
+ canvas[EXPANDO_KEY] = {
+ initial: {
+ height: renderHeight,
+ width: renderWidth,
+ style: {
+ display: style.display,
+ height: style.height,
+ width: style.width
+ }
+ }
+ };
+ style.display = style.display || 'block';
+ style.boxSizing = style.boxSizing || 'border-box';
+ if (isNullOrEmpty(renderWidth)) {
+ const displayWidth = readUsedSize(canvas, 'width');
+ if (displayWidth !== undefined) {
+ canvas.width = displayWidth;
+ }
+ }
+ if (isNullOrEmpty(renderHeight)) {
+ if (canvas.style.height === '') {
+ canvas.height = canvas.width / (aspectRatio || 2);
+ } else {
+ const displayHeight = readUsedSize(canvas, 'height');
+ if (displayHeight !== undefined) {
+ canvas.height = displayHeight;
+ }
+ }
+ }
+ return canvas;
+}
+const eventListenerOptions = supportsEventListenerOptions ? {passive: true} : false;
+function addListener(node, type, listener) {
+ node.addEventListener(type, listener, eventListenerOptions);
+}
+function removeListener(chart, type, listener) {
+ chart.canvas.removeEventListener(type, listener, eventListenerOptions);
+}
+function fromNativeEvent(event, chart) {
+ const type = EVENT_TYPES[event.type] || event.type;
+ const {x, y} = getRelativePosition$1(event, chart);
+ return {
+ type,
+ chart,
+ native: event,
+ x: x !== undefined ? x : null,
+ y: y !== undefined ? y : null,
+ };
+}
+function nodeListContains(nodeList, canvas) {
+ for (const node of nodeList) {
+ if (node === canvas || node.contains(canvas)) {
+ return true;
+ }
+ }
+}
+function createAttachObserver(chart, type, listener) {
+ const canvas = chart.canvas;
+ const observer = new MutationObserver(entries => {
+ let trigger = false;
+ for (const entry of entries) {
+ trigger = trigger || nodeListContains(entry.addedNodes, canvas);
+ trigger = trigger && !nodeListContains(entry.removedNodes, canvas);
+ }
+ if (trigger) {
+ listener();
+ }
+ });
+ observer.observe(document, {childList: true, subtree: true});
+ return observer;
+}
+function createDetachObserver(chart, type, listener) {
+ const canvas = chart.canvas;
+ const observer = new MutationObserver(entries => {
+ let trigger = false;
+ for (const entry of entries) {
+ trigger = trigger || nodeListContains(entry.removedNodes, canvas);
+ trigger = trigger && !nodeListContains(entry.addedNodes, canvas);
+ }
+ if (trigger) {
+ listener();
+ }
+ });
+ observer.observe(document, {childList: true, subtree: true});
+ return observer;
+}
+const drpListeningCharts = new Map();
+let oldDevicePixelRatio = 0;
+function onWindowResize() {
+ const dpr = window.devicePixelRatio;
+ if (dpr === oldDevicePixelRatio) {
+ return;
+ }
+ oldDevicePixelRatio = dpr;
+ drpListeningCharts.forEach((resize, chart) => {
+ if (chart.currentDevicePixelRatio !== dpr) {
+ resize();
+ }
+ });
+}
+function listenDevicePixelRatioChanges(chart, resize) {
+ if (!drpListeningCharts.size) {
+ window.addEventListener('resize', onWindowResize);
+ }
+ drpListeningCharts.set(chart, resize);
+}
+function unlistenDevicePixelRatioChanges(chart) {
+ drpListeningCharts.delete(chart);
+ if (!drpListeningCharts.size) {
+ window.removeEventListener('resize', onWindowResize);
+ }
+}
+function createResizeObserver(chart, type, listener) {
+ const canvas = chart.canvas;
+ const container = canvas && _getParentNode(canvas);
+ if (!container) {
+ return;
+ }
+ const resize = throttled((width, height) => {
+ const w = container.clientWidth;
+ listener(width, height);
+ if (w < container.clientWidth) {
+ listener();
+ }
+ }, window);
+ const observer = new ResizeObserver(entries => {
+ const entry = entries[0];
+ const width = entry.contentRect.width;
+ const height = entry.contentRect.height;
+ if (width === 0 && height === 0) {
+ return;
+ }
+ resize(width, height);
+ });
+ observer.observe(container);
+ listenDevicePixelRatioChanges(chart, resize);
+ return observer;
+}
+function releaseObserver(chart, type, observer) {
+ if (observer) {
+ observer.disconnect();
+ }
+ if (type === 'resize') {
+ unlistenDevicePixelRatioChanges(chart);
+ }
+}
+function createProxyAndListen(chart, type, listener) {
+ const canvas = chart.canvas;
+ const proxy = throttled((event) => {
+ if (chart.ctx !== null) {
+ listener(fromNativeEvent(event, chart));
+ }
+ }, chart, (args) => {
+ const event = args[0];
+ return [event, event.offsetX, event.offsetY];
+ });
+ addListener(canvas, type, proxy);
+ return proxy;
+}
+class DomPlatform extends BasePlatform {
+ acquireContext(canvas, aspectRatio) {
+ const context = canvas && canvas.getContext && canvas.getContext('2d');
+ if (context && context.canvas === canvas) {
+ initCanvas(canvas, aspectRatio);
+ return context;
+ }
+ return null;
+ }
+ releaseContext(context) {
+ const canvas = context.canvas;
+ if (!canvas[EXPANDO_KEY]) {
+ return false;
+ }
+ const initial = canvas[EXPANDO_KEY].initial;
+ ['height', 'width'].forEach((prop) => {
+ const value = initial[prop];
+ if (isNullOrUndef(value)) {
+ canvas.removeAttribute(prop);
+ } else {
+ canvas.setAttribute(prop, value);
+ }
+ });
+ const style = initial.style || {};
+ Object.keys(style).forEach((key) => {
+ canvas.style[key] = style[key];
+ });
+ canvas.width = canvas.width;
+ delete canvas[EXPANDO_KEY];
+ return true;
+ }
+ addEventListener(chart, type, listener) {
+ this.removeEventListener(chart, type);
+ const proxies = chart.$proxies || (chart.$proxies = {});
+ const handlers = {
+ attach: createAttachObserver,
+ detach: createDetachObserver,
+ resize: createResizeObserver
+ };
+ const handler = handlers[type] || createProxyAndListen;
+ proxies[type] = handler(chart, type, listener);
+ }
+ removeEventListener(chart, type) {
+ const proxies = chart.$proxies || (chart.$proxies = {});
+ const proxy = proxies[type];
+ if (!proxy) {
+ return;
+ }
+ const handlers = {
+ attach: releaseObserver,
+ detach: releaseObserver,
+ resize: releaseObserver
+ };
+ const handler = handlers[type] || removeListener;
+ handler(chart, type, proxy);
+ proxies[type] = undefined;
+ }
+ getDevicePixelRatio() {
+ return window.devicePixelRatio;
+ }
+ getMaximumSize(canvas, width, height, aspectRatio) {
+ return getMaximumSize(canvas, width, height, aspectRatio);
+ }
+ isAttached(canvas) {
+ const container = _getParentNode(canvas);
+ return !!(container && container.isConnected);
+ }
+}
+
+function _detectPlatform(canvas) {
+ if (!_isDomSupported() || (typeof OffscreenCanvas !== 'undefined' && canvas instanceof OffscreenCanvas)) {
+ return BasicPlatform;
+ }
+ return DomPlatform;
+}
+
+var platforms = /*#__PURE__*/Object.freeze({
+__proto__: null,
+_detectPlatform: _detectPlatform,
+BasePlatform: BasePlatform,
+BasicPlatform: BasicPlatform,
+DomPlatform: DomPlatform
+});
+
+const transparent = 'transparent';
+const interpolators = {
+ boolean(from, to, factor) {
+ return factor > 0.5 ? to : from;
+ },
+ color(from, to, factor) {
+ const c0 = color(from || transparent);
+ const c1 = c0.valid && color(to || transparent);
+ return c1 && c1.valid
+ ? c1.mix(c0, factor).hexString()
+ : to;
+ },
+ number(from, to, factor) {
+ return from + (to - from) * factor;
+ }
+};
+class Animation {
+ constructor(cfg, target, prop, to) {
+ const currentValue = target[prop];
+ to = resolve([cfg.to, to, currentValue, cfg.from]);
+ const from = resolve([cfg.from, currentValue, to]);
+ this._active = true;
+ this._fn = cfg.fn || interpolators[cfg.type || typeof from];
+ this._easing = effects[cfg.easing] || effects.linear;
+ this._start = Math.floor(Date.now() + (cfg.delay || 0));
+ this._duration = this._total = Math.floor(cfg.duration);
+ this._loop = !!cfg.loop;
+ this._target = target;
+ this._prop = prop;
+ this._from = from;
+ this._to = to;
+ this._promises = undefined;
+ }
+ active() {
+ return this._active;
+ }
+ update(cfg, to, date) {
+ if (this._active) {
+ this._notify(false);
+ const currentValue = this._target[this._prop];
+ const elapsed = date - this._start;
+ const remain = this._duration - elapsed;
+ this._start = date;
+ this._duration = Math.floor(Math.max(remain, cfg.duration));
+ this._total += elapsed;
+ this._loop = !!cfg.loop;
+ this._to = resolve([cfg.to, to, currentValue, cfg.from]);
+ this._from = resolve([cfg.from, currentValue, to]);
+ }
+ }
+ cancel() {
+ if (this._active) {
+ this.tick(Date.now());
+ this._active = false;
+ this._notify(false);
+ }
+ }
+ tick(date) {
+ const elapsed = date - this._start;
+ const duration = this._duration;
+ const prop = this._prop;
+ const from = this._from;
+ const loop = this._loop;
+ const to = this._to;
+ let factor;
+ this._active = from !== to && (loop || (elapsed < duration));
+ if (!this._active) {
+ this._target[prop] = to;
+ this._notify(true);
+ return;
+ }
+ if (elapsed < 0) {
+ this._target[prop] = from;
+ return;
+ }
+ factor = (elapsed / duration) % 2;
+ factor = loop && factor > 1 ? 2 - factor : factor;
+ factor = this._easing(Math.min(1, Math.max(0, factor)));
+ this._target[prop] = this._fn(from, to, factor);
+ }
+ wait() {
+ const promises = this._promises || (this._promises = []);
+ return new Promise((res, rej) => {
+ promises.push({res, rej});
+ });
+ }
+ _notify(resolved) {
+ const method = resolved ? 'res' : 'rej';
+ const promises = this._promises || [];
+ for (let i = 0; i < promises.length; i++) {
+ promises[i][method]();
+ }
+ }
+}
+
+const numbers = ['x', 'y', 'borderWidth', 'radius', 'tension'];
+const colors = ['color', 'borderColor', 'backgroundColor'];
+defaults.set('animation', {
+ delay: undefined,
+ duration: 1000,
+ easing: 'easeOutQuart',
+ fn: undefined,
+ from: undefined,
+ loop: undefined,
+ to: undefined,
+ type: undefined,
+});
+const animationOptions = Object.keys(defaults.animation);
+defaults.describe('animation', {
+ _fallback: false,
+ _indexable: false,
+ _scriptable: (name) => name !== 'onProgress' && name !== 'onComplete' && name !== 'fn',
+});
+defaults.set('animations', {
+ colors: {
+ type: 'color',
+ properties: colors
+ },
+ numbers: {
+ type: 'number',
+ properties: numbers
+ },
+});
+defaults.describe('animations', {
+ _fallback: 'animation',
+});
+defaults.set('transitions', {
+ active: {
+ animation: {
+ duration: 400
+ }
+ },
+ resize: {
+ animation: {
+ duration: 0
+ }
+ },
+ show: {
+ animations: {
+ colors: {
+ from: 'transparent'
+ },
+ visible: {
+ type: 'boolean',
+ duration: 0
+ },
+ }
+ },
+ hide: {
+ animations: {
+ colors: {
+ to: 'transparent'
+ },
+ visible: {
+ type: 'boolean',
+ easing: 'linear',
+ fn: v => v | 0
+ },
+ }
+ }
+});
+class Animations {
+ constructor(chart, config) {
+ this._chart = chart;
+ this._properties = new Map();
+ this.configure(config);
+ }
+ configure(config) {
+ if (!isObject(config)) {
+ return;
+ }
+ const animatedProps = this._properties;
+ Object.getOwnPropertyNames(config).forEach(key => {
+ const cfg = config[key];
+ if (!isObject(cfg)) {
+ return;
+ }
+ const resolved = {};
+ for (const option of animationOptions) {
+ resolved[option] = cfg[option];
+ }
+ (isArray(cfg.properties) && cfg.properties || [key]).forEach((prop) => {
+ if (prop === key || !animatedProps.has(prop)) {
+ animatedProps.set(prop, resolved);
+ }
+ });
+ });
+ }
+ _animateOptions(target, values) {
+ const newOptions = values.options;
+ const options = resolveTargetOptions(target, newOptions);
+ if (!options) {
+ return [];
+ }
+ const animations = this._createAnimations(options, newOptions);
+ if (newOptions.$shared) {
+ awaitAll(target.options.$animations, newOptions).then(() => {
+ target.options = newOptions;
+ }, () => {
+ });
+ }
+ return animations;
+ }
+ _createAnimations(target, values) {
+ const animatedProps = this._properties;
+ const animations = [];
+ const running = target.$animations || (target.$animations = {});
+ const props = Object.keys(values);
+ const date = Date.now();
+ let i;
+ for (i = props.length - 1; i >= 0; --i) {
+ const prop = props[i];
+ if (prop.charAt(0) === '$') {
+ continue;
+ }
+ if (prop === 'options') {
+ animations.push(...this._animateOptions(target, values));
+ continue;
+ }
+ const value = values[prop];
+ let animation = running[prop];
+ const cfg = animatedProps.get(prop);
+ if (animation) {
+ if (cfg && animation.active()) {
+ animation.update(cfg, value, date);
+ continue;
+ } else {
+ animation.cancel();
+ }
+ }
+ if (!cfg || !cfg.duration) {
+ target[prop] = value;
+ continue;
+ }
+ running[prop] = animation = new Animation(cfg, target, prop, value);
+ animations.push(animation);
+ }
+ return animations;
+ }
+ update(target, values) {
+ if (this._properties.size === 0) {
+ Object.assign(target, values);
+ return;
+ }
+ const animations = this._createAnimations(target, values);
+ if (animations.length) {
+ animator.add(this._chart, animations);
+ return true;
+ }
+ }
+}
+function awaitAll(animations, properties) {
+ const running = [];
+ const keys = Object.keys(properties);
+ for (let i = 0; i < keys.length; i++) {
+ const anim = animations[keys[i]];
+ if (anim && anim.active()) {
+ running.push(anim.wait());
+ }
+ }
+ return Promise.all(running);
+}
+function resolveTargetOptions(target, newOptions) {
+ if (!newOptions) {
+ return;
+ }
+ let options = target.options;
+ if (!options) {
+ target.options = newOptions;
+ return;
+ }
+ if (options.$shared) {
+ target.options = options = Object.assign({}, options, {$shared: false, $animations: {}});
+ }
+ return options;
+}
+
+function scaleClip(scale, allowedOverflow) {
+ const opts = scale && scale.options || {};
+ const reverse = opts.reverse;
+ const min = opts.min === undefined ? allowedOverflow : 0;
+ const max = opts.max === undefined ? allowedOverflow : 0;
+ return {
+ start: reverse ? max : min,
+ end: reverse ? min : max
+ };
+}
+function defaultClip(xScale, yScale, allowedOverflow) {
+ if (allowedOverflow === false) {
+ return false;
+ }
+ const x = scaleClip(xScale, allowedOverflow);
+ const y = scaleClip(yScale, allowedOverflow);
+ return {
+ top: y.end,
+ right: x.end,
+ bottom: y.start,
+ left: x.start
+ };
+}
+function toClip(value) {
+ let t, r, b, l;
+ if (isObject(value)) {
+ t = value.top;
+ r = value.right;
+ b = value.bottom;
+ l = value.left;
+ } else {
+ t = r = b = l = value;
+ }
+ return {
+ top: t,
+ right: r,
+ bottom: b,
+ left: l,
+ disabled: value === false
+ };
+}
+function getSortedDatasetIndices(chart, filterVisible) {
+ const keys = [];
+ const metasets = chart._getSortedDatasetMetas(filterVisible);
+ let i, ilen;
+ for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+ keys.push(metasets[i].index);
+ }
+ return keys;
+}
+function applyStack(stack, value, dsIndex, options = {}) {
+ const keys = stack.keys;
+ const singleMode = options.mode === 'single';
+ let i, ilen, datasetIndex, otherValue;
+ if (value === null) {
+ return;
+ }
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
+ datasetIndex = +keys[i];
+ if (datasetIndex === dsIndex) {
+ if (options.all) {
+ continue;
+ }
+ break;
+ }
+ otherValue = stack.values[datasetIndex];
+ if (isNumberFinite(otherValue) && (singleMode || (value === 0 || sign(value) === sign(otherValue)))) {
+ value += otherValue;
+ }
+ }
+ return value;
+}
+function convertObjectDataToArray(data) {
+ const keys = Object.keys(data);
+ const adata = new Array(keys.length);
+ let i, ilen, key;
+ for (i = 0, ilen = keys.length; i < ilen; ++i) {
+ key = keys[i];
+ adata[i] = {
+ x: key,
+ y: data[key]
+ };
+ }
+ return adata;
+}
+function isStacked(scale, meta) {
+ const stacked = scale && scale.options.stacked;
+ return stacked || (stacked === undefined && meta.stack !== undefined);
+}
+function getStackKey(indexScale, valueScale, meta) {
+ return `${indexScale.id}.${valueScale.id}.${meta.stack || meta.type}`;
+}
+function getUserBounds(scale) {
+ const {min, max, minDefined, maxDefined} = scale.getUserBounds();
+ return {
+ min: minDefined ? min : Number.NEGATIVE_INFINITY,
+ max: maxDefined ? max : Number.POSITIVE_INFINITY
+ };
+}
+function getOrCreateStack(stacks, stackKey, indexValue) {
+ const subStack = stacks[stackKey] || (stacks[stackKey] = {});
+ return subStack[indexValue] || (subStack[indexValue] = {});
+}
+function getLastIndexInStack(stack, vScale, positive, type) {
+ for (const meta of vScale.getMatchingVisibleMetas(type).reverse()) {
+ const value = stack[meta.index];
+ if ((positive && value > 0) || (!positive && value < 0)) {
+ return meta.index;
+ }
+ }
+ return null;
+}
+function updateStacks(controller, parsed) {
+ const {chart, _cachedMeta: meta} = controller;
+ const stacks = chart._stacks || (chart._stacks = {});
+ const {iScale, vScale, index: datasetIndex} = meta;
+ const iAxis = iScale.axis;
+ const vAxis = vScale.axis;
+ const key = getStackKey(iScale, vScale, meta);
+ const ilen = parsed.length;
+ let stack;
+ for (let i = 0; i < ilen; ++i) {
+ const item = parsed[i];
+ const {[iAxis]: index, [vAxis]: value} = item;
+ const itemStacks = item._stacks || (item._stacks = {});
+ stack = itemStacks[vAxis] = getOrCreateStack(stacks, key, index);
+ stack[datasetIndex] = value;
+ stack._top = getLastIndexInStack(stack, vScale, true, meta.type);
+ stack._bottom = getLastIndexInStack(stack, vScale, false, meta.type);
+ }
+}
+function getFirstScaleId(chart, axis) {
+ const scales = chart.scales;
+ return Object.keys(scales).filter(key => scales[key].axis === axis).shift();
+}
+function createDatasetContext(parent, index) {
+ return createContext(parent,
+ {
+ active: false,
+ dataset: undefined,
+ datasetIndex: index,
+ index,
+ mode: 'default',
+ type: 'dataset'
+ }
+ );
+}
+function createDataContext(parent, index, element) {
+ return createContext(parent, {
+ active: false,
+ dataIndex: index,
+ parsed: undefined,
+ raw: undefined,
+ element,
+ index,
+ mode: 'default',
+ type: 'data'
+ });
+}
+function clearStacks(meta, items) {
+ const datasetIndex = meta.controller.index;
+ const axis = meta.vScale && meta.vScale.axis;
+ if (!axis) {
+ return;
+ }
+ items = items || meta._parsed;
+ for (const parsed of items) {
+ const stacks = parsed._stacks;
+ if (!stacks || stacks[axis] === undefined || stacks[axis][datasetIndex] === undefined) {
+ return;
+ }
+ delete stacks[axis][datasetIndex];
+ }
+}
+const isDirectUpdateMode = (mode) => mode === 'reset' || mode === 'none';
+const cloneIfNotShared = (cached, shared) => shared ? cached : Object.assign({}, cached);
+const createStack = (canStack, meta, chart) => canStack && !meta.hidden && meta._stacked
+ && {keys: getSortedDatasetIndices(chart, true), values: null};
+class DatasetController {
+ constructor(chart, datasetIndex) {
+ this.chart = chart;
+ this._ctx = chart.ctx;
+ this.index = datasetIndex;
+ this._cachedDataOpts = {};
+ this._cachedMeta = this.getMeta();
+ this._type = this._cachedMeta.type;
+ this.options = undefined;
+ this._parsing = false;
+ this._data = undefined;
+ this._objectData = undefined;
+ this._sharedOptions = undefined;
+ this._drawStart = undefined;
+ this._drawCount = undefined;
+ this.enableOptionSharing = false;
+ this.$context = undefined;
+ this._syncList = [];
+ this.initialize();
+ }
+ initialize() {
+ const meta = this._cachedMeta;
+ this.configure();
+ this.linkScales();
+ meta._stacked = isStacked(meta.vScale, meta);
+ this.addElements();
+ }
+ updateIndex(datasetIndex) {
+ if (this.index !== datasetIndex) {
+ clearStacks(this._cachedMeta);
+ }
+ this.index = datasetIndex;
+ }
+ linkScales() {
+ const chart = this.chart;
+ const meta = this._cachedMeta;
+ const dataset = this.getDataset();
+ const chooseId = (axis, x, y, r) => axis === 'x' ? x : axis === 'r' ? r : y;
+ const xid = meta.xAxisID = valueOrDefault(dataset.xAxisID, getFirstScaleId(chart, 'x'));
+ const yid = meta.yAxisID = valueOrDefault(dataset.yAxisID, getFirstScaleId(chart, 'y'));
+ const rid = meta.rAxisID = valueOrDefault(dataset.rAxisID, getFirstScaleId(chart, 'r'));
+ const indexAxis = meta.indexAxis;
+ const iid = meta.iAxisID = chooseId(indexAxis, xid, yid, rid);
+ const vid = meta.vAxisID = chooseId(indexAxis, yid, xid, rid);
+ meta.xScale = this.getScaleForId(xid);
+ meta.yScale = this.getScaleForId(yid);
+ meta.rScale = this.getScaleForId(rid);
+ meta.iScale = this.getScaleForId(iid);
+ meta.vScale = this.getScaleForId(vid);
+ }
+ getDataset() {
+ return this.chart.data.datasets[this.index];
+ }
+ getMeta() {
+ return this.chart.getDatasetMeta(this.index);
+ }
+ getScaleForId(scaleID) {
+ return this.chart.scales[scaleID];
+ }
+ _getOtherScale(scale) {
+ const meta = this._cachedMeta;
+ return scale === meta.iScale
+ ? meta.vScale
+ : meta.iScale;
+ }
+ reset() {
+ this._update('reset');
+ }
+ _destroy() {
+ const meta = this._cachedMeta;
+ if (this._data) {
+ unlistenArrayEvents(this._data, this);
+ }
+ if (meta._stacked) {
+ clearStacks(meta);
+ }
+ }
+ _dataCheck() {
+ const dataset = this.getDataset();
+ const data = dataset.data || (dataset.data = []);
+ const _data = this._data;
+ if (isObject(data)) {
+ this._data = convertObjectDataToArray(data);
+ } else if (_data !== data) {
+ if (_data) {
+ unlistenArrayEvents(_data, this);
+ const meta = this._cachedMeta;
+ clearStacks(meta);
+ meta._parsed = [];
+ }
+ if (data && Object.isExtensible(data)) {
+ listenArrayEvents(data, this);
+ }
+ this._syncList = [];
+ this._data = data;
+ }
+ }
+ addElements() {
+ const meta = this._cachedMeta;
+ this._dataCheck();
+ if (this.datasetElementType) {
+ meta.dataset = new this.datasetElementType();
+ }
+ }
+ buildOrUpdateElements(resetNewElements) {
+ const meta = this._cachedMeta;
+ const dataset = this.getDataset();
+ let stackChanged = false;
+ this._dataCheck();
+ const oldStacked = meta._stacked;
+ meta._stacked = isStacked(meta.vScale, meta);
+ if (meta.stack !== dataset.stack) {
+ stackChanged = true;
+ clearStacks(meta);
+ meta.stack = dataset.stack;
+ }
+ this._resyncElements(resetNewElements);
+ if (stackChanged || oldStacked !== meta._stacked) {
+ updateStacks(this, meta._parsed);
+ }
+ }
+ configure() {
+ const config = this.chart.config;
+ const scopeKeys = config.datasetScopeKeys(this._type);
+ const scopes = config.getOptionScopes(this.getDataset(), scopeKeys, true);
+ this.options = config.createResolver(scopes, this.getContext());
+ this._parsing = this.options.parsing;
+ this._cachedDataOpts = {};
+ }
+ parse(start, count) {
+ const {_cachedMeta: meta, _data: data} = this;
+ const {iScale, _stacked} = meta;
+ const iAxis = iScale.axis;
+ let sorted = start === 0 && count === data.length ? true : meta._sorted;
+ let prev = start > 0 && meta._parsed[start - 1];
+ let i, cur, parsed;
+ if (this._parsing === false) {
+ meta._parsed = data;
+ meta._sorted = true;
+ parsed = data;
+ } else {
+ if (isArray(data[start])) {
+ parsed = this.parseArrayData(meta, data, start, count);
+ } else if (isObject(data[start])) {
+ parsed = this.parseObjectData(meta, data, start, count);
+ } else {
+ parsed = this.parsePrimitiveData(meta, data, start, count);
+ }
+ const isNotInOrderComparedToPrev = () => cur[iAxis] === null || (prev && cur[iAxis] < prev[iAxis]);
+ for (i = 0; i < count; ++i) {
+ meta._parsed[i + start] = cur = parsed[i];
+ if (sorted) {
+ if (isNotInOrderComparedToPrev()) {
+ sorted = false;
+ }
+ prev = cur;
+ }
+ }
+ meta._sorted = sorted;
+ }
+ if (_stacked) {
+ updateStacks(this, parsed);
+ }
+ }
+ parsePrimitiveData(meta, data, start, count) {
+ const {iScale, vScale} = meta;
+ const iAxis = iScale.axis;
+ const vAxis = vScale.axis;
+ const labels = iScale.getLabels();
+ const singleScale = iScale === vScale;
+ const parsed = new Array(count);
+ let i, ilen, index;
+ for (i = 0, ilen = count; i < ilen; ++i) {
+ index = i + start;
+ parsed[i] = {
+ [iAxis]: singleScale || iScale.parse(labels[index], index),
+ [vAxis]: vScale.parse(data[index], index)
+ };
+ }
+ return parsed;
+ }
+ parseArrayData(meta, data, start, count) {
+ const {xScale, yScale} = meta;
+ const parsed = new Array(count);
+ let i, ilen, index, item;
+ for (i = 0, ilen = count; i < ilen; ++i) {
+ index = i + start;
+ item = data[index];
+ parsed[i] = {
+ x: xScale.parse(item[0], index),
+ y: yScale.parse(item[1], index)
+ };
+ }
+ return parsed;
+ }
+ parseObjectData(meta, data, start, count) {
+ const {xScale, yScale} = meta;
+ const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
+ const parsed = new Array(count);
+ let i, ilen, index, item;
+ for (i = 0, ilen = count; i < ilen; ++i) {
+ index = i + start;
+ item = data[index];
+ parsed[i] = {
+ x: xScale.parse(resolveObjectKey(item, xAxisKey), index),
+ y: yScale.parse(resolveObjectKey(item, yAxisKey), index)
+ };
+ }
+ return parsed;
+ }
+ getParsed(index) {
+ return this._cachedMeta._parsed[index];
+ }
+ getDataElement(index) {
+ return this._cachedMeta.data[index];
+ }
+ applyStack(scale, parsed, mode) {
+ const chart = this.chart;
+ const meta = this._cachedMeta;
+ const value = parsed[scale.axis];
+ const stack = {
+ keys: getSortedDatasetIndices(chart, true),
+ values: parsed._stacks[scale.axis]
+ };
+ return applyStack(stack, value, meta.index, {mode});
+ }
+ updateRangeFromParsed(range, scale, parsed, stack) {
+ const parsedValue = parsed[scale.axis];
+ let value = parsedValue === null ? NaN : parsedValue;
+ const values = stack && parsed._stacks[scale.axis];
+ if (stack && values) {
+ stack.values = values;
+ value = applyStack(stack, parsedValue, this._cachedMeta.index);
+ }
+ range.min = Math.min(range.min, value);
+ range.max = Math.max(range.max, value);
+ }
+ getMinMax(scale, canStack) {
+ const meta = this._cachedMeta;
+ const _parsed = meta._parsed;
+ const sorted = meta._sorted && scale === meta.iScale;
+ const ilen = _parsed.length;
+ const otherScale = this._getOtherScale(scale);
+ const stack = createStack(canStack, meta, this.chart);
+ const range = {min: Number.POSITIVE_INFINITY, max: Number.NEGATIVE_INFINITY};
+ const {min: otherMin, max: otherMax} = getUserBounds(otherScale);
+ let i, parsed;
+ function _skip() {
+ parsed = _parsed[i];
+ const otherValue = parsed[otherScale.axis];
+ return !isNumberFinite(parsed[scale.axis]) || otherMin > otherValue || otherMax < otherValue;
+ }
+ for (i = 0; i < ilen; ++i) {
+ if (_skip()) {
+ continue;
+ }
+ this.updateRangeFromParsed(range, scale, parsed, stack);
+ if (sorted) {
+ break;
+ }
+ }
+ if (sorted) {
+ for (i = ilen - 1; i >= 0; --i) {
+ if (_skip()) {
+ continue;
+ }
+ this.updateRangeFromParsed(range, scale, parsed, stack);
+ break;
+ }
+ }
+ return range;
+ }
+ getAllParsedValues(scale) {
+ const parsed = this._cachedMeta._parsed;
+ const values = [];
+ let i, ilen, value;
+ for (i = 0, ilen = parsed.length; i < ilen; ++i) {
+ value = parsed[i][scale.axis];
+ if (isNumberFinite(value)) {
+ values.push(value);
+ }
+ }
+ return values;
+ }
+ getMaxOverflow() {
+ return false;
+ }
+ getLabelAndValue(index) {
+ const meta = this._cachedMeta;
+ const iScale = meta.iScale;
+ const vScale = meta.vScale;
+ const parsed = this.getParsed(index);
+ return {
+ label: iScale ? '' + iScale.getLabelForValue(parsed[iScale.axis]) : '',
+ value: vScale ? '' + vScale.getLabelForValue(parsed[vScale.axis]) : ''
+ };
+ }
+ _update(mode) {
+ const meta = this._cachedMeta;
+ this.update(mode || 'default');
+ meta._clip = toClip(valueOrDefault(this.options.clip, defaultClip(meta.xScale, meta.yScale, this.getMaxOverflow())));
+ }
+ update(mode) {}
+ draw() {
+ const ctx = this._ctx;
+ const chart = this.chart;
+ const meta = this._cachedMeta;
+ const elements = meta.data || [];
+ const area = chart.chartArea;
+ const active = [];
+ const start = this._drawStart || 0;
+ const count = this._drawCount || (elements.length - start);
+ const drawActiveElementsOnTop = this.options.drawActiveElementsOnTop;
+ let i;
+ if (meta.dataset) {
+ meta.dataset.draw(ctx, area, start, count);
+ }
+ for (i = start; i < start + count; ++i) {
+ const element = elements[i];
+ if (element.hidden) {
+ continue;
+ }
+ if (element.active && drawActiveElementsOnTop) {
+ active.push(element);
+ } else {
+ element.draw(ctx, area);
+ }
+ }
+ for (i = 0; i < active.length; ++i) {
+ active[i].draw(ctx, area);
+ }
+ }
+ getStyle(index, active) {
+ const mode = active ? 'active' : 'default';
+ return index === undefined && this._cachedMeta.dataset
+ ? this.resolveDatasetElementOptions(mode)
+ : this.resolveDataElementOptions(index || 0, mode);
+ }
+ getContext(index, active, mode) {
+ const dataset = this.getDataset();
+ let context;
+ if (index >= 0 && index < this._cachedMeta.data.length) {
+ const element = this._cachedMeta.data[index];
+ context = element.$context ||
+ (element.$context = createDataContext(this.getContext(), index, element));
+ context.parsed = this.getParsed(index);
+ context.raw = dataset.data[index];
+ context.index = context.dataIndex = index;
+ } else {
+ context = this.$context ||
+ (this.$context = createDatasetContext(this.chart.getContext(), this.index));
+ context.dataset = dataset;
+ context.index = context.datasetIndex = this.index;
+ }
+ context.active = !!active;
+ context.mode = mode;
+ return context;
+ }
+ resolveDatasetElementOptions(mode) {
+ return this._resolveElementOptions(this.datasetElementType.id, mode);
+ }
+ resolveDataElementOptions(index, mode) {
+ return this._resolveElementOptions(this.dataElementType.id, mode, index);
+ }
+ _resolveElementOptions(elementType, mode = 'default', index) {
+ const active = mode === 'active';
+ const cache = this._cachedDataOpts;
+ const cacheKey = elementType + '-' + mode;
+ const cached = cache[cacheKey];
+ const sharing = this.enableOptionSharing && defined(index);
+ if (cached) {
+ return cloneIfNotShared(cached, sharing);
+ }
+ const config = this.chart.config;
+ const scopeKeys = config.datasetElementScopeKeys(this._type, elementType);
+ const prefixes = active ? [`${elementType}Hover`, 'hover', elementType, ''] : [elementType, ''];
+ const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
+ const names = Object.keys(defaults.elements[elementType]);
+ const context = () => this.getContext(index, active);
+ const values = config.resolveNamedOptions(scopes, names, context, prefixes);
+ if (values.$shared) {
+ values.$shared = sharing;
+ cache[cacheKey] = Object.freeze(cloneIfNotShared(values, sharing));
+ }
+ return values;
+ }
+ _resolveAnimations(index, transition, active) {
+ const chart = this.chart;
+ const cache = this._cachedDataOpts;
+ const cacheKey = `animation-${transition}`;
+ const cached = cache[cacheKey];
+ if (cached) {
+ return cached;
+ }
+ let options;
+ if (chart.options.animation !== false) {
+ const config = this.chart.config;
+ const scopeKeys = config.datasetAnimationScopeKeys(this._type, transition);
+ const scopes = config.getOptionScopes(this.getDataset(), scopeKeys);
+ options = config.createResolver(scopes, this.getContext(index, active, transition));
+ }
+ const animations = new Animations(chart, options && options.animations);
+ if (options && options._cacheable) {
+ cache[cacheKey] = Object.freeze(animations);
+ }
+ return animations;
+ }
+ getSharedOptions(options) {
+ if (!options.$shared) {
+ return;
+ }
+ return this._sharedOptions || (this._sharedOptions = Object.assign({}, options));
+ }
+ includeOptions(mode, sharedOptions) {
+ return !sharedOptions || isDirectUpdateMode(mode) || this.chart._animationsDisabled;
+ }
+ updateElement(element, index, properties, mode) {
+ if (isDirectUpdateMode(mode)) {
+ Object.assign(element, properties);
+ } else {
+ this._resolveAnimations(index, mode).update(element, properties);
+ }
+ }
+ updateSharedOptions(sharedOptions, mode, newOptions) {
+ if (sharedOptions && !isDirectUpdateMode(mode)) {
+ this._resolveAnimations(undefined, mode).update(sharedOptions, newOptions);
+ }
+ }
+ _setStyle(element, index, mode, active) {
+ element.active = active;
+ const options = this.getStyle(index, active);
+ this._resolveAnimations(index, mode, active).update(element, {
+ options: (!active && this.getSharedOptions(options)) || options
+ });
+ }
+ removeHoverStyle(element, datasetIndex, index) {
+ this._setStyle(element, index, 'active', false);
+ }
+ setHoverStyle(element, datasetIndex, index) {
+ this._setStyle(element, index, 'active', true);
+ }
+ _removeDatasetHoverStyle() {
+ const element = this._cachedMeta.dataset;
+ if (element) {
+ this._setStyle(element, undefined, 'active', false);
+ }
+ }
+ _setDatasetHoverStyle() {
+ const element = this._cachedMeta.dataset;
+ if (element) {
+ this._setStyle(element, undefined, 'active', true);
+ }
+ }
+ _resyncElements(resetNewElements) {
+ const data = this._data;
+ const elements = this._cachedMeta.data;
+ for (const [method, arg1, arg2] of this._syncList) {
+ this[method](arg1, arg2);
+ }
+ this._syncList = [];
+ const numMeta = elements.length;
+ const numData = data.length;
+ const count = Math.min(numData, numMeta);
+ if (count) {
+ this.parse(0, count);
+ }
+ if (numData > numMeta) {
+ this._insertElements(numMeta, numData - numMeta, resetNewElements);
+ } else if (numData < numMeta) {
+ this._removeElements(numData, numMeta - numData);
+ }
+ }
+ _insertElements(start, count, resetNewElements = true) {
+ const meta = this._cachedMeta;
+ const data = meta.data;
+ const end = start + count;
+ let i;
+ const move = (arr) => {
+ arr.length += count;
+ for (i = arr.length - 1; i >= end; i--) {
+ arr[i] = arr[i - count];
+ }
+ };
+ move(data);
+ for (i = start; i < end; ++i) {
+ data[i] = new this.dataElementType();
+ }
+ if (this._parsing) {
+ move(meta._parsed);
+ }
+ this.parse(start, count);
+ if (resetNewElements) {
+ this.updateElements(data, start, count, 'reset');
+ }
+ }
+ updateElements(element, start, count, mode) {}
+ _removeElements(start, count) {
+ const meta = this._cachedMeta;
+ if (this._parsing) {
+ const removed = meta._parsed.splice(start, count);
+ if (meta._stacked) {
+ clearStacks(meta, removed);
+ }
+ }
+ meta.data.splice(start, count);
+ }
+ _sync(args) {
+ if (this._parsing) {
+ this._syncList.push(args);
+ } else {
+ const [method, arg1, arg2] = args;
+ this[method](arg1, arg2);
+ }
+ this.chart._dataChanges.push([this.index, ...args]);
+ }
+ _onDataPush() {
+ const count = arguments.length;
+ this._sync(['_insertElements', this.getDataset().data.length - count, count]);
+ }
+ _onDataPop() {
+ this._sync(['_removeElements', this._cachedMeta.data.length - 1, 1]);
+ }
+ _onDataShift() {
+ this._sync(['_removeElements', 0, 1]);
+ }
+ _onDataSplice(start, count) {
+ if (count) {
+ this._sync(['_removeElements', start, count]);
+ }
+ const newCount = arguments.length - 2;
+ if (newCount) {
+ this._sync(['_insertElements', start, newCount]);
+ }
+ }
+ _onDataUnshift() {
+ this._sync(['_insertElements', 0, arguments.length]);
+ }
+}
+DatasetController.defaults = {};
+DatasetController.prototype.datasetElementType = null;
+DatasetController.prototype.dataElementType = null;
+
+class Element {
+ constructor() {
+ this.x = undefined;
+ this.y = undefined;
+ this.active = false;
+ this.options = undefined;
+ this.$animations = undefined;
+ }
+ tooltipPosition(useFinalPosition) {
+ const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+ return {x, y};
+ }
+ hasValue() {
+ return isNumber(this.x) && isNumber(this.y);
+ }
+ getProps(props, final) {
+ const anims = this.$animations;
+ if (!final || !anims) {
+ return this;
+ }
+ const ret = {};
+ props.forEach(prop => {
+ ret[prop] = anims[prop] && anims[prop].active() ? anims[prop]._to : this[prop];
+ });
+ return ret;
+ }
+}
+Element.defaults = {};
+Element.defaultRoutes = undefined;
+
+const formatters = {
+ values(value) {
+ return isArray(value) ? value : '' + value;
+ },
+ numeric(tickValue, index, ticks) {
+ if (tickValue === 0) {
+ return '0';
+ }
+ const locale = this.chart.options.locale;
+ let notation;
+ let delta = tickValue;
+ if (ticks.length > 1) {
+ const maxTick = Math.max(Math.abs(ticks[0].value), Math.abs(ticks[ticks.length - 1].value));
+ if (maxTick < 1e-4 || maxTick > 1e+15) {
+ notation = 'scientific';
+ }
+ delta = calculateDelta(tickValue, ticks);
+ }
+ const logDelta = log10(Math.abs(delta));
+ const numDecimal = Math.max(Math.min(-1 * Math.floor(logDelta), 20), 0);
+ const options = {notation, minimumFractionDigits: numDecimal, maximumFractionDigits: numDecimal};
+ Object.assign(options, this.options.ticks.format);
+ return formatNumber(tickValue, locale, options);
+ },
+ logarithmic(tickValue, index, ticks) {
+ if (tickValue === 0) {
+ return '0';
+ }
+ const remain = tickValue / (Math.pow(10, Math.floor(log10(tickValue))));
+ if (remain === 1 || remain === 2 || remain === 5) {
+ return formatters.numeric.call(this, tickValue, index, ticks);
+ }
+ return '';
+ }
+};
+function calculateDelta(tickValue, ticks) {
+ let delta = ticks.length > 3 ? ticks[2].value - ticks[1].value : ticks[1].value - ticks[0].value;
+ if (Math.abs(delta) >= 1 && tickValue !== Math.floor(tickValue)) {
+ delta = tickValue - Math.floor(tickValue);
+ }
+ return delta;
+}
+var Ticks = {formatters};
+
+defaults.set('scale', {
+ display: true,
+ offset: false,
+ reverse: false,
+ beginAtZero: false,
+ bounds: 'ticks',
+ grace: 0,
+ grid: {
+ display: true,
+ lineWidth: 1,
+ drawBorder: true,
+ drawOnChartArea: true,
+ drawTicks: true,
+ tickLength: 8,
+ tickWidth: (_ctx, options) => options.lineWidth,
+ tickColor: (_ctx, options) => options.color,
+ offset: false,
+ borderDash: [],
+ borderDashOffset: 0.0,
+ borderWidth: 1
+ },
+ title: {
+ display: false,
+ text: '',
+ padding: {
+ top: 4,
+ bottom: 4
+ }
+ },
+ ticks: {
+ minRotation: 0,
+ maxRotation: 50,
+ mirror: false,
+ textStrokeWidth: 0,
+ textStrokeColor: '',
+ padding: 3,
+ display: true,
+ autoSkip: true,
+ autoSkipPadding: 3,
+ labelOffset: 0,
+ callback: Ticks.formatters.values,
+ minor: {},
+ major: {},
+ align: 'center',
+ crossAlign: 'near',
+ showLabelBackdrop: false,
+ backdropColor: 'rgba(255, 255, 255, 0.75)',
+ backdropPadding: 2,
+ }
+});
+defaults.route('scale.ticks', 'color', '', 'color');
+defaults.route('scale.grid', 'color', '', 'borderColor');
+defaults.route('scale.grid', 'borderColor', '', 'borderColor');
+defaults.route('scale.title', 'color', '', 'color');
+defaults.describe('scale', {
+ _fallback: false,
+ _scriptable: (name) => !name.startsWith('before') && !name.startsWith('after') && name !== 'callback' && name !== 'parser',
+ _indexable: (name) => name !== 'borderDash' && name !== 'tickBorderDash',
+});
+defaults.describe('scales', {
+ _fallback: 'scale',
+});
+defaults.describe('scale.ticks', {
+ _scriptable: (name) => name !== 'backdropPadding' && name !== 'callback',
+ _indexable: (name) => name !== 'backdropPadding',
+});
+
+function autoSkip(scale, ticks) {
+ const tickOpts = scale.options.ticks;
+ const ticksLimit = tickOpts.maxTicksLimit || determineMaxTicks(scale);
+ const majorIndices = tickOpts.major.enabled ? getMajorIndices(ticks) : [];
+ const numMajorIndices = majorIndices.length;
+ const first = majorIndices[0];
+ const last = majorIndices[numMajorIndices - 1];
+ const newTicks = [];
+ if (numMajorIndices > ticksLimit) {
+ skipMajors(ticks, newTicks, majorIndices, numMajorIndices / ticksLimit);
+ return newTicks;
+ }
+ const spacing = calculateSpacing(majorIndices, ticks, ticksLimit);
+ if (numMajorIndices > 0) {
+ let i, ilen;
+ const avgMajorSpacing = numMajorIndices > 1 ? Math.round((last - first) / (numMajorIndices - 1)) : null;
+ skip(ticks, newTicks, spacing, isNullOrUndef(avgMajorSpacing) ? 0 : first - avgMajorSpacing, first);
+ for (i = 0, ilen = numMajorIndices - 1; i < ilen; i++) {
+ skip(ticks, newTicks, spacing, majorIndices[i], majorIndices[i + 1]);
+ }
+ skip(ticks, newTicks, spacing, last, isNullOrUndef(avgMajorSpacing) ? ticks.length : last + avgMajorSpacing);
+ return newTicks;
+ }
+ skip(ticks, newTicks, spacing);
+ return newTicks;
+}
+function determineMaxTicks(scale) {
+ const offset = scale.options.offset;
+ const tickLength = scale._tickSize();
+ const maxScale = scale._length / tickLength + (offset ? 0 : 1);
+ const maxChart = scale._maxLength / tickLength;
+ return Math.floor(Math.min(maxScale, maxChart));
+}
+function calculateSpacing(majorIndices, ticks, ticksLimit) {
+ const evenMajorSpacing = getEvenSpacing(majorIndices);
+ const spacing = ticks.length / ticksLimit;
+ if (!evenMajorSpacing) {
+ return Math.max(spacing, 1);
+ }
+ const factors = _factorize(evenMajorSpacing);
+ for (let i = 0, ilen = factors.length - 1; i < ilen; i++) {
+ const factor = factors[i];
+ if (factor > spacing) {
+ return factor;
+ }
+ }
+ return Math.max(spacing, 1);
+}
+function getMajorIndices(ticks) {
+ const result = [];
+ let i, ilen;
+ for (i = 0, ilen = ticks.length; i < ilen; i++) {
+ if (ticks[i].major) {
+ result.push(i);
+ }
+ }
+ return result;
+}
+function skipMajors(ticks, newTicks, majorIndices, spacing) {
+ let count = 0;
+ let next = majorIndices[0];
+ let i;
+ spacing = Math.ceil(spacing);
+ for (i = 0; i < ticks.length; i++) {
+ if (i === next) {
+ newTicks.push(ticks[i]);
+ count++;
+ next = majorIndices[count * spacing];
+ }
+ }
+}
+function skip(ticks, newTicks, spacing, majorStart, majorEnd) {
+ const start = valueOrDefault(majorStart, 0);
+ const end = Math.min(valueOrDefault(majorEnd, ticks.length), ticks.length);
+ let count = 0;
+ let length, i, next;
+ spacing = Math.ceil(spacing);
+ if (majorEnd) {
+ length = majorEnd - majorStart;
+ spacing = length / Math.floor(length / spacing);
+ }
+ next = start;
+ while (next < 0) {
+ count++;
+ next = Math.round(start + count * spacing);
+ }
+ for (i = Math.max(start, 0); i < end; i++) {
+ if (i === next) {
+ newTicks.push(ticks[i]);
+ count++;
+ next = Math.round(start + count * spacing);
+ }
+ }
+}
+function getEvenSpacing(arr) {
+ const len = arr.length;
+ let i, diff;
+ if (len < 2) {
+ return false;
+ }
+ for (diff = arr[0], i = 1; i < len; ++i) {
+ if (arr[i] - arr[i - 1] !== diff) {
+ return false;
+ }
+ }
+ return diff;
+}
+
+const reverseAlign = (align) => align === 'left' ? 'right' : align === 'right' ? 'left' : align;
+const offsetFromEdge = (scale, edge, offset) => edge === 'top' || edge === 'left' ? scale[edge] + offset : scale[edge] - offset;
+function sample(arr, numItems) {
+ const result = [];
+ const increment = arr.length / numItems;
+ const len = arr.length;
+ let i = 0;
+ for (; i < len; i += increment) {
+ result.push(arr[Math.floor(i)]);
+ }
+ return result;
+}
+function getPixelForGridLine(scale, index, offsetGridLines) {
+ const length = scale.ticks.length;
+ const validIndex = Math.min(index, length - 1);
+ const start = scale._startPixel;
+ const end = scale._endPixel;
+ const epsilon = 1e-6;
+ let lineValue = scale.getPixelForTick(validIndex);
+ let offset;
+ if (offsetGridLines) {
+ if (length === 1) {
+ offset = Math.max(lineValue - start, end - lineValue);
+ } else if (index === 0) {
+ offset = (scale.getPixelForTick(1) - lineValue) / 2;
+ } else {
+ offset = (lineValue - scale.getPixelForTick(validIndex - 1)) / 2;
+ }
+ lineValue += validIndex < index ? offset : -offset;
+ if (lineValue < start - epsilon || lineValue > end + epsilon) {
+ return;
+ }
+ }
+ return lineValue;
+}
+function garbageCollect(caches, length) {
+ each(caches, (cache) => {
+ const gc = cache.gc;
+ const gcLen = gc.length / 2;
+ let i;
+ if (gcLen > length) {
+ for (i = 0; i < gcLen; ++i) {
+ delete cache.data[gc[i]];
+ }
+ gc.splice(0, gcLen);
+ }
+ });
+}
+function getTickMarkLength(options) {
+ return options.drawTicks ? options.tickLength : 0;
+}
+function getTitleHeight(options, fallback) {
+ if (!options.display) {
+ return 0;
+ }
+ const font = toFont(options.font, fallback);
+ const padding = toPadding(options.padding);
+ const lines = isArray(options.text) ? options.text.length : 1;
+ return (lines * font.lineHeight) + padding.height;
+}
+function createScaleContext(parent, scale) {
+ return createContext(parent, {
+ scale,
+ type: 'scale'
+ });
+}
+function createTickContext(parent, index, tick) {
+ return createContext(parent, {
+ tick,
+ index,
+ type: 'tick'
+ });
+}
+function titleAlign(align, position, reverse) {
+ let ret = _toLeftRightCenter(align);
+ if ((reverse && position !== 'right') || (!reverse && position === 'right')) {
+ ret = reverseAlign(ret);
+ }
+ return ret;
+}
+function titleArgs(scale, offset, position, align) {
+ const {top, left, bottom, right, chart} = scale;
+ const {chartArea, scales} = chart;
+ let rotation = 0;
+ let maxWidth, titleX, titleY;
+ const height = bottom - top;
+ const width = right - left;
+ if (scale.isHorizontal()) {
+ titleX = _alignStartEnd(align, left, right);
+ if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ titleY = scales[positionAxisID].getPixelForValue(value) + height - offset;
+ } else if (position === 'center') {
+ titleY = (chartArea.bottom + chartArea.top) / 2 + height - offset;
+ } else {
+ titleY = offsetFromEdge(scale, position, offset);
+ }
+ maxWidth = right - left;
+ } else {
+ if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ titleX = scales[positionAxisID].getPixelForValue(value) - width + offset;
+ } else if (position === 'center') {
+ titleX = (chartArea.left + chartArea.right) / 2 - width + offset;
+ } else {
+ titleX = offsetFromEdge(scale, position, offset);
+ }
+ titleY = _alignStartEnd(align, bottom, top);
+ rotation = position === 'left' ? -HALF_PI : HALF_PI;
+ }
+ return {titleX, titleY, maxWidth, rotation};
+}
+class Scale extends Element {
+ constructor(cfg) {
+ super();
+ this.id = cfg.id;
+ this.type = cfg.type;
+ this.options = undefined;
+ this.ctx = cfg.ctx;
+ this.chart = cfg.chart;
+ this.top = undefined;
+ this.bottom = undefined;
+ this.left = undefined;
+ this.right = undefined;
+ this.width = undefined;
+ this.height = undefined;
+ this._margins = {
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0
+ };
+ this.maxWidth = undefined;
+ this.maxHeight = undefined;
+ this.paddingTop = undefined;
+ this.paddingBottom = undefined;
+ this.paddingLeft = undefined;
+ this.paddingRight = undefined;
+ this.axis = undefined;
+ this.labelRotation = undefined;
+ this.min = undefined;
+ this.max = undefined;
+ this._range = undefined;
+ this.ticks = [];
+ this._gridLineItems = null;
+ this._labelItems = null;
+ this._labelSizes = null;
+ this._length = 0;
+ this._maxLength = 0;
+ this._longestTextCache = {};
+ this._startPixel = undefined;
+ this._endPixel = undefined;
+ this._reversePixels = false;
+ this._userMax = undefined;
+ this._userMin = undefined;
+ this._suggestedMax = undefined;
+ this._suggestedMin = undefined;
+ this._ticksLength = 0;
+ this._borderValue = 0;
+ this._cache = {};
+ this._dataLimitsCached = false;
+ this.$context = undefined;
+ }
+ init(options) {
+ this.options = options.setContext(this.getContext());
+ this.axis = options.axis;
+ this._userMin = this.parse(options.min);
+ this._userMax = this.parse(options.max);
+ this._suggestedMin = this.parse(options.suggestedMin);
+ this._suggestedMax = this.parse(options.suggestedMax);
+ }
+ parse(raw, index) {
+ return raw;
+ }
+ getUserBounds() {
+ let {_userMin, _userMax, _suggestedMin, _suggestedMax} = this;
+ _userMin = finiteOrDefault(_userMin, Number.POSITIVE_INFINITY);
+ _userMax = finiteOrDefault(_userMax, Number.NEGATIVE_INFINITY);
+ _suggestedMin = finiteOrDefault(_suggestedMin, Number.POSITIVE_INFINITY);
+ _suggestedMax = finiteOrDefault(_suggestedMax, Number.NEGATIVE_INFINITY);
+ return {
+ min: finiteOrDefault(_userMin, _suggestedMin),
+ max: finiteOrDefault(_userMax, _suggestedMax),
+ minDefined: isNumberFinite(_userMin),
+ maxDefined: isNumberFinite(_userMax)
+ };
+ }
+ getMinMax(canStack) {
+ let {min, max, minDefined, maxDefined} = this.getUserBounds();
+ let range;
+ if (minDefined && maxDefined) {
+ return {min, max};
+ }
+ const metas = this.getMatchingVisibleMetas();
+ for (let i = 0, ilen = metas.length; i < ilen; ++i) {
+ range = metas[i].controller.getMinMax(this, canStack);
+ if (!minDefined) {
+ min = Math.min(min, range.min);
+ }
+ if (!maxDefined) {
+ max = Math.max(max, range.max);
+ }
+ }
+ min = maxDefined && min > max ? max : min;
+ max = minDefined && min > max ? min : max;
+ return {
+ min: finiteOrDefault(min, finiteOrDefault(max, min)),
+ max: finiteOrDefault(max, finiteOrDefault(min, max))
+ };
+ }
+ getPadding() {
+ return {
+ left: this.paddingLeft || 0,
+ top: this.paddingTop || 0,
+ right: this.paddingRight || 0,
+ bottom: this.paddingBottom || 0
+ };
+ }
+ getTicks() {
+ return this.ticks;
+ }
+ getLabels() {
+ const data = this.chart.data;
+ return this.options.labels || (this.isHorizontal() ? data.xLabels : data.yLabels) || data.labels || [];
+ }
+ beforeLayout() {
+ this._cache = {};
+ this._dataLimitsCached = false;
+ }
+ beforeUpdate() {
+ callback(this.options.beforeUpdate, [this]);
+ }
+ update(maxWidth, maxHeight, margins) {
+ const {beginAtZero, grace, ticks: tickOpts} = this.options;
+ const sampleSize = tickOpts.sampleSize;
+ this.beforeUpdate();
+ this.maxWidth = maxWidth;
+ this.maxHeight = maxHeight;
+ this._margins = margins = Object.assign({
+ left: 0,
+ right: 0,
+ top: 0,
+ bottom: 0
+ }, margins);
+ this.ticks = null;
+ this._labelSizes = null;
+ this._gridLineItems = null;
+ this._labelItems = null;
+ this.beforeSetDimensions();
+ this.setDimensions();
+ this.afterSetDimensions();
+ this._maxLength = this.isHorizontal()
+ ? this.width + margins.left + margins.right
+ : this.height + margins.top + margins.bottom;
+ if (!this._dataLimitsCached) {
+ this.beforeDataLimits();
+ this.determineDataLimits();
+ this.afterDataLimits();
+ this._range = _addGrace(this, grace, beginAtZero);
+ this._dataLimitsCached = true;
+ }
+ this.beforeBuildTicks();
+ this.ticks = this.buildTicks() || [];
+ this.afterBuildTicks();
+ const samplingEnabled = sampleSize < this.ticks.length;
+ this._convertTicksToLabels(samplingEnabled ? sample(this.ticks, sampleSize) : this.ticks);
+ this.configure();
+ this.beforeCalculateLabelRotation();
+ this.calculateLabelRotation();
+ this.afterCalculateLabelRotation();
+ if (tickOpts.display && (tickOpts.autoSkip || tickOpts.source === 'auto')) {
+ this.ticks = autoSkip(this, this.ticks);
+ this._labelSizes = null;
+ }
+ if (samplingEnabled) {
+ this._convertTicksToLabels(this.ticks);
+ }
+ this.beforeFit();
+ this.fit();
+ this.afterFit();
+ this.afterUpdate();
+ }
+ configure() {
+ let reversePixels = this.options.reverse;
+ let startPixel, endPixel;
+ if (this.isHorizontal()) {
+ startPixel = this.left;
+ endPixel = this.right;
+ } else {
+ startPixel = this.top;
+ endPixel = this.bottom;
+ reversePixels = !reversePixels;
+ }
+ this._startPixel = startPixel;
+ this._endPixel = endPixel;
+ this._reversePixels = reversePixels;
+ this._length = endPixel - startPixel;
+ this._alignToPixels = this.options.alignToPixels;
+ }
+ afterUpdate() {
+ callback(this.options.afterUpdate, [this]);
+ }
+ beforeSetDimensions() {
+ callback(this.options.beforeSetDimensions, [this]);
+ }
+ setDimensions() {
+ if (this.isHorizontal()) {
+ this.width = this.maxWidth;
+ this.left = 0;
+ this.right = this.width;
+ } else {
+ this.height = this.maxHeight;
+ this.top = 0;
+ this.bottom = this.height;
+ }
+ this.paddingLeft = 0;
+ this.paddingTop = 0;
+ this.paddingRight = 0;
+ this.paddingBottom = 0;
+ }
+ afterSetDimensions() {
+ callback(this.options.afterSetDimensions, [this]);
+ }
+ _callHooks(name) {
+ this.chart.notifyPlugins(name, this.getContext());
+ callback(this.options[name], [this]);
+ }
+ beforeDataLimits() {
+ this._callHooks('beforeDataLimits');
+ }
+ determineDataLimits() {}
+ afterDataLimits() {
+ this._callHooks('afterDataLimits');
+ }
+ beforeBuildTicks() {
+ this._callHooks('beforeBuildTicks');
+ }
+ buildTicks() {
+ return [];
+ }
+ afterBuildTicks() {
+ this._callHooks('afterBuildTicks');
+ }
+ beforeTickToLabelConversion() {
+ callback(this.options.beforeTickToLabelConversion, [this]);
+ }
+ generateTickLabels(ticks) {
+ const tickOpts = this.options.ticks;
+ let i, ilen, tick;
+ for (i = 0, ilen = ticks.length; i < ilen; i++) {
+ tick = ticks[i];
+ tick.label = callback(tickOpts.callback, [tick.value, i, ticks], this);
+ }
+ }
+ afterTickToLabelConversion() {
+ callback(this.options.afterTickToLabelConversion, [this]);
+ }
+ beforeCalculateLabelRotation() {
+ callback(this.options.beforeCalculateLabelRotation, [this]);
+ }
+ calculateLabelRotation() {
+ const options = this.options;
+ const tickOpts = options.ticks;
+ const numTicks = this.ticks.length;
+ const minRotation = tickOpts.minRotation || 0;
+ const maxRotation = tickOpts.maxRotation;
+ let labelRotation = minRotation;
+ let tickWidth, maxHeight, maxLabelDiagonal;
+ if (!this._isVisible() || !tickOpts.display || minRotation >= maxRotation || numTicks <= 1 || !this.isHorizontal()) {
+ this.labelRotation = minRotation;
+ return;
+ }
+ const labelSizes = this._getLabelSizes();
+ const maxLabelWidth = labelSizes.widest.width;
+ const maxLabelHeight = labelSizes.highest.height;
+ const maxWidth = _limitValue(this.chart.width - maxLabelWidth, 0, this.maxWidth);
+ tickWidth = options.offset ? this.maxWidth / numTicks : maxWidth / (numTicks - 1);
+ if (maxLabelWidth + 6 > tickWidth) {
+ tickWidth = maxWidth / (numTicks - (options.offset ? 0.5 : 1));
+ maxHeight = this.maxHeight - getTickMarkLength(options.grid)
+ - tickOpts.padding - getTitleHeight(options.title, this.chart.options.font);
+ maxLabelDiagonal = Math.sqrt(maxLabelWidth * maxLabelWidth + maxLabelHeight * maxLabelHeight);
+ labelRotation = toDegrees(Math.min(
+ Math.asin(_limitValue((labelSizes.highest.height + 6) / tickWidth, -1, 1)),
+ Math.asin(_limitValue(maxHeight / maxLabelDiagonal, -1, 1)) - Math.asin(_limitValue(maxLabelHeight / maxLabelDiagonal, -1, 1))
+ ));
+ labelRotation = Math.max(minRotation, Math.min(maxRotation, labelRotation));
+ }
+ this.labelRotation = labelRotation;
+ }
+ afterCalculateLabelRotation() {
+ callback(this.options.afterCalculateLabelRotation, [this]);
+ }
+ beforeFit() {
+ callback(this.options.beforeFit, [this]);
+ }
+ fit() {
+ const minSize = {
+ width: 0,
+ height: 0
+ };
+ const {chart, options: {ticks: tickOpts, title: titleOpts, grid: gridOpts}} = this;
+ const display = this._isVisible();
+ const isHorizontal = this.isHorizontal();
+ if (display) {
+ const titleHeight = getTitleHeight(titleOpts, chart.options.font);
+ if (isHorizontal) {
+ minSize.width = this.maxWidth;
+ minSize.height = getTickMarkLength(gridOpts) + titleHeight;
+ } else {
+ minSize.height = this.maxHeight;
+ minSize.width = getTickMarkLength(gridOpts) + titleHeight;
+ }
+ if (tickOpts.display && this.ticks.length) {
+ const {first, last, widest, highest} = this._getLabelSizes();
+ const tickPadding = tickOpts.padding * 2;
+ const angleRadians = toRadians(this.labelRotation);
+ const cos = Math.cos(angleRadians);
+ const sin = Math.sin(angleRadians);
+ if (isHorizontal) {
+ const labelHeight = tickOpts.mirror ? 0 : sin * widest.width + cos * highest.height;
+ minSize.height = Math.min(this.maxHeight, minSize.height + labelHeight + tickPadding);
+ } else {
+ const labelWidth = tickOpts.mirror ? 0 : cos * widest.width + sin * highest.height;
+ minSize.width = Math.min(this.maxWidth, minSize.width + labelWidth + tickPadding);
+ }
+ this._calculatePadding(first, last, sin, cos);
+ }
+ }
+ this._handleMargins();
+ if (isHorizontal) {
+ this.width = this._length = chart.width - this._margins.left - this._margins.right;
+ this.height = minSize.height;
+ } else {
+ this.width = minSize.width;
+ this.height = this._length = chart.height - this._margins.top - this._margins.bottom;
+ }
+ }
+ _calculatePadding(first, last, sin, cos) {
+ const {ticks: {align, padding}, position} = this.options;
+ const isRotated = this.labelRotation !== 0;
+ const labelsBelowTicks = position !== 'top' && this.axis === 'x';
+ if (this.isHorizontal()) {
+ const offsetLeft = this.getPixelForTick(0) - this.left;
+ const offsetRight = this.right - this.getPixelForTick(this.ticks.length - 1);
+ let paddingLeft = 0;
+ let paddingRight = 0;
+ if (isRotated) {
+ if (labelsBelowTicks) {
+ paddingLeft = cos * first.width;
+ paddingRight = sin * last.height;
+ } else {
+ paddingLeft = sin * first.height;
+ paddingRight = cos * last.width;
+ }
+ } else if (align === 'start') {
+ paddingRight = last.width;
+ } else if (align === 'end') {
+ paddingLeft = first.width;
+ } else {
+ paddingLeft = first.width / 2;
+ paddingRight = last.width / 2;
+ }
+ this.paddingLeft = Math.max((paddingLeft - offsetLeft + padding) * this.width / (this.width - offsetLeft), 0);
+ this.paddingRight = Math.max((paddingRight - offsetRight + padding) * this.width / (this.width - offsetRight), 0);
+ } else {
+ let paddingTop = last.height / 2;
+ let paddingBottom = first.height / 2;
+ if (align === 'start') {
+ paddingTop = 0;
+ paddingBottom = first.height;
+ } else if (align === 'end') {
+ paddingTop = last.height;
+ paddingBottom = 0;
+ }
+ this.paddingTop = paddingTop + padding;
+ this.paddingBottom = paddingBottom + padding;
+ }
+ }
+ _handleMargins() {
+ if (this._margins) {
+ this._margins.left = Math.max(this.paddingLeft, this._margins.left);
+ this._margins.top = Math.max(this.paddingTop, this._margins.top);
+ this._margins.right = Math.max(this.paddingRight, this._margins.right);
+ this._margins.bottom = Math.max(this.paddingBottom, this._margins.bottom);
+ }
+ }
+ afterFit() {
+ callback(this.options.afterFit, [this]);
+ }
+ isHorizontal() {
+ const {axis, position} = this.options;
+ return position === 'top' || position === 'bottom' || axis === 'x';
+ }
+ isFullSize() {
+ return this.options.fullSize;
+ }
+ _convertTicksToLabels(ticks) {
+ this.beforeTickToLabelConversion();
+ this.generateTickLabels(ticks);
+ let i, ilen;
+ for (i = 0, ilen = ticks.length; i < ilen; i++) {
+ if (isNullOrUndef(ticks[i].label)) {
+ ticks.splice(i, 1);
+ ilen--;
+ i--;
+ }
+ }
+ this.afterTickToLabelConversion();
+ }
+ _getLabelSizes() {
+ let labelSizes = this._labelSizes;
+ if (!labelSizes) {
+ const sampleSize = this.options.ticks.sampleSize;
+ let ticks = this.ticks;
+ if (sampleSize < ticks.length) {
+ ticks = sample(ticks, sampleSize);
+ }
+ this._labelSizes = labelSizes = this._computeLabelSizes(ticks, ticks.length);
+ }
+ return labelSizes;
+ }
+ _computeLabelSizes(ticks, length) {
+ const {ctx, _longestTextCache: caches} = this;
+ const widths = [];
+ const heights = [];
+ let widestLabelSize = 0;
+ let highestLabelSize = 0;
+ let i, j, jlen, label, tickFont, fontString, cache, lineHeight, width, height, nestedLabel;
+ for (i = 0; i < length; ++i) {
+ label = ticks[i].label;
+ tickFont = this._resolveTickFontOptions(i);
+ ctx.font = fontString = tickFont.string;
+ cache = caches[fontString] = caches[fontString] || {data: {}, gc: []};
+ lineHeight = tickFont.lineHeight;
+ width = height = 0;
+ if (!isNullOrUndef(label) && !isArray(label)) {
+ width = _measureText(ctx, cache.data, cache.gc, width, label);
+ height = lineHeight;
+ } else if (isArray(label)) {
+ for (j = 0, jlen = label.length; j < jlen; ++j) {
+ nestedLabel = label[j];
+ if (!isNullOrUndef(nestedLabel) && !isArray(nestedLabel)) {
+ width = _measureText(ctx, cache.data, cache.gc, width, nestedLabel);
+ height += lineHeight;
+ }
+ }
+ }
+ widths.push(width);
+ heights.push(height);
+ widestLabelSize = Math.max(width, widestLabelSize);
+ highestLabelSize = Math.max(height, highestLabelSize);
+ }
+ garbageCollect(caches, length);
+ const widest = widths.indexOf(widestLabelSize);
+ const highest = heights.indexOf(highestLabelSize);
+ const valueAt = (idx) => ({width: widths[idx] || 0, height: heights[idx] || 0});
+ return {
+ first: valueAt(0),
+ last: valueAt(length - 1),
+ widest: valueAt(widest),
+ highest: valueAt(highest),
+ widths,
+ heights,
+ };
+ }
+ getLabelForValue(value) {
+ return value;
+ }
+ getPixelForValue(value, index) {
+ return NaN;
+ }
+ getValueForPixel(pixel) {}
+ getPixelForTick(index) {
+ const ticks = this.ticks;
+ if (index < 0 || index > ticks.length - 1) {
+ return null;
+ }
+ return this.getPixelForValue(ticks[index].value);
+ }
+ getPixelForDecimal(decimal) {
+ if (this._reversePixels) {
+ decimal = 1 - decimal;
+ }
+ const pixel = this._startPixel + decimal * this._length;
+ return _int16Range(this._alignToPixels ? _alignPixel(this.chart, pixel, 0) : pixel);
+ }
+ getDecimalForPixel(pixel) {
+ const decimal = (pixel - this._startPixel) / this._length;
+ return this._reversePixels ? 1 - decimal : decimal;
+ }
+ getBasePixel() {
+ return this.getPixelForValue(this.getBaseValue());
+ }
+ getBaseValue() {
+ const {min, max} = this;
+ return min < 0 && max < 0 ? max :
+ min > 0 && max > 0 ? min :
+ 0;
+ }
+ getContext(index) {
+ const ticks = this.ticks || [];
+ if (index >= 0 && index < ticks.length) {
+ const tick = ticks[index];
+ return tick.$context ||
+ (tick.$context = createTickContext(this.getContext(), index, tick));
+ }
+ return this.$context ||
+ (this.$context = createScaleContext(this.chart.getContext(), this));
+ }
+ _tickSize() {
+ const optionTicks = this.options.ticks;
+ const rot = toRadians(this.labelRotation);
+ const cos = Math.abs(Math.cos(rot));
+ const sin = Math.abs(Math.sin(rot));
+ const labelSizes = this._getLabelSizes();
+ const padding = optionTicks.autoSkipPadding || 0;
+ const w = labelSizes ? labelSizes.widest.width + padding : 0;
+ const h = labelSizes ? labelSizes.highest.height + padding : 0;
+ return this.isHorizontal()
+ ? h * cos > w * sin ? w / cos : h / sin
+ : h * sin < w * cos ? h / cos : w / sin;
+ }
+ _isVisible() {
+ const display = this.options.display;
+ if (display !== 'auto') {
+ return !!display;
+ }
+ return this.getMatchingVisibleMetas().length > 0;
+ }
+ _computeGridLineItems(chartArea) {
+ const axis = this.axis;
+ const chart = this.chart;
+ const options = this.options;
+ const {grid, position} = options;
+ const offset = grid.offset;
+ const isHorizontal = this.isHorizontal();
+ const ticks = this.ticks;
+ const ticksLength = ticks.length + (offset ? 1 : 0);
+ const tl = getTickMarkLength(grid);
+ const items = [];
+ const borderOpts = grid.setContext(this.getContext());
+ const axisWidth = borderOpts.drawBorder ? borderOpts.borderWidth : 0;
+ const axisHalfWidth = axisWidth / 2;
+ const alignBorderValue = function(pixel) {
+ return _alignPixel(chart, pixel, axisWidth);
+ };
+ let borderValue, i, lineValue, alignedLineValue;
+ let tx1, ty1, tx2, ty2, x1, y1, x2, y2;
+ if (position === 'top') {
+ borderValue = alignBorderValue(this.bottom);
+ ty1 = this.bottom - tl;
+ ty2 = borderValue - axisHalfWidth;
+ y1 = alignBorderValue(chartArea.top) + axisHalfWidth;
+ y2 = chartArea.bottom;
+ } else if (position === 'bottom') {
+ borderValue = alignBorderValue(this.top);
+ y1 = chartArea.top;
+ y2 = alignBorderValue(chartArea.bottom) - axisHalfWidth;
+ ty1 = borderValue + axisHalfWidth;
+ ty2 = this.top + tl;
+ } else if (position === 'left') {
+ borderValue = alignBorderValue(this.right);
+ tx1 = this.right - tl;
+ tx2 = borderValue - axisHalfWidth;
+ x1 = alignBorderValue(chartArea.left) + axisHalfWidth;
+ x2 = chartArea.right;
+ } else if (position === 'right') {
+ borderValue = alignBorderValue(this.left);
+ x1 = chartArea.left;
+ x2 = alignBorderValue(chartArea.right) - axisHalfWidth;
+ tx1 = borderValue + axisHalfWidth;
+ tx2 = this.left + tl;
+ } else if (axis === 'x') {
+ if (position === 'center') {
+ borderValue = alignBorderValue((chartArea.top + chartArea.bottom) / 2 + 0.5);
+ } else if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
+ }
+ y1 = chartArea.top;
+ y2 = chartArea.bottom;
+ ty1 = borderValue + axisHalfWidth;
+ ty2 = ty1 + tl;
+ } else if (axis === 'y') {
+ if (position === 'center') {
+ borderValue = alignBorderValue((chartArea.left + chartArea.right) / 2);
+ } else if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ borderValue = alignBorderValue(this.chart.scales[positionAxisID].getPixelForValue(value));
+ }
+ tx1 = borderValue - axisHalfWidth;
+ tx2 = tx1 - tl;
+ x1 = chartArea.left;
+ x2 = chartArea.right;
+ }
+ const limit = valueOrDefault(options.ticks.maxTicksLimit, ticksLength);
+ const step = Math.max(1, Math.ceil(ticksLength / limit));
+ for (i = 0; i < ticksLength; i += step) {
+ const optsAtIndex = grid.setContext(this.getContext(i));
+ const lineWidth = optsAtIndex.lineWidth;
+ const lineColor = optsAtIndex.color;
+ const borderDash = grid.borderDash || [];
+ const borderDashOffset = optsAtIndex.borderDashOffset;
+ const tickWidth = optsAtIndex.tickWidth;
+ const tickColor = optsAtIndex.tickColor;
+ const tickBorderDash = optsAtIndex.tickBorderDash || [];
+ const tickBorderDashOffset = optsAtIndex.tickBorderDashOffset;
+ lineValue = getPixelForGridLine(this, i, offset);
+ if (lineValue === undefined) {
+ continue;
+ }
+ alignedLineValue = _alignPixel(chart, lineValue, lineWidth);
+ if (isHorizontal) {
+ tx1 = tx2 = x1 = x2 = alignedLineValue;
+ } else {
+ ty1 = ty2 = y1 = y2 = alignedLineValue;
+ }
+ items.push({
+ tx1,
+ ty1,
+ tx2,
+ ty2,
+ x1,
+ y1,
+ x2,
+ y2,
+ width: lineWidth,
+ color: lineColor,
+ borderDash,
+ borderDashOffset,
+ tickWidth,
+ tickColor,
+ tickBorderDash,
+ tickBorderDashOffset,
+ });
+ }
+ this._ticksLength = ticksLength;
+ this._borderValue = borderValue;
+ return items;
+ }
+ _computeLabelItems(chartArea) {
+ const axis = this.axis;
+ const options = this.options;
+ const {position, ticks: optionTicks} = options;
+ const isHorizontal = this.isHorizontal();
+ const ticks = this.ticks;
+ const {align, crossAlign, padding, mirror} = optionTicks;
+ const tl = getTickMarkLength(options.grid);
+ const tickAndPadding = tl + padding;
+ const hTickAndPadding = mirror ? -padding : tickAndPadding;
+ const rotation = -toRadians(this.labelRotation);
+ const items = [];
+ let i, ilen, tick, label, x, y, textAlign, pixel, font, lineHeight, lineCount, textOffset;
+ let textBaseline = 'middle';
+ if (position === 'top') {
+ y = this.bottom - hTickAndPadding;
+ textAlign = this._getXAxisLabelAlignment();
+ } else if (position === 'bottom') {
+ y = this.top + hTickAndPadding;
+ textAlign = this._getXAxisLabelAlignment();
+ } else if (position === 'left') {
+ const ret = this._getYAxisLabelAlignment(tl);
+ textAlign = ret.textAlign;
+ x = ret.x;
+ } else if (position === 'right') {
+ const ret = this._getYAxisLabelAlignment(tl);
+ textAlign = ret.textAlign;
+ x = ret.x;
+ } else if (axis === 'x') {
+ if (position === 'center') {
+ y = ((chartArea.top + chartArea.bottom) / 2) + tickAndPadding;
+ } else if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ y = this.chart.scales[positionAxisID].getPixelForValue(value) + tickAndPadding;
+ }
+ textAlign = this._getXAxisLabelAlignment();
+ } else if (axis === 'y') {
+ if (position === 'center') {
+ x = ((chartArea.left + chartArea.right) / 2) - tickAndPadding;
+ } else if (isObject(position)) {
+ const positionAxisID = Object.keys(position)[0];
+ const value = position[positionAxisID];
+ x = this.chart.scales[positionAxisID].getPixelForValue(value);
+ }
+ textAlign = this._getYAxisLabelAlignment(tl).textAlign;
+ }
+ if (axis === 'y') {
+ if (align === 'start') {
+ textBaseline = 'top';
+ } else if (align === 'end') {
+ textBaseline = 'bottom';
+ }
+ }
+ const labelSizes = this._getLabelSizes();
+ for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+ tick = ticks[i];
+ label = tick.label;
+ const optsAtIndex = optionTicks.setContext(this.getContext(i));
+ pixel = this.getPixelForTick(i) + optionTicks.labelOffset;
+ font = this._resolveTickFontOptions(i);
+ lineHeight = font.lineHeight;
+ lineCount = isArray(label) ? label.length : 1;
+ const halfCount = lineCount / 2;
+ const color = optsAtIndex.color;
+ const strokeColor = optsAtIndex.textStrokeColor;
+ const strokeWidth = optsAtIndex.textStrokeWidth;
+ if (isHorizontal) {
+ x = pixel;
+ if (position === 'top') {
+ if (crossAlign === 'near' || rotation !== 0) {
+ textOffset = -lineCount * lineHeight + lineHeight / 2;
+ } else if (crossAlign === 'center') {
+ textOffset = -labelSizes.highest.height / 2 - halfCount * lineHeight + lineHeight;
+ } else {
+ textOffset = -labelSizes.highest.height + lineHeight / 2;
+ }
+ } else {
+ if (crossAlign === 'near' || rotation !== 0) {
+ textOffset = lineHeight / 2;
+ } else if (crossAlign === 'center') {
+ textOffset = labelSizes.highest.height / 2 - halfCount * lineHeight;
+ } else {
+ textOffset = labelSizes.highest.height - lineCount * lineHeight;
+ }
+ }
+ if (mirror) {
+ textOffset *= -1;
+ }
+ } else {
+ y = pixel;
+ textOffset = (1 - lineCount) * lineHeight / 2;
+ }
+ let backdrop;
+ if (optsAtIndex.showLabelBackdrop) {
+ const labelPadding = toPadding(optsAtIndex.backdropPadding);
+ const height = labelSizes.heights[i];
+ const width = labelSizes.widths[i];
+ let top = y + textOffset - labelPadding.top;
+ let left = x - labelPadding.left;
+ switch (textBaseline) {
+ case 'middle':
+ top -= height / 2;
+ break;
+ case 'bottom':
+ top -= height;
+ break;
+ }
+ switch (textAlign) {
+ case 'center':
+ left -= width / 2;
+ break;
+ case 'right':
+ left -= width;
+ break;
+ }
+ backdrop = {
+ left,
+ top,
+ width: width + labelPadding.width,
+ height: height + labelPadding.height,
+ color: optsAtIndex.backdropColor,
+ };
+ }
+ items.push({
+ rotation,
+ label,
+ font,
+ color,
+ strokeColor,
+ strokeWidth,
+ textOffset,
+ textAlign,
+ textBaseline,
+ translation: [x, y],
+ backdrop,
+ });
+ }
+ return items;
+ }
+ _getXAxisLabelAlignment() {
+ const {position, ticks} = this.options;
+ const rotation = -toRadians(this.labelRotation);
+ if (rotation) {
+ return position === 'top' ? 'left' : 'right';
+ }
+ let align = 'center';
+ if (ticks.align === 'start') {
+ align = 'left';
+ } else if (ticks.align === 'end') {
+ align = 'right';
+ }
+ return align;
+ }
+ _getYAxisLabelAlignment(tl) {
+ const {position, ticks: {crossAlign, mirror, padding}} = this.options;
+ const labelSizes = this._getLabelSizes();
+ const tickAndPadding = tl + padding;
+ const widest = labelSizes.widest.width;
+ let textAlign;
+ let x;
+ if (position === 'left') {
+ if (mirror) {
+ x = this.right + padding;
+ if (crossAlign === 'near') {
+ textAlign = 'left';
+ } else if (crossAlign === 'center') {
+ textAlign = 'center';
+ x += (widest / 2);
+ } else {
+ textAlign = 'right';
+ x += widest;
+ }
+ } else {
+ x = this.right - tickAndPadding;
+ if (crossAlign === 'near') {
+ textAlign = 'right';
+ } else if (crossAlign === 'center') {
+ textAlign = 'center';
+ x -= (widest / 2);
+ } else {
+ textAlign = 'left';
+ x = this.left;
+ }
+ }
+ } else if (position === 'right') {
+ if (mirror) {
+ x = this.left + padding;
+ if (crossAlign === 'near') {
+ textAlign = 'right';
+ } else if (crossAlign === 'center') {
+ textAlign = 'center';
+ x -= (widest / 2);
+ } else {
+ textAlign = 'left';
+ x -= widest;
+ }
+ } else {
+ x = this.left + tickAndPadding;
+ if (crossAlign === 'near') {
+ textAlign = 'left';
+ } else if (crossAlign === 'center') {
+ textAlign = 'center';
+ x += widest / 2;
+ } else {
+ textAlign = 'right';
+ x = this.right;
+ }
+ }
+ } else {
+ textAlign = 'right';
+ }
+ return {textAlign, x};
+ }
+ _computeLabelArea() {
+ if (this.options.ticks.mirror) {
+ return;
+ }
+ const chart = this.chart;
+ const position = this.options.position;
+ if (position === 'left' || position === 'right') {
+ return {top: 0, left: this.left, bottom: chart.height, right: this.right};
+ } if (position === 'top' || position === 'bottom') {
+ return {top: this.top, left: 0, bottom: this.bottom, right: chart.width};
+ }
+ }
+ drawBackground() {
+ const {ctx, options: {backgroundColor}, left, top, width, height} = this;
+ if (backgroundColor) {
+ ctx.save();
+ ctx.fillStyle = backgroundColor;
+ ctx.fillRect(left, top, width, height);
+ ctx.restore();
+ }
+ }
+ getLineWidthForValue(value) {
+ const grid = this.options.grid;
+ if (!this._isVisible() || !grid.display) {
+ return 0;
+ }
+ const ticks = this.ticks;
+ const index = ticks.findIndex(t => t.value === value);
+ if (index >= 0) {
+ const opts = grid.setContext(this.getContext(index));
+ return opts.lineWidth;
+ }
+ return 0;
+ }
+ drawGrid(chartArea) {
+ const grid = this.options.grid;
+ const ctx = this.ctx;
+ const items = this._gridLineItems || (this._gridLineItems = this._computeGridLineItems(chartArea));
+ let i, ilen;
+ const drawLine = (p1, p2, style) => {
+ if (!style.width || !style.color) {
+ return;
+ }
+ ctx.save();
+ ctx.lineWidth = style.width;
+ ctx.strokeStyle = style.color;
+ ctx.setLineDash(style.borderDash || []);
+ ctx.lineDashOffset = style.borderDashOffset;
+ ctx.beginPath();
+ ctx.moveTo(p1.x, p1.y);
+ ctx.lineTo(p2.x, p2.y);
+ ctx.stroke();
+ ctx.restore();
+ };
+ if (grid.display) {
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
+ const item = items[i];
+ if (grid.drawOnChartArea) {
+ drawLine(
+ {x: item.x1, y: item.y1},
+ {x: item.x2, y: item.y2},
+ item
+ );
+ }
+ if (grid.drawTicks) {
+ drawLine(
+ {x: item.tx1, y: item.ty1},
+ {x: item.tx2, y: item.ty2},
+ {
+ color: item.tickColor,
+ width: item.tickWidth,
+ borderDash: item.tickBorderDash,
+ borderDashOffset: item.tickBorderDashOffset
+ }
+ );
+ }
+ }
+ }
+ }
+ drawBorder() {
+ const {chart, ctx, options: {grid}} = this;
+ const borderOpts = grid.setContext(this.getContext());
+ const axisWidth = grid.drawBorder ? borderOpts.borderWidth : 0;
+ if (!axisWidth) {
+ return;
+ }
+ const lastLineWidth = grid.setContext(this.getContext(0)).lineWidth;
+ const borderValue = this._borderValue;
+ let x1, x2, y1, y2;
+ if (this.isHorizontal()) {
+ x1 = _alignPixel(chart, this.left, axisWidth) - axisWidth / 2;
+ x2 = _alignPixel(chart, this.right, lastLineWidth) + lastLineWidth / 2;
+ y1 = y2 = borderValue;
+ } else {
+ y1 = _alignPixel(chart, this.top, axisWidth) - axisWidth / 2;
+ y2 = _alignPixel(chart, this.bottom, lastLineWidth) + lastLineWidth / 2;
+ x1 = x2 = borderValue;
+ }
+ ctx.save();
+ ctx.lineWidth = borderOpts.borderWidth;
+ ctx.strokeStyle = borderOpts.borderColor;
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+ ctx.restore();
+ }
+ drawLabels(chartArea) {
+ const optionTicks = this.options.ticks;
+ if (!optionTicks.display) {
+ return;
+ }
+ const ctx = this.ctx;
+ const area = this._computeLabelArea();
+ if (area) {
+ clipArea(ctx, area);
+ }
+ const items = this._labelItems || (this._labelItems = this._computeLabelItems(chartArea));
+ let i, ilen;
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
+ const item = items[i];
+ const tickFont = item.font;
+ const label = item.label;
+ if (item.backdrop) {
+ ctx.fillStyle = item.backdrop.color;
+ ctx.fillRect(item.backdrop.left, item.backdrop.top, item.backdrop.width, item.backdrop.height);
+ }
+ let y = item.textOffset;
+ renderText(ctx, label, 0, y, tickFont, item);
+ }
+ if (area) {
+ unclipArea(ctx);
+ }
+ }
+ drawTitle() {
+ const {ctx, options: {position, title, reverse}} = this;
+ if (!title.display) {
+ return;
+ }
+ const font = toFont(title.font);
+ const padding = toPadding(title.padding);
+ const align = title.align;
+ let offset = font.lineHeight / 2;
+ if (position === 'bottom' || position === 'center' || isObject(position)) {
+ offset += padding.bottom;
+ if (isArray(title.text)) {
+ offset += font.lineHeight * (title.text.length - 1);
+ }
+ } else {
+ offset += padding.top;
+ }
+ const {titleX, titleY, maxWidth, rotation} = titleArgs(this, offset, position, align);
+ renderText(ctx, title.text, 0, 0, font, {
+ color: title.color,
+ maxWidth,
+ rotation,
+ textAlign: titleAlign(align, position, reverse),
+ textBaseline: 'middle',
+ translation: [titleX, titleY],
+ });
+ }
+ draw(chartArea) {
+ if (!this._isVisible()) {
+ return;
+ }
+ this.drawBackground();
+ this.drawGrid(chartArea);
+ this.drawBorder();
+ this.drawTitle();
+ this.drawLabels(chartArea);
+ }
+ _layers() {
+ const opts = this.options;
+ const tz = opts.ticks && opts.ticks.z || 0;
+ const gz = valueOrDefault(opts.grid && opts.grid.z, -1);
+ if (!this._isVisible() || this.draw !== Scale.prototype.draw) {
+ return [{
+ z: tz,
+ draw: (chartArea) => {
+ this.draw(chartArea);
+ }
+ }];
+ }
+ return [{
+ z: gz,
+ draw: (chartArea) => {
+ this.drawBackground();
+ this.drawGrid(chartArea);
+ this.drawTitle();
+ }
+ }, {
+ z: gz + 1,
+ draw: () => {
+ this.drawBorder();
+ }
+ }, {
+ z: tz,
+ draw: (chartArea) => {
+ this.drawLabels(chartArea);
+ }
+ }];
+ }
+ getMatchingVisibleMetas(type) {
+ const metas = this.chart.getSortedVisibleDatasetMetas();
+ const axisID = this.axis + 'AxisID';
+ const result = [];
+ let i, ilen;
+ for (i = 0, ilen = metas.length; i < ilen; ++i) {
+ const meta = metas[i];
+ if (meta[axisID] === this.id && (!type || meta.type === type)) {
+ result.push(meta);
+ }
+ }
+ return result;
+ }
+ _resolveTickFontOptions(index) {
+ const opts = this.options.ticks.setContext(this.getContext(index));
+ return toFont(opts.font);
+ }
+ _maxDigits() {
+ const fontSize = this._resolveTickFontOptions(0).lineHeight;
+ return (this.isHorizontal() ? this.width : this.height) / fontSize;
+ }
+}
+
+class TypedRegistry {
+ constructor(type, scope, override) {
+ this.type = type;
+ this.scope = scope;
+ this.override = override;
+ this.items = Object.create(null);
+ }
+ isForType(type) {
+ return Object.prototype.isPrototypeOf.call(this.type.prototype, type.prototype);
+ }
+ register(item) {
+ const proto = Object.getPrototypeOf(item);
+ let parentScope;
+ if (isIChartComponent(proto)) {
+ parentScope = this.register(proto);
+ }
+ const items = this.items;
+ const id = item.id;
+ const scope = this.scope + '.' + id;
+ if (!id) {
+ throw new Error('class does not have id: ' + item);
+ }
+ if (id in items) {
+ return scope;
+ }
+ items[id] = item;
+ registerDefaults(item, scope, parentScope);
+ if (this.override) {
+ defaults.override(item.id, item.overrides);
+ }
+ return scope;
+ }
+ get(id) {
+ return this.items[id];
+ }
+ unregister(item) {
+ const items = this.items;
+ const id = item.id;
+ const scope = this.scope;
+ if (id in items) {
+ delete items[id];
+ }
+ if (scope && id in defaults[scope]) {
+ delete defaults[scope][id];
+ if (this.override) {
+ delete overrides[id];
+ }
+ }
+ }
+}
+function registerDefaults(item, scope, parentScope) {
+ const itemDefaults = merge(Object.create(null), [
+ parentScope ? defaults.get(parentScope) : {},
+ defaults.get(scope),
+ item.defaults
+ ]);
+ defaults.set(scope, itemDefaults);
+ if (item.defaultRoutes) {
+ routeDefaults(scope, item.defaultRoutes);
+ }
+ if (item.descriptors) {
+ defaults.describe(scope, item.descriptors);
+ }
+}
+function routeDefaults(scope, routes) {
+ Object.keys(routes).forEach(property => {
+ const propertyParts = property.split('.');
+ const sourceName = propertyParts.pop();
+ const sourceScope = [scope].concat(propertyParts).join('.');
+ const parts = routes[property].split('.');
+ const targetName = parts.pop();
+ const targetScope = parts.join('.');
+ defaults.route(sourceScope, sourceName, targetScope, targetName);
+ });
+}
+function isIChartComponent(proto) {
+ return 'id' in proto && 'defaults' in proto;
+}
+
+class Registry {
+ constructor() {
+ this.controllers = new TypedRegistry(DatasetController, 'datasets', true);
+ this.elements = new TypedRegistry(Element, 'elements');
+ this.plugins = new TypedRegistry(Object, 'plugins');
+ this.scales = new TypedRegistry(Scale, 'scales');
+ this._typedRegistries = [this.controllers, this.scales, this.elements];
+ }
+ add(...args) {
+ this._each('register', args);
+ }
+ remove(...args) {
+ this._each('unregister', args);
+ }
+ addControllers(...args) {
+ this._each('register', args, this.controllers);
+ }
+ addElements(...args) {
+ this._each('register', args, this.elements);
+ }
+ addPlugins(...args) {
+ this._each('register', args, this.plugins);
+ }
+ addScales(...args) {
+ this._each('register', args, this.scales);
+ }
+ getController(id) {
+ return this._get(id, this.controllers, 'controller');
+ }
+ getElement(id) {
+ return this._get(id, this.elements, 'element');
+ }
+ getPlugin(id) {
+ return this._get(id, this.plugins, 'plugin');
+ }
+ getScale(id) {
+ return this._get(id, this.scales, 'scale');
+ }
+ removeControllers(...args) {
+ this._each('unregister', args, this.controllers);
+ }
+ removeElements(...args) {
+ this._each('unregister', args, this.elements);
+ }
+ removePlugins(...args) {
+ this._each('unregister', args, this.plugins);
+ }
+ removeScales(...args) {
+ this._each('unregister', args, this.scales);
+ }
+ _each(method, args, typedRegistry) {
+ [...args].forEach(arg => {
+ const reg = typedRegistry || this._getRegistryForType(arg);
+ if (typedRegistry || reg.isForType(arg) || (reg === this.plugins && arg.id)) {
+ this._exec(method, reg, arg);
+ } else {
+ each(arg, item => {
+ const itemReg = typedRegistry || this._getRegistryForType(item);
+ this._exec(method, itemReg, item);
+ });
+ }
+ });
+ }
+ _exec(method, registry, component) {
+ const camelMethod = _capitalize(method);
+ callback(component['before' + camelMethod], [], component);
+ registry[method](component);
+ callback(component['after' + camelMethod], [], component);
+ }
+ _getRegistryForType(type) {
+ for (let i = 0; i < this._typedRegistries.length; i++) {
+ const reg = this._typedRegistries[i];
+ if (reg.isForType(type)) {
+ return reg;
+ }
+ }
+ return this.plugins;
+ }
+ _get(id, typedRegistry, type) {
+ const item = typedRegistry.get(id);
+ if (item === undefined) {
+ throw new Error('"' + id + '" is not a registered ' + type + '.');
+ }
+ return item;
+ }
+}
+var registry = new Registry();
+
+class PluginService {
+ constructor() {
+ this._init = [];
+ }
+ notify(chart, hook, args, filter) {
+ if (hook === 'beforeInit') {
+ this._init = this._createDescriptors(chart, true);
+ this._notify(this._init, chart, 'install');
+ }
+ const descriptors = filter ? this._descriptors(chart).filter(filter) : this._descriptors(chart);
+ const result = this._notify(descriptors, chart, hook, args);
+ if (hook === 'afterDestroy') {
+ this._notify(descriptors, chart, 'stop');
+ this._notify(this._init, chart, 'uninstall');
+ }
+ return result;
+ }
+ _notify(descriptors, chart, hook, args) {
+ args = args || {};
+ for (const descriptor of descriptors) {
+ const plugin = descriptor.plugin;
+ const method = plugin[hook];
+ const params = [chart, args, descriptor.options];
+ if (callback(method, params, plugin) === false && args.cancelable) {
+ return false;
+ }
+ }
+ return true;
+ }
+ invalidate() {
+ if (!isNullOrUndef(this._cache)) {
+ this._oldCache = this._cache;
+ this._cache = undefined;
+ }
+ }
+ _descriptors(chart) {
+ if (this._cache) {
+ return this._cache;
+ }
+ const descriptors = this._cache = this._createDescriptors(chart);
+ this._notifyStateChanges(chart);
+ return descriptors;
+ }
+ _createDescriptors(chart, all) {
+ const config = chart && chart.config;
+ const options = valueOrDefault(config.options && config.options.plugins, {});
+ const plugins = allPlugins(config);
+ return options === false && !all ? [] : createDescriptors(chart, plugins, options, all);
+ }
+ _notifyStateChanges(chart) {
+ const previousDescriptors = this._oldCache || [];
+ const descriptors = this._cache;
+ const diff = (a, b) => a.filter(x => !b.some(y => x.plugin.id === y.plugin.id));
+ this._notify(diff(previousDescriptors, descriptors), chart, 'stop');
+ this._notify(diff(descriptors, previousDescriptors), chart, 'start');
+ }
+}
+function allPlugins(config) {
+ const plugins = [];
+ const keys = Object.keys(registry.plugins.items);
+ for (let i = 0; i < keys.length; i++) {
+ plugins.push(registry.getPlugin(keys[i]));
+ }
+ const local = config.plugins || [];
+ for (let i = 0; i < local.length; i++) {
+ const plugin = local[i];
+ if (plugins.indexOf(plugin) === -1) {
+ plugins.push(plugin);
+ }
+ }
+ return plugins;
+}
+function getOpts(options, all) {
+ if (!all && options === false) {
+ return null;
+ }
+ if (options === true) {
+ return {};
+ }
+ return options;
+}
+function createDescriptors(chart, plugins, options, all) {
+ const result = [];
+ const context = chart.getContext();
+ for (let i = 0; i < plugins.length; i++) {
+ const plugin = plugins[i];
+ const id = plugin.id;
+ const opts = getOpts(options[id], all);
+ if (opts === null) {
+ continue;
+ }
+ result.push({
+ plugin,
+ options: pluginOpts(chart.config, plugin, opts, context)
+ });
+ }
+ return result;
+}
+function pluginOpts(config, plugin, opts, context) {
+ const keys = config.pluginScopeKeys(plugin);
+ const scopes = config.getOptionScopes(opts, keys);
+ return config.createResolver(scopes, context, [''], {scriptable: false, indexable: false, allKeys: true});
+}
+
+function getIndexAxis(type, options) {
+ const datasetDefaults = defaults.datasets[type] || {};
+ const datasetOptions = (options.datasets || {})[type] || {};
+ return datasetOptions.indexAxis || options.indexAxis || datasetDefaults.indexAxis || 'x';
+}
+function getAxisFromDefaultScaleID(id, indexAxis) {
+ let axis = id;
+ if (id === '_index_') {
+ axis = indexAxis;
+ } else if (id === '_value_') {
+ axis = indexAxis === 'x' ? 'y' : 'x';
+ }
+ return axis;
+}
+function getDefaultScaleIDFromAxis(axis, indexAxis) {
+ return axis === indexAxis ? '_index_' : '_value_';
+}
+function axisFromPosition(position) {
+ if (position === 'top' || position === 'bottom') {
+ return 'x';
+ }
+ if (position === 'left' || position === 'right') {
+ return 'y';
+ }
+}
+function determineAxis(id, scaleOptions) {
+ if (id === 'x' || id === 'y') {
+ return id;
+ }
+ return scaleOptions.axis || axisFromPosition(scaleOptions.position) || id.charAt(0).toLowerCase();
+}
+function mergeScaleConfig(config, options) {
+ const chartDefaults = overrides[config.type] || {scales: {}};
+ const configScales = options.scales || {};
+ const chartIndexAxis = getIndexAxis(config.type, options);
+ const firstIDs = Object.create(null);
+ const scales = Object.create(null);
+ Object.keys(configScales).forEach(id => {
+ const scaleConf = configScales[id];
+ if (!isObject(scaleConf)) {
+ return console.error(`Invalid scale configuration for scale: ${id}`);
+ }
+ if (scaleConf._proxy) {
+ return console.warn(`Ignoring resolver passed as options for scale: ${id}`);
+ }
+ const axis = determineAxis(id, scaleConf);
+ const defaultId = getDefaultScaleIDFromAxis(axis, chartIndexAxis);
+ const defaultScaleOptions = chartDefaults.scales || {};
+ firstIDs[axis] = firstIDs[axis] || id;
+ scales[id] = mergeIf(Object.create(null), [{axis}, scaleConf, defaultScaleOptions[axis], defaultScaleOptions[defaultId]]);
+ });
+ config.data.datasets.forEach(dataset => {
+ const type = dataset.type || config.type;
+ const indexAxis = dataset.indexAxis || getIndexAxis(type, options);
+ const datasetDefaults = overrides[type] || {};
+ const defaultScaleOptions = datasetDefaults.scales || {};
+ Object.keys(defaultScaleOptions).forEach(defaultID => {
+ const axis = getAxisFromDefaultScaleID(defaultID, indexAxis);
+ const id = dataset[axis + 'AxisID'] || firstIDs[axis] || axis;
+ scales[id] = scales[id] || Object.create(null);
+ mergeIf(scales[id], [{axis}, configScales[id], defaultScaleOptions[defaultID]]);
+ });
+ });
+ Object.keys(scales).forEach(key => {
+ const scale = scales[key];
+ mergeIf(scale, [defaults.scales[scale.type], defaults.scale]);
+ });
+ return scales;
+}
+function initOptions(config) {
+ const options = config.options || (config.options = {});
+ options.plugins = valueOrDefault(options.plugins, {});
+ options.scales = mergeScaleConfig(config, options);
+}
+function initData(data) {
+ data = data || {};
+ data.datasets = data.datasets || [];
+ data.labels = data.labels || [];
+ return data;
+}
+function initConfig(config) {
+ config = config || {};
+ config.data = initData(config.data);
+ initOptions(config);
+ return config;
+}
+const keyCache = new Map();
+const keysCached = new Set();
+function cachedKeys(cacheKey, generate) {
+ let keys = keyCache.get(cacheKey);
+ if (!keys) {
+ keys = generate();
+ keyCache.set(cacheKey, keys);
+ keysCached.add(keys);
+ }
+ return keys;
+}
+const addIfFound = (set, obj, key) => {
+ const opts = resolveObjectKey(obj, key);
+ if (opts !== undefined) {
+ set.add(opts);
+ }
+};
+class Config {
+ constructor(config) {
+ this._config = initConfig(config);
+ this._scopeCache = new Map();
+ this._resolverCache = new Map();
+ }
+ get platform() {
+ return this._config.platform;
+ }
+ get type() {
+ return this._config.type;
+ }
+ set type(type) {
+ this._config.type = type;
+ }
+ get data() {
+ return this._config.data;
+ }
+ set data(data) {
+ this._config.data = initData(data);
+ }
+ get options() {
+ return this._config.options;
+ }
+ set options(options) {
+ this._config.options = options;
+ }
+ get plugins() {
+ return this._config.plugins;
+ }
+ update() {
+ const config = this._config;
+ this.clearCache();
+ initOptions(config);
+ }
+ clearCache() {
+ this._scopeCache.clear();
+ this._resolverCache.clear();
+ }
+ datasetScopeKeys(datasetType) {
+ return cachedKeys(datasetType,
+ () => [[
+ `datasets.${datasetType}`,
+ ''
+ ]]);
+ }
+ datasetAnimationScopeKeys(datasetType, transition) {
+ return cachedKeys(`${datasetType}.transition.${transition}`,
+ () => [
+ [
+ `datasets.${datasetType}.transitions.${transition}`,
+ `transitions.${transition}`,
+ ],
+ [
+ `datasets.${datasetType}`,
+ ''
+ ]
+ ]);
+ }
+ datasetElementScopeKeys(datasetType, elementType) {
+ return cachedKeys(`${datasetType}-${elementType}`,
+ () => [[
+ `datasets.${datasetType}.elements.${elementType}`,
+ `datasets.${datasetType}`,
+ `elements.${elementType}`,
+ ''
+ ]]);
+ }
+ pluginScopeKeys(plugin) {
+ const id = plugin.id;
+ const type = this.type;
+ return cachedKeys(`${type}-plugin-${id}`,
+ () => [[
+ `plugins.${id}`,
+ ...plugin.additionalOptionScopes || [],
+ ]]);
+ }
+ _cachedScopes(mainScope, resetCache) {
+ const _scopeCache = this._scopeCache;
+ let cache = _scopeCache.get(mainScope);
+ if (!cache || resetCache) {
+ cache = new Map();
+ _scopeCache.set(mainScope, cache);
+ }
+ return cache;
+ }
+ getOptionScopes(mainScope, keyLists, resetCache) {
+ const {options, type} = this;
+ const cache = this._cachedScopes(mainScope, resetCache);
+ const cached = cache.get(keyLists);
+ if (cached) {
+ return cached;
+ }
+ const scopes = new Set();
+ keyLists.forEach(keys => {
+ if (mainScope) {
+ scopes.add(mainScope);
+ keys.forEach(key => addIfFound(scopes, mainScope, key));
+ }
+ keys.forEach(key => addIfFound(scopes, options, key));
+ keys.forEach(key => addIfFound(scopes, overrides[type] || {}, key));
+ keys.forEach(key => addIfFound(scopes, defaults, key));
+ keys.forEach(key => addIfFound(scopes, descriptors, key));
+ });
+ const array = Array.from(scopes);
+ if (array.length === 0) {
+ array.push(Object.create(null));
+ }
+ if (keysCached.has(keyLists)) {
+ cache.set(keyLists, array);
+ }
+ return array;
+ }
+ chartOptionScopes() {
+ const {options, type} = this;
+ return [
+ options,
+ overrides[type] || {},
+ defaults.datasets[type] || {},
+ {type},
+ defaults,
+ descriptors
+ ];
+ }
+ resolveNamedOptions(scopes, names, context, prefixes = ['']) {
+ const result = {$shared: true};
+ const {resolver, subPrefixes} = getResolver(this._resolverCache, scopes, prefixes);
+ let options = resolver;
+ if (needContext(resolver, names)) {
+ result.$shared = false;
+ context = isFunction(context) ? context() : context;
+ const subResolver = this.createResolver(scopes, context, subPrefixes);
+ options = _attachContext(resolver, context, subResolver);
+ }
+ for (const prop of names) {
+ result[prop] = options[prop];
+ }
+ return result;
+ }
+ createResolver(scopes, context, prefixes = [''], descriptorDefaults) {
+ const {resolver} = getResolver(this._resolverCache, scopes, prefixes);
+ return isObject(context)
+ ? _attachContext(resolver, context, undefined, descriptorDefaults)
+ : resolver;
+ }
+}
+function getResolver(resolverCache, scopes, prefixes) {
+ let cache = resolverCache.get(scopes);
+ if (!cache) {
+ cache = new Map();
+ resolverCache.set(scopes, cache);
+ }
+ const cacheKey = prefixes.join();
+ let cached = cache.get(cacheKey);
+ if (!cached) {
+ const resolver = _createResolver(scopes, prefixes);
+ cached = {
+ resolver,
+ subPrefixes: prefixes.filter(p => !p.toLowerCase().includes('hover'))
+ };
+ cache.set(cacheKey, cached);
+ }
+ return cached;
+}
+const hasFunction = value => isObject(value)
+ && Object.getOwnPropertyNames(value).reduce((acc, key) => acc || isFunction(value[key]), false);
+function needContext(proxy, names) {
+ const {isScriptable, isIndexable} = _descriptors(proxy);
+ for (const prop of names) {
+ const scriptable = isScriptable(prop);
+ const indexable = isIndexable(prop);
+ const value = (indexable || scriptable) && proxy[prop];
+ if ((scriptable && (isFunction(value) || hasFunction(value)))
+ || (indexable && isArray(value))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+var version = "3.7.1";
+
+const KNOWN_POSITIONS = ['top', 'bottom', 'left', 'right', 'chartArea'];
+function positionIsHorizontal(position, axis) {
+ return position === 'top' || position === 'bottom' || (KNOWN_POSITIONS.indexOf(position) === -1 && axis === 'x');
+}
+function compare2Level(l1, l2) {
+ return function(a, b) {
+ return a[l1] === b[l1]
+ ? a[l2] - b[l2]
+ : a[l1] - b[l1];
+ };
+}
+function onAnimationsComplete(context) {
+ const chart = context.chart;
+ const animationOptions = chart.options.animation;
+ chart.notifyPlugins('afterRender');
+ callback(animationOptions && animationOptions.onComplete, [context], chart);
+}
+function onAnimationProgress(context) {
+ const chart = context.chart;
+ const animationOptions = chart.options.animation;
+ callback(animationOptions && animationOptions.onProgress, [context], chart);
+}
+function getCanvas(item) {
+ if (_isDomSupported() && typeof item === 'string') {
+ item = document.getElementById(item);
+ } else if (item && item.length) {
+ item = item[0];
+ }
+ if (item && item.canvas) {
+ item = item.canvas;
+ }
+ return item;
+}
+const instances = {};
+const getChart = (key) => {
+ const canvas = getCanvas(key);
+ return Object.values(instances).filter((c) => c.canvas === canvas).pop();
+};
+function moveNumericKeys(obj, start, move) {
+ const keys = Object.keys(obj);
+ for (const key of keys) {
+ const intKey = +key;
+ if (intKey >= start) {
+ const value = obj[key];
+ delete obj[key];
+ if (move > 0 || intKey > start) {
+ obj[intKey + move] = value;
+ }
+ }
+ }
+}
+function determineLastEvent(e, lastEvent, inChartArea, isClick) {
+ if (!inChartArea || e.type === 'mouseout') {
+ return null;
+ }
+ if (isClick) {
+ return lastEvent;
+ }
+ return e;
+}
+class Chart {
+ constructor(item, userConfig) {
+ const config = this.config = new Config(userConfig);
+ const initialCanvas = getCanvas(item);
+ const existingChart = getChart(initialCanvas);
+ if (existingChart) {
+ throw new Error(
+ 'Canvas is already in use. Chart with ID \'' + existingChart.id + '\'' +
+ ' must be destroyed before the canvas can be reused.'
+ );
+ }
+ const options = config.createResolver(config.chartOptionScopes(), this.getContext());
+ this.platform = new (config.platform || _detectPlatform(initialCanvas))();
+ this.platform.updateConfig(config);
+ const context = this.platform.acquireContext(initialCanvas, options.aspectRatio);
+ const canvas = context && context.canvas;
+ const height = canvas && canvas.height;
+ const width = canvas && canvas.width;
+ this.id = uid();
+ this.ctx = context;
+ this.canvas = canvas;
+ this.width = width;
+ this.height = height;
+ this._options = options;
+ this._aspectRatio = this.aspectRatio;
+ this._layers = [];
+ this._metasets = [];
+ this._stacks = undefined;
+ this.boxes = [];
+ this.currentDevicePixelRatio = undefined;
+ this.chartArea = undefined;
+ this._active = [];
+ this._lastEvent = undefined;
+ this._listeners = {};
+ this._responsiveListeners = undefined;
+ this._sortedMetasets = [];
+ this.scales = {};
+ this._plugins = new PluginService();
+ this.$proxies = {};
+ this._hiddenIndices = {};
+ this.attached = false;
+ this._animationsDisabled = undefined;
+ this.$context = undefined;
+ this._doResize = debounce(mode => this.update(mode), options.resizeDelay || 0);
+ this._dataChanges = [];
+ instances[this.id] = this;
+ if (!context || !canvas) {
+ console.error("Failed to create chart: can't acquire context from the given item");
+ return;
+ }
+ animator.listen(this, 'complete', onAnimationsComplete);
+ animator.listen(this, 'progress', onAnimationProgress);
+ this._initialize();
+ if (this.attached) {
+ this.update();
+ }
+ }
+ get aspectRatio() {
+ const {options: {aspectRatio, maintainAspectRatio}, width, height, _aspectRatio} = this;
+ if (!isNullOrUndef(aspectRatio)) {
+ return aspectRatio;
+ }
+ if (maintainAspectRatio && _aspectRatio) {
+ return _aspectRatio;
+ }
+ return height ? width / height : null;
+ }
+ get data() {
+ return this.config.data;
+ }
+ set data(data) {
+ this.config.data = data;
+ }
+ get options() {
+ return this._options;
+ }
+ set options(options) {
+ this.config.options = options;
+ }
+ _initialize() {
+ this.notifyPlugins('beforeInit');
+ if (this.options.responsive) {
+ this.resize();
+ } else {
+ retinaScale(this, this.options.devicePixelRatio);
+ }
+ this.bindEvents();
+ this.notifyPlugins('afterInit');
+ return this;
+ }
+ clear() {
+ clearCanvas(this.canvas, this.ctx);
+ return this;
+ }
+ stop() {
+ animator.stop(this);
+ return this;
+ }
+ resize(width, height) {
+ if (!animator.running(this)) {
+ this._resize(width, height);
+ } else {
+ this._resizeBeforeDraw = {width, height};
+ }
+ }
+ _resize(width, height) {
+ const options = this.options;
+ const canvas = this.canvas;
+ const aspectRatio = options.maintainAspectRatio && this.aspectRatio;
+ const newSize = this.platform.getMaximumSize(canvas, width, height, aspectRatio);
+ const newRatio = options.devicePixelRatio || this.platform.getDevicePixelRatio();
+ const mode = this.width ? 'resize' : 'attach';
+ this.width = newSize.width;
+ this.height = newSize.height;
+ this._aspectRatio = this.aspectRatio;
+ if (!retinaScale(this, newRatio, true)) {
+ return;
+ }
+ this.notifyPlugins('resize', {size: newSize});
+ callback(options.onResize, [this, newSize], this);
+ if (this.attached) {
+ if (this._doResize(mode)) {
+ this.render();
+ }
+ }
+ }
+ ensureScalesHaveIDs() {
+ const options = this.options;
+ const scalesOptions = options.scales || {};
+ each(scalesOptions, (axisOptions, axisID) => {
+ axisOptions.id = axisID;
+ });
+ }
+ buildOrUpdateScales() {
+ const options = this.options;
+ const scaleOpts = options.scales;
+ const scales = this.scales;
+ const updated = Object.keys(scales).reduce((obj, id) => {
+ obj[id] = false;
+ return obj;
+ }, {});
+ let items = [];
+ if (scaleOpts) {
+ items = items.concat(
+ Object.keys(scaleOpts).map((id) => {
+ const scaleOptions = scaleOpts[id];
+ const axis = determineAxis(id, scaleOptions);
+ const isRadial = axis === 'r';
+ const isHorizontal = axis === 'x';
+ return {
+ options: scaleOptions,
+ dposition: isRadial ? 'chartArea' : isHorizontal ? 'bottom' : 'left',
+ dtype: isRadial ? 'radialLinear' : isHorizontal ? 'category' : 'linear'
+ };
+ })
+ );
+ }
+ each(items, (item) => {
+ const scaleOptions = item.options;
+ const id = scaleOptions.id;
+ const axis = determineAxis(id, scaleOptions);
+ const scaleType = valueOrDefault(scaleOptions.type, item.dtype);
+ if (scaleOptions.position === undefined || positionIsHorizontal(scaleOptions.position, axis) !== positionIsHorizontal(item.dposition)) {
+ scaleOptions.position = item.dposition;
+ }
+ updated[id] = true;
+ let scale = null;
+ if (id in scales && scales[id].type === scaleType) {
+ scale = scales[id];
+ } else {
+ const scaleClass = registry.getScale(scaleType);
+ scale = new scaleClass({
+ id,
+ type: scaleType,
+ ctx: this.ctx,
+ chart: this
+ });
+ scales[scale.id] = scale;
+ }
+ scale.init(scaleOptions, options);
+ });
+ each(updated, (hasUpdated, id) => {
+ if (!hasUpdated) {
+ delete scales[id];
+ }
+ });
+ each(scales, (scale) => {
+ layouts.configure(this, scale, scale.options);
+ layouts.addBox(this, scale);
+ });
+ }
+ _updateMetasets() {
+ const metasets = this._metasets;
+ const numData = this.data.datasets.length;
+ const numMeta = metasets.length;
+ metasets.sort((a, b) => a.index - b.index);
+ if (numMeta > numData) {
+ for (let i = numData; i < numMeta; ++i) {
+ this._destroyDatasetMeta(i);
+ }
+ metasets.splice(numData, numMeta - numData);
+ }
+ this._sortedMetasets = metasets.slice(0).sort(compare2Level('order', 'index'));
+ }
+ _removeUnreferencedMetasets() {
+ const {_metasets: metasets, data: {datasets}} = this;
+ if (metasets.length > datasets.length) {
+ delete this._stacks;
+ }
+ metasets.forEach((meta, index) => {
+ if (datasets.filter(x => x === meta._dataset).length === 0) {
+ this._destroyDatasetMeta(index);
+ }
+ });
+ }
+ buildOrUpdateControllers() {
+ const newControllers = [];
+ const datasets = this.data.datasets;
+ let i, ilen;
+ this._removeUnreferencedMetasets();
+ for (i = 0, ilen = datasets.length; i < ilen; i++) {
+ const dataset = datasets[i];
+ let meta = this.getDatasetMeta(i);
+ const type = dataset.type || this.config.type;
+ if (meta.type && meta.type !== type) {
+ this._destroyDatasetMeta(i);
+ meta = this.getDatasetMeta(i);
+ }
+ meta.type = type;
+ meta.indexAxis = dataset.indexAxis || getIndexAxis(type, this.options);
+ meta.order = dataset.order || 0;
+ meta.index = i;
+ meta.label = '' + dataset.label;
+ meta.visible = this.isDatasetVisible(i);
+ if (meta.controller) {
+ meta.controller.updateIndex(i);
+ meta.controller.linkScales();
+ } else {
+ const ControllerClass = registry.getController(type);
+ const {datasetElementType, dataElementType} = defaults.datasets[type];
+ Object.assign(ControllerClass.prototype, {
+ dataElementType: registry.getElement(dataElementType),
+ datasetElementType: datasetElementType && registry.getElement(datasetElementType)
+ });
+ meta.controller = new ControllerClass(this, i);
+ newControllers.push(meta.controller);
+ }
+ }
+ this._updateMetasets();
+ return newControllers;
+ }
+ _resetElements() {
+ each(this.data.datasets, (dataset, datasetIndex) => {
+ this.getDatasetMeta(datasetIndex).controller.reset();
+ }, this);
+ }
+ reset() {
+ this._resetElements();
+ this.notifyPlugins('reset');
+ }
+ update(mode) {
+ const config = this.config;
+ config.update();
+ const options = this._options = config.createResolver(config.chartOptionScopes(), this.getContext());
+ const animsDisabled = this._animationsDisabled = !options.animation;
+ this._updateScales();
+ this._checkEventBindings();
+ this._updateHiddenIndices();
+ this._plugins.invalidate();
+ if (this.notifyPlugins('beforeUpdate', {mode, cancelable: true}) === false) {
+ return;
+ }
+ const newControllers = this.buildOrUpdateControllers();
+ this.notifyPlugins('beforeElementsUpdate');
+ let minPadding = 0;
+ for (let i = 0, ilen = this.data.datasets.length; i < ilen; i++) {
+ const {controller} = this.getDatasetMeta(i);
+ const reset = !animsDisabled && newControllers.indexOf(controller) === -1;
+ controller.buildOrUpdateElements(reset);
+ minPadding = Math.max(+controller.getMaxOverflow(), minPadding);
+ }
+ minPadding = this._minPadding = options.layout.autoPadding ? minPadding : 0;
+ this._updateLayout(minPadding);
+ if (!animsDisabled) {
+ each(newControllers, (controller) => {
+ controller.reset();
+ });
+ }
+ this._updateDatasets(mode);
+ this.notifyPlugins('afterUpdate', {mode});
+ this._layers.sort(compare2Level('z', '_idx'));
+ const {_active, _lastEvent} = this;
+ if (_lastEvent) {
+ this._eventHandler(_lastEvent, true);
+ } else if (_active.length) {
+ this._updateHoverStyles(_active, _active, true);
+ }
+ this.render();
+ }
+ _updateScales() {
+ each(this.scales, (scale) => {
+ layouts.removeBox(this, scale);
+ });
+ this.ensureScalesHaveIDs();
+ this.buildOrUpdateScales();
+ }
+ _checkEventBindings() {
+ const options = this.options;
+ const existingEvents = new Set(Object.keys(this._listeners));
+ const newEvents = new Set(options.events);
+ if (!setsEqual(existingEvents, newEvents) || !!this._responsiveListeners !== options.responsive) {
+ this.unbindEvents();
+ this.bindEvents();
+ }
+ }
+ _updateHiddenIndices() {
+ const {_hiddenIndices} = this;
+ const changes = this._getUniformDataChanges() || [];
+ for (const {method, start, count} of changes) {
+ const move = method === '_removeElements' ? -count : count;
+ moveNumericKeys(_hiddenIndices, start, move);
+ }
+ }
+ _getUniformDataChanges() {
+ const _dataChanges = this._dataChanges;
+ if (!_dataChanges || !_dataChanges.length) {
+ return;
+ }
+ this._dataChanges = [];
+ const datasetCount = this.data.datasets.length;
+ const makeSet = (idx) => new Set(
+ _dataChanges
+ .filter(c => c[0] === idx)
+ .map((c, i) => i + ',' + c.splice(1).join(','))
+ );
+ const changeSet = makeSet(0);
+ for (let i = 1; i < datasetCount; i++) {
+ if (!setsEqual(changeSet, makeSet(i))) {
+ return;
+ }
+ }
+ return Array.from(changeSet)
+ .map(c => c.split(','))
+ .map(a => ({method: a[1], start: +a[2], count: +a[3]}));
+ }
+ _updateLayout(minPadding) {
+ if (this.notifyPlugins('beforeLayout', {cancelable: true}) === false) {
+ return;
+ }
+ layouts.update(this, this.width, this.height, minPadding);
+ const area = this.chartArea;
+ const noArea = area.width <= 0 || area.height <= 0;
+ this._layers = [];
+ each(this.boxes, (box) => {
+ if (noArea && box.position === 'chartArea') {
+ return;
+ }
+ if (box.configure) {
+ box.configure();
+ }
+ this._layers.push(...box._layers());
+ }, this);
+ this._layers.forEach((item, index) => {
+ item._idx = index;
+ });
+ this.notifyPlugins('afterLayout');
+ }
+ _updateDatasets(mode) {
+ if (this.notifyPlugins('beforeDatasetsUpdate', {mode, cancelable: true}) === false) {
+ return;
+ }
+ for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
+ this.getDatasetMeta(i).controller.configure();
+ }
+ for (let i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
+ this._updateDataset(i, isFunction(mode) ? mode({datasetIndex: i}) : mode);
+ }
+ this.notifyPlugins('afterDatasetsUpdate', {mode});
+ }
+ _updateDataset(index, mode) {
+ const meta = this.getDatasetMeta(index);
+ const args = {meta, index, mode, cancelable: true};
+ if (this.notifyPlugins('beforeDatasetUpdate', args) === false) {
+ return;
+ }
+ meta.controller._update(mode);
+ args.cancelable = false;
+ this.notifyPlugins('afterDatasetUpdate', args);
+ }
+ render() {
+ if (this.notifyPlugins('beforeRender', {cancelable: true}) === false) {
+ return;
+ }
+ if (animator.has(this)) {
+ if (this.attached && !animator.running(this)) {
+ animator.start(this);
+ }
+ } else {
+ this.draw();
+ onAnimationsComplete({chart: this});
+ }
+ }
+ draw() {
+ let i;
+ if (this._resizeBeforeDraw) {
+ const {width, height} = this._resizeBeforeDraw;
+ this._resize(width, height);
+ this._resizeBeforeDraw = null;
+ }
+ this.clear();
+ if (this.width <= 0 || this.height <= 0) {
+ return;
+ }
+ if (this.notifyPlugins('beforeDraw', {cancelable: true}) === false) {
+ return;
+ }
+ const layers = this._layers;
+ for (i = 0; i < layers.length && layers[i].z <= 0; ++i) {
+ layers[i].draw(this.chartArea);
+ }
+ this._drawDatasets();
+ for (; i < layers.length; ++i) {
+ layers[i].draw(this.chartArea);
+ }
+ this.notifyPlugins('afterDraw');
+ }
+ _getSortedDatasetMetas(filterVisible) {
+ const metasets = this._sortedMetasets;
+ const result = [];
+ let i, ilen;
+ for (i = 0, ilen = metasets.length; i < ilen; ++i) {
+ const meta = metasets[i];
+ if (!filterVisible || meta.visible) {
+ result.push(meta);
+ }
+ }
+ return result;
+ }
+ getSortedVisibleDatasetMetas() {
+ return this._getSortedDatasetMetas(true);
+ }
+ _drawDatasets() {
+ if (this.notifyPlugins('beforeDatasetsDraw', {cancelable: true}) === false) {
+ return;
+ }
+ const metasets = this.getSortedVisibleDatasetMetas();
+ for (let i = metasets.length - 1; i >= 0; --i) {
+ this._drawDataset(metasets[i]);
+ }
+ this.notifyPlugins('afterDatasetsDraw');
+ }
+ _drawDataset(meta) {
+ const ctx = this.ctx;
+ const clip = meta._clip;
+ const useClip = !clip.disabled;
+ const area = this.chartArea;
+ const args = {
+ meta,
+ index: meta.index,
+ cancelable: true
+ };
+ if (this.notifyPlugins('beforeDatasetDraw', args) === false) {
+ return;
+ }
+ if (useClip) {
+ clipArea(ctx, {
+ left: clip.left === false ? 0 : area.left - clip.left,
+ right: clip.right === false ? this.width : area.right + clip.right,
+ top: clip.top === false ? 0 : area.top - clip.top,
+ bottom: clip.bottom === false ? this.height : area.bottom + clip.bottom
+ });
+ }
+ meta.controller.draw();
+ if (useClip) {
+ unclipArea(ctx);
+ }
+ args.cancelable = false;
+ this.notifyPlugins('afterDatasetDraw', args);
+ }
+ getElementsAtEventForMode(e, mode, options, useFinalPosition) {
+ const method = Interaction.modes[mode];
+ if (typeof method === 'function') {
+ return method(this, e, options, useFinalPosition);
+ }
+ return [];
+ }
+ getDatasetMeta(datasetIndex) {
+ const dataset = this.data.datasets[datasetIndex];
+ const metasets = this._metasets;
+ let meta = metasets.filter(x => x && x._dataset === dataset).pop();
+ if (!meta) {
+ meta = {
+ type: null,
+ data: [],
+ dataset: null,
+ controller: null,
+ hidden: null,
+ xAxisID: null,
+ yAxisID: null,
+ order: dataset && dataset.order || 0,
+ index: datasetIndex,
+ _dataset: dataset,
+ _parsed: [],
+ _sorted: false
+ };
+ metasets.push(meta);
+ }
+ return meta;
+ }
+ getContext() {
+ return this.$context || (this.$context = createContext(null, {chart: this, type: 'chart'}));
+ }
+ getVisibleDatasetCount() {
+ return this.getSortedVisibleDatasetMetas().length;
+ }
+ isDatasetVisible(datasetIndex) {
+ const dataset = this.data.datasets[datasetIndex];
+ if (!dataset) {
+ return false;
+ }
+ const meta = this.getDatasetMeta(datasetIndex);
+ return typeof meta.hidden === 'boolean' ? !meta.hidden : !dataset.hidden;
+ }
+ setDatasetVisibility(datasetIndex, visible) {
+ const meta = this.getDatasetMeta(datasetIndex);
+ meta.hidden = !visible;
+ }
+ toggleDataVisibility(index) {
+ this._hiddenIndices[index] = !this._hiddenIndices[index];
+ }
+ getDataVisibility(index) {
+ return !this._hiddenIndices[index];
+ }
+ _updateVisibility(datasetIndex, dataIndex, visible) {
+ const mode = visible ? 'show' : 'hide';
+ const meta = this.getDatasetMeta(datasetIndex);
+ const anims = meta.controller._resolveAnimations(undefined, mode);
+ if (defined(dataIndex)) {
+ meta.data[dataIndex].hidden = !visible;
+ this.update();
+ } else {
+ this.setDatasetVisibility(datasetIndex, visible);
+ anims.update(meta, {visible});
+ this.update((ctx) => ctx.datasetIndex === datasetIndex ? mode : undefined);
+ }
+ }
+ hide(datasetIndex, dataIndex) {
+ this._updateVisibility(datasetIndex, dataIndex, false);
+ }
+ show(datasetIndex, dataIndex) {
+ this._updateVisibility(datasetIndex, dataIndex, true);
+ }
+ _destroyDatasetMeta(datasetIndex) {
+ const meta = this._metasets[datasetIndex];
+ if (meta && meta.controller) {
+ meta.controller._destroy();
+ }
+ delete this._metasets[datasetIndex];
+ }
+ _stop() {
+ let i, ilen;
+ this.stop();
+ animator.remove(this);
+ for (i = 0, ilen = this.data.datasets.length; i < ilen; ++i) {
+ this._destroyDatasetMeta(i);
+ }
+ }
+ destroy() {
+ this.notifyPlugins('beforeDestroy');
+ const {canvas, ctx} = this;
+ this._stop();
+ this.config.clearCache();
+ if (canvas) {
+ this.unbindEvents();
+ clearCanvas(canvas, ctx);
+ this.platform.releaseContext(ctx);
+ this.canvas = null;
+ this.ctx = null;
+ }
+ this.notifyPlugins('destroy');
+ delete instances[this.id];
+ this.notifyPlugins('afterDestroy');
+ }
+ toBase64Image(...args) {
+ return this.canvas.toDataURL(...args);
+ }
+ bindEvents() {
+ this.bindUserEvents();
+ if (this.options.responsive) {
+ this.bindResponsiveEvents();
+ } else {
+ this.attached = true;
+ }
+ }
+ bindUserEvents() {
+ const listeners = this._listeners;
+ const platform = this.platform;
+ const _add = (type, listener) => {
+ platform.addEventListener(this, type, listener);
+ listeners[type] = listener;
+ };
+ const listener = (e, x, y) => {
+ e.offsetX = x;
+ e.offsetY = y;
+ this._eventHandler(e);
+ };
+ each(this.options.events, (type) => _add(type, listener));
+ }
+ bindResponsiveEvents() {
+ if (!this._responsiveListeners) {
+ this._responsiveListeners = {};
+ }
+ const listeners = this._responsiveListeners;
+ const platform = this.platform;
+ const _add = (type, listener) => {
+ platform.addEventListener(this, type, listener);
+ listeners[type] = listener;
+ };
+ const _remove = (type, listener) => {
+ if (listeners[type]) {
+ platform.removeEventListener(this, type, listener);
+ delete listeners[type];
+ }
+ };
+ const listener = (width, height) => {
+ if (this.canvas) {
+ this.resize(width, height);
+ }
+ };
+ let detached;
+ const attached = () => {
+ _remove('attach', attached);
+ this.attached = true;
+ this.resize();
+ _add('resize', listener);
+ _add('detach', detached);
+ };
+ detached = () => {
+ this.attached = false;
+ _remove('resize', listener);
+ this._stop();
+ this._resize(0, 0);
+ _add('attach', attached);
+ };
+ if (platform.isAttached(this.canvas)) {
+ attached();
+ } else {
+ detached();
+ }
+ }
+ unbindEvents() {
+ each(this._listeners, (listener, type) => {
+ this.platform.removeEventListener(this, type, listener);
+ });
+ this._listeners = {};
+ each(this._responsiveListeners, (listener, type) => {
+ this.platform.removeEventListener(this, type, listener);
+ });
+ this._responsiveListeners = undefined;
+ }
+ updateHoverStyle(items, mode, enabled) {
+ const prefix = enabled ? 'set' : 'remove';
+ let meta, item, i, ilen;
+ if (mode === 'dataset') {
+ meta = this.getDatasetMeta(items[0].datasetIndex);
+ meta.controller['_' + prefix + 'DatasetHoverStyle']();
+ }
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
+ item = items[i];
+ const controller = item && this.getDatasetMeta(item.datasetIndex).controller;
+ if (controller) {
+ controller[prefix + 'HoverStyle'](item.element, item.datasetIndex, item.index);
+ }
+ }
+ }
+ getActiveElements() {
+ return this._active || [];
+ }
+ setActiveElements(activeElements) {
+ const lastActive = this._active || [];
+ const active = activeElements.map(({datasetIndex, index}) => {
+ const meta = this.getDatasetMeta(datasetIndex);
+ if (!meta) {
+ throw new Error('No dataset found at index ' + datasetIndex);
+ }
+ return {
+ datasetIndex,
+ element: meta.data[index],
+ index,
+ };
+ });
+ const changed = !_elementsEqual(active, lastActive);
+ if (changed) {
+ this._active = active;
+ this._lastEvent = null;
+ this._updateHoverStyles(active, lastActive);
+ }
+ }
+ notifyPlugins(hook, args, filter) {
+ return this._plugins.notify(this, hook, args, filter);
+ }
+ _updateHoverStyles(active, lastActive, replay) {
+ const hoverOptions = this.options.hover;
+ const diff = (a, b) => a.filter(x => !b.some(y => x.datasetIndex === y.datasetIndex && x.index === y.index));
+ const deactivated = diff(lastActive, active);
+ const activated = replay ? active : diff(active, lastActive);
+ if (deactivated.length) {
+ this.updateHoverStyle(deactivated, hoverOptions.mode, false);
+ }
+ if (activated.length && hoverOptions.mode) {
+ this.updateHoverStyle(activated, hoverOptions.mode, true);
+ }
+ }
+ _eventHandler(e, replay) {
+ const args = {
+ event: e,
+ replay,
+ cancelable: true,
+ inChartArea: _isPointInArea(e, this.chartArea, this._minPadding)
+ };
+ const eventFilter = (plugin) => (plugin.options.events || this.options.events).includes(e.native.type);
+ if (this.notifyPlugins('beforeEvent', args, eventFilter) === false) {
+ return;
+ }
+ const changed = this._handleEvent(e, replay, args.inChartArea);
+ args.cancelable = false;
+ this.notifyPlugins('afterEvent', args, eventFilter);
+ if (changed || args.changed) {
+ this.render();
+ }
+ return this;
+ }
+ _handleEvent(e, replay, inChartArea) {
+ const {_active: lastActive = [], options} = this;
+ const useFinalPosition = replay;
+ const active = this._getActiveElements(e, lastActive, inChartArea, useFinalPosition);
+ const isClick = _isClickEvent(e);
+ const lastEvent = determineLastEvent(e, this._lastEvent, inChartArea, isClick);
+ if (inChartArea) {
+ this._lastEvent = null;
+ callback(options.onHover, [e, active, this], this);
+ if (isClick) {
+ callback(options.onClick, [e, active, this], this);
+ }
+ }
+ const changed = !_elementsEqual(active, lastActive);
+ if (changed || replay) {
+ this._active = active;
+ this._updateHoverStyles(active, lastActive, replay);
+ }
+ this._lastEvent = lastEvent;
+ return changed;
+ }
+ _getActiveElements(e, lastActive, inChartArea, useFinalPosition) {
+ if (e.type === 'mouseout') {
+ return [];
+ }
+ if (!inChartArea) {
+ return lastActive;
+ }
+ const hoverOptions = this.options.hover;
+ return this.getElementsAtEventForMode(e, hoverOptions.mode, hoverOptions, useFinalPosition);
+ }
+}
+const invalidatePlugins = () => each(Chart.instances, (chart) => chart._plugins.invalidate());
+const enumerable = true;
+Object.defineProperties(Chart, {
+ defaults: {
+ enumerable,
+ value: defaults
+ },
+ instances: {
+ enumerable,
+ value: instances
+ },
+ overrides: {
+ enumerable,
+ value: overrides
+ },
+ registry: {
+ enumerable,
+ value: registry
+ },
+ version: {
+ enumerable,
+ value: version
+ },
+ getChart: {
+ enumerable,
+ value: getChart
+ },
+ register: {
+ enumerable,
+ value: (...items) => {
+ registry.add(...items);
+ invalidatePlugins();
+ }
+ },
+ unregister: {
+ enumerable,
+ value: (...items) => {
+ registry.remove(...items);
+ invalidatePlugins();
+ }
+ }
+});
+
+function abstract() {
+ throw new Error('This method is not implemented: Check that a complete date adapter is provided.');
+}
+class DateAdapter {
+ constructor(options) {
+ this.options = options || {};
+ }
+ formats() {
+ return abstract();
+ }
+ parse(value, format) {
+ return abstract();
+ }
+ format(timestamp, format) {
+ return abstract();
+ }
+ add(timestamp, amount, unit) {
+ return abstract();
+ }
+ diff(a, b, unit) {
+ return abstract();
+ }
+ startOf(timestamp, unit, weekday) {
+ return abstract();
+ }
+ endOf(timestamp, unit) {
+ return abstract();
+ }
+}
+DateAdapter.override = function(members) {
+ Object.assign(DateAdapter.prototype, members);
+};
+var _adapters = {
+ _date: DateAdapter
+};
+
+function getAllScaleValues(scale, type) {
+ if (!scale._cache.$bar) {
+ const visibleMetas = scale.getMatchingVisibleMetas(type);
+ let values = [];
+ for (let i = 0, ilen = visibleMetas.length; i < ilen; i++) {
+ values = values.concat(visibleMetas[i].controller.getAllParsedValues(scale));
+ }
+ scale._cache.$bar = _arrayUnique(values.sort((a, b) => a - b));
+ }
+ return scale._cache.$bar;
+}
+function computeMinSampleSize(meta) {
+ const scale = meta.iScale;
+ const values = getAllScaleValues(scale, meta.type);
+ let min = scale._length;
+ let i, ilen, curr, prev;
+ const updateMinAndPrev = () => {
+ if (curr === 32767 || curr === -32768) {
+ return;
+ }
+ if (defined(prev)) {
+ min = Math.min(min, Math.abs(curr - prev) || min);
+ }
+ prev = curr;
+ };
+ for (i = 0, ilen = values.length; i < ilen; ++i) {
+ curr = scale.getPixelForValue(values[i]);
+ updateMinAndPrev();
+ }
+ prev = undefined;
+ for (i = 0, ilen = scale.ticks.length; i < ilen; ++i) {
+ curr = scale.getPixelForTick(i);
+ updateMinAndPrev();
+ }
+ return min;
+}
+function computeFitCategoryTraits(index, ruler, options, stackCount) {
+ const thickness = options.barThickness;
+ let size, ratio;
+ if (isNullOrUndef(thickness)) {
+ size = ruler.min * options.categoryPercentage;
+ ratio = options.barPercentage;
+ } else {
+ size = thickness * stackCount;
+ ratio = 1;
+ }
+ return {
+ chunk: size / stackCount,
+ ratio,
+ start: ruler.pixels[index] - (size / 2)
+ };
+}
+function computeFlexCategoryTraits(index, ruler, options, stackCount) {
+ const pixels = ruler.pixels;
+ const curr = pixels[index];
+ let prev = index > 0 ? pixels[index - 1] : null;
+ let next = index < pixels.length - 1 ? pixels[index + 1] : null;
+ const percent = options.categoryPercentage;
+ if (prev === null) {
+ prev = curr - (next === null ? ruler.end - ruler.start : next - curr);
+ }
+ if (next === null) {
+ next = curr + curr - prev;
+ }
+ const start = curr - (curr - Math.min(prev, next)) / 2 * percent;
+ const size = Math.abs(next - prev) / 2 * percent;
+ return {
+ chunk: size / stackCount,
+ ratio: options.barPercentage,
+ start
+ };
+}
+function parseFloatBar(entry, item, vScale, i) {
+ const startValue = vScale.parse(entry[0], i);
+ const endValue = vScale.parse(entry[1], i);
+ const min = Math.min(startValue, endValue);
+ const max = Math.max(startValue, endValue);
+ let barStart = min;
+ let barEnd = max;
+ if (Math.abs(min) > Math.abs(max)) {
+ barStart = max;
+ barEnd = min;
+ }
+ item[vScale.axis] = barEnd;
+ item._custom = {
+ barStart,
+ barEnd,
+ start: startValue,
+ end: endValue,
+ min,
+ max
+ };
+}
+function parseValue(entry, item, vScale, i) {
+ if (isArray(entry)) {
+ parseFloatBar(entry, item, vScale, i);
+ } else {
+ item[vScale.axis] = vScale.parse(entry, i);
+ }
+ return item;
+}
+function parseArrayOrPrimitive(meta, data, start, count) {
+ const iScale = meta.iScale;
+ const vScale = meta.vScale;
+ const labels = iScale.getLabels();
+ const singleScale = iScale === vScale;
+ const parsed = [];
+ let i, ilen, item, entry;
+ for (i = start, ilen = start + count; i < ilen; ++i) {
+ entry = data[i];
+ item = {};
+ item[iScale.axis] = singleScale || iScale.parse(labels[i], i);
+ parsed.push(parseValue(entry, item, vScale, i));
+ }
+ return parsed;
+}
+function isFloatBar(custom) {
+ return custom && custom.barStart !== undefined && custom.barEnd !== undefined;
+}
+function barSign(size, vScale, actualBase) {
+ if (size !== 0) {
+ return sign(size);
+ }
+ return (vScale.isHorizontal() ? 1 : -1) * (vScale.min >= actualBase ? 1 : -1);
+}
+function borderProps(properties) {
+ let reverse, start, end, top, bottom;
+ if (properties.horizontal) {
+ reverse = properties.base > properties.x;
+ start = 'left';
+ end = 'right';
+ } else {
+ reverse = properties.base < properties.y;
+ start = 'bottom';
+ end = 'top';
+ }
+ if (reverse) {
+ top = 'end';
+ bottom = 'start';
+ } else {
+ top = 'start';
+ bottom = 'end';
+ }
+ return {start, end, reverse, top, bottom};
+}
+function setBorderSkipped(properties, options, stack, index) {
+ let edge = options.borderSkipped;
+ const res = {};
+ if (!edge) {
+ properties.borderSkipped = res;
+ return;
+ }
+ const {start, end, reverse, top, bottom} = borderProps(properties);
+ if (edge === 'middle' && stack) {
+ properties.enableBorderRadius = true;
+ if ((stack._top || 0) === index) {
+ edge = top;
+ } else if ((stack._bottom || 0) === index) {
+ edge = bottom;
+ } else {
+ res[parseEdge(bottom, start, end, reverse)] = true;
+ edge = top;
+ }
+ }
+ res[parseEdge(edge, start, end, reverse)] = true;
+ properties.borderSkipped = res;
+}
+function parseEdge(edge, a, b, reverse) {
+ if (reverse) {
+ edge = swap(edge, a, b);
+ edge = startEnd(edge, b, a);
+ } else {
+ edge = startEnd(edge, a, b);
+ }
+ return edge;
+}
+function swap(orig, v1, v2) {
+ return orig === v1 ? v2 : orig === v2 ? v1 : orig;
+}
+function startEnd(v, start, end) {
+ return v === 'start' ? start : v === 'end' ? end : v;
+}
+function setInflateAmount(properties, {inflateAmount}, ratio) {
+ properties.inflateAmount = inflateAmount === 'auto'
+ ? ratio === 1 ? 0.33 : 0
+ : inflateAmount;
+}
+class BarController extends DatasetController {
+ parsePrimitiveData(meta, data, start, count) {
+ return parseArrayOrPrimitive(meta, data, start, count);
+ }
+ parseArrayData(meta, data, start, count) {
+ return parseArrayOrPrimitive(meta, data, start, count);
+ }
+ parseObjectData(meta, data, start, count) {
+ const {iScale, vScale} = meta;
+ const {xAxisKey = 'x', yAxisKey = 'y'} = this._parsing;
+ const iAxisKey = iScale.axis === 'x' ? xAxisKey : yAxisKey;
+ const vAxisKey = vScale.axis === 'x' ? xAxisKey : yAxisKey;
+ const parsed = [];
+ let i, ilen, item, obj;
+ for (i = start, ilen = start + count; i < ilen; ++i) {
+ obj = data[i];
+ item = {};
+ item[iScale.axis] = iScale.parse(resolveObjectKey(obj, iAxisKey), i);
+ parsed.push(parseValue(resolveObjectKey(obj, vAxisKey), item, vScale, i));
+ }
+ return parsed;
+ }
+ updateRangeFromParsed(range, scale, parsed, stack) {
+ super.updateRangeFromParsed(range, scale, parsed, stack);
+ const custom = parsed._custom;
+ if (custom && scale === this._cachedMeta.vScale) {
+ range.min = Math.min(range.min, custom.min);
+ range.max = Math.max(range.max, custom.max);
+ }
+ }
+ getMaxOverflow() {
+ return 0;
+ }
+ getLabelAndValue(index) {
+ const meta = this._cachedMeta;
+ const {iScale, vScale} = meta;
+ const parsed = this.getParsed(index);
+ const custom = parsed._custom;
+ const value = isFloatBar(custom)
+ ? '[' + custom.start + ', ' + custom.end + ']'
+ : '' + vScale.getLabelForValue(parsed[vScale.axis]);
+ return {
+ label: '' + iScale.getLabelForValue(parsed[iScale.axis]),
+ value
+ };
+ }
+ initialize() {
+ this.enableOptionSharing = true;
+ super.initialize();
+ const meta = this._cachedMeta;
+ meta.stack = this.getDataset().stack;
+ }
+ update(mode) {
+ const meta = this._cachedMeta;
+ this.updateElements(meta.data, 0, meta.data.length, mode);
+ }
+ updateElements(bars, start, count, mode) {
+ const reset = mode === 'reset';
+ const {index, _cachedMeta: {vScale}} = this;
+ const base = vScale.getBasePixel();
+ const horizontal = vScale.isHorizontal();
+ const ruler = this._getRuler();
+ const firstOpts = this.resolveDataElementOptions(start, mode);
+ const sharedOptions = this.getSharedOptions(firstOpts);
+ const includeOptions = this.includeOptions(mode, sharedOptions);
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
+ for (let i = start; i < start + count; i++) {
+ const parsed = this.getParsed(i);
+ const vpixels = reset || isNullOrUndef(parsed[vScale.axis]) ? {base, head: base} : this._calculateBarValuePixels(i);
+ const ipixels = this._calculateBarIndexPixels(i, ruler);
+ const stack = (parsed._stacks || {})[vScale.axis];
+ const properties = {
+ horizontal,
+ base: vpixels.base,
+ enableBorderRadius: !stack || isFloatBar(parsed._custom) || (index === stack._top || index === stack._bottom),
+ x: horizontal ? vpixels.head : ipixels.center,
+ y: horizontal ? ipixels.center : vpixels.head,
+ height: horizontal ? ipixels.size : Math.abs(vpixels.size),
+ width: horizontal ? Math.abs(vpixels.size) : ipixels.size
+ };
+ if (includeOptions) {
+ properties.options = sharedOptions || this.resolveDataElementOptions(i, bars[i].active ? 'active' : mode);
+ }
+ const options = properties.options || bars[i].options;
+ setBorderSkipped(properties, options, stack, index);
+ setInflateAmount(properties, options, ruler.ratio);
+ this.updateElement(bars[i], i, properties, mode);
+ }
+ }
+ _getStacks(last, dataIndex) {
+ const meta = this._cachedMeta;
+ const iScale = meta.iScale;
+ const metasets = iScale.getMatchingVisibleMetas(this._type);
+ const stacked = iScale.options.stacked;
+ const ilen = metasets.length;
+ const stacks = [];
+ let i, item;
+ for (i = 0; i < ilen; ++i) {
+ item = metasets[i];
+ if (!item.controller.options.grouped) {
+ continue;
+ }
+ if (typeof dataIndex !== 'undefined') {
+ const val = item.controller.getParsed(dataIndex)[
+ item.controller._cachedMeta.vScale.axis
+ ];
+ if (isNullOrUndef(val) || isNaN(val)) {
+ continue;
+ }
+ }
+ if (stacked === false || stacks.indexOf(item.stack) === -1 ||
+ (stacked === undefined && item.stack === undefined)) {
+ stacks.push(item.stack);
+ }
+ if (item.index === last) {
+ break;
+ }
+ }
+ if (!stacks.length) {
+ stacks.push(undefined);
+ }
+ return stacks;
+ }
+ _getStackCount(index) {
+ return this._getStacks(undefined, index).length;
+ }
+ _getStackIndex(datasetIndex, name, dataIndex) {
+ const stacks = this._getStacks(datasetIndex, dataIndex);
+ const index = (name !== undefined)
+ ? stacks.indexOf(name)
+ : -1;
+ return (index === -1)
+ ? stacks.length - 1
+ : index;
+ }
+ _getRuler() {
+ const opts = this.options;
+ const meta = this._cachedMeta;
+ const iScale = meta.iScale;
+ const pixels = [];
+ let i, ilen;
+ for (i = 0, ilen = meta.data.length; i < ilen; ++i) {
+ pixels.push(iScale.getPixelForValue(this.getParsed(i)[iScale.axis], i));
+ }
+ const barThickness = opts.barThickness;
+ const min = barThickness || computeMinSampleSize(meta);
+ return {
+ min,
+ pixels,
+ start: iScale._startPixel,
+ end: iScale._endPixel,
+ stackCount: this._getStackCount(),
+ scale: iScale,
+ grouped: opts.grouped,
+ ratio: barThickness ? 1 : opts.categoryPercentage * opts.barPercentage
+ };
+ }
+ _calculateBarValuePixels(index) {
+ const {_cachedMeta: {vScale, _stacked}, options: {base: baseValue, minBarLength}} = this;
+ const actualBase = baseValue || 0;
+ const parsed = this.getParsed(index);
+ const custom = parsed._custom;
+ const floating = isFloatBar(custom);
+ let value = parsed[vScale.axis];
+ let start = 0;
+ let length = _stacked ? this.applyStack(vScale, parsed, _stacked) : value;
+ let head, size;
+ if (length !== value) {
+ start = length - value;
+ length = value;
+ }
+ if (floating) {
+ value = custom.barStart;
+ length = custom.barEnd - custom.barStart;
+ if (value !== 0 && sign(value) !== sign(custom.barEnd)) {
+ start = 0;
+ }
+ start += value;
+ }
+ const startValue = !isNullOrUndef(baseValue) && !floating ? baseValue : start;
+ let base = vScale.getPixelForValue(startValue);
+ if (this.chart.getDataVisibility(index)) {
+ head = vScale.getPixelForValue(start + length);
+ } else {
+ head = base;
+ }
+ size = head - base;
+ if (Math.abs(size) < minBarLength) {
+ size = barSign(size, vScale, actualBase) * minBarLength;
+ if (value === actualBase) {
+ base -= size / 2;
+ }
+ head = base + size;
+ }
+ if (base === vScale.getPixelForValue(actualBase)) {
+ const halfGrid = sign(size) * vScale.getLineWidthForValue(actualBase) / 2;
+ base += halfGrid;
+ size -= halfGrid;
+ }
+ return {
+ size,
+ base,
+ head,
+ center: head + size / 2
+ };
+ }
+ _calculateBarIndexPixels(index, ruler) {
+ const scale = ruler.scale;
+ const options = this.options;
+ const skipNull = options.skipNull;
+ const maxBarThickness = valueOrDefault(options.maxBarThickness, Infinity);
+ let center, size;
+ if (ruler.grouped) {
+ const stackCount = skipNull ? this._getStackCount(index) : ruler.stackCount;
+ const range = options.barThickness === 'flex'
+ ? computeFlexCategoryTraits(index, ruler, options, stackCount)
+ : computeFitCategoryTraits(index, ruler, options, stackCount);
+ const stackIndex = this._getStackIndex(this.index, this._cachedMeta.stack, skipNull ? index : undefined);
+ center = range.start + (range.chunk * stackIndex) + (range.chunk / 2);
+ size = Math.min(maxBarThickness, range.chunk * range.ratio);
+ } else {
+ center = scale.getPixelForValue(this.getParsed(index)[scale.axis], index);
+ size = Math.min(maxBarThickness, ruler.min * ruler.ratio);
+ }
+ return {
+ base: center - size / 2,
+ head: center + size / 2,
+ center,
+ size
+ };
+ }
+ draw() {
+ const meta = this._cachedMeta;
+ const vScale = meta.vScale;
+ const rects = meta.data;
+ const ilen = rects.length;
+ let i = 0;
+ for (; i < ilen; ++i) {
+ if (this.getParsed(i)[vScale.axis] !== null) {
+ rects[i].draw(this._ctx);
+ }
+ }
+ }
+}
+BarController.id = 'bar';
+BarController.defaults = {
+ datasetElementType: false,
+ dataElementType: 'bar',
+ categoryPercentage: 0.8,
+ barPercentage: 0.9,
+ grouped: true,
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['x', 'y', 'base', 'width', 'height']
+ }
+ }
+};
+BarController.overrides = {
+ scales: {
+ _index_: {
+ type: 'category',
+ offset: true,
+ grid: {
+ offset: true
+ }
+ },
+ _value_: {
+ type: 'linear',
+ beginAtZero: true,
+ }
+ }
+};
+
+class BubbleController extends DatasetController {
+ initialize() {
+ this.enableOptionSharing = true;
+ super.initialize();
+ }
+ parsePrimitiveData(meta, data, start, count) {
+ const parsed = super.parsePrimitiveData(meta, data, start, count);
+ for (let i = 0; i < parsed.length; i++) {
+ parsed[i]._custom = this.resolveDataElementOptions(i + start).radius;
+ }
+ return parsed;
+ }
+ parseArrayData(meta, data, start, count) {
+ const parsed = super.parseArrayData(meta, data, start, count);
+ for (let i = 0; i < parsed.length; i++) {
+ const item = data[start + i];
+ parsed[i]._custom = valueOrDefault(item[2], this.resolveDataElementOptions(i + start).radius);
+ }
+ return parsed;
+ }
+ parseObjectData(meta, data, start, count) {
+ const parsed = super.parseObjectData(meta, data, start, count);
+ for (let i = 0; i < parsed.length; i++) {
+ const item = data[start + i];
+ parsed[i]._custom = valueOrDefault(item && item.r && +item.r, this.resolveDataElementOptions(i + start).radius);
+ }
+ return parsed;
+ }
+ getMaxOverflow() {
+ const data = this._cachedMeta.data;
+ let max = 0;
+ for (let i = data.length - 1; i >= 0; --i) {
+ max = Math.max(max, data[i].size(this.resolveDataElementOptions(i)) / 2);
+ }
+ return max > 0 && max;
+ }
+ getLabelAndValue(index) {
+ const meta = this._cachedMeta;
+ const {xScale, yScale} = meta;
+ const parsed = this.getParsed(index);
+ const x = xScale.getLabelForValue(parsed.x);
+ const y = yScale.getLabelForValue(parsed.y);
+ const r = parsed._custom;
+ return {
+ label: meta.label,
+ value: '(' + x + ', ' + y + (r ? ', ' + r : '') + ')'
+ };
+ }
+ update(mode) {
+ const points = this._cachedMeta.data;
+ this.updateElements(points, 0, points.length, mode);
+ }
+ updateElements(points, start, count, mode) {
+ const reset = mode === 'reset';
+ const {iScale, vScale} = this._cachedMeta;
+ const firstOpts = this.resolveDataElementOptions(start, mode);
+ const sharedOptions = this.getSharedOptions(firstOpts);
+ const includeOptions = this.includeOptions(mode, sharedOptions);
+ const iAxis = iScale.axis;
+ const vAxis = vScale.axis;
+ for (let i = start; i < start + count; i++) {
+ const point = points[i];
+ const parsed = !reset && this.getParsed(i);
+ const properties = {};
+ const iPixel = properties[iAxis] = reset ? iScale.getPixelForDecimal(0.5) : iScale.getPixelForValue(parsed[iAxis]);
+ const vPixel = properties[vAxis] = reset ? vScale.getBasePixel() : vScale.getPixelForValue(parsed[vAxis]);
+ properties.skip = isNaN(iPixel) || isNaN(vPixel);
+ if (includeOptions) {
+ properties.options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
+ if (reset) {
+ properties.options.radius = 0;
+ }
+ }
+ this.updateElement(point, i, properties, mode);
+ }
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
+ }
+ resolveDataElementOptions(index, mode) {
+ const parsed = this.getParsed(index);
+ let values = super.resolveDataElementOptions(index, mode);
+ if (values.$shared) {
+ values = Object.assign({}, values, {$shared: false});
+ }
+ const radius = values.radius;
+ if (mode !== 'active') {
+ values.radius = 0;
+ }
+ values.radius += valueOrDefault(parsed && parsed._custom, radius);
+ return values;
+ }
+}
+BubbleController.id = 'bubble';
+BubbleController.defaults = {
+ datasetElementType: false,
+ dataElementType: 'point',
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['x', 'y', 'borderWidth', 'radius']
+ }
+ }
+};
+BubbleController.overrides = {
+ scales: {
+ x: {
+ type: 'linear'
+ },
+ y: {
+ type: 'linear'
+ }
+ },
+ plugins: {
+ tooltip: {
+ callbacks: {
+ title() {
+ return '';
+ }
+ }
+ }
+ }
+};
+
+function getRatioAndOffset(rotation, circumference, cutout) {
+ let ratioX = 1;
+ let ratioY = 1;
+ let offsetX = 0;
+ let offsetY = 0;
+ if (circumference < TAU) {
+ const startAngle = rotation;
+ const endAngle = startAngle + circumference;
+ const startX = Math.cos(startAngle);
+ const startY = Math.sin(startAngle);
+ const endX = Math.cos(endAngle);
+ const endY = Math.sin(endAngle);
+ const calcMax = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? 1 : Math.max(a, a * cutout, b, b * cutout);
+ const calcMin = (angle, a, b) => _angleBetween(angle, startAngle, endAngle, true) ? -1 : Math.min(a, a * cutout, b, b * cutout);
+ const maxX = calcMax(0, startX, endX);
+ const maxY = calcMax(HALF_PI, startY, endY);
+ const minX = calcMin(PI, startX, endX);
+ const minY = calcMin(PI + HALF_PI, startY, endY);
+ ratioX = (maxX - minX) / 2;
+ ratioY = (maxY - minY) / 2;
+ offsetX = -(maxX + minX) / 2;
+ offsetY = -(maxY + minY) / 2;
+ }
+ return {ratioX, ratioY, offsetX, offsetY};
+}
+class DoughnutController extends DatasetController {
+ constructor(chart, datasetIndex) {
+ super(chart, datasetIndex);
+ this.enableOptionSharing = true;
+ this.innerRadius = undefined;
+ this.outerRadius = undefined;
+ this.offsetX = undefined;
+ this.offsetY = undefined;
+ }
+ linkScales() {}
+ parse(start, count) {
+ const data = this.getDataset().data;
+ const meta = this._cachedMeta;
+ if (this._parsing === false) {
+ meta._parsed = data;
+ } else {
+ let getter = (i) => +data[i];
+ if (isObject(data[start])) {
+ const {key = 'value'} = this._parsing;
+ getter = (i) => +resolveObjectKey(data[i], key);
+ }
+ let i, ilen;
+ for (i = start, ilen = start + count; i < ilen; ++i) {
+ meta._parsed[i] = getter(i);
+ }
+ }
+ }
+ _getRotation() {
+ return toRadians(this.options.rotation - 90);
+ }
+ _getCircumference() {
+ return toRadians(this.options.circumference);
+ }
+ _getRotationExtents() {
+ let min = TAU;
+ let max = -TAU;
+ for (let i = 0; i < this.chart.data.datasets.length; ++i) {
+ if (this.chart.isDatasetVisible(i)) {
+ const controller = this.chart.getDatasetMeta(i).controller;
+ const rotation = controller._getRotation();
+ const circumference = controller._getCircumference();
+ min = Math.min(min, rotation);
+ max = Math.max(max, rotation + circumference);
+ }
+ }
+ return {
+ rotation: min,
+ circumference: max - min,
+ };
+ }
+ update(mode) {
+ const chart = this.chart;
+ const {chartArea} = chart;
+ const meta = this._cachedMeta;
+ const arcs = meta.data;
+ const spacing = this.getMaxBorderWidth() + this.getMaxOffset(arcs) + this.options.spacing;
+ const maxSize = Math.max((Math.min(chartArea.width, chartArea.height) - spacing) / 2, 0);
+ const cutout = Math.min(toPercentage(this.options.cutout, maxSize), 1);
+ const chartWeight = this._getRingWeight(this.index);
+ const {circumference, rotation} = this._getRotationExtents();
+ const {ratioX, ratioY, offsetX, offsetY} = getRatioAndOffset(rotation, circumference, cutout);
+ const maxWidth = (chartArea.width - spacing) / ratioX;
+ const maxHeight = (chartArea.height - spacing) / ratioY;
+ const maxRadius = Math.max(Math.min(maxWidth, maxHeight) / 2, 0);
+ const outerRadius = toDimension(this.options.radius, maxRadius);
+ const innerRadius = Math.max(outerRadius * cutout, 0);
+ const radiusLength = (outerRadius - innerRadius) / this._getVisibleDatasetWeightTotal();
+ this.offsetX = offsetX * outerRadius;
+ this.offsetY = offsetY * outerRadius;
+ meta.total = this.calculateTotal();
+ this.outerRadius = outerRadius - radiusLength * this._getRingWeightOffset(this.index);
+ this.innerRadius = Math.max(this.outerRadius - radiusLength * chartWeight, 0);
+ this.updateElements(arcs, 0, arcs.length, mode);
+ }
+ _circumference(i, reset) {
+ const opts = this.options;
+ const meta = this._cachedMeta;
+ const circumference = this._getCircumference();
+ if ((reset && opts.animation.animateRotate) || !this.chart.getDataVisibility(i) || meta._parsed[i] === null || meta.data[i].hidden) {
+ return 0;
+ }
+ return this.calculateCircumference(meta._parsed[i] * circumference / TAU);
+ }
+ updateElements(arcs, start, count, mode) {
+ const reset = mode === 'reset';
+ const chart = this.chart;
+ const chartArea = chart.chartArea;
+ const opts = chart.options;
+ const animationOpts = opts.animation;
+ const centerX = (chartArea.left + chartArea.right) / 2;
+ const centerY = (chartArea.top + chartArea.bottom) / 2;
+ const animateScale = reset && animationOpts.animateScale;
+ const innerRadius = animateScale ? 0 : this.innerRadius;
+ const outerRadius = animateScale ? 0 : this.outerRadius;
+ const firstOpts = this.resolveDataElementOptions(start, mode);
+ const sharedOptions = this.getSharedOptions(firstOpts);
+ const includeOptions = this.includeOptions(mode, sharedOptions);
+ let startAngle = this._getRotation();
+ let i;
+ for (i = 0; i < start; ++i) {
+ startAngle += this._circumference(i, reset);
+ }
+ for (i = start; i < start + count; ++i) {
+ const circumference = this._circumference(i, reset);
+ const arc = arcs[i];
+ const properties = {
+ x: centerX + this.offsetX,
+ y: centerY + this.offsetY,
+ startAngle,
+ endAngle: startAngle + circumference,
+ circumference,
+ outerRadius,
+ innerRadius
+ };
+ if (includeOptions) {
+ properties.options = sharedOptions || this.resolveDataElementOptions(i, arc.active ? 'active' : mode);
+ }
+ startAngle += circumference;
+ this.updateElement(arc, i, properties, mode);
+ }
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
+ }
+ calculateTotal() {
+ const meta = this._cachedMeta;
+ const metaData = meta.data;
+ let total = 0;
+ let i;
+ for (i = 0; i < metaData.length; i++) {
+ const value = meta._parsed[i];
+ if (value !== null && !isNaN(value) && this.chart.getDataVisibility(i) && !metaData[i].hidden) {
+ total += Math.abs(value);
+ }
+ }
+ return total;
+ }
+ calculateCircumference(value) {
+ const total = this._cachedMeta.total;
+ if (total > 0 && !isNaN(value)) {
+ return TAU * (Math.abs(value) / total);
+ }
+ return 0;
+ }
+ getLabelAndValue(index) {
+ const meta = this._cachedMeta;
+ const chart = this.chart;
+ const labels = chart.data.labels || [];
+ const value = formatNumber(meta._parsed[index], chart.options.locale);
+ return {
+ label: labels[index] || '',
+ value,
+ };
+ }
+ getMaxBorderWidth(arcs) {
+ let max = 0;
+ const chart = this.chart;
+ let i, ilen, meta, controller, options;
+ if (!arcs) {
+ for (i = 0, ilen = chart.data.datasets.length; i < ilen; ++i) {
+ if (chart.isDatasetVisible(i)) {
+ meta = chart.getDatasetMeta(i);
+ arcs = meta.data;
+ controller = meta.controller;
+ break;
+ }
+ }
+ }
+ if (!arcs) {
+ return 0;
+ }
+ for (i = 0, ilen = arcs.length; i < ilen; ++i) {
+ options = controller.resolveDataElementOptions(i);
+ if (options.borderAlign !== 'inner') {
+ max = Math.max(max, options.borderWidth || 0, options.hoverBorderWidth || 0);
+ }
+ }
+ return max;
+ }
+ getMaxOffset(arcs) {
+ let max = 0;
+ for (let i = 0, ilen = arcs.length; i < ilen; ++i) {
+ const options = this.resolveDataElementOptions(i);
+ max = Math.max(max, options.offset || 0, options.hoverOffset || 0);
+ }
+ return max;
+ }
+ _getRingWeightOffset(datasetIndex) {
+ let ringWeightOffset = 0;
+ for (let i = 0; i < datasetIndex; ++i) {
+ if (this.chart.isDatasetVisible(i)) {
+ ringWeightOffset += this._getRingWeight(i);
+ }
+ }
+ return ringWeightOffset;
+ }
+ _getRingWeight(datasetIndex) {
+ return Math.max(valueOrDefault(this.chart.data.datasets[datasetIndex].weight, 1), 0);
+ }
+ _getVisibleDatasetWeightTotal() {
+ return this._getRingWeightOffset(this.chart.data.datasets.length) || 1;
+ }
+}
+DoughnutController.id = 'doughnut';
+DoughnutController.defaults = {
+ datasetElementType: false,
+ dataElementType: 'arc',
+ animation: {
+ animateRotate: true,
+ animateScale: false
+ },
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['circumference', 'endAngle', 'innerRadius', 'outerRadius', 'startAngle', 'x', 'y', 'offset', 'borderWidth', 'spacing']
+ },
+ },
+ cutout: '50%',
+ rotation: 0,
+ circumference: 360,
+ radius: '100%',
+ spacing: 0,
+ indexAxis: 'r',
+};
+DoughnutController.descriptors = {
+ _scriptable: (name) => name !== 'spacing',
+ _indexable: (name) => name !== 'spacing',
+};
+DoughnutController.overrides = {
+ aspectRatio: 1,
+ plugins: {
+ legend: {
+ labels: {
+ generateLabels(chart) {
+ const data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ const {labels: {pointStyle}} = chart.legend.options;
+ return data.labels.map((label, i) => {
+ const meta = chart.getDatasetMeta(0);
+ const style = meta.controller.getStyle(i);
+ return {
+ text: label,
+ fillStyle: style.backgroundColor,
+ strokeStyle: style.borderColor,
+ lineWidth: style.borderWidth,
+ pointStyle: pointStyle,
+ hidden: !chart.getDataVisibility(i),
+ index: i
+ };
+ });
+ }
+ return [];
+ }
+ },
+ onClick(e, legendItem, legend) {
+ legend.chart.toggleDataVisibility(legendItem.index);
+ legend.chart.update();
+ }
+ },
+ tooltip: {
+ callbacks: {
+ title() {
+ return '';
+ },
+ label(tooltipItem) {
+ let dataLabel = tooltipItem.label;
+ const value = ': ' + tooltipItem.formattedValue;
+ if (isArray(dataLabel)) {
+ dataLabel = dataLabel.slice();
+ dataLabel[0] += value;
+ } else {
+ dataLabel += value;
+ }
+ return dataLabel;
+ }
+ }
+ }
+ }
+};
+
+class LineController extends DatasetController {
+ initialize() {
+ this.enableOptionSharing = true;
+ super.initialize();
+ }
+ update(mode) {
+ const meta = this._cachedMeta;
+ const {dataset: line, data: points = [], _dataset} = meta;
+ const animationsDisabled = this.chart._animationsDisabled;
+ let {start, count} = getStartAndCountOfVisiblePoints(meta, points, animationsDisabled);
+ this._drawStart = start;
+ this._drawCount = count;
+ if (scaleRangesChanged(meta)) {
+ start = 0;
+ count = points.length;
+ }
+ line._chart = this.chart;
+ line._datasetIndex = this.index;
+ line._decimated = !!_dataset._decimated;
+ line.points = points;
+ const options = this.resolveDatasetElementOptions(mode);
+ if (!this.options.showLine) {
+ options.borderWidth = 0;
+ }
+ options.segment = this.options.segment;
+ this.updateElement(line, undefined, {
+ animated: !animationsDisabled,
+ options
+ }, mode);
+ this.updateElements(points, start, count, mode);
+ }
+ updateElements(points, start, count, mode) {
+ const reset = mode === 'reset';
+ const {iScale, vScale, _stacked, _dataset} = this._cachedMeta;
+ const firstOpts = this.resolveDataElementOptions(start, mode);
+ const sharedOptions = this.getSharedOptions(firstOpts);
+ const includeOptions = this.includeOptions(mode, sharedOptions);
+ const iAxis = iScale.axis;
+ const vAxis = vScale.axis;
+ const {spanGaps, segment} = this.options;
+ const maxGapLength = isNumber(spanGaps) ? spanGaps : Number.POSITIVE_INFINITY;
+ const directUpdate = this.chart._animationsDisabled || reset || mode === 'none';
+ let prevParsed = start > 0 && this.getParsed(start - 1);
+ for (let i = start; i < start + count; ++i) {
+ const point = points[i];
+ const parsed = this.getParsed(i);
+ const properties = directUpdate ? point : {};
+ const nullData = isNullOrUndef(parsed[vAxis]);
+ const iPixel = properties[iAxis] = iScale.getPixelForValue(parsed[iAxis], i);
+ const vPixel = properties[vAxis] = reset || nullData ? vScale.getBasePixel() : vScale.getPixelForValue(_stacked ? this.applyStack(vScale, parsed, _stacked) : parsed[vAxis], i);
+ properties.skip = isNaN(iPixel) || isNaN(vPixel) || nullData;
+ properties.stop = i > 0 && (parsed[iAxis] - prevParsed[iAxis]) > maxGapLength;
+ if (segment) {
+ properties.parsed = parsed;
+ properties.raw = _dataset.data[i];
+ }
+ if (includeOptions) {
+ properties.options = sharedOptions || this.resolveDataElementOptions(i, point.active ? 'active' : mode);
+ }
+ if (!directUpdate) {
+ this.updateElement(point, i, properties, mode);
+ }
+ prevParsed = parsed;
+ }
+ this.updateSharedOptions(sharedOptions, mode, firstOpts);
+ }
+ getMaxOverflow() {
+ const meta = this._cachedMeta;
+ const dataset = meta.dataset;
+ const border = dataset.options && dataset.options.borderWidth || 0;
+ const data = meta.data || [];
+ if (!data.length) {
+ return border;
+ }
+ const firstPoint = data[0].size(this.resolveDataElementOptions(0));
+ const lastPoint = data[data.length - 1].size(this.resolveDataElementOptions(data.length - 1));
+ return Math.max(border, firstPoint, lastPoint) / 2;
+ }
+ draw() {
+ const meta = this._cachedMeta;
+ meta.dataset.updateControlPoints(this.chart.chartArea, meta.iScale.axis);
+ super.draw();
+ }
+}
+LineController.id = 'line';
+LineController.defaults = {
+ datasetElementType: 'line',
+ dataElementType: 'point',
+ showLine: true,
+ spanGaps: false,
+};
+LineController.overrides = {
+ scales: {
+ _index_: {
+ type: 'category',
+ },
+ _value_: {
+ type: 'linear',
+ },
+ }
+};
+function getStartAndCountOfVisiblePoints(meta, points, animationsDisabled) {
+ const pointCount = points.length;
+ let start = 0;
+ let count = pointCount;
+ if (meta._sorted) {
+ const {iScale, _parsed} = meta;
+ const axis = iScale.axis;
+ const {min, max, minDefined, maxDefined} = iScale.getUserBounds();
+ if (minDefined) {
+ start = _limitValue(Math.min(
+ _lookupByKey(_parsed, iScale.axis, min).lo,
+ animationsDisabled ? pointCount : _lookupByKey(points, axis, iScale.getPixelForValue(min)).lo),
+ 0, pointCount - 1);
+ }
+ if (maxDefined) {
+ count = _limitValue(Math.max(
+ _lookupByKey(_parsed, iScale.axis, max).hi + 1,
+ animationsDisabled ? 0 : _lookupByKey(points, axis, iScale.getPixelForValue(max)).hi + 1),
+ start, pointCount) - start;
+ } else {
+ count = pointCount - start;
+ }
+ }
+ return {start, count};
+}
+function scaleRangesChanged(meta) {
+ const {xScale, yScale, _scaleRanges} = meta;
+ const newRanges = {
+ xmin: xScale.min,
+ xmax: xScale.max,
+ ymin: yScale.min,
+ ymax: yScale.max
+ };
+ if (!_scaleRanges) {
+ meta._scaleRanges = newRanges;
+ return true;
+ }
+ const changed = _scaleRanges.xmin !== xScale.min
+ || _scaleRanges.xmax !== xScale.max
+ || _scaleRanges.ymin !== yScale.min
+ || _scaleRanges.ymax !== yScale.max;
+ Object.assign(_scaleRanges, newRanges);
+ return changed;
+}
+
+class PolarAreaController extends DatasetController {
+ constructor(chart, datasetIndex) {
+ super(chart, datasetIndex);
+ this.innerRadius = undefined;
+ this.outerRadius = undefined;
+ }
+ getLabelAndValue(index) {
+ const meta = this._cachedMeta;
+ const chart = this.chart;
+ const labels = chart.data.labels || [];
+ const value = formatNumber(meta._parsed[index].r, chart.options.locale);
+ return {
+ label: labels[index] || '',
+ value,
+ };
+ }
+ update(mode) {
+ const arcs = this._cachedMeta.data;
+ this._updateRadius();
+ this.updateElements(arcs, 0, arcs.length, mode);
+ }
+ _updateRadius() {
+ const chart = this.chart;
+ const chartArea = chart.chartArea;
+ const opts = chart.options;
+ const minSize = Math.min(chartArea.right - chartArea.left, chartArea.bottom - chartArea.top);
+ const outerRadius = Math.max(minSize / 2, 0);
+ const innerRadius = Math.max(opts.cutoutPercentage ? (outerRadius / 100) * (opts.cutoutPercentage) : 1, 0);
+ const radiusLength = (outerRadius - innerRadius) / chart.getVisibleDatasetCount();
+ this.outerRadius = outerRadius - (radiusLength * this.index);
+ this.innerRadius = this.outerRadius - radiusLength;
+ }
+ updateElements(arcs, start, count, mode) {
+ const reset = mode === 'reset';
+ const chart = this.chart;
+ const dataset = this.getDataset();
+ const opts = chart.options;
+ const animationOpts = opts.animation;
+ const scale = this._cachedMeta.rScale;
+ const centerX = scale.xCenter;
+ const centerY = scale.yCenter;
+ const datasetStartAngle = scale.getIndexAngle(0) - 0.5 * PI;
+ let angle = datasetStartAngle;
+ let i;
+ const defaultAngle = 360 / this.countVisibleElements();
+ for (i = 0; i < start; ++i) {
+ angle += this._computeAngle(i, mode, defaultAngle);
+ }
+ for (i = start; i < start + count; i++) {
+ const arc = arcs[i];
+ let startAngle = angle;
+ let endAngle = angle + this._computeAngle(i, mode, defaultAngle);
+ let outerRadius = chart.getDataVisibility(i) ? scale.getDistanceFromCenterForValue(dataset.data[i]) : 0;
+ angle = endAngle;
+ if (reset) {
+ if (animationOpts.animateScale) {
+ outerRadius = 0;
+ }
+ if (animationOpts.animateRotate) {
+ startAngle = endAngle = datasetStartAngle;
+ }
+ }
+ const properties = {
+ x: centerX,
+ y: centerY,
+ innerRadius: 0,
+ outerRadius,
+ startAngle,
+ endAngle,
+ options: this.resolveDataElementOptions(i, arc.active ? 'active' : mode)
+ };
+ this.updateElement(arc, i, properties, mode);
+ }
+ }
+ countVisibleElements() {
+ const dataset = this.getDataset();
+ const meta = this._cachedMeta;
+ let count = 0;
+ meta.data.forEach((element, index) => {
+ if (!isNaN(dataset.data[index]) && this.chart.getDataVisibility(index)) {
+ count++;
+ }
+ });
+ return count;
+ }
+ _computeAngle(index, mode, defaultAngle) {
+ return this.chart.getDataVisibility(index)
+ ? toRadians(this.resolveDataElementOptions(index, mode).angle || defaultAngle)
+ : 0;
+ }
+}
+PolarAreaController.id = 'polarArea';
+PolarAreaController.defaults = {
+ dataElementType: 'arc',
+ animation: {
+ animateRotate: true,
+ animateScale: true
+ },
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['x', 'y', 'startAngle', 'endAngle', 'innerRadius', 'outerRadius']
+ },
+ },
+ indexAxis: 'r',
+ startAngle: 0,
+};
+PolarAreaController.overrides = {
+ aspectRatio: 1,
+ plugins: {
+ legend: {
+ labels: {
+ generateLabels(chart) {
+ const data = chart.data;
+ if (data.labels.length && data.datasets.length) {
+ const {labels: {pointStyle}} = chart.legend.options;
+ return data.labels.map((label, i) => {
+ const meta = chart.getDatasetMeta(0);
+ const style = meta.controller.getStyle(i);
+ return {
+ text: label,
+ fillStyle: style.backgroundColor,
+ strokeStyle: style.borderColor,
+ lineWidth: style.borderWidth,
+ pointStyle: pointStyle,
+ hidden: !chart.getDataVisibility(i),
+ index: i
+ };
+ });
+ }
+ return [];
+ }
+ },
+ onClick(e, legendItem, legend) {
+ legend.chart.toggleDataVisibility(legendItem.index);
+ legend.chart.update();
+ }
+ },
+ tooltip: {
+ callbacks: {
+ title() {
+ return '';
+ },
+ label(context) {
+ return context.chart.data.labels[context.dataIndex] + ': ' + context.formattedValue;
+ }
+ }
+ }
+ },
+ scales: {
+ r: {
+ type: 'radialLinear',
+ angleLines: {
+ display: false
+ },
+ beginAtZero: true,
+ grid: {
+ circular: true
+ },
+ pointLabels: {
+ display: false
+ },
+ startAngle: 0
+ }
+ }
+};
+
+class PieController extends DoughnutController {
+}
+PieController.id = 'pie';
+PieController.defaults = {
+ cutout: 0,
+ rotation: 0,
+ circumference: 360,
+ radius: '100%'
+};
+
+class RadarController extends DatasetController {
+ getLabelAndValue(index) {
+ const vScale = this._cachedMeta.vScale;
+ const parsed = this.getParsed(index);
+ return {
+ label: vScale.getLabels()[index],
+ value: '' + vScale.getLabelForValue(parsed[vScale.axis])
+ };
+ }
+ update(mode) {
+ const meta = this._cachedMeta;
+ const line = meta.dataset;
+ const points = meta.data || [];
+ const labels = meta.iScale.getLabels();
+ line.points = points;
+ if (mode !== 'resize') {
+ const options = this.resolveDatasetElementOptions(mode);
+ if (!this.options.showLine) {
+ options.borderWidth = 0;
+ }
+ const properties = {
+ _loop: true,
+ _fullLoop: labels.length === points.length,
+ options
+ };
+ this.updateElement(line, undefined, properties, mode);
+ }
+ this.updateElements(points, 0, points.length, mode);
+ }
+ updateElements(points, start, count, mode) {
+ const dataset = this.getDataset();
+ const scale = this._cachedMeta.rScale;
+ const reset = mode === 'reset';
+ for (let i = start; i < start + count; i++) {
+ const point = points[i];
+ const options = this.resolveDataElementOptions(i, point.active ? 'active' : mode);
+ const pointPosition = scale.getPointPositionForValue(i, dataset.data[i]);
+ const x = reset ? scale.xCenter : pointPosition.x;
+ const y = reset ? scale.yCenter : pointPosition.y;
+ const properties = {
+ x,
+ y,
+ angle: pointPosition.angle,
+ skip: isNaN(x) || isNaN(y),
+ options
+ };
+ this.updateElement(point, i, properties, mode);
+ }
+ }
+}
+RadarController.id = 'radar';
+RadarController.defaults = {
+ datasetElementType: 'line',
+ dataElementType: 'point',
+ indexAxis: 'r',
+ showLine: true,
+ elements: {
+ line: {
+ fill: 'start'
+ }
+ },
+};
+RadarController.overrides = {
+ aspectRatio: 1,
+ scales: {
+ r: {
+ type: 'radialLinear',
+ }
+ }
+};
+
+class ScatterController extends LineController {
+}
+ScatterController.id = 'scatter';
+ScatterController.defaults = {
+ showLine: false,
+ fill: false
+};
+ScatterController.overrides = {
+ interaction: {
+ mode: 'point'
+ },
+ plugins: {
+ tooltip: {
+ callbacks: {
+ title() {
+ return '';
+ },
+ label(item) {
+ return '(' + item.label + ', ' + item.formattedValue + ')';
+ }
+ }
+ }
+ },
+ scales: {
+ x: {
+ type: 'linear'
+ },
+ y: {
+ type: 'linear'
+ }
+ }
+};
+
+var controllers = /*#__PURE__*/Object.freeze({
+__proto__: null,
+BarController: BarController,
+BubbleController: BubbleController,
+DoughnutController: DoughnutController,
+LineController: LineController,
+PolarAreaController: PolarAreaController,
+PieController: PieController,
+RadarController: RadarController,
+ScatterController: ScatterController
+});
+
+function clipArc(ctx, element, endAngle) {
+ const {startAngle, pixelMargin, x, y, outerRadius, innerRadius} = element;
+ let angleMargin = pixelMargin / outerRadius;
+ ctx.beginPath();
+ ctx.arc(x, y, outerRadius, startAngle - angleMargin, endAngle + angleMargin);
+ if (innerRadius > pixelMargin) {
+ angleMargin = pixelMargin / innerRadius;
+ ctx.arc(x, y, innerRadius, endAngle + angleMargin, startAngle - angleMargin, true);
+ } else {
+ ctx.arc(x, y, pixelMargin, endAngle + HALF_PI, startAngle - HALF_PI);
+ }
+ ctx.closePath();
+ ctx.clip();
+}
+function toRadiusCorners(value) {
+ return _readValueToProps(value, ['outerStart', 'outerEnd', 'innerStart', 'innerEnd']);
+}
+function parseBorderRadius$1(arc, innerRadius, outerRadius, angleDelta) {
+ const o = toRadiusCorners(arc.options.borderRadius);
+ const halfThickness = (outerRadius - innerRadius) / 2;
+ const innerLimit = Math.min(halfThickness, angleDelta * innerRadius / 2);
+ const computeOuterLimit = (val) => {
+ const outerArcLimit = (outerRadius - Math.min(halfThickness, val)) * angleDelta / 2;
+ return _limitValue(val, 0, Math.min(halfThickness, outerArcLimit));
+ };
+ return {
+ outerStart: computeOuterLimit(o.outerStart),
+ outerEnd: computeOuterLimit(o.outerEnd),
+ innerStart: _limitValue(o.innerStart, 0, innerLimit),
+ innerEnd: _limitValue(o.innerEnd, 0, innerLimit),
+ };
+}
+function rThetaToXY(r, theta, x, y) {
+ return {
+ x: x + r * Math.cos(theta),
+ y: y + r * Math.sin(theta),
+ };
+}
+function pathArc(ctx, element, offset, spacing, end) {
+ const {x, y, startAngle: start, pixelMargin, innerRadius: innerR} = element;
+ const outerRadius = Math.max(element.outerRadius + spacing + offset - pixelMargin, 0);
+ const innerRadius = innerR > 0 ? innerR + spacing + offset + pixelMargin : 0;
+ let spacingOffset = 0;
+ const alpha = end - start;
+ if (spacing) {
+ const noSpacingInnerRadius = innerR > 0 ? innerR - spacing : 0;
+ const noSpacingOuterRadius = outerRadius > 0 ? outerRadius - spacing : 0;
+ const avNogSpacingRadius = (noSpacingInnerRadius + noSpacingOuterRadius) / 2;
+ const adjustedAngle = avNogSpacingRadius !== 0 ? (alpha * avNogSpacingRadius) / (avNogSpacingRadius + spacing) : alpha;
+ spacingOffset = (alpha - adjustedAngle) / 2;
+ }
+ const beta = Math.max(0.001, alpha * outerRadius - offset / PI) / outerRadius;
+ const angleOffset = (alpha - beta) / 2;
+ const startAngle = start + angleOffset + spacingOffset;
+ const endAngle = end - angleOffset - spacingOffset;
+ const {outerStart, outerEnd, innerStart, innerEnd} = parseBorderRadius$1(element, innerRadius, outerRadius, endAngle - startAngle);
+ const outerStartAdjustedRadius = outerRadius - outerStart;
+ const outerEndAdjustedRadius = outerRadius - outerEnd;
+ const outerStartAdjustedAngle = startAngle + outerStart / outerStartAdjustedRadius;
+ const outerEndAdjustedAngle = endAngle - outerEnd / outerEndAdjustedRadius;
+ const innerStartAdjustedRadius = innerRadius + innerStart;
+ const innerEndAdjustedRadius = innerRadius + innerEnd;
+ const innerStartAdjustedAngle = startAngle + innerStart / innerStartAdjustedRadius;
+ const innerEndAdjustedAngle = endAngle - innerEnd / innerEndAdjustedRadius;
+ ctx.beginPath();
+ ctx.arc(x, y, outerRadius, outerStartAdjustedAngle, outerEndAdjustedAngle);
+ if (outerEnd > 0) {
+ const pCenter = rThetaToXY(outerEndAdjustedRadius, outerEndAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, outerEnd, outerEndAdjustedAngle, endAngle + HALF_PI);
+ }
+ const p4 = rThetaToXY(innerEndAdjustedRadius, endAngle, x, y);
+ ctx.lineTo(p4.x, p4.y);
+ if (innerEnd > 0) {
+ const pCenter = rThetaToXY(innerEndAdjustedRadius, innerEndAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, innerEnd, endAngle + HALF_PI, innerEndAdjustedAngle + Math.PI);
+ }
+ ctx.arc(x, y, innerRadius, endAngle - (innerEnd / innerRadius), startAngle + (innerStart / innerRadius), true);
+ if (innerStart > 0) {
+ const pCenter = rThetaToXY(innerStartAdjustedRadius, innerStartAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, innerStart, innerStartAdjustedAngle + Math.PI, startAngle - HALF_PI);
+ }
+ const p8 = rThetaToXY(outerStartAdjustedRadius, startAngle, x, y);
+ ctx.lineTo(p8.x, p8.y);
+ if (outerStart > 0) {
+ const pCenter = rThetaToXY(outerStartAdjustedRadius, outerStartAdjustedAngle, x, y);
+ ctx.arc(pCenter.x, pCenter.y, outerStart, startAngle - HALF_PI, outerStartAdjustedAngle);
+ }
+ ctx.closePath();
+}
+function drawArc(ctx, element, offset, spacing) {
+ const {fullCircles, startAngle, circumference} = element;
+ let endAngle = element.endAngle;
+ if (fullCircles) {
+ pathArc(ctx, element, offset, spacing, startAngle + TAU);
+ for (let i = 0; i < fullCircles; ++i) {
+ ctx.fill();
+ }
+ if (!isNaN(circumference)) {
+ endAngle = startAngle + circumference % TAU;
+ if (circumference % TAU === 0) {
+ endAngle += TAU;
+ }
+ }
+ }
+ pathArc(ctx, element, offset, spacing, endAngle);
+ ctx.fill();
+ return endAngle;
+}
+function drawFullCircleBorders(ctx, element, inner) {
+ const {x, y, startAngle, pixelMargin, fullCircles} = element;
+ const outerRadius = Math.max(element.outerRadius - pixelMargin, 0);
+ const innerRadius = element.innerRadius + pixelMargin;
+ let i;
+ if (inner) {
+ clipArc(ctx, element, startAngle + TAU);
+ }
+ ctx.beginPath();
+ ctx.arc(x, y, innerRadius, startAngle + TAU, startAngle, true);
+ for (i = 0; i < fullCircles; ++i) {
+ ctx.stroke();
+ }
+ ctx.beginPath();
+ ctx.arc(x, y, outerRadius, startAngle, startAngle + TAU);
+ for (i = 0; i < fullCircles; ++i) {
+ ctx.stroke();
+ }
+}
+function drawBorder(ctx, element, offset, spacing, endAngle) {
+ const {options} = element;
+ const {borderWidth, borderJoinStyle} = options;
+ const inner = options.borderAlign === 'inner';
+ if (!borderWidth) {
+ return;
+ }
+ if (inner) {
+ ctx.lineWidth = borderWidth * 2;
+ ctx.lineJoin = borderJoinStyle || 'round';
+ } else {
+ ctx.lineWidth = borderWidth;
+ ctx.lineJoin = borderJoinStyle || 'bevel';
+ }
+ if (element.fullCircles) {
+ drawFullCircleBorders(ctx, element, inner);
+ }
+ if (inner) {
+ clipArc(ctx, element, endAngle);
+ }
+ pathArc(ctx, element, offset, spacing, endAngle);
+ ctx.stroke();
+}
+class ArcElement extends Element {
+ constructor(cfg) {
+ super();
+ this.options = undefined;
+ this.circumference = undefined;
+ this.startAngle = undefined;
+ this.endAngle = undefined;
+ this.innerRadius = undefined;
+ this.outerRadius = undefined;
+ this.pixelMargin = 0;
+ this.fullCircles = 0;
+ if (cfg) {
+ Object.assign(this, cfg);
+ }
+ }
+ inRange(chartX, chartY, useFinalPosition) {
+ const point = this.getProps(['x', 'y'], useFinalPosition);
+ const {angle, distance} = getAngleFromPoint(point, {x: chartX, y: chartY});
+ const {startAngle, endAngle, innerRadius, outerRadius, circumference} = this.getProps([
+ 'startAngle',
+ 'endAngle',
+ 'innerRadius',
+ 'outerRadius',
+ 'circumference'
+ ], useFinalPosition);
+ const rAdjust = this.options.spacing / 2;
+ const _circumference = valueOrDefault(circumference, endAngle - startAngle);
+ const betweenAngles = _circumference >= TAU || _angleBetween(angle, startAngle, endAngle);
+ const withinRadius = _isBetween(distance, innerRadius + rAdjust, outerRadius + rAdjust);
+ return (betweenAngles && withinRadius);
+ }
+ getCenterPoint(useFinalPosition) {
+ const {x, y, startAngle, endAngle, innerRadius, outerRadius} = this.getProps([
+ 'x',
+ 'y',
+ 'startAngle',
+ 'endAngle',
+ 'innerRadius',
+ 'outerRadius',
+ 'circumference',
+ ], useFinalPosition);
+ const {offset, spacing} = this.options;
+ const halfAngle = (startAngle + endAngle) / 2;
+ const halfRadius = (innerRadius + outerRadius + spacing + offset) / 2;
+ return {
+ x: x + Math.cos(halfAngle) * halfRadius,
+ y: y + Math.sin(halfAngle) * halfRadius
+ };
+ }
+ tooltipPosition(useFinalPosition) {
+ return this.getCenterPoint(useFinalPosition);
+ }
+ draw(ctx) {
+ const {options, circumference} = this;
+ const offset = (options.offset || 0) / 2;
+ const spacing = (options.spacing || 0) / 2;
+ this.pixelMargin = (options.borderAlign === 'inner') ? 0.33 : 0;
+ this.fullCircles = circumference > TAU ? Math.floor(circumference / TAU) : 0;
+ if (circumference === 0 || this.innerRadius < 0 || this.outerRadius < 0) {
+ return;
+ }
+ ctx.save();
+ let radiusOffset = 0;
+ if (offset) {
+ radiusOffset = offset / 2;
+ const halfAngle = (this.startAngle + this.endAngle) / 2;
+ ctx.translate(Math.cos(halfAngle) * radiusOffset, Math.sin(halfAngle) * radiusOffset);
+ if (this.circumference >= PI) {
+ radiusOffset = offset;
+ }
+ }
+ ctx.fillStyle = options.backgroundColor;
+ ctx.strokeStyle = options.borderColor;
+ const endAngle = drawArc(ctx, this, radiusOffset, spacing);
+ drawBorder(ctx, this, radiusOffset, spacing, endAngle);
+ ctx.restore();
+ }
+}
+ArcElement.id = 'arc';
+ArcElement.defaults = {
+ borderAlign: 'center',
+ borderColor: '#fff',
+ borderJoinStyle: undefined,
+ borderRadius: 0,
+ borderWidth: 2,
+ offset: 0,
+ spacing: 0,
+ angle: undefined,
+};
+ArcElement.defaultRoutes = {
+ backgroundColor: 'backgroundColor'
+};
+
+function setStyle(ctx, options, style = options) {
+ ctx.lineCap = valueOrDefault(style.borderCapStyle, options.borderCapStyle);
+ ctx.setLineDash(valueOrDefault(style.borderDash, options.borderDash));
+ ctx.lineDashOffset = valueOrDefault(style.borderDashOffset, options.borderDashOffset);
+ ctx.lineJoin = valueOrDefault(style.borderJoinStyle, options.borderJoinStyle);
+ ctx.lineWidth = valueOrDefault(style.borderWidth, options.borderWidth);
+ ctx.strokeStyle = valueOrDefault(style.borderColor, options.borderColor);
+}
+function lineTo(ctx, previous, target) {
+ ctx.lineTo(target.x, target.y);
+}
+function getLineMethod(options) {
+ if (options.stepped) {
+ return _steppedLineTo;
+ }
+ if (options.tension || options.cubicInterpolationMode === 'monotone') {
+ return _bezierCurveTo;
+ }
+ return lineTo;
+}
+function pathVars(points, segment, params = {}) {
+ const count = points.length;
+ const {start: paramsStart = 0, end: paramsEnd = count - 1} = params;
+ const {start: segmentStart, end: segmentEnd} = segment;
+ const start = Math.max(paramsStart, segmentStart);
+ const end = Math.min(paramsEnd, segmentEnd);
+ const outside = paramsStart < segmentStart && paramsEnd < segmentStart || paramsStart > segmentEnd && paramsEnd > segmentEnd;
+ return {
+ count,
+ start,
+ loop: segment.loop,
+ ilen: end < start && !outside ? count + end - start : end - start
+ };
+}
+function pathSegment(ctx, line, segment, params) {
+ const {points, options} = line;
+ const {count, start, loop, ilen} = pathVars(points, segment, params);
+ const lineMethod = getLineMethod(options);
+ let {move = true, reverse} = params || {};
+ let i, point, prev;
+ for (i = 0; i <= ilen; ++i) {
+ point = points[(start + (reverse ? ilen - i : i)) % count];
+ if (point.skip) {
+ continue;
+ } else if (move) {
+ ctx.moveTo(point.x, point.y);
+ move = false;
+ } else {
+ lineMethod(ctx, prev, point, reverse, options.stepped);
+ }
+ prev = point;
+ }
+ if (loop) {
+ point = points[(start + (reverse ? ilen : 0)) % count];
+ lineMethod(ctx, prev, point, reverse, options.stepped);
+ }
+ return !!loop;
+}
+function fastPathSegment(ctx, line, segment, params) {
+ const points = line.points;
+ const {count, start, ilen} = pathVars(points, segment, params);
+ const {move = true, reverse} = params || {};
+ let avgX = 0;
+ let countX = 0;
+ let i, point, prevX, minY, maxY, lastY;
+ const pointIndex = (index) => (start + (reverse ? ilen - index : index)) % count;
+ const drawX = () => {
+ if (minY !== maxY) {
+ ctx.lineTo(avgX, maxY);
+ ctx.lineTo(avgX, minY);
+ ctx.lineTo(avgX, lastY);
+ }
+ };
+ if (move) {
+ point = points[pointIndex(0)];
+ ctx.moveTo(point.x, point.y);
+ }
+ for (i = 0; i <= ilen; ++i) {
+ point = points[pointIndex(i)];
+ if (point.skip) {
+ continue;
+ }
+ const x = point.x;
+ const y = point.y;
+ const truncX = x | 0;
+ if (truncX === prevX) {
+ if (y < minY) {
+ minY = y;
+ } else if (y > maxY) {
+ maxY = y;
+ }
+ avgX = (countX * avgX + x) / ++countX;
+ } else {
+ drawX();
+ ctx.lineTo(x, y);
+ prevX = truncX;
+ countX = 0;
+ minY = maxY = y;
+ }
+ lastY = y;
+ }
+ drawX();
+}
+function _getSegmentMethod(line) {
+ const opts = line.options;
+ const borderDash = opts.borderDash && opts.borderDash.length;
+ const useFastPath = !line._decimated && !line._loop && !opts.tension && opts.cubicInterpolationMode !== 'monotone' && !opts.stepped && !borderDash;
+ return useFastPath ? fastPathSegment : pathSegment;
+}
+function _getInterpolationMethod(options) {
+ if (options.stepped) {
+ return _steppedInterpolation;
+ }
+ if (options.tension || options.cubicInterpolationMode === 'monotone') {
+ return _bezierInterpolation;
+ }
+ return _pointInLine;
+}
+function strokePathWithCache(ctx, line, start, count) {
+ let path = line._path;
+ if (!path) {
+ path = line._path = new Path2D();
+ if (line.path(path, start, count)) {
+ path.closePath();
+ }
+ }
+ setStyle(ctx, line.options);
+ ctx.stroke(path);
+}
+function strokePathDirect(ctx, line, start, count) {
+ const {segments, options} = line;
+ const segmentMethod = _getSegmentMethod(line);
+ for (const segment of segments) {
+ setStyle(ctx, options, segment.style);
+ ctx.beginPath();
+ if (segmentMethod(ctx, line, segment, {start, end: start + count - 1})) {
+ ctx.closePath();
+ }
+ ctx.stroke();
+ }
+}
+const usePath2D = typeof Path2D === 'function';
+function draw(ctx, line, start, count) {
+ if (usePath2D && !line.options.segment) {
+ strokePathWithCache(ctx, line, start, count);
+ } else {
+ strokePathDirect(ctx, line, start, count);
+ }
+}
+class LineElement extends Element {
+ constructor(cfg) {
+ super();
+ this.animated = true;
+ this.options = undefined;
+ this._chart = undefined;
+ this._loop = undefined;
+ this._fullLoop = undefined;
+ this._path = undefined;
+ this._points = undefined;
+ this._segments = undefined;
+ this._decimated = false;
+ this._pointsUpdated = false;
+ this._datasetIndex = undefined;
+ if (cfg) {
+ Object.assign(this, cfg);
+ }
+ }
+ updateControlPoints(chartArea, indexAxis) {
+ const options = this.options;
+ if ((options.tension || options.cubicInterpolationMode === 'monotone') && !options.stepped && !this._pointsUpdated) {
+ const loop = options.spanGaps ? this._loop : this._fullLoop;
+ _updateBezierControlPoints(this._points, options, chartArea, loop, indexAxis);
+ this._pointsUpdated = true;
+ }
+ }
+ set points(points) {
+ this._points = points;
+ delete this._segments;
+ delete this._path;
+ this._pointsUpdated = false;
+ }
+ get points() {
+ return this._points;
+ }
+ get segments() {
+ return this._segments || (this._segments = _computeSegments(this, this.options.segment));
+ }
+ first() {
+ const segments = this.segments;
+ const points = this.points;
+ return segments.length && points[segments[0].start];
+ }
+ last() {
+ const segments = this.segments;
+ const points = this.points;
+ const count = segments.length;
+ return count && points[segments[count - 1].end];
+ }
+ interpolate(point, property) {
+ const options = this.options;
+ const value = point[property];
+ const points = this.points;
+ const segments = _boundSegments(this, {property, start: value, end: value});
+ if (!segments.length) {
+ return;
+ }
+ const result = [];
+ const _interpolate = _getInterpolationMethod(options);
+ let i, ilen;
+ for (i = 0, ilen = segments.length; i < ilen; ++i) {
+ const {start, end} = segments[i];
+ const p1 = points[start];
+ const p2 = points[end];
+ if (p1 === p2) {
+ result.push(p1);
+ continue;
+ }
+ const t = Math.abs((value - p1[property]) / (p2[property] - p1[property]));
+ const interpolated = _interpolate(p1, p2, t, options.stepped);
+ interpolated[property] = point[property];
+ result.push(interpolated);
+ }
+ return result.length === 1 ? result[0] : result;
+ }
+ pathSegment(ctx, segment, params) {
+ const segmentMethod = _getSegmentMethod(this);
+ return segmentMethod(ctx, this, segment, params);
+ }
+ path(ctx, start, count) {
+ const segments = this.segments;
+ const segmentMethod = _getSegmentMethod(this);
+ let loop = this._loop;
+ start = start || 0;
+ count = count || (this.points.length - start);
+ for (const segment of segments) {
+ loop &= segmentMethod(ctx, this, segment, {start, end: start + count - 1});
+ }
+ return !!loop;
+ }
+ draw(ctx, chartArea, start, count) {
+ const options = this.options || {};
+ const points = this.points || [];
+ if (points.length && options.borderWidth) {
+ ctx.save();
+ draw(ctx, this, start, count);
+ ctx.restore();
+ }
+ if (this.animated) {
+ this._pointsUpdated = false;
+ this._path = undefined;
+ }
+ }
+}
+LineElement.id = 'line';
+LineElement.defaults = {
+ borderCapStyle: 'butt',
+ borderDash: [],
+ borderDashOffset: 0,
+ borderJoinStyle: 'miter',
+ borderWidth: 3,
+ capBezierPoints: true,
+ cubicInterpolationMode: 'default',
+ fill: false,
+ spanGaps: false,
+ stepped: false,
+ tension: 0,
+};
+LineElement.defaultRoutes = {
+ backgroundColor: 'backgroundColor',
+ borderColor: 'borderColor'
+};
+LineElement.descriptors = {
+ _scriptable: true,
+ _indexable: (name) => name !== 'borderDash' && name !== 'fill',
+};
+
+function inRange$1(el, pos, axis, useFinalPosition) {
+ const options = el.options;
+ const {[axis]: value} = el.getProps([axis], useFinalPosition);
+ return (Math.abs(pos - value) < options.radius + options.hitRadius);
+}
+class PointElement extends Element {
+ constructor(cfg) {
+ super();
+ this.options = undefined;
+ this.parsed = undefined;
+ this.skip = undefined;
+ this.stop = undefined;
+ if (cfg) {
+ Object.assign(this, cfg);
+ }
+ }
+ inRange(mouseX, mouseY, useFinalPosition) {
+ const options = this.options;
+ const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+ return ((Math.pow(mouseX - x, 2) + Math.pow(mouseY - y, 2)) < Math.pow(options.hitRadius + options.radius, 2));
+ }
+ inXRange(mouseX, useFinalPosition) {
+ return inRange$1(this, mouseX, 'x', useFinalPosition);
+ }
+ inYRange(mouseY, useFinalPosition) {
+ return inRange$1(this, mouseY, 'y', useFinalPosition);
+ }
+ getCenterPoint(useFinalPosition) {
+ const {x, y} = this.getProps(['x', 'y'], useFinalPosition);
+ return {x, y};
+ }
+ size(options) {
+ options = options || this.options || {};
+ let radius = options.radius || 0;
+ radius = Math.max(radius, radius && options.hoverRadius || 0);
+ const borderWidth = radius && options.borderWidth || 0;
+ return (radius + borderWidth) * 2;
+ }
+ draw(ctx, area) {
+ const options = this.options;
+ if (this.skip || options.radius < 0.1 || !_isPointInArea(this, area, this.size(options) / 2)) {
+ return;
+ }
+ ctx.strokeStyle = options.borderColor;
+ ctx.lineWidth = options.borderWidth;
+ ctx.fillStyle = options.backgroundColor;
+ drawPoint(ctx, options, this.x, this.y);
+ }
+ getRange() {
+ const options = this.options || {};
+ return options.radius + options.hitRadius;
+ }
+}
+PointElement.id = 'point';
+PointElement.defaults = {
+ borderWidth: 1,
+ hitRadius: 1,
+ hoverBorderWidth: 1,
+ hoverRadius: 4,
+ pointStyle: 'circle',
+ radius: 3,
+ rotation: 0
+};
+PointElement.defaultRoutes = {
+ backgroundColor: 'backgroundColor',
+ borderColor: 'borderColor'
+};
+
+function getBarBounds(bar, useFinalPosition) {
+ const {x, y, base, width, height} = bar.getProps(['x', 'y', 'base', 'width', 'height'], useFinalPosition);
+ let left, right, top, bottom, half;
+ if (bar.horizontal) {
+ half = height / 2;
+ left = Math.min(x, base);
+ right = Math.max(x, base);
+ top = y - half;
+ bottom = y + half;
+ } else {
+ half = width / 2;
+ left = x - half;
+ right = x + half;
+ top = Math.min(y, base);
+ bottom = Math.max(y, base);
+ }
+ return {left, top, right, bottom};
+}
+function skipOrLimit(skip, value, min, max) {
+ return skip ? 0 : _limitValue(value, min, max);
+}
+function parseBorderWidth(bar, maxW, maxH) {
+ const value = bar.options.borderWidth;
+ const skip = bar.borderSkipped;
+ const o = toTRBL(value);
+ return {
+ t: skipOrLimit(skip.top, o.top, 0, maxH),
+ r: skipOrLimit(skip.right, o.right, 0, maxW),
+ b: skipOrLimit(skip.bottom, o.bottom, 0, maxH),
+ l: skipOrLimit(skip.left, o.left, 0, maxW)
+ };
+}
+function parseBorderRadius(bar, maxW, maxH) {
+ const {enableBorderRadius} = bar.getProps(['enableBorderRadius']);
+ const value = bar.options.borderRadius;
+ const o = toTRBLCorners(value);
+ const maxR = Math.min(maxW, maxH);
+ const skip = bar.borderSkipped;
+ const enableBorder = enableBorderRadius || isObject(value);
+ return {
+ topLeft: skipOrLimit(!enableBorder || skip.top || skip.left, o.topLeft, 0, maxR),
+ topRight: skipOrLimit(!enableBorder || skip.top || skip.right, o.topRight, 0, maxR),
+ bottomLeft: skipOrLimit(!enableBorder || skip.bottom || skip.left, o.bottomLeft, 0, maxR),
+ bottomRight: skipOrLimit(!enableBorder || skip.bottom || skip.right, o.bottomRight, 0, maxR)
+ };
+}
+function boundingRects(bar) {
+ const bounds = getBarBounds(bar);
+ const width = bounds.right - bounds.left;
+ const height = bounds.bottom - bounds.top;
+ const border = parseBorderWidth(bar, width / 2, height / 2);
+ const radius = parseBorderRadius(bar, width / 2, height / 2);
+ return {
+ outer: {
+ x: bounds.left,
+ y: bounds.top,
+ w: width,
+ h: height,
+ radius
+ },
+ inner: {
+ x: bounds.left + border.l,
+ y: bounds.top + border.t,
+ w: width - border.l - border.r,
+ h: height - border.t - border.b,
+ radius: {
+ topLeft: Math.max(0, radius.topLeft - Math.max(border.t, border.l)),
+ topRight: Math.max(0, radius.topRight - Math.max(border.t, border.r)),
+ bottomLeft: Math.max(0, radius.bottomLeft - Math.max(border.b, border.l)),
+ bottomRight: Math.max(0, radius.bottomRight - Math.max(border.b, border.r)),
+ }
+ }
+ };
+}
+function inRange(bar, x, y, useFinalPosition) {
+ const skipX = x === null;
+ const skipY = y === null;
+ const skipBoth = skipX && skipY;
+ const bounds = bar && !skipBoth && getBarBounds(bar, useFinalPosition);
+ return bounds
+ && (skipX || _isBetween(x, bounds.left, bounds.right))
+ && (skipY || _isBetween(y, bounds.top, bounds.bottom));
+}
+function hasRadius(radius) {
+ return radius.topLeft || radius.topRight || radius.bottomLeft || radius.bottomRight;
+}
+function addNormalRectPath(ctx, rect) {
+ ctx.rect(rect.x, rect.y, rect.w, rect.h);
+}
+function inflateRect(rect, amount, refRect = {}) {
+ const x = rect.x !== refRect.x ? -amount : 0;
+ const y = rect.y !== refRect.y ? -amount : 0;
+ const w = (rect.x + rect.w !== refRect.x + refRect.w ? amount : 0) - x;
+ const h = (rect.y + rect.h !== refRect.y + refRect.h ? amount : 0) - y;
+ return {
+ x: rect.x + x,
+ y: rect.y + y,
+ w: rect.w + w,
+ h: rect.h + h,
+ radius: rect.radius
+ };
+}
+class BarElement extends Element {
+ constructor(cfg) {
+ super();
+ this.options = undefined;
+ this.horizontal = undefined;
+ this.base = undefined;
+ this.width = undefined;
+ this.height = undefined;
+ this.inflateAmount = undefined;
+ if (cfg) {
+ Object.assign(this, cfg);
+ }
+ }
+ draw(ctx) {
+ const {inflateAmount, options: {borderColor, backgroundColor}} = this;
+ const {inner, outer} = boundingRects(this);
+ const addRectPath = hasRadius(outer.radius) ? addRoundedRectPath : addNormalRectPath;
+ ctx.save();
+ if (outer.w !== inner.w || outer.h !== inner.h) {
+ ctx.beginPath();
+ addRectPath(ctx, inflateRect(outer, inflateAmount, inner));
+ ctx.clip();
+ addRectPath(ctx, inflateRect(inner, -inflateAmount, outer));
+ ctx.fillStyle = borderColor;
+ ctx.fill('evenodd');
+ }
+ ctx.beginPath();
+ addRectPath(ctx, inflateRect(inner, inflateAmount));
+ ctx.fillStyle = backgroundColor;
+ ctx.fill();
+ ctx.restore();
+ }
+ inRange(mouseX, mouseY, useFinalPosition) {
+ return inRange(this, mouseX, mouseY, useFinalPosition);
+ }
+ inXRange(mouseX, useFinalPosition) {
+ return inRange(this, mouseX, null, useFinalPosition);
+ }
+ inYRange(mouseY, useFinalPosition) {
+ return inRange(this, null, mouseY, useFinalPosition);
+ }
+ getCenterPoint(useFinalPosition) {
+ const {x, y, base, horizontal} = this.getProps(['x', 'y', 'base', 'horizontal'], useFinalPosition);
+ return {
+ x: horizontal ? (x + base) / 2 : x,
+ y: horizontal ? y : (y + base) / 2
+ };
+ }
+ getRange(axis) {
+ return axis === 'x' ? this.width / 2 : this.height / 2;
+ }
+}
+BarElement.id = 'bar';
+BarElement.defaults = {
+ borderSkipped: 'start',
+ borderWidth: 0,
+ borderRadius: 0,
+ inflateAmount: 'auto',
+ pointStyle: undefined
+};
+BarElement.defaultRoutes = {
+ backgroundColor: 'backgroundColor',
+ borderColor: 'borderColor'
+};
+
+var elements = /*#__PURE__*/Object.freeze({
+__proto__: null,
+ArcElement: ArcElement,
+LineElement: LineElement,
+PointElement: PointElement,
+BarElement: BarElement
+});
+
+function lttbDecimation(data, start, count, availableWidth, options) {
+ const samples = options.samples || availableWidth;
+ if (samples >= count) {
+ return data.slice(start, start + count);
+ }
+ const decimated = [];
+ const bucketWidth = (count - 2) / (samples - 2);
+ let sampledIndex = 0;
+ const endIndex = start + count - 1;
+ let a = start;
+ let i, maxAreaPoint, maxArea, area, nextA;
+ decimated[sampledIndex++] = data[a];
+ for (i = 0; i < samples - 2; i++) {
+ let avgX = 0;
+ let avgY = 0;
+ let j;
+ const avgRangeStart = Math.floor((i + 1) * bucketWidth) + 1 + start;
+ const avgRangeEnd = Math.min(Math.floor((i + 2) * bucketWidth) + 1, count) + start;
+ const avgRangeLength = avgRangeEnd - avgRangeStart;
+ for (j = avgRangeStart; j < avgRangeEnd; j++) {
+ avgX += data[j].x;
+ avgY += data[j].y;
+ }
+ avgX /= avgRangeLength;
+ avgY /= avgRangeLength;
+ const rangeOffs = Math.floor(i * bucketWidth) + 1 + start;
+ const rangeTo = Math.min(Math.floor((i + 1) * bucketWidth) + 1, count) + start;
+ const {x: pointAx, y: pointAy} = data[a];
+ maxArea = area = -1;
+ for (j = rangeOffs; j < rangeTo; j++) {
+ area = 0.5 * Math.abs(
+ (pointAx - avgX) * (data[j].y - pointAy) -
+ (pointAx - data[j].x) * (avgY - pointAy)
+ );
+ if (area > maxArea) {
+ maxArea = area;
+ maxAreaPoint = data[j];
+ nextA = j;
+ }
+ }
+ decimated[sampledIndex++] = maxAreaPoint;
+ a = nextA;
+ }
+ decimated[sampledIndex++] = data[endIndex];
+ return decimated;
+}
+function minMaxDecimation(data, start, count, availableWidth) {
+ let avgX = 0;
+ let countX = 0;
+ let i, point, x, y, prevX, minIndex, maxIndex, startIndex, minY, maxY;
+ const decimated = [];
+ const endIndex = start + count - 1;
+ const xMin = data[start].x;
+ const xMax = data[endIndex].x;
+ const dx = xMax - xMin;
+ for (i = start; i < start + count; ++i) {
+ point = data[i];
+ x = (point.x - xMin) / dx * availableWidth;
+ y = point.y;
+ const truncX = x | 0;
+ if (truncX === prevX) {
+ if (y < minY) {
+ minY = y;
+ minIndex = i;
+ } else if (y > maxY) {
+ maxY = y;
+ maxIndex = i;
+ }
+ avgX = (countX * avgX + point.x) / ++countX;
+ } else {
+ const lastIndex = i - 1;
+ if (!isNullOrUndef(minIndex) && !isNullOrUndef(maxIndex)) {
+ const intermediateIndex1 = Math.min(minIndex, maxIndex);
+ const intermediateIndex2 = Math.max(minIndex, maxIndex);
+ if (intermediateIndex1 !== startIndex && intermediateIndex1 !== lastIndex) {
+ decimated.push({
+ ...data[intermediateIndex1],
+ x: avgX,
+ });
+ }
+ if (intermediateIndex2 !== startIndex && intermediateIndex2 !== lastIndex) {
+ decimated.push({
+ ...data[intermediateIndex2],
+ x: avgX
+ });
+ }
+ }
+ if (i > 0 && lastIndex !== startIndex) {
+ decimated.push(data[lastIndex]);
+ }
+ decimated.push(point);
+ prevX = truncX;
+ countX = 0;
+ minY = maxY = y;
+ minIndex = maxIndex = startIndex = i;
+ }
+ }
+ return decimated;
+}
+function cleanDecimatedDataset(dataset) {
+ if (dataset._decimated) {
+ const data = dataset._data;
+ delete dataset._decimated;
+ delete dataset._data;
+ Object.defineProperty(dataset, 'data', {value: data});
+ }
+}
+function cleanDecimatedData(chart) {
+ chart.data.datasets.forEach((dataset) => {
+ cleanDecimatedDataset(dataset);
+ });
+}
+function getStartAndCountOfVisiblePointsSimplified(meta, points) {
+ const pointCount = points.length;
+ let start = 0;
+ let count;
+ const {iScale} = meta;
+ const {min, max, minDefined, maxDefined} = iScale.getUserBounds();
+ if (minDefined) {
+ start = _limitValue(_lookupByKey(points, iScale.axis, min).lo, 0, pointCount - 1);
+ }
+ if (maxDefined) {
+ count = _limitValue(_lookupByKey(points, iScale.axis, max).hi + 1, start, pointCount) - start;
+ } else {
+ count = pointCount - start;
+ }
+ return {start, count};
+}
+var plugin_decimation = {
+ id: 'decimation',
+ defaults: {
+ algorithm: 'min-max',
+ enabled: false,
+ },
+ beforeElementsUpdate: (chart, args, options) => {
+ if (!options.enabled) {
+ cleanDecimatedData(chart);
+ return;
+ }
+ const availableWidth = chart.width;
+ chart.data.datasets.forEach((dataset, datasetIndex) => {
+ const {_data, indexAxis} = dataset;
+ const meta = chart.getDatasetMeta(datasetIndex);
+ const data = _data || dataset.data;
+ if (resolve([indexAxis, chart.options.indexAxis]) === 'y') {
+ return;
+ }
+ if (meta.type !== 'line') {
+ return;
+ }
+ const xAxis = chart.scales[meta.xAxisID];
+ if (xAxis.type !== 'linear' && xAxis.type !== 'time') {
+ return;
+ }
+ if (chart.options.parsing) {
+ return;
+ }
+ let {start, count} = getStartAndCountOfVisiblePointsSimplified(meta, data);
+ const threshold = options.threshold || 4 * availableWidth;
+ if (count <= threshold) {
+ cleanDecimatedDataset(dataset);
+ return;
+ }
+ if (isNullOrUndef(_data)) {
+ dataset._data = data;
+ delete dataset.data;
+ Object.defineProperty(dataset, 'data', {
+ configurable: true,
+ enumerable: true,
+ get: function() {
+ return this._decimated;
+ },
+ set: function(d) {
+ this._data = d;
+ }
+ });
+ }
+ let decimated;
+ switch (options.algorithm) {
+ case 'lttb':
+ decimated = lttbDecimation(data, start, count, availableWidth, options);
+ break;
+ case 'min-max':
+ decimated = minMaxDecimation(data, start, count, availableWidth);
+ break;
+ default:
+ throw new Error(`Unsupported decimation algorithm '${options.algorithm}'`);
+ }
+ dataset._decimated = decimated;
+ });
+ },
+ destroy(chart) {
+ cleanDecimatedData(chart);
+ }
+};
+
+function getLineByIndex(chart, index) {
+ const meta = chart.getDatasetMeta(index);
+ const visible = meta && chart.isDatasetVisible(index);
+ return visible ? meta.dataset : null;
+}
+function parseFillOption(line) {
+ const options = line.options;
+ const fillOption = options.fill;
+ let fill = valueOrDefault(fillOption && fillOption.target, fillOption);
+ if (fill === undefined) {
+ fill = !!options.backgroundColor;
+ }
+ if (fill === false || fill === null) {
+ return false;
+ }
+ if (fill === true) {
+ return 'origin';
+ }
+ return fill;
+}
+function decodeFill(line, index, count) {
+ const fill = parseFillOption(line);
+ if (isObject(fill)) {
+ return isNaN(fill.value) ? false : fill;
+ }
+ let target = parseFloat(fill);
+ if (isNumberFinite(target) && Math.floor(target) === target) {
+ if (fill[0] === '-' || fill[0] === '+') {
+ target = index + target;
+ }
+ if (target === index || target < 0 || target >= count) {
+ return false;
+ }
+ return target;
+ }
+ return ['origin', 'start', 'end', 'stack', 'shape'].indexOf(fill) >= 0 && fill;
+}
+function computeLinearBoundary(source) {
+ const {scale = {}, fill} = source;
+ let target = null;
+ let horizontal;
+ if (fill === 'start') {
+ target = scale.bottom;
+ } else if (fill === 'end') {
+ target = scale.top;
+ } else if (isObject(fill)) {
+ target = scale.getPixelForValue(fill.value);
+ } else if (scale.getBasePixel) {
+ target = scale.getBasePixel();
+ }
+ if (isNumberFinite(target)) {
+ horizontal = scale.isHorizontal();
+ return {
+ x: horizontal ? target : null,
+ y: horizontal ? null : target
+ };
+ }
+ return null;
+}
+class simpleArc {
+ constructor(opts) {
+ this.x = opts.x;
+ this.y = opts.y;
+ this.radius = opts.radius;
+ }
+ pathSegment(ctx, bounds, opts) {
+ const {x, y, radius} = this;
+ bounds = bounds || {start: 0, end: TAU};
+ ctx.arc(x, y, radius, bounds.end, bounds.start, true);
+ return !opts.bounds;
+ }
+ interpolate(point) {
+ const {x, y, radius} = this;
+ const angle = point.angle;
+ return {
+ x: x + Math.cos(angle) * radius,
+ y: y + Math.sin(angle) * radius,
+ angle
+ };
+ }
+}
+function computeCircularBoundary(source) {
+ const {scale, fill} = source;
+ const options = scale.options;
+ const length = scale.getLabels().length;
+ const target = [];
+ const start = options.reverse ? scale.max : scale.min;
+ const end = options.reverse ? scale.min : scale.max;
+ let i, center, value;
+ if (fill === 'start') {
+ value = start;
+ } else if (fill === 'end') {
+ value = end;
+ } else if (isObject(fill)) {
+ value = fill.value;
+ } else {
+ value = scale.getBaseValue();
+ }
+ if (options.grid.circular) {
+ center = scale.getPointPositionForValue(0, start);
+ return new simpleArc({
+ x: center.x,
+ y: center.y,
+ radius: scale.getDistanceFromCenterForValue(value)
+ });
+ }
+ for (i = 0; i < length; ++i) {
+ target.push(scale.getPointPositionForValue(i, value));
+ }
+ return target;
+}
+function computeBoundary(source) {
+ const scale = source.scale || {};
+ if (scale.getPointPositionForValue) {
+ return computeCircularBoundary(source);
+ }
+ return computeLinearBoundary(source);
+}
+function findSegmentEnd(start, end, points) {
+ for (;end > start; end--) {
+ const point = points[end];
+ if (!isNaN(point.x) && !isNaN(point.y)) {
+ break;
+ }
+ }
+ return end;
+}
+function pointsFromSegments(boundary, line) {
+ const {x = null, y = null} = boundary || {};
+ const linePoints = line.points;
+ const points = [];
+ line.segments.forEach(({start, end}) => {
+ end = findSegmentEnd(start, end, linePoints);
+ const first = linePoints[start];
+ const last = linePoints[end];
+ if (y !== null) {
+ points.push({x: first.x, y});
+ points.push({x: last.x, y});
+ } else if (x !== null) {
+ points.push({x, y: first.y});
+ points.push({x, y: last.y});
+ }
+ });
+ return points;
+}
+function buildStackLine(source) {
+ const {scale, index, line} = source;
+ const points = [];
+ const segments = line.segments;
+ const sourcePoints = line.points;
+ const linesBelow = getLinesBelow(scale, index);
+ linesBelow.push(createBoundaryLine({x: null, y: scale.bottom}, line));
+ for (let i = 0; i < segments.length; i++) {
+ const segment = segments[i];
+ for (let j = segment.start; j <= segment.end; j++) {
+ addPointsBelow(points, sourcePoints[j], linesBelow);
+ }
+ }
+ return new LineElement({points, options: {}});
+}
+function getLinesBelow(scale, index) {
+ const below = [];
+ const metas = scale.getMatchingVisibleMetas('line');
+ for (let i = 0; i < metas.length; i++) {
+ const meta = metas[i];
+ if (meta.index === index) {
+ break;
+ }
+ if (!meta.hidden) {
+ below.unshift(meta.dataset);
+ }
+ }
+ return below;
+}
+function addPointsBelow(points, sourcePoint, linesBelow) {
+ const postponed = [];
+ for (let j = 0; j < linesBelow.length; j++) {
+ const line = linesBelow[j];
+ const {first, last, point} = findPoint(line, sourcePoint, 'x');
+ if (!point || (first && last)) {
+ continue;
+ }
+ if (first) {
+ postponed.unshift(point);
+ } else {
+ points.push(point);
+ if (!last) {
+ break;
+ }
+ }
+ }
+ points.push(...postponed);
+}
+function findPoint(line, sourcePoint, property) {
+ const point = line.interpolate(sourcePoint, property);
+ if (!point) {
+ return {};
+ }
+ const pointValue = point[property];
+ const segments = line.segments;
+ const linePoints = line.points;
+ let first = false;
+ let last = false;
+ for (let i = 0; i < segments.length; i++) {
+ const segment = segments[i];
+ const firstValue = linePoints[segment.start][property];
+ const lastValue = linePoints[segment.end][property];
+ if (_isBetween(pointValue, firstValue, lastValue)) {
+ first = pointValue === firstValue;
+ last = pointValue === lastValue;
+ break;
+ }
+ }
+ return {first, last, point};
+}
+function getTarget(source) {
+ const {chart, fill, line} = source;
+ if (isNumberFinite(fill)) {
+ return getLineByIndex(chart, fill);
+ }
+ if (fill === 'stack') {
+ return buildStackLine(source);
+ }
+ if (fill === 'shape') {
+ return true;
+ }
+ const boundary = computeBoundary(source);
+ if (boundary instanceof simpleArc) {
+ return boundary;
+ }
+ return createBoundaryLine(boundary, line);
+}
+function createBoundaryLine(boundary, line) {
+ let points = [];
+ let _loop = false;
+ if (isArray(boundary)) {
+ _loop = true;
+ points = boundary;
+ } else {
+ points = pointsFromSegments(boundary, line);
+ }
+ return points.length ? new LineElement({
+ points,
+ options: {tension: 0},
+ _loop,
+ _fullLoop: _loop
+ }) : null;
+}
+function resolveTarget(sources, index, propagate) {
+ const source = sources[index];
+ let fill = source.fill;
+ const visited = [index];
+ let target;
+ if (!propagate) {
+ return fill;
+ }
+ while (fill !== false && visited.indexOf(fill) === -1) {
+ if (!isNumberFinite(fill)) {
+ return fill;
+ }
+ target = sources[fill];
+ if (!target) {
+ return false;
+ }
+ if (target.visible) {
+ return fill;
+ }
+ visited.push(fill);
+ fill = target.fill;
+ }
+ return false;
+}
+function _clip(ctx, target, clipY) {
+ const {segments, points} = target;
+ let first = true;
+ let lineLoop = false;
+ ctx.beginPath();
+ for (const segment of segments) {
+ const {start, end} = segment;
+ const firstPoint = points[start];
+ const lastPoint = points[findSegmentEnd(start, end, points)];
+ if (first) {
+ ctx.moveTo(firstPoint.x, firstPoint.y);
+ first = false;
+ } else {
+ ctx.lineTo(firstPoint.x, clipY);
+ ctx.lineTo(firstPoint.x, firstPoint.y);
+ }
+ lineLoop = !!target.pathSegment(ctx, segment, {move: lineLoop});
+ if (lineLoop) {
+ ctx.closePath();
+ } else {
+ ctx.lineTo(lastPoint.x, clipY);
+ }
+ }
+ ctx.lineTo(target.first().x, clipY);
+ ctx.closePath();
+ ctx.clip();
+}
+function getBounds(property, first, last, loop) {
+ if (loop) {
+ return;
+ }
+ let start = first[property];
+ let end = last[property];
+ if (property === 'angle') {
+ start = _normalizeAngle(start);
+ end = _normalizeAngle(end);
+ }
+ return {property, start, end};
+}
+function _getEdge(a, b, prop, fn) {
+ if (a && b) {
+ return fn(a[prop], b[prop]);
+ }
+ return a ? a[prop] : b ? b[prop] : 0;
+}
+function _segments(line, target, property) {
+ const segments = line.segments;
+ const points = line.points;
+ const tpoints = target.points;
+ const parts = [];
+ for (const segment of segments) {
+ let {start, end} = segment;
+ end = findSegmentEnd(start, end, points);
+ const bounds = getBounds(property, points[start], points[end], segment.loop);
+ if (!target.segments) {
+ parts.push({
+ source: segment,
+ target: bounds,
+ start: points[start],
+ end: points[end]
+ });
+ continue;
+ }
+ const targetSegments = _boundSegments(target, bounds);
+ for (const tgt of targetSegments) {
+ const subBounds = getBounds(property, tpoints[tgt.start], tpoints[tgt.end], tgt.loop);
+ const fillSources = _boundSegment(segment, points, subBounds);
+ for (const fillSource of fillSources) {
+ parts.push({
+ source: fillSource,
+ target: tgt,
+ start: {
+ [property]: _getEdge(bounds, subBounds, 'start', Math.max)
+ },
+ end: {
+ [property]: _getEdge(bounds, subBounds, 'end', Math.min)
+ }
+ });
+ }
+ }
+ }
+ return parts;
+}
+function clipBounds(ctx, scale, bounds) {
+ const {top, bottom} = scale.chart.chartArea;
+ const {property, start, end} = bounds || {};
+ if (property === 'x') {
+ ctx.beginPath();
+ ctx.rect(start, top, end - start, bottom - top);
+ ctx.clip();
+ }
+}
+function interpolatedLineTo(ctx, target, point, property) {
+ const interpolatedPoint = target.interpolate(point, property);
+ if (interpolatedPoint) {
+ ctx.lineTo(interpolatedPoint.x, interpolatedPoint.y);
+ }
+}
+function _fill(ctx, cfg) {
+ const {line, target, property, color, scale} = cfg;
+ const segments = _segments(line, target, property);
+ for (const {source: src, target: tgt, start, end} of segments) {
+ const {style: {backgroundColor = color} = {}} = src;
+ const notShape = target !== true;
+ ctx.save();
+ ctx.fillStyle = backgroundColor;
+ clipBounds(ctx, scale, notShape && getBounds(property, start, end));
+ ctx.beginPath();
+ const lineLoop = !!line.pathSegment(ctx, src);
+ let loop;
+ if (notShape) {
+ if (lineLoop) {
+ ctx.closePath();
+ } else {
+ interpolatedLineTo(ctx, target, end, property);
+ }
+ const targetLoop = !!target.pathSegment(ctx, tgt, {move: lineLoop, reverse: true});
+ loop = lineLoop && targetLoop;
+ if (!loop) {
+ interpolatedLineTo(ctx, target, start, property);
+ }
+ }
+ ctx.closePath();
+ ctx.fill(loop ? 'evenodd' : 'nonzero');
+ ctx.restore();
+ }
+}
+function doFill(ctx, cfg) {
+ const {line, target, above, below, area, scale} = cfg;
+ const property = line._loop ? 'angle' : cfg.axis;
+ ctx.save();
+ if (property === 'x' && below !== above) {
+ _clip(ctx, target, area.top);
+ _fill(ctx, {line, target, color: above, scale, property});
+ ctx.restore();
+ ctx.save();
+ _clip(ctx, target, area.bottom);
+ }
+ _fill(ctx, {line, target, color: below, scale, property});
+ ctx.restore();
+}
+function drawfill(ctx, source, area) {
+ const target = getTarget(source);
+ const {line, scale, axis} = source;
+ const lineOpts = line.options;
+ const fillOption = lineOpts.fill;
+ const color = lineOpts.backgroundColor;
+ const {above = color, below = color} = fillOption || {};
+ if (target && line.points.length) {
+ clipArea(ctx, area);
+ doFill(ctx, {line, target, above, below, area, scale, axis});
+ unclipArea(ctx);
+ }
+}
+var plugin_filler = {
+ id: 'filler',
+ afterDatasetsUpdate(chart, _args, options) {
+ const count = (chart.data.datasets || []).length;
+ const sources = [];
+ let meta, i, line, source;
+ for (i = 0; i < count; ++i) {
+ meta = chart.getDatasetMeta(i);
+ line = meta.dataset;
+ source = null;
+ if (line && line.options && line instanceof LineElement) {
+ source = {
+ visible: chart.isDatasetVisible(i),
+ index: i,
+ fill: decodeFill(line, i, count),
+ chart,
+ axis: meta.controller.options.indexAxis,
+ scale: meta.vScale,
+ line,
+ };
+ }
+ meta.$filler = source;
+ sources.push(source);
+ }
+ for (i = 0; i < count; ++i) {
+ source = sources[i];
+ if (!source || source.fill === false) {
+ continue;
+ }
+ source.fill = resolveTarget(sources, i, options.propagate);
+ }
+ },
+ beforeDraw(chart, _args, options) {
+ const draw = options.drawTime === 'beforeDraw';
+ const metasets = chart.getSortedVisibleDatasetMetas();
+ const area = chart.chartArea;
+ for (let i = metasets.length - 1; i >= 0; --i) {
+ const source = metasets[i].$filler;
+ if (!source) {
+ continue;
+ }
+ source.line.updateControlPoints(area, source.axis);
+ if (draw) {
+ drawfill(chart.ctx, source, area);
+ }
+ }
+ },
+ beforeDatasetsDraw(chart, _args, options) {
+ if (options.drawTime !== 'beforeDatasetsDraw') {
+ return;
+ }
+ const metasets = chart.getSortedVisibleDatasetMetas();
+ for (let i = metasets.length - 1; i >= 0; --i) {
+ const source = metasets[i].$filler;
+ if (source) {
+ drawfill(chart.ctx, source, chart.chartArea);
+ }
+ }
+ },
+ beforeDatasetDraw(chart, args, options) {
+ const source = args.meta.$filler;
+ if (!source || source.fill === false || options.drawTime !== 'beforeDatasetDraw') {
+ return;
+ }
+ drawfill(chart.ctx, source, chart.chartArea);
+ },
+ defaults: {
+ propagate: true,
+ drawTime: 'beforeDatasetDraw'
+ }
+};
+
+const getBoxSize = (labelOpts, fontSize) => {
+ let {boxHeight = fontSize, boxWidth = fontSize} = labelOpts;
+ if (labelOpts.usePointStyle) {
+ boxHeight = Math.min(boxHeight, fontSize);
+ boxWidth = Math.min(boxWidth, fontSize);
+ }
+ return {
+ boxWidth,
+ boxHeight,
+ itemHeight: Math.max(fontSize, boxHeight)
+ };
+};
+const itemsEqual = (a, b) => a !== null && b !== null && a.datasetIndex === b.datasetIndex && a.index === b.index;
+class Legend extends Element {
+ constructor(config) {
+ super();
+ this._added = false;
+ this.legendHitBoxes = [];
+ this._hoveredItem = null;
+ this.doughnutMode = false;
+ this.chart = config.chart;
+ this.options = config.options;
+ this.ctx = config.ctx;
+ this.legendItems = undefined;
+ this.columnSizes = undefined;
+ this.lineWidths = undefined;
+ this.maxHeight = undefined;
+ this.maxWidth = undefined;
+ this.top = undefined;
+ this.bottom = undefined;
+ this.left = undefined;
+ this.right = undefined;
+ this.height = undefined;
+ this.width = undefined;
+ this._margins = undefined;
+ this.position = undefined;
+ this.weight = undefined;
+ this.fullSize = undefined;
+ }
+ update(maxWidth, maxHeight, margins) {
+ this.maxWidth = maxWidth;
+ this.maxHeight = maxHeight;
+ this._margins = margins;
+ this.setDimensions();
+ this.buildLabels();
+ this.fit();
+ }
+ setDimensions() {
+ if (this.isHorizontal()) {
+ this.width = this.maxWidth;
+ this.left = this._margins.left;
+ this.right = this.width;
+ } else {
+ this.height = this.maxHeight;
+ this.top = this._margins.top;
+ this.bottom = this.height;
+ }
+ }
+ buildLabels() {
+ const labelOpts = this.options.labels || {};
+ let legendItems = callback(labelOpts.generateLabels, [this.chart], this) || [];
+ if (labelOpts.filter) {
+ legendItems = legendItems.filter((item) => labelOpts.filter(item, this.chart.data));
+ }
+ if (labelOpts.sort) {
+ legendItems = legendItems.sort((a, b) => labelOpts.sort(a, b, this.chart.data));
+ }
+ if (this.options.reverse) {
+ legendItems.reverse();
+ }
+ this.legendItems = legendItems;
+ }
+ fit() {
+ const {options, ctx} = this;
+ if (!options.display) {
+ this.width = this.height = 0;
+ return;
+ }
+ const labelOpts = options.labels;
+ const labelFont = toFont(labelOpts.font);
+ const fontSize = labelFont.size;
+ const titleHeight = this._computeTitleHeight();
+ const {boxWidth, itemHeight} = getBoxSize(labelOpts, fontSize);
+ let width, height;
+ ctx.font = labelFont.string;
+ if (this.isHorizontal()) {
+ width = this.maxWidth;
+ height = this._fitRows(titleHeight, fontSize, boxWidth, itemHeight) + 10;
+ } else {
+ height = this.maxHeight;
+ width = this._fitCols(titleHeight, fontSize, boxWidth, itemHeight) + 10;
+ }
+ this.width = Math.min(width, options.maxWidth || this.maxWidth);
+ this.height = Math.min(height, options.maxHeight || this.maxHeight);
+ }
+ _fitRows(titleHeight, fontSize, boxWidth, itemHeight) {
+ const {ctx, maxWidth, options: {labels: {padding}}} = this;
+ const hitboxes = this.legendHitBoxes = [];
+ const lineWidths = this.lineWidths = [0];
+ const lineHeight = itemHeight + padding;
+ let totalHeight = titleHeight;
+ ctx.textAlign = 'left';
+ ctx.textBaseline = 'middle';
+ let row = -1;
+ let top = -lineHeight;
+ this.legendItems.forEach((legendItem, i) => {
+ const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+ if (i === 0 || lineWidths[lineWidths.length - 1] + itemWidth + 2 * padding > maxWidth) {
+ totalHeight += lineHeight;
+ lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
+ top += lineHeight;
+ row++;
+ }
+ hitboxes[i] = {left: 0, top, row, width: itemWidth, height: itemHeight};
+ lineWidths[lineWidths.length - 1] += itemWidth + padding;
+ });
+ return totalHeight;
+ }
+ _fitCols(titleHeight, fontSize, boxWidth, itemHeight) {
+ const {ctx, maxHeight, options: {labels: {padding}}} = this;
+ const hitboxes = this.legendHitBoxes = [];
+ const columnSizes = this.columnSizes = [];
+ const heightLimit = maxHeight - titleHeight;
+ let totalWidth = padding;
+ let currentColWidth = 0;
+ let currentColHeight = 0;
+ let left = 0;
+ let col = 0;
+ this.legendItems.forEach((legendItem, i) => {
+ const itemWidth = boxWidth + (fontSize / 2) + ctx.measureText(legendItem.text).width;
+ if (i > 0 && currentColHeight + itemHeight + 2 * padding > heightLimit) {
+ totalWidth += currentColWidth + padding;
+ columnSizes.push({width: currentColWidth, height: currentColHeight});
+ left += currentColWidth + padding;
+ col++;
+ currentColWidth = currentColHeight = 0;
+ }
+ hitboxes[i] = {left, top: currentColHeight, col, width: itemWidth, height: itemHeight};
+ currentColWidth = Math.max(currentColWidth, itemWidth);
+ currentColHeight += itemHeight + padding;
+ });
+ totalWidth += currentColWidth;
+ columnSizes.push({width: currentColWidth, height: currentColHeight});
+ return totalWidth;
+ }
+ adjustHitBoxes() {
+ if (!this.options.display) {
+ return;
+ }
+ const titleHeight = this._computeTitleHeight();
+ const {legendHitBoxes: hitboxes, options: {align, labels: {padding}, rtl}} = this;
+ const rtlHelper = getRtlAdapter(rtl, this.left, this.width);
+ if (this.isHorizontal()) {
+ let row = 0;
+ let left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
+ for (const hitbox of hitboxes) {
+ if (row !== hitbox.row) {
+ row = hitbox.row;
+ left = _alignStartEnd(align, this.left + padding, this.right - this.lineWidths[row]);
+ }
+ hitbox.top += this.top + titleHeight + padding;
+ hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(left), hitbox.width);
+ left += hitbox.width + padding;
+ }
+ } else {
+ let col = 0;
+ let top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
+ for (const hitbox of hitboxes) {
+ if (hitbox.col !== col) {
+ col = hitbox.col;
+ top = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - this.columnSizes[col].height);
+ }
+ hitbox.top = top;
+ hitbox.left += this.left + padding;
+ hitbox.left = rtlHelper.leftForLtr(rtlHelper.x(hitbox.left), hitbox.width);
+ top += hitbox.height + padding;
+ }
+ }
+ }
+ isHorizontal() {
+ return this.options.position === 'top' || this.options.position === 'bottom';
+ }
+ draw() {
+ if (this.options.display) {
+ const ctx = this.ctx;
+ clipArea(ctx, this);
+ this._draw();
+ unclipArea(ctx);
+ }
+ }
+ _draw() {
+ const {options: opts, columnSizes, lineWidths, ctx} = this;
+ const {align, labels: labelOpts} = opts;
+ const defaultColor = defaults.color;
+ const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
+ const labelFont = toFont(labelOpts.font);
+ const {color: fontColor, padding} = labelOpts;
+ const fontSize = labelFont.size;
+ const halfFontSize = fontSize / 2;
+ let cursor;
+ this.drawTitle();
+ ctx.textAlign = rtlHelper.textAlign('left');
+ ctx.textBaseline = 'middle';
+ ctx.lineWidth = 0.5;
+ ctx.font = labelFont.string;
+ const {boxWidth, boxHeight, itemHeight} = getBoxSize(labelOpts, fontSize);
+ const drawLegendBox = function(x, y, legendItem) {
+ if (isNaN(boxWidth) || boxWidth <= 0 || isNaN(boxHeight) || boxHeight < 0) {
+ return;
+ }
+ ctx.save();
+ const lineWidth = valueOrDefault(legendItem.lineWidth, 1);
+ ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
+ ctx.lineCap = valueOrDefault(legendItem.lineCap, 'butt');
+ ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, 0);
+ ctx.lineJoin = valueOrDefault(legendItem.lineJoin, 'miter');
+ ctx.lineWidth = lineWidth;
+ ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
+ ctx.setLineDash(valueOrDefault(legendItem.lineDash, []));
+ if (labelOpts.usePointStyle) {
+ const drawOptions = {
+ radius: boxWidth * Math.SQRT2 / 2,
+ pointStyle: legendItem.pointStyle,
+ rotation: legendItem.rotation,
+ borderWidth: lineWidth
+ };
+ const centerX = rtlHelper.xPlus(x, boxWidth / 2);
+ const centerY = y + halfFontSize;
+ drawPoint(ctx, drawOptions, centerX, centerY);
+ } else {
+ const yBoxTop = y + Math.max((fontSize - boxHeight) / 2, 0);
+ const xBoxLeft = rtlHelper.leftForLtr(x, boxWidth);
+ const borderRadius = toTRBLCorners(legendItem.borderRadius);
+ ctx.beginPath();
+ if (Object.values(borderRadius).some(v => v !== 0)) {
+ addRoundedRectPath(ctx, {
+ x: xBoxLeft,
+ y: yBoxTop,
+ w: boxWidth,
+ h: boxHeight,
+ radius: borderRadius,
+ });
+ } else {
+ ctx.rect(xBoxLeft, yBoxTop, boxWidth, boxHeight);
+ }
+ ctx.fill();
+ if (lineWidth !== 0) {
+ ctx.stroke();
+ }
+ }
+ ctx.restore();
+ };
+ const fillText = function(x, y, legendItem) {
+ renderText(ctx, legendItem.text, x, y + (itemHeight / 2), labelFont, {
+ strikethrough: legendItem.hidden,
+ textAlign: rtlHelper.textAlign(legendItem.textAlign)
+ });
+ };
+ const isHorizontal = this.isHorizontal();
+ const titleHeight = this._computeTitleHeight();
+ if (isHorizontal) {
+ cursor = {
+ x: _alignStartEnd(align, this.left + padding, this.right - lineWidths[0]),
+ y: this.top + padding + titleHeight,
+ line: 0
+ };
+ } else {
+ cursor = {
+ x: this.left + padding,
+ y: _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[0].height),
+ line: 0
+ };
+ }
+ overrideTextDirection(this.ctx, opts.textDirection);
+ const lineHeight = itemHeight + padding;
+ this.legendItems.forEach((legendItem, i) => {
+ ctx.strokeStyle = legendItem.fontColor || fontColor;
+ ctx.fillStyle = legendItem.fontColor || fontColor;
+ const textWidth = ctx.measureText(legendItem.text).width;
+ const textAlign = rtlHelper.textAlign(legendItem.textAlign || (legendItem.textAlign = labelOpts.textAlign));
+ const width = boxWidth + halfFontSize + textWidth;
+ let x = cursor.x;
+ let y = cursor.y;
+ rtlHelper.setWidth(this.width);
+ if (isHorizontal) {
+ if (i > 0 && x + width + padding > this.right) {
+ y = cursor.y += lineHeight;
+ cursor.line++;
+ x = cursor.x = _alignStartEnd(align, this.left + padding, this.right - lineWidths[cursor.line]);
+ }
+ } else if (i > 0 && y + lineHeight > this.bottom) {
+ x = cursor.x = x + columnSizes[cursor.line].width + padding;
+ cursor.line++;
+ y = cursor.y = _alignStartEnd(align, this.top + titleHeight + padding, this.bottom - columnSizes[cursor.line].height);
+ }
+ const realX = rtlHelper.x(x);
+ drawLegendBox(realX, y, legendItem);
+ x = _textX(textAlign, x + boxWidth + halfFontSize, isHorizontal ? x + width : this.right, opts.rtl);
+ fillText(rtlHelper.x(x), y, legendItem);
+ if (isHorizontal) {
+ cursor.x += width + padding;
+ } else {
+ cursor.y += lineHeight;
+ }
+ });
+ restoreTextDirection(this.ctx, opts.textDirection);
+ }
+ drawTitle() {
+ const opts = this.options;
+ const titleOpts = opts.title;
+ const titleFont = toFont(titleOpts.font);
+ const titlePadding = toPadding(titleOpts.padding);
+ if (!titleOpts.display) {
+ return;
+ }
+ const rtlHelper = getRtlAdapter(opts.rtl, this.left, this.width);
+ const ctx = this.ctx;
+ const position = titleOpts.position;
+ const halfFontSize = titleFont.size / 2;
+ const topPaddingPlusHalfFontSize = titlePadding.top + halfFontSize;
+ let y;
+ let left = this.left;
+ let maxWidth = this.width;
+ if (this.isHorizontal()) {
+ maxWidth = Math.max(...this.lineWidths);
+ y = this.top + topPaddingPlusHalfFontSize;
+ left = _alignStartEnd(opts.align, left, this.right - maxWidth);
+ } else {
+ const maxHeight = this.columnSizes.reduce((acc, size) => Math.max(acc, size.height), 0);
+ y = topPaddingPlusHalfFontSize + _alignStartEnd(opts.align, this.top, this.bottom - maxHeight - opts.labels.padding - this._computeTitleHeight());
+ }
+ const x = _alignStartEnd(position, left, left + maxWidth);
+ ctx.textAlign = rtlHelper.textAlign(_toLeftRightCenter(position));
+ ctx.textBaseline = 'middle';
+ ctx.strokeStyle = titleOpts.color;
+ ctx.fillStyle = titleOpts.color;
+ ctx.font = titleFont.string;
+ renderText(ctx, titleOpts.text, x, y, titleFont);
+ }
+ _computeTitleHeight() {
+ const titleOpts = this.options.title;
+ const titleFont = toFont(titleOpts.font);
+ const titlePadding = toPadding(titleOpts.padding);
+ return titleOpts.display ? titleFont.lineHeight + titlePadding.height : 0;
+ }
+ _getLegendItemAt(x, y) {
+ let i, hitBox, lh;
+ if (_isBetween(x, this.left, this.right)
+ && _isBetween(y, this.top, this.bottom)) {
+ lh = this.legendHitBoxes;
+ for (i = 0; i < lh.length; ++i) {
+ hitBox = lh[i];
+ if (_isBetween(x, hitBox.left, hitBox.left + hitBox.width)
+ && _isBetween(y, hitBox.top, hitBox.top + hitBox.height)) {
+ return this.legendItems[i];
+ }
+ }
+ }
+ return null;
+ }
+ handleEvent(e) {
+ const opts = this.options;
+ if (!isListened(e.type, opts)) {
+ return;
+ }
+ const hoveredItem = this._getLegendItemAt(e.x, e.y);
+ if (e.type === 'mousemove') {
+ const previous = this._hoveredItem;
+ const sameItem = itemsEqual(previous, hoveredItem);
+ if (previous && !sameItem) {
+ callback(opts.onLeave, [e, previous, this], this);
+ }
+ this._hoveredItem = hoveredItem;
+ if (hoveredItem && !sameItem) {
+ callback(opts.onHover, [e, hoveredItem, this], this);
+ }
+ } else if (hoveredItem) {
+ callback(opts.onClick, [e, hoveredItem, this], this);
+ }
+ }
+}
+function isListened(type, opts) {
+ if (type === 'mousemove' && (opts.onHover || opts.onLeave)) {
+ return true;
+ }
+ if (opts.onClick && (type === 'click' || type === 'mouseup')) {
+ return true;
+ }
+ return false;
+}
+var plugin_legend = {
+ id: 'legend',
+ _element: Legend,
+ start(chart, _args, options) {
+ const legend = chart.legend = new Legend({ctx: chart.ctx, options, chart});
+ layouts.configure(chart, legend, options);
+ layouts.addBox(chart, legend);
+ },
+ stop(chart) {
+ layouts.removeBox(chart, chart.legend);
+ delete chart.legend;
+ },
+ beforeUpdate(chart, _args, options) {
+ const legend = chart.legend;
+ layouts.configure(chart, legend, options);
+ legend.options = options;
+ },
+ afterUpdate(chart) {
+ const legend = chart.legend;
+ legend.buildLabels();
+ legend.adjustHitBoxes();
+ },
+ afterEvent(chart, args) {
+ if (!args.replay) {
+ chart.legend.handleEvent(args.event);
+ }
+ },
+ defaults: {
+ display: true,
+ position: 'top',
+ align: 'center',
+ fullSize: true,
+ reverse: false,
+ weight: 1000,
+ onClick(e, legendItem, legend) {
+ const index = legendItem.datasetIndex;
+ const ci = legend.chart;
+ if (ci.isDatasetVisible(index)) {
+ ci.hide(index);
+ legendItem.hidden = true;
+ } else {
+ ci.show(index);
+ legendItem.hidden = false;
+ }
+ },
+ onHover: null,
+ onLeave: null,
+ labels: {
+ color: (ctx) => ctx.chart.options.color,
+ boxWidth: 40,
+ padding: 10,
+ generateLabels(chart) {
+ const datasets = chart.data.datasets;
+ const {labels: {usePointStyle, pointStyle, textAlign, color}} = chart.legend.options;
+ return chart._getSortedDatasetMetas().map((meta) => {
+ const style = meta.controller.getStyle(usePointStyle ? 0 : undefined);
+ const borderWidth = toPadding(style.borderWidth);
+ return {
+ text: datasets[meta.index].label,
+ fillStyle: style.backgroundColor,
+ fontColor: color,
+ hidden: !meta.visible,
+ lineCap: style.borderCapStyle,
+ lineDash: style.borderDash,
+ lineDashOffset: style.borderDashOffset,
+ lineJoin: style.borderJoinStyle,
+ lineWidth: (borderWidth.width + borderWidth.height) / 4,
+ strokeStyle: style.borderColor,
+ pointStyle: pointStyle || style.pointStyle,
+ rotation: style.rotation,
+ textAlign: textAlign || style.textAlign,
+ borderRadius: 0,
+ datasetIndex: meta.index
+ };
+ }, this);
+ }
+ },
+ title: {
+ color: (ctx) => ctx.chart.options.color,
+ display: false,
+ position: 'center',
+ text: '',
+ }
+ },
+ descriptors: {
+ _scriptable: (name) => !name.startsWith('on'),
+ labels: {
+ _scriptable: (name) => !['generateLabels', 'filter', 'sort'].includes(name),
+ }
+ },
+};
+
+class Title extends Element {
+ constructor(config) {
+ super();
+ this.chart = config.chart;
+ this.options = config.options;
+ this.ctx = config.ctx;
+ this._padding = undefined;
+ this.top = undefined;
+ this.bottom = undefined;
+ this.left = undefined;
+ this.right = undefined;
+ this.width = undefined;
+ this.height = undefined;
+ this.position = undefined;
+ this.weight = undefined;
+ this.fullSize = undefined;
+ }
+ update(maxWidth, maxHeight) {
+ const opts = this.options;
+ this.left = 0;
+ this.top = 0;
+ if (!opts.display) {
+ this.width = this.height = this.right = this.bottom = 0;
+ return;
+ }
+ this.width = this.right = maxWidth;
+ this.height = this.bottom = maxHeight;
+ const lineCount = isArray(opts.text) ? opts.text.length : 1;
+ this._padding = toPadding(opts.padding);
+ const textSize = lineCount * toFont(opts.font).lineHeight + this._padding.height;
+ if (this.isHorizontal()) {
+ this.height = textSize;
+ } else {
+ this.width = textSize;
+ }
+ }
+ isHorizontal() {
+ const pos = this.options.position;
+ return pos === 'top' || pos === 'bottom';
+ }
+ _drawArgs(offset) {
+ const {top, left, bottom, right, options} = this;
+ const align = options.align;
+ let rotation = 0;
+ let maxWidth, titleX, titleY;
+ if (this.isHorizontal()) {
+ titleX = _alignStartEnd(align, left, right);
+ titleY = top + offset;
+ maxWidth = right - left;
+ } else {
+ if (options.position === 'left') {
+ titleX = left + offset;
+ titleY = _alignStartEnd(align, bottom, top);
+ rotation = PI * -0.5;
+ } else {
+ titleX = right - offset;
+ titleY = _alignStartEnd(align, top, bottom);
+ rotation = PI * 0.5;
+ }
+ maxWidth = bottom - top;
+ }
+ return {titleX, titleY, maxWidth, rotation};
+ }
+ draw() {
+ const ctx = this.ctx;
+ const opts = this.options;
+ if (!opts.display) {
+ return;
+ }
+ const fontOpts = toFont(opts.font);
+ const lineHeight = fontOpts.lineHeight;
+ const offset = lineHeight / 2 + this._padding.top;
+ const {titleX, titleY, maxWidth, rotation} = this._drawArgs(offset);
+ renderText(ctx, opts.text, 0, 0, fontOpts, {
+ color: opts.color,
+ maxWidth,
+ rotation,
+ textAlign: _toLeftRightCenter(opts.align),
+ textBaseline: 'middle',
+ translation: [titleX, titleY],
+ });
+ }
+}
+function createTitle(chart, titleOpts) {
+ const title = new Title({
+ ctx: chart.ctx,
+ options: titleOpts,
+ chart
+ });
+ layouts.configure(chart, title, titleOpts);
+ layouts.addBox(chart, title);
+ chart.titleBlock = title;
+}
+var plugin_title = {
+ id: 'title',
+ _element: Title,
+ start(chart, _args, options) {
+ createTitle(chart, options);
+ },
+ stop(chart) {
+ const titleBlock = chart.titleBlock;
+ layouts.removeBox(chart, titleBlock);
+ delete chart.titleBlock;
+ },
+ beforeUpdate(chart, _args, options) {
+ const title = chart.titleBlock;
+ layouts.configure(chart, title, options);
+ title.options = options;
+ },
+ defaults: {
+ align: 'center',
+ display: false,
+ font: {
+ weight: 'bold',
+ },
+ fullSize: true,
+ padding: 10,
+ position: 'top',
+ text: '',
+ weight: 2000
+ },
+ defaultRoutes: {
+ color: 'color'
+ },
+ descriptors: {
+ _scriptable: true,
+ _indexable: false,
+ },
+};
+
+const map = new WeakMap();
+var plugin_subtitle = {
+ id: 'subtitle',
+ start(chart, _args, options) {
+ const title = new Title({
+ ctx: chart.ctx,
+ options,
+ chart
+ });
+ layouts.configure(chart, title, options);
+ layouts.addBox(chart, title);
+ map.set(chart, title);
+ },
+ stop(chart) {
+ layouts.removeBox(chart, map.get(chart));
+ map.delete(chart);
+ },
+ beforeUpdate(chart, _args, options) {
+ const title = map.get(chart);
+ layouts.configure(chart, title, options);
+ title.options = options;
+ },
+ defaults: {
+ align: 'center',
+ display: false,
+ font: {
+ weight: 'normal',
+ },
+ fullSize: true,
+ padding: 0,
+ position: 'top',
+ text: '',
+ weight: 1500
+ },
+ defaultRoutes: {
+ color: 'color'
+ },
+ descriptors: {
+ _scriptable: true,
+ _indexable: false,
+ },
+};
+
+const positioners = {
+ average(items) {
+ if (!items.length) {
+ return false;
+ }
+ let i, len;
+ let x = 0;
+ let y = 0;
+ let count = 0;
+ for (i = 0, len = items.length; i < len; ++i) {
+ const el = items[i].element;
+ if (el && el.hasValue()) {
+ const pos = el.tooltipPosition();
+ x += pos.x;
+ y += pos.y;
+ ++count;
+ }
+ }
+ return {
+ x: x / count,
+ y: y / count
+ };
+ },
+ nearest(items, eventPosition) {
+ if (!items.length) {
+ return false;
+ }
+ let x = eventPosition.x;
+ let y = eventPosition.y;
+ let minDistance = Number.POSITIVE_INFINITY;
+ let i, len, nearestElement;
+ for (i = 0, len = items.length; i < len; ++i) {
+ const el = items[i].element;
+ if (el && el.hasValue()) {
+ const center = el.getCenterPoint();
+ const d = distanceBetweenPoints(eventPosition, center);
+ if (d < minDistance) {
+ minDistance = d;
+ nearestElement = el;
+ }
+ }
+ }
+ if (nearestElement) {
+ const tp = nearestElement.tooltipPosition();
+ x = tp.x;
+ y = tp.y;
+ }
+ return {
+ x,
+ y
+ };
+ }
+};
+function pushOrConcat(base, toPush) {
+ if (toPush) {
+ if (isArray(toPush)) {
+ Array.prototype.push.apply(base, toPush);
+ } else {
+ base.push(toPush);
+ }
+ }
+ return base;
+}
+function splitNewlines(str) {
+ if ((typeof str === 'string' || str instanceof String) && str.indexOf('\n') > -1) {
+ return str.split('\n');
+ }
+ return str;
+}
+function createTooltipItem(chart, item) {
+ const {element, datasetIndex, index} = item;
+ const controller = chart.getDatasetMeta(datasetIndex).controller;
+ const {label, value} = controller.getLabelAndValue(index);
+ return {
+ chart,
+ label,
+ parsed: controller.getParsed(index),
+ raw: chart.data.datasets[datasetIndex].data[index],
+ formattedValue: value,
+ dataset: controller.getDataset(),
+ dataIndex: index,
+ datasetIndex,
+ element
+ };
+}
+function getTooltipSize(tooltip, options) {
+ const ctx = tooltip.chart.ctx;
+ const {body, footer, title} = tooltip;
+ const {boxWidth, boxHeight} = options;
+ const bodyFont = toFont(options.bodyFont);
+ const titleFont = toFont(options.titleFont);
+ const footerFont = toFont(options.footerFont);
+ const titleLineCount = title.length;
+ const footerLineCount = footer.length;
+ const bodyLineItemCount = body.length;
+ const padding = toPadding(options.padding);
+ let height = padding.height;
+ let width = 0;
+ let combinedBodyLength = body.reduce((count, bodyItem) => count + bodyItem.before.length + bodyItem.lines.length + bodyItem.after.length, 0);
+ combinedBodyLength += tooltip.beforeBody.length + tooltip.afterBody.length;
+ if (titleLineCount) {
+ height += titleLineCount * titleFont.lineHeight
+ + (titleLineCount - 1) * options.titleSpacing
+ + options.titleMarginBottom;
+ }
+ if (combinedBodyLength) {
+ const bodyLineHeight = options.displayColors ? Math.max(boxHeight, bodyFont.lineHeight) : bodyFont.lineHeight;
+ height += bodyLineItemCount * bodyLineHeight
+ + (combinedBodyLength - bodyLineItemCount) * bodyFont.lineHeight
+ + (combinedBodyLength - 1) * options.bodySpacing;
+ }
+ if (footerLineCount) {
+ height += options.footerMarginTop
+ + footerLineCount * footerFont.lineHeight
+ + (footerLineCount - 1) * options.footerSpacing;
+ }
+ let widthPadding = 0;
+ const maxLineWidth = function(line) {
+ width = Math.max(width, ctx.measureText(line).width + widthPadding);
+ };
+ ctx.save();
+ ctx.font = titleFont.string;
+ each(tooltip.title, maxLineWidth);
+ ctx.font = bodyFont.string;
+ each(tooltip.beforeBody.concat(tooltip.afterBody), maxLineWidth);
+ widthPadding = options.displayColors ? (boxWidth + 2 + options.boxPadding) : 0;
+ each(body, (bodyItem) => {
+ each(bodyItem.before, maxLineWidth);
+ each(bodyItem.lines, maxLineWidth);
+ each(bodyItem.after, maxLineWidth);
+ });
+ widthPadding = 0;
+ ctx.font = footerFont.string;
+ each(tooltip.footer, maxLineWidth);
+ ctx.restore();
+ width += padding.width;
+ return {width, height};
+}
+function determineYAlign(chart, size) {
+ const {y, height} = size;
+ if (y < height / 2) {
+ return 'top';
+ } else if (y > (chart.height - height / 2)) {
+ return 'bottom';
+ }
+ return 'center';
+}
+function doesNotFitWithAlign(xAlign, chart, options, size) {
+ const {x, width} = size;
+ const caret = options.caretSize + options.caretPadding;
+ if (xAlign === 'left' && x + width + caret > chart.width) {
+ return true;
+ }
+ if (xAlign === 'right' && x - width - caret < 0) {
+ return true;
+ }
+}
+function determineXAlign(chart, options, size, yAlign) {
+ const {x, width} = size;
+ const {width: chartWidth, chartArea: {left, right}} = chart;
+ let xAlign = 'center';
+ if (yAlign === 'center') {
+ xAlign = x <= (left + right) / 2 ? 'left' : 'right';
+ } else if (x <= width / 2) {
+ xAlign = 'left';
+ } else if (x >= chartWidth - width / 2) {
+ xAlign = 'right';
+ }
+ if (doesNotFitWithAlign(xAlign, chart, options, size)) {
+ xAlign = 'center';
+ }
+ return xAlign;
+}
+function determineAlignment(chart, options, size) {
+ const yAlign = size.yAlign || options.yAlign || determineYAlign(chart, size);
+ return {
+ xAlign: size.xAlign || options.xAlign || determineXAlign(chart, options, size, yAlign),
+ yAlign
+ };
+}
+function alignX(size, xAlign) {
+ let {x, width} = size;
+ if (xAlign === 'right') {
+ x -= width;
+ } else if (xAlign === 'center') {
+ x -= (width / 2);
+ }
+ return x;
+}
+function alignY(size, yAlign, paddingAndSize) {
+ let {y, height} = size;
+ if (yAlign === 'top') {
+ y += paddingAndSize;
+ } else if (yAlign === 'bottom') {
+ y -= height + paddingAndSize;
+ } else {
+ y -= (height / 2);
+ }
+ return y;
+}
+function getBackgroundPoint(options, size, alignment, chart) {
+ const {caretSize, caretPadding, cornerRadius} = options;
+ const {xAlign, yAlign} = alignment;
+ const paddingAndSize = caretSize + caretPadding;
+ const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);
+ let x = alignX(size, xAlign);
+ const y = alignY(size, yAlign, paddingAndSize);
+ if (yAlign === 'center') {
+ if (xAlign === 'left') {
+ x += paddingAndSize;
+ } else if (xAlign === 'right') {
+ x -= paddingAndSize;
+ }
+ } else if (xAlign === 'left') {
+ x -= Math.max(topLeft, bottomLeft) + caretSize;
+ } else if (xAlign === 'right') {
+ x += Math.max(topRight, bottomRight) + caretSize;
+ }
+ return {
+ x: _limitValue(x, 0, chart.width - size.width),
+ y: _limitValue(y, 0, chart.height - size.height)
+ };
+}
+function getAlignedX(tooltip, align, options) {
+ const padding = toPadding(options.padding);
+ return align === 'center'
+ ? tooltip.x + tooltip.width / 2
+ : align === 'right'
+ ? tooltip.x + tooltip.width - padding.right
+ : tooltip.x + padding.left;
+}
+function getBeforeAfterBodyLines(callback) {
+ return pushOrConcat([], splitNewlines(callback));
+}
+function createTooltipContext(parent, tooltip, tooltipItems) {
+ return createContext(parent, {
+ tooltip,
+ tooltipItems,
+ type: 'tooltip'
+ });
+}
+function overrideCallbacks(callbacks, context) {
+ const override = context && context.dataset && context.dataset.tooltip && context.dataset.tooltip.callbacks;
+ return override ? callbacks.override(override) : callbacks;
+}
+class Tooltip extends Element {
+ constructor(config) {
+ super();
+ this.opacity = 0;
+ this._active = [];
+ this._eventPosition = undefined;
+ this._size = undefined;
+ this._cachedAnimations = undefined;
+ this._tooltipItems = [];
+ this.$animations = undefined;
+ this.$context = undefined;
+ this.chart = config.chart || config._chart;
+ this._chart = this.chart;
+ this.options = config.options;
+ this.dataPoints = undefined;
+ this.title = undefined;
+ this.beforeBody = undefined;
+ this.body = undefined;
+ this.afterBody = undefined;
+ this.footer = undefined;
+ this.xAlign = undefined;
+ this.yAlign = undefined;
+ this.x = undefined;
+ this.y = undefined;
+ this.height = undefined;
+ this.width = undefined;
+ this.caretX = undefined;
+ this.caretY = undefined;
+ this.labelColors = undefined;
+ this.labelPointStyles = undefined;
+ this.labelTextColors = undefined;
+ }
+ initialize(options) {
+ this.options = options;
+ this._cachedAnimations = undefined;
+ this.$context = undefined;
+ }
+ _resolveAnimations() {
+ const cached = this._cachedAnimations;
+ if (cached) {
+ return cached;
+ }
+ const chart = this.chart;
+ const options = this.options.setContext(this.getContext());
+ const opts = options.enabled && chart.options.animation && options.animations;
+ const animations = new Animations(this.chart, opts);
+ if (opts._cacheable) {
+ this._cachedAnimations = Object.freeze(animations);
+ }
+ return animations;
+ }
+ getContext() {
+ return this.$context ||
+ (this.$context = createTooltipContext(this.chart.getContext(), this, this._tooltipItems));
+ }
+ getTitle(context, options) {
+ const {callbacks} = options;
+ const beforeTitle = callbacks.beforeTitle.apply(this, [context]);
+ const title = callbacks.title.apply(this, [context]);
+ const afterTitle = callbacks.afterTitle.apply(this, [context]);
+ let lines = [];
+ lines = pushOrConcat(lines, splitNewlines(beforeTitle));
+ lines = pushOrConcat(lines, splitNewlines(title));
+ lines = pushOrConcat(lines, splitNewlines(afterTitle));
+ return lines;
+ }
+ getBeforeBody(tooltipItems, options) {
+ return getBeforeAfterBodyLines(options.callbacks.beforeBody.apply(this, [tooltipItems]));
+ }
+ getBody(tooltipItems, options) {
+ const {callbacks} = options;
+ const bodyItems = [];
+ each(tooltipItems, (context) => {
+ const bodyItem = {
+ before: [],
+ lines: [],
+ after: []
+ };
+ const scoped = overrideCallbacks(callbacks, context);
+ pushOrConcat(bodyItem.before, splitNewlines(scoped.beforeLabel.call(this, context)));
+ pushOrConcat(bodyItem.lines, scoped.label.call(this, context));
+ pushOrConcat(bodyItem.after, splitNewlines(scoped.afterLabel.call(this, context)));
+ bodyItems.push(bodyItem);
+ });
+ return bodyItems;
+ }
+ getAfterBody(tooltipItems, options) {
+ return getBeforeAfterBodyLines(options.callbacks.afterBody.apply(this, [tooltipItems]));
+ }
+ getFooter(tooltipItems, options) {
+ const {callbacks} = options;
+ const beforeFooter = callbacks.beforeFooter.apply(this, [tooltipItems]);
+ const footer = callbacks.footer.apply(this, [tooltipItems]);
+ const afterFooter = callbacks.afterFooter.apply(this, [tooltipItems]);
+ let lines = [];
+ lines = pushOrConcat(lines, splitNewlines(beforeFooter));
+ lines = pushOrConcat(lines, splitNewlines(footer));
+ lines = pushOrConcat(lines, splitNewlines(afterFooter));
+ return lines;
+ }
+ _createItems(options) {
+ const active = this._active;
+ const data = this.chart.data;
+ const labelColors = [];
+ const labelPointStyles = [];
+ const labelTextColors = [];
+ let tooltipItems = [];
+ let i, len;
+ for (i = 0, len = active.length; i < len; ++i) {
+ tooltipItems.push(createTooltipItem(this.chart, active[i]));
+ }
+ if (options.filter) {
+ tooltipItems = tooltipItems.filter((element, index, array) => options.filter(element, index, array, data));
+ }
+ if (options.itemSort) {
+ tooltipItems = tooltipItems.sort((a, b) => options.itemSort(a, b, data));
+ }
+ each(tooltipItems, (context) => {
+ const scoped = overrideCallbacks(options.callbacks, context);
+ labelColors.push(scoped.labelColor.call(this, context));
+ labelPointStyles.push(scoped.labelPointStyle.call(this, context));
+ labelTextColors.push(scoped.labelTextColor.call(this, context));
+ });
+ this.labelColors = labelColors;
+ this.labelPointStyles = labelPointStyles;
+ this.labelTextColors = labelTextColors;
+ this.dataPoints = tooltipItems;
+ return tooltipItems;
+ }
+ update(changed, replay) {
+ const options = this.options.setContext(this.getContext());
+ const active = this._active;
+ let properties;
+ let tooltipItems = [];
+ if (!active.length) {
+ if (this.opacity !== 0) {
+ properties = {
+ opacity: 0
+ };
+ }
+ } else {
+ const position = positioners[options.position].call(this, active, this._eventPosition);
+ tooltipItems = this._createItems(options);
+ this.title = this.getTitle(tooltipItems, options);
+ this.beforeBody = this.getBeforeBody(tooltipItems, options);
+ this.body = this.getBody(tooltipItems, options);
+ this.afterBody = this.getAfterBody(tooltipItems, options);
+ this.footer = this.getFooter(tooltipItems, options);
+ const size = this._size = getTooltipSize(this, options);
+ const positionAndSize = Object.assign({}, position, size);
+ const alignment = determineAlignment(this.chart, options, positionAndSize);
+ const backgroundPoint = getBackgroundPoint(options, positionAndSize, alignment, this.chart);
+ this.xAlign = alignment.xAlign;
+ this.yAlign = alignment.yAlign;
+ properties = {
+ opacity: 1,
+ x: backgroundPoint.x,
+ y: backgroundPoint.y,
+ width: size.width,
+ height: size.height,
+ caretX: position.x,
+ caretY: position.y
+ };
+ }
+ this._tooltipItems = tooltipItems;
+ this.$context = undefined;
+ if (properties) {
+ this._resolveAnimations().update(this, properties);
+ }
+ if (changed && options.external) {
+ options.external.call(this, {chart: this.chart, tooltip: this, replay});
+ }
+ }
+ drawCaret(tooltipPoint, ctx, size, options) {
+ const caretPosition = this.getCaretPosition(tooltipPoint, size, options);
+ ctx.lineTo(caretPosition.x1, caretPosition.y1);
+ ctx.lineTo(caretPosition.x2, caretPosition.y2);
+ ctx.lineTo(caretPosition.x3, caretPosition.y3);
+ }
+ getCaretPosition(tooltipPoint, size, options) {
+ const {xAlign, yAlign} = this;
+ const {caretSize, cornerRadius} = options;
+ const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(cornerRadius);
+ const {x: ptX, y: ptY} = tooltipPoint;
+ const {width, height} = size;
+ let x1, x2, x3, y1, y2, y3;
+ if (yAlign === 'center') {
+ y2 = ptY + (height / 2);
+ if (xAlign === 'left') {
+ x1 = ptX;
+ x2 = x1 - caretSize;
+ y1 = y2 + caretSize;
+ y3 = y2 - caretSize;
+ } else {
+ x1 = ptX + width;
+ x2 = x1 + caretSize;
+ y1 = y2 - caretSize;
+ y3 = y2 + caretSize;
+ }
+ x3 = x1;
+ } else {
+ if (xAlign === 'left') {
+ x2 = ptX + Math.max(topLeft, bottomLeft) + (caretSize);
+ } else if (xAlign === 'right') {
+ x2 = ptX + width - Math.max(topRight, bottomRight) - caretSize;
+ } else {
+ x2 = this.caretX;
+ }
+ if (yAlign === 'top') {
+ y1 = ptY;
+ y2 = y1 - caretSize;
+ x1 = x2 - caretSize;
+ x3 = x2 + caretSize;
+ } else {
+ y1 = ptY + height;
+ y2 = y1 + caretSize;
+ x1 = x2 + caretSize;
+ x3 = x2 - caretSize;
+ }
+ y3 = y1;
+ }
+ return {x1, x2, x3, y1, y2, y3};
+ }
+ drawTitle(pt, ctx, options) {
+ const title = this.title;
+ const length = title.length;
+ let titleFont, titleSpacing, i;
+ if (length) {
+ const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
+ pt.x = getAlignedX(this, options.titleAlign, options);
+ ctx.textAlign = rtlHelper.textAlign(options.titleAlign);
+ ctx.textBaseline = 'middle';
+ titleFont = toFont(options.titleFont);
+ titleSpacing = options.titleSpacing;
+ ctx.fillStyle = options.titleColor;
+ ctx.font = titleFont.string;
+ for (i = 0; i < length; ++i) {
+ ctx.fillText(title[i], rtlHelper.x(pt.x), pt.y + titleFont.lineHeight / 2);
+ pt.y += titleFont.lineHeight + titleSpacing;
+ if (i + 1 === length) {
+ pt.y += options.titleMarginBottom - titleSpacing;
+ }
+ }
+ }
+ }
+ _drawColorBox(ctx, pt, i, rtlHelper, options) {
+ const labelColors = this.labelColors[i];
+ const labelPointStyle = this.labelPointStyles[i];
+ const {boxHeight, boxWidth, boxPadding} = options;
+ const bodyFont = toFont(options.bodyFont);
+ const colorX = getAlignedX(this, 'left', options);
+ const rtlColorX = rtlHelper.x(colorX);
+ const yOffSet = boxHeight < bodyFont.lineHeight ? (bodyFont.lineHeight - boxHeight) / 2 : 0;
+ const colorY = pt.y + yOffSet;
+ if (options.usePointStyle) {
+ const drawOptions = {
+ radius: Math.min(boxWidth, boxHeight) / 2,
+ pointStyle: labelPointStyle.pointStyle,
+ rotation: labelPointStyle.rotation,
+ borderWidth: 1
+ };
+ const centerX = rtlHelper.leftForLtr(rtlColorX, boxWidth) + boxWidth / 2;
+ const centerY = colorY + boxHeight / 2;
+ ctx.strokeStyle = options.multiKeyBackground;
+ ctx.fillStyle = options.multiKeyBackground;
+ drawPoint(ctx, drawOptions, centerX, centerY);
+ ctx.strokeStyle = labelColors.borderColor;
+ ctx.fillStyle = labelColors.backgroundColor;
+ drawPoint(ctx, drawOptions, centerX, centerY);
+ } else {
+ ctx.lineWidth = labelColors.borderWidth || 1;
+ ctx.strokeStyle = labelColors.borderColor;
+ ctx.setLineDash(labelColors.borderDash || []);
+ ctx.lineDashOffset = labelColors.borderDashOffset || 0;
+ const outerX = rtlHelper.leftForLtr(rtlColorX, boxWidth - boxPadding);
+ const innerX = rtlHelper.leftForLtr(rtlHelper.xPlus(rtlColorX, 1), boxWidth - boxPadding - 2);
+ const borderRadius = toTRBLCorners(labelColors.borderRadius);
+ if (Object.values(borderRadius).some(v => v !== 0)) {
+ ctx.beginPath();
+ ctx.fillStyle = options.multiKeyBackground;
+ addRoundedRectPath(ctx, {
+ x: outerX,
+ y: colorY,
+ w: boxWidth,
+ h: boxHeight,
+ radius: borderRadius,
+ });
+ ctx.fill();
+ ctx.stroke();
+ ctx.fillStyle = labelColors.backgroundColor;
+ ctx.beginPath();
+ addRoundedRectPath(ctx, {
+ x: innerX,
+ y: colorY + 1,
+ w: boxWidth - 2,
+ h: boxHeight - 2,
+ radius: borderRadius,
+ });
+ ctx.fill();
+ } else {
+ ctx.fillStyle = options.multiKeyBackground;
+ ctx.fillRect(outerX, colorY, boxWidth, boxHeight);
+ ctx.strokeRect(outerX, colorY, boxWidth, boxHeight);
+ ctx.fillStyle = labelColors.backgroundColor;
+ ctx.fillRect(innerX, colorY + 1, boxWidth - 2, boxHeight - 2);
+ }
+ }
+ ctx.fillStyle = this.labelTextColors[i];
+ }
+ drawBody(pt, ctx, options) {
+ const {body} = this;
+ const {bodySpacing, bodyAlign, displayColors, boxHeight, boxWidth, boxPadding} = options;
+ const bodyFont = toFont(options.bodyFont);
+ let bodyLineHeight = bodyFont.lineHeight;
+ let xLinePadding = 0;
+ const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
+ const fillLineOfText = function(line) {
+ ctx.fillText(line, rtlHelper.x(pt.x + xLinePadding), pt.y + bodyLineHeight / 2);
+ pt.y += bodyLineHeight + bodySpacing;
+ };
+ const bodyAlignForCalculation = rtlHelper.textAlign(bodyAlign);
+ let bodyItem, textColor, lines, i, j, ilen, jlen;
+ ctx.textAlign = bodyAlign;
+ ctx.textBaseline = 'middle';
+ ctx.font = bodyFont.string;
+ pt.x = getAlignedX(this, bodyAlignForCalculation, options);
+ ctx.fillStyle = options.bodyColor;
+ each(this.beforeBody, fillLineOfText);
+ xLinePadding = displayColors && bodyAlignForCalculation !== 'right'
+ ? bodyAlign === 'center' ? (boxWidth / 2 + boxPadding) : (boxWidth + 2 + boxPadding)
+ : 0;
+ for (i = 0, ilen = body.length; i < ilen; ++i) {
+ bodyItem = body[i];
+ textColor = this.labelTextColors[i];
+ ctx.fillStyle = textColor;
+ each(bodyItem.before, fillLineOfText);
+ lines = bodyItem.lines;
+ if (displayColors && lines.length) {
+ this._drawColorBox(ctx, pt, i, rtlHelper, options);
+ bodyLineHeight = Math.max(bodyFont.lineHeight, boxHeight);
+ }
+ for (j = 0, jlen = lines.length; j < jlen; ++j) {
+ fillLineOfText(lines[j]);
+ bodyLineHeight = bodyFont.lineHeight;
+ }
+ each(bodyItem.after, fillLineOfText);
+ }
+ xLinePadding = 0;
+ bodyLineHeight = bodyFont.lineHeight;
+ each(this.afterBody, fillLineOfText);
+ pt.y -= bodySpacing;
+ }
+ drawFooter(pt, ctx, options) {
+ const footer = this.footer;
+ const length = footer.length;
+ let footerFont, i;
+ if (length) {
+ const rtlHelper = getRtlAdapter(options.rtl, this.x, this.width);
+ pt.x = getAlignedX(this, options.footerAlign, options);
+ pt.y += options.footerMarginTop;
+ ctx.textAlign = rtlHelper.textAlign(options.footerAlign);
+ ctx.textBaseline = 'middle';
+ footerFont = toFont(options.footerFont);
+ ctx.fillStyle = options.footerColor;
+ ctx.font = footerFont.string;
+ for (i = 0; i < length; ++i) {
+ ctx.fillText(footer[i], rtlHelper.x(pt.x), pt.y + footerFont.lineHeight / 2);
+ pt.y += footerFont.lineHeight + options.footerSpacing;
+ }
+ }
+ }
+ drawBackground(pt, ctx, tooltipSize, options) {
+ const {xAlign, yAlign} = this;
+ const {x, y} = pt;
+ const {width, height} = tooltipSize;
+ const {topLeft, topRight, bottomLeft, bottomRight} = toTRBLCorners(options.cornerRadius);
+ ctx.fillStyle = options.backgroundColor;
+ ctx.strokeStyle = options.borderColor;
+ ctx.lineWidth = options.borderWidth;
+ ctx.beginPath();
+ ctx.moveTo(x + topLeft, y);
+ if (yAlign === 'top') {
+ this.drawCaret(pt, ctx, tooltipSize, options);
+ }
+ ctx.lineTo(x + width - topRight, y);
+ ctx.quadraticCurveTo(x + width, y, x + width, y + topRight);
+ if (yAlign === 'center' && xAlign === 'right') {
+ this.drawCaret(pt, ctx, tooltipSize, options);
+ }
+ ctx.lineTo(x + width, y + height - bottomRight);
+ ctx.quadraticCurveTo(x + width, y + height, x + width - bottomRight, y + height);
+ if (yAlign === 'bottom') {
+ this.drawCaret(pt, ctx, tooltipSize, options);
+ }
+ ctx.lineTo(x + bottomLeft, y + height);
+ ctx.quadraticCurveTo(x, y + height, x, y + height - bottomLeft);
+ if (yAlign === 'center' && xAlign === 'left') {
+ this.drawCaret(pt, ctx, tooltipSize, options);
+ }
+ ctx.lineTo(x, y + topLeft);
+ ctx.quadraticCurveTo(x, y, x + topLeft, y);
+ ctx.closePath();
+ ctx.fill();
+ if (options.borderWidth > 0) {
+ ctx.stroke();
+ }
+ }
+ _updateAnimationTarget(options) {
+ const chart = this.chart;
+ const anims = this.$animations;
+ const animX = anims && anims.x;
+ const animY = anims && anims.y;
+ if (animX || animY) {
+ const position = positioners[options.position].call(this, this._active, this._eventPosition);
+ if (!position) {
+ return;
+ }
+ const size = this._size = getTooltipSize(this, options);
+ const positionAndSize = Object.assign({}, position, this._size);
+ const alignment = determineAlignment(chart, options, positionAndSize);
+ const point = getBackgroundPoint(options, positionAndSize, alignment, chart);
+ if (animX._to !== point.x || animY._to !== point.y) {
+ this.xAlign = alignment.xAlign;
+ this.yAlign = alignment.yAlign;
+ this.width = size.width;
+ this.height = size.height;
+ this.caretX = position.x;
+ this.caretY = position.y;
+ this._resolveAnimations().update(this, point);
+ }
+ }
+ }
+ draw(ctx) {
+ const options = this.options.setContext(this.getContext());
+ let opacity = this.opacity;
+ if (!opacity) {
+ return;
+ }
+ this._updateAnimationTarget(options);
+ const tooltipSize = {
+ width: this.width,
+ height: this.height
+ };
+ const pt = {
+ x: this.x,
+ y: this.y
+ };
+ opacity = Math.abs(opacity) < 1e-3 ? 0 : opacity;
+ const padding = toPadding(options.padding);
+ const hasTooltipContent = this.title.length || this.beforeBody.length || this.body.length || this.afterBody.length || this.footer.length;
+ if (options.enabled && hasTooltipContent) {
+ ctx.save();
+ ctx.globalAlpha = opacity;
+ this.drawBackground(pt, ctx, tooltipSize, options);
+ overrideTextDirection(ctx, options.textDirection);
+ pt.y += padding.top;
+ this.drawTitle(pt, ctx, options);
+ this.drawBody(pt, ctx, options);
+ this.drawFooter(pt, ctx, options);
+ restoreTextDirection(ctx, options.textDirection);
+ ctx.restore();
+ }
+ }
+ getActiveElements() {
+ return this._active || [];
+ }
+ setActiveElements(activeElements, eventPosition) {
+ const lastActive = this._active;
+ const active = activeElements.map(({datasetIndex, index}) => {
+ const meta = this.chart.getDatasetMeta(datasetIndex);
+ if (!meta) {
+ throw new Error('Cannot find a dataset at index ' + datasetIndex);
+ }
+ return {
+ datasetIndex,
+ element: meta.data[index],
+ index,
+ };
+ });
+ const changed = !_elementsEqual(lastActive, active);
+ const positionChanged = this._positionChanged(active, eventPosition);
+ if (changed || positionChanged) {
+ this._active = active;
+ this._eventPosition = eventPosition;
+ this._ignoreReplayEvents = true;
+ this.update(true);
+ }
+ }
+ handleEvent(e, replay, inChartArea = true) {
+ if (replay && this._ignoreReplayEvents) {
+ return false;
+ }
+ this._ignoreReplayEvents = false;
+ const options = this.options;
+ const lastActive = this._active || [];
+ const active = this._getActiveElements(e, lastActive, replay, inChartArea);
+ const positionChanged = this._positionChanged(active, e);
+ const changed = replay || !_elementsEqual(active, lastActive) || positionChanged;
+ if (changed) {
+ this._active = active;
+ if (options.enabled || options.external) {
+ this._eventPosition = {
+ x: e.x,
+ y: e.y
+ };
+ this.update(true, replay);
+ }
+ }
+ return changed;
+ }
+ _getActiveElements(e, lastActive, replay, inChartArea) {
+ const options = this.options;
+ if (e.type === 'mouseout') {
+ return [];
+ }
+ if (!inChartArea) {
+ return lastActive;
+ }
+ const active = this.chart.getElementsAtEventForMode(e, options.mode, options, replay);
+ if (options.reverse) {
+ active.reverse();
+ }
+ return active;
+ }
+ _positionChanged(active, e) {
+ const {caretX, caretY, options} = this;
+ const position = positioners[options.position].call(this, active, e);
+ return position !== false && (caretX !== position.x || caretY !== position.y);
+ }
+}
+Tooltip.positioners = positioners;
+var plugin_tooltip = {
+ id: 'tooltip',
+ _element: Tooltip,
+ positioners,
+ afterInit(chart, _args, options) {
+ if (options) {
+ chart.tooltip = new Tooltip({chart, options});
+ }
+ },
+ beforeUpdate(chart, _args, options) {
+ if (chart.tooltip) {
+ chart.tooltip.initialize(options);
+ }
+ },
+ reset(chart, _args, options) {
+ if (chart.tooltip) {
+ chart.tooltip.initialize(options);
+ }
+ },
+ afterDraw(chart) {
+ const tooltip = chart.tooltip;
+ const args = {
+ tooltip
+ };
+ if (chart.notifyPlugins('beforeTooltipDraw', args) === false) {
+ return;
+ }
+ if (tooltip) {
+ tooltip.draw(chart.ctx);
+ }
+ chart.notifyPlugins('afterTooltipDraw', args);
+ },
+ afterEvent(chart, args) {
+ if (chart.tooltip) {
+ const useFinalPosition = args.replay;
+ if (chart.tooltip.handleEvent(args.event, useFinalPosition, args.inChartArea)) {
+ args.changed = true;
+ }
+ }
+ },
+ defaults: {
+ enabled: true,
+ external: null,
+ position: 'average',
+ backgroundColor: 'rgba(0,0,0,0.8)',
+ titleColor: '#fff',
+ titleFont: {
+ weight: 'bold',
+ },
+ titleSpacing: 2,
+ titleMarginBottom: 6,
+ titleAlign: 'left',
+ bodyColor: '#fff',
+ bodySpacing: 2,
+ bodyFont: {
+ },
+ bodyAlign: 'left',
+ footerColor: '#fff',
+ footerSpacing: 2,
+ footerMarginTop: 6,
+ footerFont: {
+ weight: 'bold',
+ },
+ footerAlign: 'left',
+ padding: 6,
+ caretPadding: 2,
+ caretSize: 5,
+ cornerRadius: 6,
+ boxHeight: (ctx, opts) => opts.bodyFont.size,
+ boxWidth: (ctx, opts) => opts.bodyFont.size,
+ multiKeyBackground: '#fff',
+ displayColors: true,
+ boxPadding: 0,
+ borderColor: 'rgba(0,0,0,0)',
+ borderWidth: 0,
+ animation: {
+ duration: 400,
+ easing: 'easeOutQuart',
+ },
+ animations: {
+ numbers: {
+ type: 'number',
+ properties: ['x', 'y', 'width', 'height', 'caretX', 'caretY'],
+ },
+ opacity: {
+ easing: 'linear',
+ duration: 200
+ }
+ },
+ callbacks: {
+ beforeTitle: noop,
+ title(tooltipItems) {
+ if (tooltipItems.length > 0) {
+ const item = tooltipItems[0];
+ const labels = item.chart.data.labels;
+ const labelCount = labels ? labels.length : 0;
+ if (this && this.options && this.options.mode === 'dataset') {
+ return item.dataset.label || '';
+ } else if (item.label) {
+ return item.label;
+ } else if (labelCount > 0 && item.dataIndex < labelCount) {
+ return labels[item.dataIndex];
+ }
+ }
+ return '';
+ },
+ afterTitle: noop,
+ beforeBody: noop,
+ beforeLabel: noop,
+ label(tooltipItem) {
+ if (this && this.options && this.options.mode === 'dataset') {
+ return tooltipItem.label + ': ' + tooltipItem.formattedValue || tooltipItem.formattedValue;
+ }
+ let label = tooltipItem.dataset.label || '';
+ if (label) {
+ label += ': ';
+ }
+ const value = tooltipItem.formattedValue;
+ if (!isNullOrUndef(value)) {
+ label += value;
+ }
+ return label;
+ },
+ labelColor(tooltipItem) {
+ const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+ const options = meta.controller.getStyle(tooltipItem.dataIndex);
+ return {
+ borderColor: options.borderColor,
+ backgroundColor: options.backgroundColor,
+ borderWidth: options.borderWidth,
+ borderDash: options.borderDash,
+ borderDashOffset: options.borderDashOffset,
+ borderRadius: 0,
+ };
+ },
+ labelTextColor() {
+ return this.options.bodyColor;
+ },
+ labelPointStyle(tooltipItem) {
+ const meta = tooltipItem.chart.getDatasetMeta(tooltipItem.datasetIndex);
+ const options = meta.controller.getStyle(tooltipItem.dataIndex);
+ return {
+ pointStyle: options.pointStyle,
+ rotation: options.rotation,
+ };
+ },
+ afterLabel: noop,
+ afterBody: noop,
+ beforeFooter: noop,
+ footer: noop,
+ afterFooter: noop
+ }
+ },
+ defaultRoutes: {
+ bodyFont: 'font',
+ footerFont: 'font',
+ titleFont: 'font'
+ },
+ descriptors: {
+ _scriptable: (name) => name !== 'filter' && name !== 'itemSort' && name !== 'external',
+ _indexable: false,
+ callbacks: {
+ _scriptable: false,
+ _indexable: false,
+ },
+ animation: {
+ _fallback: false
+ },
+ animations: {
+ _fallback: 'animation'
+ }
+ },
+ additionalOptionScopes: ['interaction']
+};
+
+var plugins = /*#__PURE__*/Object.freeze({
+__proto__: null,
+Decimation: plugin_decimation,
+Filler: plugin_filler,
+Legend: plugin_legend,
+SubTitle: plugin_subtitle,
+Title: plugin_title,
+Tooltip: plugin_tooltip
+});
+
+const addIfString = (labels, raw, index, addedLabels) => {
+ if (typeof raw === 'string') {
+ index = labels.push(raw) - 1;
+ addedLabels.unshift({index, label: raw});
+ } else if (isNaN(raw)) {
+ index = null;
+ }
+ return index;
+};
+function findOrAddLabel(labels, raw, index, addedLabels) {
+ const first = labels.indexOf(raw);
+ if (first === -1) {
+ return addIfString(labels, raw, index, addedLabels);
+ }
+ const last = labels.lastIndexOf(raw);
+ return first !== last ? index : first;
+}
+const validIndex = (index, max) => index === null ? null : _limitValue(Math.round(index), 0, max);
+class CategoryScale extends Scale {
+ constructor(cfg) {
+ super(cfg);
+ this._startValue = undefined;
+ this._valueRange = 0;
+ this._addedLabels = [];
+ }
+ init(scaleOptions) {
+ const added = this._addedLabels;
+ if (added.length) {
+ const labels = this.getLabels();
+ for (const {index, label} of added) {
+ if (labels[index] === label) {
+ labels.splice(index, 1);
+ }
+ }
+ this._addedLabels = [];
+ }
+ super.init(scaleOptions);
+ }
+ parse(raw, index) {
+ if (isNullOrUndef(raw)) {
+ return null;
+ }
+ const labels = this.getLabels();
+ index = isFinite(index) && labels[index] === raw ? index
+ : findOrAddLabel(labels, raw, valueOrDefault(index, raw), this._addedLabels);
+ return validIndex(index, labels.length - 1);
+ }
+ determineDataLimits() {
+ const {minDefined, maxDefined} = this.getUserBounds();
+ let {min, max} = this.getMinMax(true);
+ if (this.options.bounds === 'ticks') {
+ if (!minDefined) {
+ min = 0;
+ }
+ if (!maxDefined) {
+ max = this.getLabels().length - 1;
+ }
+ }
+ this.min = min;
+ this.max = max;
+ }
+ buildTicks() {
+ const min = this.min;
+ const max = this.max;
+ const offset = this.options.offset;
+ const ticks = [];
+ let labels = this.getLabels();
+ labels = (min === 0 && max === labels.length - 1) ? labels : labels.slice(min, max + 1);
+ this._valueRange = Math.max(labels.length - (offset ? 0 : 1), 1);
+ this._startValue = this.min - (offset ? 0.5 : 0);
+ for (let value = min; value <= max; value++) {
+ ticks.push({value});
+ }
+ return ticks;
+ }
+ getLabelForValue(value) {
+ const labels = this.getLabels();
+ if (value >= 0 && value < labels.length) {
+ return labels[value];
+ }
+ return value;
+ }
+ configure() {
+ super.configure();
+ if (!this.isHorizontal()) {
+ this._reversePixels = !this._reversePixels;
+ }
+ }
+ getPixelForValue(value) {
+ if (typeof value !== 'number') {
+ value = this.parse(value);
+ }
+ return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
+ }
+ getPixelForTick(index) {
+ const ticks = this.ticks;
+ if (index < 0 || index > ticks.length - 1) {
+ return null;
+ }
+ return this.getPixelForValue(ticks[index].value);
+ }
+ getValueForPixel(pixel) {
+ return Math.round(this._startValue + this.getDecimalForPixel(pixel) * this._valueRange);
+ }
+ getBasePixel() {
+ return this.bottom;
+ }
+}
+CategoryScale.id = 'category';
+CategoryScale.defaults = {
+ ticks: {
+ callback: CategoryScale.prototype.getLabelForValue
+ }
+};
+
+function generateTicks$1(generationOptions, dataRange) {
+ const ticks = [];
+ const MIN_SPACING = 1e-14;
+ const {bounds, step, min, max, precision, count, maxTicks, maxDigits, includeBounds} = generationOptions;
+ const unit = step || 1;
+ const maxSpaces = maxTicks - 1;
+ const {min: rmin, max: rmax} = dataRange;
+ const minDefined = !isNullOrUndef(min);
+ const maxDefined = !isNullOrUndef(max);
+ const countDefined = !isNullOrUndef(count);
+ const minSpacing = (rmax - rmin) / (maxDigits + 1);
+ let spacing = niceNum((rmax - rmin) / maxSpaces / unit) * unit;
+ let factor, niceMin, niceMax, numSpaces;
+ if (spacing < MIN_SPACING && !minDefined && !maxDefined) {
+ return [{value: rmin}, {value: rmax}];
+ }
+ numSpaces = Math.ceil(rmax / spacing) - Math.floor(rmin / spacing);
+ if (numSpaces > maxSpaces) {
+ spacing = niceNum(numSpaces * spacing / maxSpaces / unit) * unit;
+ }
+ if (!isNullOrUndef(precision)) {
+ factor = Math.pow(10, precision);
+ spacing = Math.ceil(spacing * factor) / factor;
+ }
+ if (bounds === 'ticks') {
+ niceMin = Math.floor(rmin / spacing) * spacing;
+ niceMax = Math.ceil(rmax / spacing) * spacing;
+ } else {
+ niceMin = rmin;
+ niceMax = rmax;
+ }
+ if (minDefined && maxDefined && step && almostWhole((max - min) / step, spacing / 1000)) {
+ numSpaces = Math.round(Math.min((max - min) / spacing, maxTicks));
+ spacing = (max - min) / numSpaces;
+ niceMin = min;
+ niceMax = max;
+ } else if (countDefined) {
+ niceMin = minDefined ? min : niceMin;
+ niceMax = maxDefined ? max : niceMax;
+ numSpaces = count - 1;
+ spacing = (niceMax - niceMin) / numSpaces;
+ } else {
+ numSpaces = (niceMax - niceMin) / spacing;
+ if (almostEquals(numSpaces, Math.round(numSpaces), spacing / 1000)) {
+ numSpaces = Math.round(numSpaces);
+ } else {
+ numSpaces = Math.ceil(numSpaces);
+ }
+ }
+ const decimalPlaces = Math.max(
+ _decimalPlaces(spacing),
+ _decimalPlaces(niceMin)
+ );
+ factor = Math.pow(10, isNullOrUndef(precision) ? decimalPlaces : precision);
+ niceMin = Math.round(niceMin * factor) / factor;
+ niceMax = Math.round(niceMax * factor) / factor;
+ let j = 0;
+ if (minDefined) {
+ if (includeBounds && niceMin !== min) {
+ ticks.push({value: min});
+ if (niceMin < min) {
+ j++;
+ }
+ if (almostEquals(Math.round((niceMin + j * spacing) * factor) / factor, min, relativeLabelSize(min, minSpacing, generationOptions))) {
+ j++;
+ }
+ } else if (niceMin < min) {
+ j++;
+ }
+ }
+ for (; j < numSpaces; ++j) {
+ ticks.push({value: Math.round((niceMin + j * spacing) * factor) / factor});
+ }
+ if (maxDefined && includeBounds && niceMax !== max) {
+ if (ticks.length && almostEquals(ticks[ticks.length - 1].value, max, relativeLabelSize(max, minSpacing, generationOptions))) {
+ ticks[ticks.length - 1].value = max;
+ } else {
+ ticks.push({value: max});
+ }
+ } else if (!maxDefined || niceMax === max) {
+ ticks.push({value: niceMax});
+ }
+ return ticks;
+}
+function relativeLabelSize(value, minSpacing, {horizontal, minRotation}) {
+ const rad = toRadians(minRotation);
+ const ratio = (horizontal ? Math.sin(rad) : Math.cos(rad)) || 0.001;
+ const length = 0.75 * minSpacing * ('' + value).length;
+ return Math.min(minSpacing / ratio, length);
+}
+class LinearScaleBase extends Scale {
+ constructor(cfg) {
+ super(cfg);
+ this.start = undefined;
+ this.end = undefined;
+ this._startValue = undefined;
+ this._endValue = undefined;
+ this._valueRange = 0;
+ }
+ parse(raw, index) {
+ if (isNullOrUndef(raw)) {
+ return null;
+ }
+ if ((typeof raw === 'number' || raw instanceof Number) && !isFinite(+raw)) {
+ return null;
+ }
+ return +raw;
+ }
+ handleTickRangeOptions() {
+ const {beginAtZero} = this.options;
+ const {minDefined, maxDefined} = this.getUserBounds();
+ let {min, max} = this;
+ const setMin = v => (min = minDefined ? min : v);
+ const setMax = v => (max = maxDefined ? max : v);
+ if (beginAtZero) {
+ const minSign = sign(min);
+ const maxSign = sign(max);
+ if (minSign < 0 && maxSign < 0) {
+ setMax(0);
+ } else if (minSign > 0 && maxSign > 0) {
+ setMin(0);
+ }
+ }
+ if (min === max) {
+ let offset = 1;
+ if (max >= Number.MAX_SAFE_INTEGER || min <= Number.MIN_SAFE_INTEGER) {
+ offset = Math.abs(max * 0.05);
+ }
+ setMax(max + offset);
+ if (!beginAtZero) {
+ setMin(min - offset);
+ }
+ }
+ this.min = min;
+ this.max = max;
+ }
+ getTickLimit() {
+ const tickOpts = this.options.ticks;
+ let {maxTicksLimit, stepSize} = tickOpts;
+ let maxTicks;
+ if (stepSize) {
+ maxTicks = Math.ceil(this.max / stepSize) - Math.floor(this.min / stepSize) + 1;
+ if (maxTicks > 1000) {
+ console.warn(`scales.${this.id}.ticks.stepSize: ${stepSize} would result generating up to ${maxTicks} ticks. Limiting to 1000.`);
+ maxTicks = 1000;
+ }
+ } else {
+ maxTicks = this.computeTickLimit();
+ maxTicksLimit = maxTicksLimit || 11;
+ }
+ if (maxTicksLimit) {
+ maxTicks = Math.min(maxTicksLimit, maxTicks);
+ }
+ return maxTicks;
+ }
+ computeTickLimit() {
+ return Number.POSITIVE_INFINITY;
+ }
+ buildTicks() {
+ const opts = this.options;
+ const tickOpts = opts.ticks;
+ let maxTicks = this.getTickLimit();
+ maxTicks = Math.max(2, maxTicks);
+ const numericGeneratorOptions = {
+ maxTicks,
+ bounds: opts.bounds,
+ min: opts.min,
+ max: opts.max,
+ precision: tickOpts.precision,
+ step: tickOpts.stepSize,
+ count: tickOpts.count,
+ maxDigits: this._maxDigits(),
+ horizontal: this.isHorizontal(),
+ minRotation: tickOpts.minRotation || 0,
+ includeBounds: tickOpts.includeBounds !== false
+ };
+ const dataRange = this._range || this;
+ const ticks = generateTicks$1(numericGeneratorOptions, dataRange);
+ if (opts.bounds === 'ticks') {
+ _setMinAndMaxByKey(ticks, this, 'value');
+ }
+ if (opts.reverse) {
+ ticks.reverse();
+ this.start = this.max;
+ this.end = this.min;
+ } else {
+ this.start = this.min;
+ this.end = this.max;
+ }
+ return ticks;
+ }
+ configure() {
+ const ticks = this.ticks;
+ let start = this.min;
+ let end = this.max;
+ super.configure();
+ if (this.options.offset && ticks.length) {
+ const offset = (end - start) / Math.max(ticks.length - 1, 1) / 2;
+ start -= offset;
+ end += offset;
+ }
+ this._startValue = start;
+ this._endValue = end;
+ this._valueRange = end - start;
+ }
+ getLabelForValue(value) {
+ return formatNumber(value, this.chart.options.locale, this.options.ticks.format);
+ }
+}
+
+class LinearScale extends LinearScaleBase {
+ determineDataLimits() {
+ const {min, max} = this.getMinMax(true);
+ this.min = isNumberFinite(min) ? min : 0;
+ this.max = isNumberFinite(max) ? max : 1;
+ this.handleTickRangeOptions();
+ }
+ computeTickLimit() {
+ const horizontal = this.isHorizontal();
+ const length = horizontal ? this.width : this.height;
+ const minRotation = toRadians(this.options.ticks.minRotation);
+ const ratio = (horizontal ? Math.sin(minRotation) : Math.cos(minRotation)) || 0.001;
+ const tickFont = this._resolveTickFontOptions(0);
+ return Math.ceil(length / Math.min(40, tickFont.lineHeight / ratio));
+ }
+ getPixelForValue(value) {
+ return value === null ? NaN : this.getPixelForDecimal((value - this._startValue) / this._valueRange);
+ }
+ getValueForPixel(pixel) {
+ return this._startValue + this.getDecimalForPixel(pixel) * this._valueRange;
+ }
+}
+LinearScale.id = 'linear';
+LinearScale.defaults = {
+ ticks: {
+ callback: Ticks.formatters.numeric
+ }
+};
+
+function isMajor(tickVal) {
+ const remain = tickVal / (Math.pow(10, Math.floor(log10(tickVal))));
+ return remain === 1;
+}
+function generateTicks(generationOptions, dataRange) {
+ const endExp = Math.floor(log10(dataRange.max));
+ const endSignificand = Math.ceil(dataRange.max / Math.pow(10, endExp));
+ const ticks = [];
+ let tickVal = finiteOrDefault(generationOptions.min, Math.pow(10, Math.floor(log10(dataRange.min))));
+ let exp = Math.floor(log10(tickVal));
+ let significand = Math.floor(tickVal / Math.pow(10, exp));
+ let precision = exp < 0 ? Math.pow(10, Math.abs(exp)) : 1;
+ do {
+ ticks.push({value: tickVal, major: isMajor(tickVal)});
+ ++significand;
+ if (significand === 10) {
+ significand = 1;
+ ++exp;
+ precision = exp >= 0 ? 1 : precision;
+ }
+ tickVal = Math.round(significand * Math.pow(10, exp) * precision) / precision;
+ } while (exp < endExp || (exp === endExp && significand < endSignificand));
+ const lastTick = finiteOrDefault(generationOptions.max, tickVal);
+ ticks.push({value: lastTick, major: isMajor(tickVal)});
+ return ticks;
+}
+class LogarithmicScale extends Scale {
+ constructor(cfg) {
+ super(cfg);
+ this.start = undefined;
+ this.end = undefined;
+ this._startValue = undefined;
+ this._valueRange = 0;
+ }
+ parse(raw, index) {
+ const value = LinearScaleBase.prototype.parse.apply(this, [raw, index]);
+ if (value === 0) {
+ this._zero = true;
+ return undefined;
+ }
+ return isNumberFinite(value) && value > 0 ? value : null;
+ }
+ determineDataLimits() {
+ const {min, max} = this.getMinMax(true);
+ this.min = isNumberFinite(min) ? Math.max(0, min) : null;
+ this.max = isNumberFinite(max) ? Math.max(0, max) : null;
+ if (this.options.beginAtZero) {
+ this._zero = true;
+ }
+ this.handleTickRangeOptions();
+ }
+ handleTickRangeOptions() {
+ const {minDefined, maxDefined} = this.getUserBounds();
+ let min = this.min;
+ let max = this.max;
+ const setMin = v => (min = minDefined ? min : v);
+ const setMax = v => (max = maxDefined ? max : v);
+ const exp = (v, m) => Math.pow(10, Math.floor(log10(v)) + m);
+ if (min === max) {
+ if (min <= 0) {
+ setMin(1);
+ setMax(10);
+ } else {
+ setMin(exp(min, -1));
+ setMax(exp(max, +1));
+ }
+ }
+ if (min <= 0) {
+ setMin(exp(max, -1));
+ }
+ if (max <= 0) {
+ setMax(exp(min, +1));
+ }
+ if (this._zero && this.min !== this._suggestedMin && min === exp(this.min, 0)) {
+ setMin(exp(min, -1));
+ }
+ this.min = min;
+ this.max = max;
+ }
+ buildTicks() {
+ const opts = this.options;
+ const generationOptions = {
+ min: this._userMin,
+ max: this._userMax
+ };
+ const ticks = generateTicks(generationOptions, this);
+ if (opts.bounds === 'ticks') {
+ _setMinAndMaxByKey(ticks, this, 'value');
+ }
+ if (opts.reverse) {
+ ticks.reverse();
+ this.start = this.max;
+ this.end = this.min;
+ } else {
+ this.start = this.min;
+ this.end = this.max;
+ }
+ return ticks;
+ }
+ getLabelForValue(value) {
+ return value === undefined
+ ? '0'
+ : formatNumber(value, this.chart.options.locale, this.options.ticks.format);
+ }
+ configure() {
+ const start = this.min;
+ super.configure();
+ this._startValue = log10(start);
+ this._valueRange = log10(this.max) - log10(start);
+ }
+ getPixelForValue(value) {
+ if (value === undefined || value === 0) {
+ value = this.min;
+ }
+ if (value === null || isNaN(value)) {
+ return NaN;
+ }
+ return this.getPixelForDecimal(value === this.min
+ ? 0
+ : (log10(value) - this._startValue) / this._valueRange);
+ }
+ getValueForPixel(pixel) {
+ const decimal = this.getDecimalForPixel(pixel);
+ return Math.pow(10, this._startValue + decimal * this._valueRange);
+ }
+}
+LogarithmicScale.id = 'logarithmic';
+LogarithmicScale.defaults = {
+ ticks: {
+ callback: Ticks.formatters.logarithmic,
+ major: {
+ enabled: true
+ }
+ }
+};
+
+function getTickBackdropHeight(opts) {
+ const tickOpts = opts.ticks;
+ if (tickOpts.display && opts.display) {
+ const padding = toPadding(tickOpts.backdropPadding);
+ return valueOrDefault(tickOpts.font && tickOpts.font.size, defaults.font.size) + padding.height;
+ }
+ return 0;
+}
+function measureLabelSize(ctx, font, label) {
+ label = isArray(label) ? label : [label];
+ return {
+ w: _longestText(ctx, font.string, label),
+ h: label.length * font.lineHeight
+ };
+}
+function determineLimits(angle, pos, size, min, max) {
+ if (angle === min || angle === max) {
+ return {
+ start: pos - (size / 2),
+ end: pos + (size / 2)
+ };
+ } else if (angle < min || angle > max) {
+ return {
+ start: pos - size,
+ end: pos
+ };
+ }
+ return {
+ start: pos,
+ end: pos + size
+ };
+}
+function fitWithPointLabels(scale) {
+ const orig = {
+ l: scale.left + scale._padding.left,
+ r: scale.right - scale._padding.right,
+ t: scale.top + scale._padding.top,
+ b: scale.bottom - scale._padding.bottom
+ };
+ const limits = Object.assign({}, orig);
+ const labelSizes = [];
+ const padding = [];
+ const valueCount = scale._pointLabels.length;
+ const pointLabelOpts = scale.options.pointLabels;
+ const additionalAngle = pointLabelOpts.centerPointLabels ? PI / valueCount : 0;
+ for (let i = 0; i < valueCount; i++) {
+ const opts = pointLabelOpts.setContext(scale.getPointLabelContext(i));
+ padding[i] = opts.padding;
+ const pointPosition = scale.getPointPosition(i, scale.drawingArea + padding[i], additionalAngle);
+ const plFont = toFont(opts.font);
+ const textSize = measureLabelSize(scale.ctx, plFont, scale._pointLabels[i]);
+ labelSizes[i] = textSize;
+ const angleRadians = _normalizeAngle(scale.getIndexAngle(i) + additionalAngle);
+ const angle = Math.round(toDegrees(angleRadians));
+ const hLimits = determineLimits(angle, pointPosition.x, textSize.w, 0, 180);
+ const vLimits = determineLimits(angle, pointPosition.y, textSize.h, 90, 270);
+ updateLimits(limits, orig, angleRadians, hLimits, vLimits);
+ }
+ scale.setCenterPoint(
+ orig.l - limits.l,
+ limits.r - orig.r,
+ orig.t - limits.t,
+ limits.b - orig.b
+ );
+ scale._pointLabelItems = buildPointLabelItems(scale, labelSizes, padding);
+}
+function updateLimits(limits, orig, angle, hLimits, vLimits) {
+ const sin = Math.abs(Math.sin(angle));
+ const cos = Math.abs(Math.cos(angle));
+ let x = 0;
+ let y = 0;
+ if (hLimits.start < orig.l) {
+ x = (orig.l - hLimits.start) / sin;
+ limits.l = Math.min(limits.l, orig.l - x);
+ } else if (hLimits.end > orig.r) {
+ x = (hLimits.end - orig.r) / sin;
+ limits.r = Math.max(limits.r, orig.r + x);
+ }
+ if (vLimits.start < orig.t) {
+ y = (orig.t - vLimits.start) / cos;
+ limits.t = Math.min(limits.t, orig.t - y);
+ } else if (vLimits.end > orig.b) {
+ y = (vLimits.end - orig.b) / cos;
+ limits.b = Math.max(limits.b, orig.b + y);
+ }
+}
+function buildPointLabelItems(scale, labelSizes, padding) {
+ const items = [];
+ const valueCount = scale._pointLabels.length;
+ const opts = scale.options;
+ const extra = getTickBackdropHeight(opts) / 2;
+ const outerDistance = scale.drawingArea;
+ const additionalAngle = opts.pointLabels.centerPointLabels ? PI / valueCount : 0;
+ for (let i = 0; i < valueCount; i++) {
+ const pointLabelPosition = scale.getPointPosition(i, outerDistance + extra + padding[i], additionalAngle);
+ const angle = Math.round(toDegrees(_normalizeAngle(pointLabelPosition.angle + HALF_PI)));
+ const size = labelSizes[i];
+ const y = yForAngle(pointLabelPosition.y, size.h, angle);
+ const textAlign = getTextAlignForAngle(angle);
+ const left = leftForTextAlign(pointLabelPosition.x, size.w, textAlign);
+ items.push({
+ x: pointLabelPosition.x,
+ y,
+ textAlign,
+ left,
+ top: y,
+ right: left + size.w,
+ bottom: y + size.h
+ });
+ }
+ return items;
+}
+function getTextAlignForAngle(angle) {
+ if (angle === 0 || angle === 180) {
+ return 'center';
+ } else if (angle < 180) {
+ return 'left';
+ }
+ return 'right';
+}
+function leftForTextAlign(x, w, align) {
+ if (align === 'right') {
+ x -= w;
+ } else if (align === 'center') {
+ x -= (w / 2);
+ }
+ return x;
+}
+function yForAngle(y, h, angle) {
+ if (angle === 90 || angle === 270) {
+ y -= (h / 2);
+ } else if (angle > 270 || angle < 90) {
+ y -= h;
+ }
+ return y;
+}
+function drawPointLabels(scale, labelCount) {
+ const {ctx, options: {pointLabels}} = scale;
+ for (let i = labelCount - 1; i >= 0; i--) {
+ const optsAtIndex = pointLabels.setContext(scale.getPointLabelContext(i));
+ const plFont = toFont(optsAtIndex.font);
+ const {x, y, textAlign, left, top, right, bottom} = scale._pointLabelItems[i];
+ const {backdropColor} = optsAtIndex;
+ if (!isNullOrUndef(backdropColor)) {
+ const padding = toPadding(optsAtIndex.backdropPadding);
+ ctx.fillStyle = backdropColor;
+ ctx.fillRect(left - padding.left, top - padding.top, right - left + padding.width, bottom - top + padding.height);
+ }
+ renderText(
+ ctx,
+ scale._pointLabels[i],
+ x,
+ y + (plFont.lineHeight / 2),
+ plFont,
+ {
+ color: optsAtIndex.color,
+ textAlign: textAlign,
+ textBaseline: 'middle'
+ }
+ );
+ }
+}
+function pathRadiusLine(scale, radius, circular, labelCount) {
+ const {ctx} = scale;
+ if (circular) {
+ ctx.arc(scale.xCenter, scale.yCenter, radius, 0, TAU);
+ } else {
+ let pointPosition = scale.getPointPosition(0, radius);
+ ctx.moveTo(pointPosition.x, pointPosition.y);
+ for (let i = 1; i < labelCount; i++) {
+ pointPosition = scale.getPointPosition(i, radius);
+ ctx.lineTo(pointPosition.x, pointPosition.y);
+ }
+ }
+}
+function drawRadiusLine(scale, gridLineOpts, radius, labelCount) {
+ const ctx = scale.ctx;
+ const circular = gridLineOpts.circular;
+ const {color, lineWidth} = gridLineOpts;
+ if ((!circular && !labelCount) || !color || !lineWidth || radius < 0) {
+ return;
+ }
+ ctx.save();
+ ctx.strokeStyle = color;
+ ctx.lineWidth = lineWidth;
+ ctx.setLineDash(gridLineOpts.borderDash);
+ ctx.lineDashOffset = gridLineOpts.borderDashOffset;
+ ctx.beginPath();
+ pathRadiusLine(scale, radius, circular, labelCount);
+ ctx.closePath();
+ ctx.stroke();
+ ctx.restore();
+}
+function createPointLabelContext(parent, index, label) {
+ return createContext(parent, {
+ label,
+ index,
+ type: 'pointLabel'
+ });
+}
+class RadialLinearScale extends LinearScaleBase {
+ constructor(cfg) {
+ super(cfg);
+ this.xCenter = undefined;
+ this.yCenter = undefined;
+ this.drawingArea = undefined;
+ this._pointLabels = [];
+ this._pointLabelItems = [];
+ }
+ setDimensions() {
+ const padding = this._padding = toPadding(getTickBackdropHeight(this.options) / 2);
+ const w = this.width = this.maxWidth - padding.width;
+ const h = this.height = this.maxHeight - padding.height;
+ this.xCenter = Math.floor(this.left + w / 2 + padding.left);
+ this.yCenter = Math.floor(this.top + h / 2 + padding.top);
+ this.drawingArea = Math.floor(Math.min(w, h) / 2);
+ }
+ determineDataLimits() {
+ const {min, max} = this.getMinMax(false);
+ this.min = isNumberFinite(min) && !isNaN(min) ? min : 0;
+ this.max = isNumberFinite(max) && !isNaN(max) ? max : 0;
+ this.handleTickRangeOptions();
+ }
+ computeTickLimit() {
+ return Math.ceil(this.drawingArea / getTickBackdropHeight(this.options));
+ }
+ generateTickLabels(ticks) {
+ LinearScaleBase.prototype.generateTickLabels.call(this, ticks);
+ this._pointLabels = this.getLabels()
+ .map((value, index) => {
+ const label = callback(this.options.pointLabels.callback, [value, index], this);
+ return label || label === 0 ? label : '';
+ })
+ .filter((v, i) => this.chart.getDataVisibility(i));
+ }
+ fit() {
+ const opts = this.options;
+ if (opts.display && opts.pointLabels.display) {
+ fitWithPointLabels(this);
+ } else {
+ this.setCenterPoint(0, 0, 0, 0);
+ }
+ }
+ setCenterPoint(leftMovement, rightMovement, topMovement, bottomMovement) {
+ this.xCenter += Math.floor((leftMovement - rightMovement) / 2);
+ this.yCenter += Math.floor((topMovement - bottomMovement) / 2);
+ this.drawingArea -= Math.min(this.drawingArea / 2, Math.max(leftMovement, rightMovement, topMovement, bottomMovement));
+ }
+ getIndexAngle(index) {
+ const angleMultiplier = TAU / (this._pointLabels.length || 1);
+ const startAngle = this.options.startAngle || 0;
+ return _normalizeAngle(index * angleMultiplier + toRadians(startAngle));
+ }
+ getDistanceFromCenterForValue(value) {
+ if (isNullOrUndef(value)) {
+ return NaN;
+ }
+ const scalingFactor = this.drawingArea / (this.max - this.min);
+ if (this.options.reverse) {
+ return (this.max - value) * scalingFactor;
+ }
+ return (value - this.min) * scalingFactor;
+ }
+ getValueForDistanceFromCenter(distance) {
+ if (isNullOrUndef(distance)) {
+ return NaN;
+ }
+ const scaledDistance = distance / (this.drawingArea / (this.max - this.min));
+ return this.options.reverse ? this.max - scaledDistance : this.min + scaledDistance;
+ }
+ getPointLabelContext(index) {
+ const pointLabels = this._pointLabels || [];
+ if (index >= 0 && index < pointLabels.length) {
+ const pointLabel = pointLabels[index];
+ return createPointLabelContext(this.getContext(), index, pointLabel);
+ }
+ }
+ getPointPosition(index, distanceFromCenter, additionalAngle = 0) {
+ const angle = this.getIndexAngle(index) - HALF_PI + additionalAngle;
+ return {
+ x: Math.cos(angle) * distanceFromCenter + this.xCenter,
+ y: Math.sin(angle) * distanceFromCenter + this.yCenter,
+ angle
+ };
+ }
+ getPointPositionForValue(index, value) {
+ return this.getPointPosition(index, this.getDistanceFromCenterForValue(value));
+ }
+ getBasePosition(index) {
+ return this.getPointPositionForValue(index || 0, this.getBaseValue());
+ }
+ getPointLabelPosition(index) {
+ const {left, top, right, bottom} = this._pointLabelItems[index];
+ return {
+ left,
+ top,
+ right,
+ bottom,
+ };
+ }
+ drawBackground() {
+ const {backgroundColor, grid: {circular}} = this.options;
+ if (backgroundColor) {
+ const ctx = this.ctx;
+ ctx.save();
+ ctx.beginPath();
+ pathRadiusLine(this, this.getDistanceFromCenterForValue(this._endValue), circular, this._pointLabels.length);
+ ctx.closePath();
+ ctx.fillStyle = backgroundColor;
+ ctx.fill();
+ ctx.restore();
+ }
+ }
+ drawGrid() {
+ const ctx = this.ctx;
+ const opts = this.options;
+ const {angleLines, grid} = opts;
+ const labelCount = this._pointLabels.length;
+ let i, offset, position;
+ if (opts.pointLabels.display) {
+ drawPointLabels(this, labelCount);
+ }
+ if (grid.display) {
+ this.ticks.forEach((tick, index) => {
+ if (index !== 0) {
+ offset = this.getDistanceFromCenterForValue(tick.value);
+ const optsAtIndex = grid.setContext(this.getContext(index - 1));
+ drawRadiusLine(this, optsAtIndex, offset, labelCount);
+ }
+ });
+ }
+ if (angleLines.display) {
+ ctx.save();
+ for (i = labelCount - 1; i >= 0; i--) {
+ const optsAtIndex = angleLines.setContext(this.getPointLabelContext(i));
+ const {color, lineWidth} = optsAtIndex;
+ if (!lineWidth || !color) {
+ continue;
+ }
+ ctx.lineWidth = lineWidth;
+ ctx.strokeStyle = color;
+ ctx.setLineDash(optsAtIndex.borderDash);
+ ctx.lineDashOffset = optsAtIndex.borderDashOffset;
+ offset = this.getDistanceFromCenterForValue(opts.ticks.reverse ? this.min : this.max);
+ position = this.getPointPosition(i, offset);
+ ctx.beginPath();
+ ctx.moveTo(this.xCenter, this.yCenter);
+ ctx.lineTo(position.x, position.y);
+ ctx.stroke();
+ }
+ ctx.restore();
+ }
+ }
+ drawBorder() {}
+ drawLabels() {
+ const ctx = this.ctx;
+ const opts = this.options;
+ const tickOpts = opts.ticks;
+ if (!tickOpts.display) {
+ return;
+ }
+ const startAngle = this.getIndexAngle(0);
+ let offset, width;
+ ctx.save();
+ ctx.translate(this.xCenter, this.yCenter);
+ ctx.rotate(startAngle);
+ ctx.textAlign = 'center';
+ ctx.textBaseline = 'middle';
+ this.ticks.forEach((tick, index) => {
+ if (index === 0 && !opts.reverse) {
+ return;
+ }
+ const optsAtIndex = tickOpts.setContext(this.getContext(index));
+ const tickFont = toFont(optsAtIndex.font);
+ offset = this.getDistanceFromCenterForValue(this.ticks[index].value);
+ if (optsAtIndex.showLabelBackdrop) {
+ ctx.font = tickFont.string;
+ width = ctx.measureText(tick.label).width;
+ ctx.fillStyle = optsAtIndex.backdropColor;
+ const padding = toPadding(optsAtIndex.backdropPadding);
+ ctx.fillRect(
+ -width / 2 - padding.left,
+ -offset - tickFont.size / 2 - padding.top,
+ width + padding.width,
+ tickFont.size + padding.height
+ );
+ }
+ renderText(ctx, tick.label, 0, -offset, tickFont, {
+ color: optsAtIndex.color,
+ });
+ });
+ ctx.restore();
+ }
+ drawTitle() {}
+}
+RadialLinearScale.id = 'radialLinear';
+RadialLinearScale.defaults = {
+ display: true,
+ animate: true,
+ position: 'chartArea',
+ angleLines: {
+ display: true,
+ lineWidth: 1,
+ borderDash: [],
+ borderDashOffset: 0.0
+ },
+ grid: {
+ circular: false
+ },
+ startAngle: 0,
+ ticks: {
+ showLabelBackdrop: true,
+ callback: Ticks.formatters.numeric
+ },
+ pointLabels: {
+ backdropColor: undefined,
+ backdropPadding: 2,
+ display: true,
+ font: {
+ size: 10
+ },
+ callback(label) {
+ return label;
+ },
+ padding: 5,
+ centerPointLabels: false
+ }
+};
+RadialLinearScale.defaultRoutes = {
+ 'angleLines.color': 'borderColor',
+ 'pointLabels.color': 'color',
+ 'ticks.color': 'color'
+};
+RadialLinearScale.descriptors = {
+ angleLines: {
+ _fallback: 'grid'
+ }
+};
+
+const INTERVALS = {
+ millisecond: {common: true, size: 1, steps: 1000},
+ second: {common: true, size: 1000, steps: 60},
+ minute: {common: true, size: 60000, steps: 60},
+ hour: {common: true, size: 3600000, steps: 24},
+ day: {common: true, size: 86400000, steps: 30},
+ week: {common: false, size: 604800000, steps: 4},
+ month: {common: true, size: 2.628e9, steps: 12},
+ quarter: {common: false, size: 7.884e9, steps: 4},
+ year: {common: true, size: 3.154e10}
+};
+const UNITS = (Object.keys(INTERVALS));
+function sorter(a, b) {
+ return a - b;
+}
+function parse(scale, input) {
+ if (isNullOrUndef(input)) {
+ return null;
+ }
+ const adapter = scale._adapter;
+ const {parser, round, isoWeekday} = scale._parseOpts;
+ let value = input;
+ if (typeof parser === 'function') {
+ value = parser(value);
+ }
+ if (!isNumberFinite(value)) {
+ value = typeof parser === 'string'
+ ? adapter.parse(value, parser)
+ : adapter.parse(value);
+ }
+ if (value === null) {
+ return null;
+ }
+ if (round) {
+ value = round === 'week' && (isNumber(isoWeekday) || isoWeekday === true)
+ ? adapter.startOf(value, 'isoWeek', isoWeekday)
+ : adapter.startOf(value, round);
+ }
+ return +value;
+}
+function determineUnitForAutoTicks(minUnit, min, max, capacity) {
+ const ilen = UNITS.length;
+ for (let i = UNITS.indexOf(minUnit); i < ilen - 1; ++i) {
+ const interval = INTERVALS[UNITS[i]];
+ const factor = interval.steps ? interval.steps : Number.MAX_SAFE_INTEGER;
+ if (interval.common && Math.ceil((max - min) / (factor * interval.size)) <= capacity) {
+ return UNITS[i];
+ }
+ }
+ return UNITS[ilen - 1];
+}
+function determineUnitForFormatting(scale, numTicks, minUnit, min, max) {
+ for (let i = UNITS.length - 1; i >= UNITS.indexOf(minUnit); i--) {
+ const unit = UNITS[i];
+ if (INTERVALS[unit].common && scale._adapter.diff(max, min, unit) >= numTicks - 1) {
+ return unit;
+ }
+ }
+ return UNITS[minUnit ? UNITS.indexOf(minUnit) : 0];
+}
+function determineMajorUnit(unit) {
+ for (let i = UNITS.indexOf(unit) + 1, ilen = UNITS.length; i < ilen; ++i) {
+ if (INTERVALS[UNITS[i]].common) {
+ return UNITS[i];
+ }
+ }
+}
+function addTick(ticks, time, timestamps) {
+ if (!timestamps) {
+ ticks[time] = true;
+ } else if (timestamps.length) {
+ const {lo, hi} = _lookup(timestamps, time);
+ const timestamp = timestamps[lo] >= time ? timestamps[lo] : timestamps[hi];
+ ticks[timestamp] = true;
+ }
+}
+function setMajorTicks(scale, ticks, map, majorUnit) {
+ const adapter = scale._adapter;
+ const first = +adapter.startOf(ticks[0].value, majorUnit);
+ const last = ticks[ticks.length - 1].value;
+ let major, index;
+ for (major = first; major <= last; major = +adapter.add(major, 1, majorUnit)) {
+ index = map[major];
+ if (index >= 0) {
+ ticks[index].major = true;
+ }
+ }
+ return ticks;
+}
+function ticksFromTimestamps(scale, values, majorUnit) {
+ const ticks = [];
+ const map = {};
+ const ilen = values.length;
+ let i, value;
+ for (i = 0; i < ilen; ++i) {
+ value = values[i];
+ map[value] = i;
+ ticks.push({
+ value,
+ major: false
+ });
+ }
+ return (ilen === 0 || !majorUnit) ? ticks : setMajorTicks(scale, ticks, map, majorUnit);
+}
+class TimeScale extends Scale {
+ constructor(props) {
+ super(props);
+ this._cache = {
+ data: [],
+ labels: [],
+ all: []
+ };
+ this._unit = 'day';
+ this._majorUnit = undefined;
+ this._offsets = {};
+ this._normalized = false;
+ this._parseOpts = undefined;
+ }
+ init(scaleOpts, opts) {
+ const time = scaleOpts.time || (scaleOpts.time = {});
+ const adapter = this._adapter = new _adapters._date(scaleOpts.adapters.date);
+ mergeIf(time.displayFormats, adapter.formats());
+ this._parseOpts = {
+ parser: time.parser,
+ round: time.round,
+ isoWeekday: time.isoWeekday
+ };
+ super.init(scaleOpts);
+ this._normalized = opts.normalized;
+ }
+ parse(raw, index) {
+ if (raw === undefined) {
+ return null;
+ }
+ return parse(this, raw);
+ }
+ beforeLayout() {
+ super.beforeLayout();
+ this._cache = {
+ data: [],
+ labels: [],
+ all: []
+ };
+ }
+ determineDataLimits() {
+ const options = this.options;
+ const adapter = this._adapter;
+ const unit = options.time.unit || 'day';
+ let {min, max, minDefined, maxDefined} = this.getUserBounds();
+ function _applyBounds(bounds) {
+ if (!minDefined && !isNaN(bounds.min)) {
+ min = Math.min(min, bounds.min);
+ }
+ if (!maxDefined && !isNaN(bounds.max)) {
+ max = Math.max(max, bounds.max);
+ }
+ }
+ if (!minDefined || !maxDefined) {
+ _applyBounds(this._getLabelBounds());
+ if (options.bounds !== 'ticks' || options.ticks.source !== 'labels') {
+ _applyBounds(this.getMinMax(false));
+ }
+ }
+ min = isNumberFinite(min) && !isNaN(min) ? min : +adapter.startOf(Date.now(), unit);
+ max = isNumberFinite(max) && !isNaN(max) ? max : +adapter.endOf(Date.now(), unit) + 1;
+ this.min = Math.min(min, max - 1);
+ this.max = Math.max(min + 1, max);
+ }
+ _getLabelBounds() {
+ const arr = this.getLabelTimestamps();
+ let min = Number.POSITIVE_INFINITY;
+ let max = Number.NEGATIVE_INFINITY;
+ if (arr.length) {
+ min = arr[0];
+ max = arr[arr.length - 1];
+ }
+ return {min, max};
+ }
+ buildTicks() {
+ const options = this.options;
+ const timeOpts = options.time;
+ const tickOpts = options.ticks;
+ const timestamps = tickOpts.source === 'labels' ? this.getLabelTimestamps() : this._generate();
+ if (options.bounds === 'ticks' && timestamps.length) {
+ this.min = this._userMin || timestamps[0];
+ this.max = this._userMax || timestamps[timestamps.length - 1];
+ }
+ const min = this.min;
+ const max = this.max;
+ const ticks = _filterBetween(timestamps, min, max);
+ this._unit = timeOpts.unit || (tickOpts.autoSkip
+ ? determineUnitForAutoTicks(timeOpts.minUnit, this.min, this.max, this._getLabelCapacity(min))
+ : determineUnitForFormatting(this, ticks.length, timeOpts.minUnit, this.min, this.max));
+ this._majorUnit = !tickOpts.major.enabled || this._unit === 'year' ? undefined
+ : determineMajorUnit(this._unit);
+ this.initOffsets(timestamps);
+ if (options.reverse) {
+ ticks.reverse();
+ }
+ return ticksFromTimestamps(this, ticks, this._majorUnit);
+ }
+ initOffsets(timestamps) {
+ let start = 0;
+ let end = 0;
+ let first, last;
+ if (this.options.offset && timestamps.length) {
+ first = this.getDecimalForValue(timestamps[0]);
+ if (timestamps.length === 1) {
+ start = 1 - first;
+ } else {
+ start = (this.getDecimalForValue(timestamps[1]) - first) / 2;
+ }
+ last = this.getDecimalForValue(timestamps[timestamps.length - 1]);
+ if (timestamps.length === 1) {
+ end = last;
+ } else {
+ end = (last - this.getDecimalForValue(timestamps[timestamps.length - 2])) / 2;
+ }
+ }
+ const limit = timestamps.length < 3 ? 0.5 : 0.25;
+ start = _limitValue(start, 0, limit);
+ end = _limitValue(end, 0, limit);
+ this._offsets = {start, end, factor: 1 / (start + 1 + end)};
+ }
+ _generate() {
+ const adapter = this._adapter;
+ const min = this.min;
+ const max = this.max;
+ const options = this.options;
+ const timeOpts = options.time;
+ const minor = timeOpts.unit || determineUnitForAutoTicks(timeOpts.minUnit, min, max, this._getLabelCapacity(min));
+ const stepSize = valueOrDefault(timeOpts.stepSize, 1);
+ const weekday = minor === 'week' ? timeOpts.isoWeekday : false;
+ const hasWeekday = isNumber(weekday) || weekday === true;
+ const ticks = {};
+ let first = min;
+ let time, count;
+ if (hasWeekday) {
+ first = +adapter.startOf(first, 'isoWeek', weekday);
+ }
+ first = +adapter.startOf(first, hasWeekday ? 'day' : minor);
+ if (adapter.diff(max, min, minor) > 100000 * stepSize) {
+ throw new Error(min + ' and ' + max + ' are too far apart with stepSize of ' + stepSize + ' ' + minor);
+ }
+ const timestamps = options.ticks.source === 'data' && this.getDataTimestamps();
+ for (time = first, count = 0; time < max; time = +adapter.add(time, stepSize, minor), count++) {
+ addTick(ticks, time, timestamps);
+ }
+ if (time === max || options.bounds === 'ticks' || count === 1) {
+ addTick(ticks, time, timestamps);
+ }
+ return Object.keys(ticks).sort((a, b) => a - b).map(x => +x);
+ }
+ getLabelForValue(value) {
+ const adapter = this._adapter;
+ const timeOpts = this.options.time;
+ if (timeOpts.tooltipFormat) {
+ return adapter.format(value, timeOpts.tooltipFormat);
+ }
+ return adapter.format(value, timeOpts.displayFormats.datetime);
+ }
+ _tickFormatFunction(time, index, ticks, format) {
+ const options = this.options;
+ const formats = options.time.displayFormats;
+ const unit = this._unit;
+ const majorUnit = this._majorUnit;
+ const minorFormat = unit && formats[unit];
+ const majorFormat = majorUnit && formats[majorUnit];
+ const tick = ticks[index];
+ const major = majorUnit && majorFormat && tick && tick.major;
+ const label = this._adapter.format(time, format || (major ? majorFormat : minorFormat));
+ const formatter = options.ticks.callback;
+ return formatter ? callback(formatter, [label, index, ticks], this) : label;
+ }
+ generateTickLabels(ticks) {
+ let i, ilen, tick;
+ for (i = 0, ilen = ticks.length; i < ilen; ++i) {
+ tick = ticks[i];
+ tick.label = this._tickFormatFunction(tick.value, i, ticks);
+ }
+ }
+ getDecimalForValue(value) {
+ return value === null ? NaN : (value - this.min) / (this.max - this.min);
+ }
+ getPixelForValue(value) {
+ const offsets = this._offsets;
+ const pos = this.getDecimalForValue(value);
+ return this.getPixelForDecimal((offsets.start + pos) * offsets.factor);
+ }
+ getValueForPixel(pixel) {
+ const offsets = this._offsets;
+ const pos = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+ return this.min + pos * (this.max - this.min);
+ }
+ _getLabelSize(label) {
+ const ticksOpts = this.options.ticks;
+ const tickLabelWidth = this.ctx.measureText(label).width;
+ const angle = toRadians(this.isHorizontal() ? ticksOpts.maxRotation : ticksOpts.minRotation);
+ const cosRotation = Math.cos(angle);
+ const sinRotation = Math.sin(angle);
+ const tickFontSize = this._resolveTickFontOptions(0).size;
+ return {
+ w: (tickLabelWidth * cosRotation) + (tickFontSize * sinRotation),
+ h: (tickLabelWidth * sinRotation) + (tickFontSize * cosRotation)
+ };
+ }
+ _getLabelCapacity(exampleTime) {
+ const timeOpts = this.options.time;
+ const displayFormats = timeOpts.displayFormats;
+ const format = displayFormats[timeOpts.unit] || displayFormats.millisecond;
+ const exampleLabel = this._tickFormatFunction(exampleTime, 0, ticksFromTimestamps(this, [exampleTime], this._majorUnit), format);
+ const size = this._getLabelSize(exampleLabel);
+ const capacity = Math.floor(this.isHorizontal() ? this.width / size.w : this.height / size.h) - 1;
+ return capacity > 0 ? capacity : 1;
+ }
+ getDataTimestamps() {
+ let timestamps = this._cache.data || [];
+ let i, ilen;
+ if (timestamps.length) {
+ return timestamps;
+ }
+ const metas = this.getMatchingVisibleMetas();
+ if (this._normalized && metas.length) {
+ return (this._cache.data = metas[0].controller.getAllParsedValues(this));
+ }
+ for (i = 0, ilen = metas.length; i < ilen; ++i) {
+ timestamps = timestamps.concat(metas[i].controller.getAllParsedValues(this));
+ }
+ return (this._cache.data = this.normalize(timestamps));
+ }
+ getLabelTimestamps() {
+ const timestamps = this._cache.labels || [];
+ let i, ilen;
+ if (timestamps.length) {
+ return timestamps;
+ }
+ const labels = this.getLabels();
+ for (i = 0, ilen = labels.length; i < ilen; ++i) {
+ timestamps.push(parse(this, labels[i]));
+ }
+ return (this._cache.labels = this._normalized ? timestamps : this.normalize(timestamps));
+ }
+ normalize(values) {
+ return _arrayUnique(values.sort(sorter));
+ }
+}
+TimeScale.id = 'time';
+TimeScale.defaults = {
+ bounds: 'data',
+ adapters: {},
+ time: {
+ parser: false,
+ unit: false,
+ round: false,
+ isoWeekday: false,
+ minUnit: 'millisecond',
+ displayFormats: {}
+ },
+ ticks: {
+ source: 'auto',
+ major: {
+ enabled: false
+ }
+ }
+};
+
+function interpolate(table, val, reverse) {
+ let lo = 0;
+ let hi = table.length - 1;
+ let prevSource, nextSource, prevTarget, nextTarget;
+ if (reverse) {
+ if (val >= table[lo].pos && val <= table[hi].pos) {
+ ({lo, hi} = _lookupByKey(table, 'pos', val));
+ }
+ ({pos: prevSource, time: prevTarget} = table[lo]);
+ ({pos: nextSource, time: nextTarget} = table[hi]);
+ } else {
+ if (val >= table[lo].time && val <= table[hi].time) {
+ ({lo, hi} = _lookupByKey(table, 'time', val));
+ }
+ ({time: prevSource, pos: prevTarget} = table[lo]);
+ ({time: nextSource, pos: nextTarget} = table[hi]);
+ }
+ const span = nextSource - prevSource;
+ return span ? prevTarget + (nextTarget - prevTarget) * (val - prevSource) / span : prevTarget;
+}
+class TimeSeriesScale extends TimeScale {
+ constructor(props) {
+ super(props);
+ this._table = [];
+ this._minPos = undefined;
+ this._tableRange = undefined;
+ }
+ initOffsets() {
+ const timestamps = this._getTimestampsForTable();
+ const table = this._table = this.buildLookupTable(timestamps);
+ this._minPos = interpolate(table, this.min);
+ this._tableRange = interpolate(table, this.max) - this._minPos;
+ super.initOffsets(timestamps);
+ }
+ buildLookupTable(timestamps) {
+ const {min, max} = this;
+ const items = [];
+ const table = [];
+ let i, ilen, prev, curr, next;
+ for (i = 0, ilen = timestamps.length; i < ilen; ++i) {
+ curr = timestamps[i];
+ if (curr >= min && curr <= max) {
+ items.push(curr);
+ }
+ }
+ if (items.length < 2) {
+ return [
+ {time: min, pos: 0},
+ {time: max, pos: 1}
+ ];
+ }
+ for (i = 0, ilen = items.length; i < ilen; ++i) {
+ next = items[i + 1];
+ prev = items[i - 1];
+ curr = items[i];
+ if (Math.round((next + prev) / 2) !== curr) {
+ table.push({time: curr, pos: i / (ilen - 1)});
+ }
+ }
+ return table;
+ }
+ _getTimestampsForTable() {
+ let timestamps = this._cache.all || [];
+ if (timestamps.length) {
+ return timestamps;
+ }
+ const data = this.getDataTimestamps();
+ const label = this.getLabelTimestamps();
+ if (data.length && label.length) {
+ timestamps = this.normalize(data.concat(label));
+ } else {
+ timestamps = data.length ? data : label;
+ }
+ timestamps = this._cache.all = timestamps;
+ return timestamps;
+ }
+ getDecimalForValue(value) {
+ return (interpolate(this._table, value) - this._minPos) / this._tableRange;
+ }
+ getValueForPixel(pixel) {
+ const offsets = this._offsets;
+ const decimal = this.getDecimalForPixel(pixel) / offsets.factor - offsets.end;
+ return interpolate(this._table, decimal * this._tableRange + this._minPos, true);
+ }
+}
+TimeSeriesScale.id = 'timeseries';
+TimeSeriesScale.defaults = TimeScale.defaults;
+
+var scales = /*#__PURE__*/Object.freeze({
+__proto__: null,
+CategoryScale: CategoryScale,
+LinearScale: LinearScale,
+LogarithmicScale: LogarithmicScale,
+RadialLinearScale: RadialLinearScale,
+TimeScale: TimeScale,
+TimeSeriesScale: TimeSeriesScale
+});
+
+Chart.register(controllers, scales, elements, plugins);
+Chart.helpers = {...helpers};
+Chart._adapters = _adapters;
+Chart.Animation = Animation;
+Chart.Animations = Animations;
+Chart.animator = animator;
+Chart.controllers = registry.controllers.items;
+Chart.DatasetController = DatasetController;
+Chart.Element = Element;
+Chart.elements = elements;
+Chart.Interaction = Interaction;
+Chart.layouts = layouts;
+Chart.platforms = platforms;
+Chart.Scale = Scale;
+Chart.Ticks = Ticks;
+Object.assign(Chart, controllers, scales, elements, plugins, platforms);
+Chart.Chart = Chart;
+if (typeof window !== 'undefined') {
+ window.Chart = Chart;
+}
+
+return Chart;
+
+}));
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chart.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chart.min.js
deleted file mode 100644
index 0d9e318..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chart.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * Chart.js v2.9.2
- * https://www.chartjs.org
- * (c) 2019 Chart.js Contributors
- * Released under the MIT License
- */
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(function(){try{return require("moment")}catch(t){}}()):"function"==typeof define&&define.amd?define(["require"],(function(t){return e(function(){try{return t("moment")}catch(t){}}())})):(t=t||self).Chart=e(t.moment)}(this,(function(t){"use strict";t=t&&t.hasOwnProperty("default")?t.default:t;var e={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},n=function(t,e){return t(e={exports:{}},e.exports),e.exports}((function(t){var n={};for(var i in e)e.hasOwnProperty(i)&&(n[e[i]]=i);var a=t.exports={rgb:{channels:3,labels:"rgb"},hsl:{channels:3,labels:"hsl"},hsv:{channels:3,labels:"hsv"},hwb:{channels:3,labels:"hwb"},cmyk:{channels:4,labels:"cmyk"},xyz:{channels:3,labels:"xyz"},lab:{channels:3,labels:"lab"},lch:{channels:3,labels:"lch"},hex:{channels:1,labels:["hex"]},keyword:{channels:1,labels:["keyword"]},ansi16:{channels:1,labels:["ansi16"]},ansi256:{channels:1,labels:["ansi256"]},hcg:{channels:3,labels:["h","c","g"]},apple:{channels:3,labels:["r16","g16","b16"]},gray:{channels:1,labels:["gray"]}};for(var r in a)if(a.hasOwnProperty(r)){if(!("channels"in a[r]))throw new Error("missing channels property: "+r);if(!("labels"in a[r]))throw new Error("missing channel labels property: "+r);if(a[r].labels.length!==a[r].channels)throw new Error("channel and label counts mismatch: "+r);var o=a[r].channels,s=a[r].labels;delete a[r].channels,delete a[r].labels,Object.defineProperty(a[r],"channels",{value:o}),Object.defineProperty(a[r],"labels",{value:s})}a.rgb.hsl=function(t){var e,n,i=t[0]/255,a=t[1]/255,r=t[2]/255,o=Math.min(i,a,r),s=Math.max(i,a,r),l=s-o;return s===o?e=0:i===s?e=(a-r)/l:a===s?e=2+(r-i)/l:r===s&&(e=4+(i-a)/l),(e=Math.min(60*e,360))<0&&(e+=360),n=(o+s)/2,[e,100*(s===o?0:n<=.5?l/(s+o):l/(2-s-o)),100*n]},a.rgb.hsv=function(t){var e,n,i,a,r,o=t[0]/255,s=t[1]/255,l=t[2]/255,u=Math.max(o,s,l),d=u-Math.min(o,s,l),h=function(t){return(u-t)/6/d+.5};return 0===d?a=r=0:(r=d/u,e=h(o),n=h(s),i=h(l),o===u?a=i-n:s===u?a=1/3+e-i:l===u&&(a=2/3+n-e),a<0?a+=1:a>1&&(a-=1)),[360*a,100*r,100*u]},a.rgb.hwb=function(t){var e=t[0],n=t[1],i=t[2];return[a.rgb.hsl(t)[0],100*(1/255*Math.min(e,Math.min(n,i))),100*(i=1-1/255*Math.max(e,Math.max(n,i)))]},a.rgb.cmyk=function(t){var e,n=t[0]/255,i=t[1]/255,a=t[2]/255;return[100*((1-n-(e=Math.min(1-n,1-i,1-a)))/(1-e)||0),100*((1-i-e)/(1-e)||0),100*((1-a-e)/(1-e)||0),100*e]},a.rgb.keyword=function(t){var i=n[t];if(i)return i;var a,r,o,s=1/0;for(var l in e)if(e.hasOwnProperty(l)){var u=e[l],d=(r=t,o=u,Math.pow(r[0]-o[0],2)+Math.pow(r[1]-o[1],2)+Math.pow(r[2]-o[2],2));d<s&&(s=d,a=l)}return a},a.keyword.rgb=function(t){return e[t]},a.rgb.xyz=function(t){var e=t[0]/255,n=t[1]/255,i=t[2]/255;return[100*(.4124*(e=e>.04045?Math.pow((e+.055)/1.055,2.4):e/12.92)+.3576*(n=n>.04045?Math.pow((n+.055)/1.055,2.4):n/12.92)+.1805*(i=i>.04045?Math.pow((i+.055)/1.055,2.4):i/12.92)),100*(.2126*e+.7152*n+.0722*i),100*(.0193*e+.1192*n+.9505*i)]},a.rgb.lab=function(t){var e=a.rgb.xyz(t),n=e[0],i=e[1],r=e[2];return i/=100,r/=108.883,n=(n/=95.047)>.008856?Math.pow(n,1/3):7.787*n+16/116,[116*(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116)-16,500*(n-i),200*(i-(r=r>.008856?Math.pow(r,1/3):7.787*r+16/116))]},a.hsl.rgb=function(t){var e,n,i,a,r,o=t[0]/360,s=t[1]/100,l=t[2]/100;if(0===s)return[r=255*l,r,r];e=2*l-(n=l<.5?l*(1+s):l+s-l*s),a=[0,0,0];for(var u=0;u<3;u++)(i=o+1/3*-(u-1))<0&&i++,i>1&&i--,r=6*i<1?e+6*(n-e)*i:2*i<1?n:3*i<2?e+(n-e)*(2/3-i)*6:e,a[u]=255*r;return a},a.hsl.hsv=function(t){var e=t[0],n=t[1]/100,i=t[2]/100,a=n,r=Math.max(i,.01);return n*=(i*=2)<=1?i:2-i,a*=r<=1?r:2-r,[e,100*(0===i?2*a/(r+a):2*n/(i+n)),100*((i+n)/2)]},a.hsv.rgb=function(t){var e=t[0]/60,n=t[1]/100,i=t[2]/100,a=Math.floor(e)%6,r=e-Math.floor(e),o=255*i*(1-n),s=255*i*(1-n*r),l=255*i*(1-n*(1-r));switch(i*=255,a){case 0:return[i,l,o];case 1:return[s,i,o];case 2:return[o,i,l];case 3:return[o,s,i];case 4:return[l,o,i];case 5:return[i,o,s]}},a.hsv.hsl=function(t){var e,n,i,a=t[0],r=t[1]/100,o=t[2]/100,s=Math.max(o,.01);return i=(2-r)*o,n=r*s,[a,100*(n=(n/=(e=(2-r)*s)<=1?e:2-e)||0),100*(i/=2)]},a.hwb.rgb=function(t){var e,n,i,a,r,o,s,l=t[0]/360,u=t[1]/100,d=t[2]/100,h=u+d;switch(h>1&&(u/=h,d/=h),i=6*l-(e=Math.floor(6*l)),0!=(1&e)&&(i=1-i),a=u+i*((n=1-d)-u),e){default:case 6:case 0:r=n,o=a,s=u;break;case 1:r=a,o=n,s=u;break;case 2:r=u,o=n,s=a;break;case 3:r=u,o=a,s=n;break;case 4:r=a,o=u,s=n;break;case 5:r=n,o=u,s=a}return[255*r,255*o,255*s]},a.cmyk.rgb=function(t){var e=t[0]/100,n=t[1]/100,i=t[2]/100,a=t[3]/100;return[255*(1-Math.min(1,e*(1-a)+a)),255*(1-Math.min(1,n*(1-a)+a)),255*(1-Math.min(1,i*(1-a)+a))]},a.xyz.rgb=function(t){var e,n,i,a=t[0]/100,r=t[1]/100,o=t[2]/100;return n=-.9689*a+1.8758*r+.0415*o,i=.0557*a+-.204*r+1.057*o,e=(e=3.2406*a+-1.5372*r+-.4986*o)>.0031308?1.055*Math.pow(e,1/2.4)-.055:12.92*e,n=n>.0031308?1.055*Math.pow(n,1/2.4)-.055:12.92*n,i=i>.0031308?1.055*Math.pow(i,1/2.4)-.055:12.92*i,[255*(e=Math.min(Math.max(0,e),1)),255*(n=Math.min(Math.max(0,n),1)),255*(i=Math.min(Math.max(0,i),1))]},a.xyz.lab=function(t){var e=t[0],n=t[1],i=t[2];return n/=100,i/=108.883,e=(e/=95.047)>.008856?Math.pow(e,1/3):7.787*e+16/116,[116*(n=n>.008856?Math.pow(n,1/3):7.787*n+16/116)-16,500*(e-n),200*(n-(i=i>.008856?Math.pow(i,1/3):7.787*i+16/116))]},a.lab.xyz=function(t){var e,n,i,a=t[0];e=t[1]/500+(n=(a+16)/116),i=n-t[2]/200;var r=Math.pow(n,3),o=Math.pow(e,3),s=Math.pow(i,3);return n=r>.008856?r:(n-16/116)/7.787,e=o>.008856?o:(e-16/116)/7.787,i=s>.008856?s:(i-16/116)/7.787,[e*=95.047,n*=100,i*=108.883]},a.lab.lch=function(t){var e,n=t[0],i=t[1],a=t[2];return(e=360*Math.atan2(a,i)/2/Math.PI)<0&&(e+=360),[n,Math.sqrt(i*i+a*a),e]},a.lch.lab=function(t){var e,n=t[0],i=t[1];return e=t[2]/360*2*Math.PI,[n,i*Math.cos(e),i*Math.sin(e)]},a.rgb.ansi16=function(t){var e=t[0],n=t[1],i=t[2],r=1 in arguments?arguments[1]:a.rgb.hsv(t)[2];if(0===(r=Math.round(r/50)))return 30;var o=30+(Math.round(i/255)<<2|Math.round(n/255)<<1|Math.round(e/255));return 2===r&&(o+=60),o},a.hsv.ansi16=function(t){return a.rgb.ansi16(a.hsv.rgb(t),t[2])},a.rgb.ansi256=function(t){var e=t[0],n=t[1],i=t[2];return e===n&&n===i?e<8?16:e>248?231:Math.round((e-8)/247*24)+232:16+36*Math.round(e/255*5)+6*Math.round(n/255*5)+Math.round(i/255*5)},a.ansi16.rgb=function(t){var e=t%10;if(0===e||7===e)return t>50&&(e+=3.5),[e=e/10.5*255,e,e];var n=.5*(1+~~(t>50));return[(1&e)*n*255,(e>>1&1)*n*255,(e>>2&1)*n*255]},a.ansi256.rgb=function(t){if(t>=232){var e=10*(t-232)+8;return[e,e,e]}var n;return t-=16,[Math.floor(t/36)/5*255,Math.floor((n=t%36)/6)/5*255,n%6/5*255]},a.rgb.hex=function(t){var e=(((255&Math.round(t[0]))<<16)+((255&Math.round(t[1]))<<8)+(255&Math.round(t[2]))).toString(16).toUpperCase();return"000000".substring(e.length)+e},a.hex.rgb=function(t){var e=t.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);if(!e)return[0,0,0];var n=e[0];3===e[0].length&&(n=n.split("").map((function(t){return t+t})).join(""));var i=parseInt(n,16);return[i>>16&255,i>>8&255,255&i]},a.rgb.hcg=function(t){var e,n=t[0]/255,i=t[1]/255,a=t[2]/255,r=Math.max(Math.max(n,i),a),o=Math.min(Math.min(n,i),a),s=r-o;return e=s<=0?0:r===n?(i-a)/s%6:r===i?2+(a-n)/s:4+(n-i)/s+4,e/=6,[360*(e%=1),100*s,100*(s<1?o/(1-s):0)]},a.hsl.hcg=function(t){var e=t[1]/100,n=t[2]/100,i=1,a=0;return(i=n<.5?2*e*n:2*e*(1-n))<1&&(a=(n-.5*i)/(1-i)),[t[0],100*i,100*a]},a.hsv.hcg=function(t){var e=t[1]/100,n=t[2]/100,i=e*n,a=0;return i<1&&(a=(n-i)/(1-i)),[t[0],100*i,100*a]},a.hcg.rgb=function(t){var e=t[0]/360,n=t[1]/100,i=t[2]/100;if(0===n)return[255*i,255*i,255*i];var a,r=[0,0,0],o=e%1*6,s=o%1,l=1-s;switch(Math.floor(o)){case 0:r[0]=1,r[1]=s,r[2]=0;break;case 1:r[0]=l,r[1]=1,r[2]=0;break;case 2:r[0]=0,r[1]=1,r[2]=s;break;case 3:r[0]=0,r[1]=l,r[2]=1;break;case 4:r[0]=s,r[1]=0,r[2]=1;break;default:r[0]=1,r[1]=0,r[2]=l}return a=(1-n)*i,[255*(n*r[0]+a),255*(n*r[1]+a),255*(n*r[2]+a)]},a.hcg.hsv=function(t){var e=t[1]/100,n=e+t[2]/100*(1-e),i=0;return n>0&&(i=e/n),[t[0],100*i,100*n]},a.hcg.hsl=function(t){var e=t[1]/100,n=t[2]/100*(1-e)+.5*e,i=0;return n>0&&n<.5?i=e/(2*n):n>=.5&&n<1&&(i=e/(2*(1-n))),[t[0],100*i,100*n]},a.hcg.hwb=function(t){var e=t[1]/100,n=e+t[2]/100*(1-e);return[t[0],100*(n-e),100*(1-n)]},a.hwb.hcg=function(t){var e=t[1]/100,n=1-t[2]/100,i=n-e,a=0;return i<1&&(a=(n-i)/(1-i)),[t[0],100*i,100*a]},a.apple.rgb=function(t){return[t[0]/65535*255,t[1]/65535*255,t[2]/65535*255]},a.rgb.apple=function(t){return[t[0]/255*65535,t[1]/255*65535,t[2]/255*65535]},a.gray.rgb=function(t){return[t[0]/100*255,t[0]/100*255,t[0]/100*255]},a.gray.hsl=a.gray.hsv=function(t){return[0,0,t[0]]},a.gray.hwb=function(t){return[0,100,t[0]]},a.gray.cmyk=function(t){return[0,0,0,t[0]]},a.gray.lab=function(t){return[t[0],0,0]},a.gray.hex=function(t){var e=255&Math.round(t[0]/100*255),n=((e<<16)+(e<<8)+e).toString(16).toUpperCase();return"000000".substring(n.length)+n},a.rgb.gray=function(t){return[(t[0]+t[1]+t[2])/3/255*100]}}));n.rgb,n.hsl,n.hsv,n.hwb,n.cmyk,n.xyz,n.lab,n.lch,n.hex,n.keyword,n.ansi16,n.ansi256,n.hcg,n.apple,n.gray;function i(t){var e=function(){for(var t={},e=Object.keys(n),i=e.length,a=0;a<i;a++)t[e[a]]={distance:-1,parent:null};return t}(),i=[t];for(e[t].distance=0;i.length;)for(var a=i.pop(),r=Object.keys(n[a]),o=r.length,s=0;s<o;s++){var l=r[s],u=e[l];-1===u.distance&&(u.distance=e[a].distance+1,u.parent=a,i.unshift(l))}return e}function a(t,e){return function(n){return e(t(n))}}function r(t,e){for(var i=[e[t].parent,t],r=n[e[t].parent][t],o=e[t].parent;e[o].parent;)i.unshift(e[o].parent),r=a(n[e[o].parent][o],r),o=e[o].parent;return r.conversion=i,r}var o={};Object.keys(n).forEach((function(t){o[t]={},Object.defineProperty(o[t],"channels",{value:n[t].channels}),Object.defineProperty(o[t],"labels",{value:n[t].labels});var e=function(t){for(var e=i(t),n={},a=Object.keys(e),o=a.length,s=0;s<o;s++){var l=a[s];null!==e[l].parent&&(n[l]=r(l,e))}return n}(t);Object.keys(e).forEach((function(n){var i=e[n];o[t][n]=function(t){var e=function(e){if(null==e)return e;arguments.length>1&&(e=Array.prototype.slice.call(arguments));var n=t(e);if("object"==typeof n)for(var i=n.length,a=0;a<i;a++)n[a]=Math.round(n[a]);return n};return"conversion"in t&&(e.conversion=t.conversion),e}(i),o[t][n].raw=function(t){var e=function(e){return null==e?e:(arguments.length>1&&(e=Array.prototype.slice.call(arguments)),t(e))};return"conversion"in t&&(e.conversion=t.conversion),e}(i)}))}));var s=o,l={aliceblue:[240,248,255],antiquewhite:[250,235,215],aqua:[0,255,255],aquamarine:[127,255,212],azure:[240,255,255],beige:[245,245,220],bisque:[255,228,196],black:[0,0,0],blanchedalmond:[255,235,205],blue:[0,0,255],blueviolet:[138,43,226],brown:[165,42,42],burlywood:[222,184,135],cadetblue:[95,158,160],chartreuse:[127,255,0],chocolate:[210,105,30],coral:[255,127,80],cornflowerblue:[100,149,237],cornsilk:[255,248,220],crimson:[220,20,60],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgoldenrod:[184,134,11],darkgray:[169,169,169],darkgreen:[0,100,0],darkgrey:[169,169,169],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkseagreen:[143,188,143],darkslateblue:[72,61,139],darkslategray:[47,79,79],darkslategrey:[47,79,79],darkturquoise:[0,206,209],darkviolet:[148,0,211],deeppink:[255,20,147],deepskyblue:[0,191,255],dimgray:[105,105,105],dimgrey:[105,105,105],dodgerblue:[30,144,255],firebrick:[178,34,34],floralwhite:[255,250,240],forestgreen:[34,139,34],fuchsia:[255,0,255],gainsboro:[220,220,220],ghostwhite:[248,248,255],gold:[255,215,0],goldenrod:[218,165,32],gray:[128,128,128],green:[0,128,0],greenyellow:[173,255,47],grey:[128,128,128],honeydew:[240,255,240],hotpink:[255,105,180],indianred:[205,92,92],indigo:[75,0,130],ivory:[255,255,240],khaki:[240,230,140],lavender:[230,230,250],lavenderblush:[255,240,245],lawngreen:[124,252,0],lemonchiffon:[255,250,205],lightblue:[173,216,230],lightcoral:[240,128,128],lightcyan:[224,255,255],lightgoldenrodyellow:[250,250,210],lightgray:[211,211,211],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightsalmon:[255,160,122],lightseagreen:[32,178,170],lightskyblue:[135,206,250],lightslategray:[119,136,153],lightslategrey:[119,136,153],lightsteelblue:[176,196,222],lightyellow:[255,255,224],lime:[0,255,0],limegreen:[50,205,50],linen:[250,240,230],magenta:[255,0,255],maroon:[128,0,0],mediumaquamarine:[102,205,170],mediumblue:[0,0,205],mediumorchid:[186,85,211],mediumpurple:[147,112,219],mediumseagreen:[60,179,113],mediumslateblue:[123,104,238],mediumspringgreen:[0,250,154],mediumturquoise:[72,209,204],mediumvioletred:[199,21,133],midnightblue:[25,25,112],mintcream:[245,255,250],mistyrose:[255,228,225],moccasin:[255,228,181],navajowhite:[255,222,173],navy:[0,0,128],oldlace:[253,245,230],olive:[128,128,0],olivedrab:[107,142,35],orange:[255,165,0],orangered:[255,69,0],orchid:[218,112,214],palegoldenrod:[238,232,170],palegreen:[152,251,152],paleturquoise:[175,238,238],palevioletred:[219,112,147],papayawhip:[255,239,213],peachpuff:[255,218,185],peru:[205,133,63],pink:[255,192,203],plum:[221,160,221],powderblue:[176,224,230],purple:[128,0,128],rebeccapurple:[102,51,153],red:[255,0,0],rosybrown:[188,143,143],royalblue:[65,105,225],saddlebrown:[139,69,19],salmon:[250,128,114],sandybrown:[244,164,96],seagreen:[46,139,87],seashell:[255,245,238],sienna:[160,82,45],silver:[192,192,192],skyblue:[135,206,235],slateblue:[106,90,205],slategray:[112,128,144],slategrey:[112,128,144],snow:[255,250,250],springgreen:[0,255,127],steelblue:[70,130,180],tan:[210,180,140],teal:[0,128,128],thistle:[216,191,216],tomato:[255,99,71],turquoise:[64,224,208],violet:[238,130,238],wheat:[245,222,179],white:[255,255,255],whitesmoke:[245,245,245],yellow:[255,255,0],yellowgreen:[154,205,50]},u={getRgba:d,getHsla:h,getRgb:function(t){var e=d(t);return e&&e.slice(0,3)},getHsl:function(t){var e=h(t);return e&&e.slice(0,3)},getHwb:c,getAlpha:function(t){var e=d(t);if(e)return e[3];if(e=h(t))return e[3];if(e=c(t))return e[3]},hexString:function(t,e){e=void 0!==e&&3===t.length?e:t[3];return"#"+v(t[0])+v(t[1])+v(t[2])+(e>=0&&e<1?v(Math.round(255*e)):"")},rgbString:function(t,e){if(e<1||t[3]&&t[3]<1)return f(t,e);return"rgb("+t[0]+", "+t[1]+", "+t[2]+")"},rgbaString:f,percentString:function(t,e){if(e<1||t[3]&&t[3]<1)return g(t,e);var n=Math.round(t[0]/255*100),i=Math.round(t[1]/255*100),a=Math.round(t[2]/255*100);return"rgb("+n+"%, "+i+"%, "+a+"%)"},percentaString:g,hslString:function(t,e){if(e<1||t[3]&&t[3]<1)return p(t,e);return"hsl("+t[0]+", "+t[1]+"%, "+t[2]+"%)"},hslaString:p,hwbString:function(t,e){void 0===e&&(e=void 0!==t[3]?t[3]:1);return"hwb("+t[0]+", "+t[1]+"%, "+t[2]+"%"+(void 0!==e&&1!==e?", "+e:"")+")"},keyword:function(t){return b[t.slice(0,3)]}};function d(t){if(t){var e=[0,0,0],n=1,i=t.match(/^#([a-fA-F0-9]{3,4})$/i),a="";if(i){a=(i=i[1])[3];for(var r=0;r<e.length;r++)e[r]=parseInt(i[r]+i[r],16);a&&(n=Math.round(parseInt(a+a,16)/255*100)/100)}else if(i=t.match(/^#([a-fA-F0-9]{6}([a-fA-F0-9]{2})?)$/i)){a=i[2],i=i[1];for(r=0;r<e.length;r++)e[r]=parseInt(i.slice(2*r,2*r+2),16);a&&(n=Math.round(parseInt(a,16)/255*100)/100)}else if(i=t.match(/^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(r=0;r<e.length;r++)e[r]=parseInt(i[r+1]);n=parseFloat(i[4])}else if(i=t.match(/^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/i)){for(r=0;r<e.length;r++)e[r]=Math.round(2.55*parseFloat(i[r+1]));n=parseFloat(i[4])}else if(i=t.match(/(\w+)/)){if("transparent"==i[1])return[0,0,0,0];if(!(e=l[i[1]]))return}for(r=0;r<e.length;r++)e[r]=m(e[r],0,255);return n=n||0==n?m(n,0,1):1,e[3]=n,e}}function h(t){if(t){var e=t.match(/^hsla?\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[m(parseInt(e[1]),0,360),m(parseFloat(e[2]),0,100),m(parseFloat(e[3]),0,100),m(isNaN(n)?1:n,0,1)]}}}function c(t){if(t){var e=t.match(/^hwb\(\s*([+-]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)/);if(e){var n=parseFloat(e[4]);return[m(parseInt(e[1]),0,360),m(parseFloat(e[2]),0,100),m(parseFloat(e[3]),0,100),m(isNaN(n)?1:n,0,1)]}}}function f(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"rgba("+t[0]+", "+t[1]+", "+t[2]+", "+e+")"}function g(t,e){return"rgba("+Math.round(t[0]/255*100)+"%, "+Math.round(t[1]/255*100)+"%, "+Math.round(t[2]/255*100)+"%, "+(e||t[3]||1)+")"}function p(t,e){return void 0===e&&(e=void 0!==t[3]?t[3]:1),"hsla("+t[0]+", "+t[1]+"%, "+t[2]+"%, "+e+")"}function m(t,e,n){return Math.min(Math.max(e,t),n)}function v(t){var e=t.toString(16).toUpperCase();return e.length<2?"0"+e:e}var b={};for(var x in l)b[l[x]]=x;var y=function(t){return t instanceof y?t:this instanceof y?(this.valid=!1,this.values={rgb:[0,0,0],hsl:[0,0,0],hsv:[0,0,0],hwb:[0,0,0],cmyk:[0,0,0,0],alpha:1},void("string"==typeof t?(e=u.getRgba(t))?this.setValues("rgb",e):(e=u.getHsla(t))?this.setValues("hsl",e):(e=u.getHwb(t))&&this.setValues("hwb",e):"object"==typeof t&&(void 0!==(e=t).r||void 0!==e.red?this.setValues("rgb",e):void 0!==e.l||void 0!==e.lightness?this.setValues("hsl",e):void 0!==e.v||void 0!==e.value?this.setValues("hsv",e):void 0!==e.w||void 0!==e.whiteness?this.setValues("hwb",e):void 0===e.c&&void 0===e.cyan||this.setValues("cmyk",e)))):new y(t);var e};y.prototype={isValid:function(){return this.valid},rgb:function(){return this.setSpace("rgb",arguments)},hsl:function(){return this.setSpace("hsl",arguments)},hsv:function(){return this.setSpace("hsv",arguments)},hwb:function(){return this.setSpace("hwb",arguments)},cmyk:function(){return this.setSpace("cmyk",arguments)},rgbArray:function(){return this.values.rgb},hslArray:function(){return this.values.hsl},hsvArray:function(){return this.values.hsv},hwbArray:function(){var t=this.values;return 1!==t.alpha?t.hwb.concat([t.alpha]):t.hwb},cmykArray:function(){return this.values.cmyk},rgbaArray:function(){var t=this.values;return t.rgb.concat([t.alpha])},hslaArray:function(){var t=this.values;return t.hsl.concat([t.alpha])},alpha:function(t){return void 0===t?this.values.alpha:(this.setValues("alpha",t),this)},red:function(t){return this.setChannel("rgb",0,t)},green:function(t){return this.setChannel("rgb",1,t)},blue:function(t){return this.setChannel("rgb",2,t)},hue:function(t){return t&&(t=(t%=360)<0?360+t:t),this.setChannel("hsl",0,t)},saturation:function(t){return this.setChannel("hsl",1,t)},lightness:function(t){return this.setChannel("hsl",2,t)},saturationv:function(t){return this.setChannel("hsv",1,t)},whiteness:function(t){return this.setChannel("hwb",1,t)},blackness:function(t){return this.setChannel("hwb",2,t)},value:function(t){return this.setChannel("hsv",2,t)},cyan:function(t){return this.setChannel("cmyk",0,t)},magenta:function(t){return this.setChannel("cmyk",1,t)},yellow:function(t){return this.setChannel("cmyk",2,t)},black:function(t){return this.setChannel("cmyk",3,t)},hexString:function(){return u.hexString(this.values.rgb)},rgbString:function(){return u.rgbString(this.values.rgb,this.values.alpha)},rgbaString:function(){return u.rgbaString(this.values.rgb,this.values.alpha)},percentString:function(){return u.percentString(this.values.rgb,this.values.alpha)},hslString:function(){return u.hslString(this.values.hsl,this.values.alpha)},hslaString:function(){return u.hslaString(this.values.hsl,this.values.alpha)},hwbString:function(){return u.hwbString(this.values.hwb,this.values.alpha)},keyword:function(){return u.keyword(this.values.rgb,this.values.alpha)},rgbNumber:function(){var t=this.values.rgb;return t[0]<<16|t[1]<<8|t[2]},luminosity:function(){for(var t=this.values.rgb,e=[],n=0;n<t.length;n++){var i=t[n]/255;e[n]=i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4)}return.2126*e[0]+.7152*e[1]+.0722*e[2]},contrast:function(t){var e=this.luminosity(),n=t.luminosity();return e>n?(e+.05)/(n+.05):(n+.05)/(e+.05)},level:function(t){var e=this.contrast(t);return e>=7.1?"AAA":e>=4.5?"AA":""},dark:function(){var t=this.values.rgb;return(299*t[0]+587*t[1]+114*t[2])/1e3<128},light:function(){return!this.dark()},negate:function(){for(var t=[],e=0;e<3;e++)t[e]=255-this.values.rgb[e];return this.setValues("rgb",t),this},lighten:function(t){var e=this.values.hsl;return e[2]+=e[2]*t,this.setValues("hsl",e),this},darken:function(t){var e=this.values.hsl;return e[2]-=e[2]*t,this.setValues("hsl",e),this},saturate:function(t){var e=this.values.hsl;return e[1]+=e[1]*t,this.setValues("hsl",e),this},desaturate:function(t){var e=this.values.hsl;return e[1]-=e[1]*t,this.setValues("hsl",e),this},whiten:function(t){var e=this.values.hwb;return e[1]+=e[1]*t,this.setValues("hwb",e),this},blacken:function(t){var e=this.values.hwb;return e[2]+=e[2]*t,this.setValues("hwb",e),this},greyscale:function(){var t=this.values.rgb,e=.3*t[0]+.59*t[1]+.11*t[2];return this.setValues("rgb",[e,e,e]),this},clearer:function(t){var e=this.values.alpha;return this.setValues("alpha",e-e*t),this},opaquer:function(t){var e=this.values.alpha;return this.setValues("alpha",e+e*t),this},rotate:function(t){var e=this.values.hsl,n=(e[0]+t)%360;return e[0]=n<0?360+n:n,this.setValues("hsl",e),this},mix:function(t,e){var n=t,i=void 0===e?.5:e,a=2*i-1,r=this.alpha()-n.alpha(),o=((a*r==-1?a:(a+r)/(1+a*r))+1)/2,s=1-o;return this.rgb(o*this.red()+s*n.red(),o*this.green()+s*n.green(),o*this.blue()+s*n.blue()).alpha(this.alpha()*i+n.alpha()*(1-i))},toJSON:function(){return this.rgb()},clone:function(){var t,e,n=new y,i=this.values,a=n.values;for(var r in i)i.hasOwnProperty(r)&&(t=i[r],"[object Array]"===(e={}.toString.call(t))?a[r]=t.slice(0):"[object Number]"===e?a[r]=t:console.error("unexpected color value:",t));return n}},y.prototype.spaces={rgb:["red","green","blue"],hsl:["hue","saturation","lightness"],hsv:["hue","saturation","value"],hwb:["hue","whiteness","blackness"],cmyk:["cyan","magenta","yellow","black"]},y.prototype.maxes={rgb:[255,255,255],hsl:[360,100,100],hsv:[360,100,100],hwb:[360,100,100],cmyk:[100,100,100,100]},y.prototype.getValues=function(t){for(var e=this.values,n={},i=0;i<t.length;i++)n[t.charAt(i)]=e[t][i];return 1!==e.alpha&&(n.a=e.alpha),n},y.prototype.setValues=function(t,e){var n,i,a=this.values,r=this.spaces,o=this.maxes,l=1;if(this.valid=!0,"alpha"===t)l=e;else if(e.length)a[t]=e.slice(0,t.length),l=e[t.length];else if(void 0!==e[t.charAt(0)]){for(n=0;n<t.length;n++)a[t][n]=e[t.charAt(n)];l=e.a}else if(void 0!==e[r[t][0]]){var u=r[t];for(n=0;n<t.length;n++)a[t][n]=e[u[n]];l=e.alpha}if(a.alpha=Math.max(0,Math.min(1,void 0===l?a.alpha:l)),"alpha"===t)return!1;for(n=0;n<t.length;n++)i=Math.max(0,Math.min(o[t][n],a[t][n])),a[t][n]=Math.round(i);for(var d in r)d!==t&&(a[d]=s[t][d](a[t]));return!0},y.prototype.setSpace=function(t,e){var n=e[0];return void 0===n?this.getValues(t):("number"==typeof n&&(n=Array.prototype.slice.call(e)),this.setValues(t,n),this)},y.prototype.setChannel=function(t,e,n){var i=this.values[t];return void 0===n?i[e]:n===i[e]?this:(i[e]=n,this.setValues(t,i),this)},"undefined"!=typeof window&&(window.Color=y);var _,k=y,w={noop:function(){},uid:(_=0,function(){return _++}),isNullOrUndef:function(t){return null==t},isArray:function(t){if(Array.isArray&&Array.isArray(t))return!0;var e=Object.prototype.toString.call(t);return"[object"===e.substr(0,7)&&"Array]"===e.substr(-6)},isObject:function(t){return null!==t&&"[object Object]"===Object.prototype.toString.call(t)},isFinite:function(t){return("number"==typeof t||t instanceof Number)&&isFinite(t)},valueOrDefault:function(t,e){return void 0===t?e:t},valueAtIndexOrDefault:function(t,e,n){return w.valueOrDefault(w.isArray(t)?t[e]:t,n)},callback:function(t,e,n){if(t&&"function"==typeof t.call)return t.apply(n,e)},each:function(t,e,n,i){var a,r,o;if(w.isArray(t))if(r=t.length,i)for(a=r-1;a>=0;a--)e.call(n,t[a],a);else for(a=0;a<r;a++)e.call(n,t[a],a);else if(w.isObject(t))for(r=(o=Object.keys(t)).length,a=0;a<r;a++)e.call(n,t[o[a]],o[a])},arrayEquals:function(t,e){var n,i,a,r;if(!t||!e||t.length!==e.length)return!1;for(n=0,i=t.length;n<i;++n)if(a=t[n],r=e[n],a instanceof Array&&r instanceof Array){if(!w.arrayEquals(a,r))return!1}else if(a!==r)return!1;return!0},clone:function(t){if(w.isArray(t))return t.map(w.clone);if(w.isObject(t)){for(var e={},n=Object.keys(t),i=n.length,a=0;a<i;++a)e[n[a]]=w.clone(t[n[a]]);return e}return t},_merger:function(t,e,n,i){var a=e[t],r=n[t];w.isObject(a)&&w.isObject(r)?w.merge(a,r,i):e[t]=w.clone(r)},_mergerIf:function(t,e,n){var i=e[t],a=n[t];w.isObject(i)&&w.isObject(a)?w.mergeIf(i,a):e.hasOwnProperty(t)||(e[t]=w.clone(a))},merge:function(t,e,n){var i,a,r,o,s,l=w.isArray(e)?e:[e],u=l.length;if(!w.isObject(t))return t;for(i=(n=n||{}).merger||w._merger,a=0;a<u;++a)if(e=l[a],w.isObject(e))for(s=0,o=(r=Object.keys(e)).length;s<o;++s)i(r[s],t,e,n);return t},mergeIf:function(t,e){return w.merge(t,e,{merger:w._mergerIf})},extend:Object.assign||function(t){return w.merge(t,[].slice.call(arguments,1),{merger:function(t,e,n){e[t]=n[t]}})},inherits:function(t){var e=this,n=t&&t.hasOwnProperty("constructor")?t.constructor:function(){return e.apply(this,arguments)},i=function(){this.constructor=n};return i.prototype=e.prototype,n.prototype=new i,n.extend=w.inherits,t&&w.extend(n.prototype,t),n.__super__=e.prototype,n},_deprecated:function(t,e,n,i){void 0!==e&&console.warn(t+': "'+n+'" is deprecated. Please use "'+i+'" instead')}},M=w;w.callCallback=w.callback,w.indexOf=function(t,e,n){return Array.prototype.indexOf.call(t,e,n)},w.getValueOrDefault=w.valueOrDefault,w.getValueAtIndexOrDefault=w.valueAtIndexOrDefault;var S={linear:function(t){return t},easeInQuad:function(t){return t*t},easeOutQuad:function(t){return-t*(t-2)},easeInOutQuad:function(t){return(t/=.5)<1?.5*t*t:-.5*(--t*(t-2)-1)},easeInCubic:function(t){return t*t*t},easeOutCubic:function(t){return(t-=1)*t*t+1},easeInOutCubic:function(t){return(t/=.5)<1?.5*t*t*t:.5*((t-=2)*t*t+2)},easeInQuart:function(t){return t*t*t*t},easeOutQuart:function(t){return-((t-=1)*t*t*t-1)},easeInOutQuart:function(t){return(t/=.5)<1?.5*t*t*t*t:-.5*((t-=2)*t*t*t-2)},easeInQuint:function(t){return t*t*t*t*t},easeOutQuint:function(t){return(t-=1)*t*t*t*t+1},easeInOutQuint:function(t){return(t/=.5)<1?.5*t*t*t*t*t:.5*((t-=2)*t*t*t*t+2)},easeInSine:function(t){return 1-Math.cos(t*(Math.PI/2))},easeOutSine:function(t){return Math.sin(t*(Math.PI/2))},easeInOutSine:function(t){return-.5*(Math.cos(Math.PI*t)-1)},easeInExpo:function(t){return 0===t?0:Math.pow(2,10*(t-1))},easeOutExpo:function(t){return 1===t?1:1-Math.pow(2,-10*t)},easeInOutExpo:function(t){return 0===t?0:1===t?1:(t/=.5)<1?.5*Math.pow(2,10*(t-1)):.5*(2-Math.pow(2,-10*--t))},easeInCirc:function(t){return t>=1?t:-(Math.sqrt(1-t*t)-1)},easeOutCirc:function(t){return Math.sqrt(1-(t-=1)*t)},easeInOutCirc:function(t){return(t/=.5)<1?-.5*(Math.sqrt(1-t*t)-1):.5*(Math.sqrt(1-(t-=2)*t)+1)},easeInElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),-i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n))},easeOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:1===t?1:(n||(n=.3),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),i*Math.pow(2,-10*t)*Math.sin((t-e)*(2*Math.PI)/n)+1)},easeInOutElastic:function(t){var e=1.70158,n=0,i=1;return 0===t?0:2==(t/=.5)?1:(n||(n=.45),i<1?(i=1,e=n/4):e=n/(2*Math.PI)*Math.asin(1/i),t<1?i*Math.pow(2,10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*-.5:i*Math.pow(2,-10*(t-=1))*Math.sin((t-e)*(2*Math.PI)/n)*.5+1)},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},easeInOutBack:function(t){var e=1.70158;return(t/=.5)<1?t*t*((1+(e*=1.525))*t-e)*.5:.5*((t-=2)*t*((1+(e*=1.525))*t+e)+2)},easeInBounce:function(t){return 1-S.easeOutBounce(1-t)},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInOutBounce:function(t){return t<.5?.5*S.easeInBounce(2*t):.5*S.easeOutBounce(2*t-1)+.5}},C={effects:S};M.easingEffects=S;var P=Math.PI,A=P/180,D=2*P,T=P/2,I=P/4,F=2*P/3,L={clear:function(t){t.ctx.clearRect(0,0,t.width,t.height)},roundedRect:function(t,e,n,i,a,r){if(r){var o=Math.min(r,a/2,i/2),s=e+o,l=n+o,u=e+i-o,d=n+a-o;t.moveTo(e,l),s<u&&l<d?(t.arc(s,l,o,-P,-T),t.arc(u,l,o,-T,0),t.arc(u,d,o,0,T),t.arc(s,d,o,T,P)):s<u?(t.moveTo(s,n),t.arc(u,l,o,-T,T),t.arc(s,l,o,T,P+T)):l<d?(t.arc(s,l,o,-P,0),t.arc(s,d,o,0,P)):t.arc(s,l,o,-P,P),t.closePath(),t.moveTo(e,n)}else t.rect(e,n,i,a)},drawPoint:function(t,e,n,i,a,r){var o,s,l,u,d,h=(r||0)*A;if(e&&"object"==typeof e&&("[object HTMLImageElement]"===(o=e.toString())||"[object HTMLCanvasElement]"===o))return t.save(),t.translate(i,a),t.rotate(h),t.drawImage(e,-e.width/2,-e.height/2,e.width,e.height),void t.restore();if(!(isNaN(n)||n<=0)){switch(t.beginPath(),e){default:t.arc(i,a,n,0,D),t.closePath();break;case"triangle":t.moveTo(i+Math.sin(h)*n,a-Math.cos(h)*n),h+=F,t.lineTo(i+Math.sin(h)*n,a-Math.cos(h)*n),h+=F,t.lineTo(i+Math.sin(h)*n,a-Math.cos(h)*n),t.closePath();break;case"rectRounded":u=n-(d=.516*n),s=Math.cos(h+I)*u,l=Math.sin(h+I)*u,t.arc(i-s,a-l,d,h-P,h-T),t.arc(i+l,a-s,d,h-T,h),t.arc(i+s,a+l,d,h,h+T),t.arc(i-l,a+s,d,h+T,h+P),t.closePath();break;case"rect":if(!r){u=Math.SQRT1_2*n,t.rect(i-u,a-u,2*u,2*u);break}h+=I;case"rectRot":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+l,a-s),t.lineTo(i+s,a+l),t.lineTo(i-l,a+s),t.closePath();break;case"crossRot":h+=I;case"cross":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s);break;case"star":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s),h+=I,s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l),t.moveTo(i+l,a-s),t.lineTo(i-l,a+s);break;case"line":s=Math.cos(h)*n,l=Math.sin(h)*n,t.moveTo(i-s,a-l),t.lineTo(i+s,a+l);break;case"dash":t.moveTo(i,a),t.lineTo(i+Math.cos(h)*n,a+Math.sin(h)*n)}t.fill(),t.stroke()}},_isPointInArea:function(t,e){return t.x>e.left-1e-6&&t.x<e.right+1e-6&&t.y>e.top-1e-6&&t.y<e.bottom+1e-6},clipArea:function(t,e){t.save(),t.beginPath(),t.rect(e.left,e.top,e.right-e.left,e.bottom-e.top),t.clip()},unclipArea:function(t){t.restore()},lineTo:function(t,e,n,i){var a=n.steppedLine;if(a){if("middle"===a){var r=(e.x+n.x)/2;t.lineTo(r,i?n.y:e.y),t.lineTo(r,i?e.y:n.y)}else"after"===a&&!i||"after"!==a&&i?t.lineTo(e.x,n.y):t.lineTo(n.x,e.y);t.lineTo(n.x,n.y)}else n.tension?t.bezierCurveTo(i?e.controlPointPreviousX:e.controlPointNextX,i?e.controlPointPreviousY:e.controlPointNextY,i?n.controlPointNextX:n.controlPointPreviousX,i?n.controlPointNextY:n.controlPointPreviousY,n.x,n.y):t.lineTo(n.x,n.y)}},O=L;M.clear=L.clear,M.drawRoundedRectangle=function(t){t.beginPath(),L.roundedRect.apply(L,arguments)};var R={_set:function(t,e){return M.merge(this[t]||(this[t]={}),e)}};R._set("global",{defaultColor:"rgba(0,0,0,0.1)",defaultFontColor:"#666",defaultFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif",defaultFontSize:12,defaultFontStyle:"normal",defaultLineHeight:1.2,showLines:!0});var z=R,N=M.valueOrDefault;var B={toLineHeight:function(t,e){var n=(""+t).match(/^(normal|(\d+(?:\.\d+)?)(px|em|%)?)$/);if(!n||"normal"===n[1])return 1.2*e;switch(t=+n[2],n[3]){case"px":return t;case"%":t/=100}return e*t},toPadding:function(t){var e,n,i,a;return M.isObject(t)?(e=+t.top||0,n=+t.right||0,i=+t.bottom||0,a=+t.left||0):e=n=i=a=+t||0,{top:e,right:n,bottom:i,left:a,height:e+i,width:a+n}},_parseFont:function(t){var e=z.global,n=N(t.fontSize,e.defaultFontSize),i={family:N(t.fontFamily,e.defaultFontFamily),lineHeight:M.options.toLineHeight(N(t.lineHeight,e.defaultLineHeight),n),size:n,style:N(t.fontStyle,e.defaultFontStyle),weight:null,string:""};return i.string=function(t){return!t||M.isNullOrUndef(t.size)||M.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family}(i),i},resolve:function(t,e,n,i){var a,r,o,s=!0;for(a=0,r=t.length;a<r;++a)if(void 0!==(o=t[a])&&(void 0!==e&&"function"==typeof o&&(o=o(e),s=!1),void 0!==n&&M.isArray(o)&&(o=o[n],s=!1),void 0!==o))return i&&!s&&(i.cacheable=!1),o}},E={_factorize:function(t){var e,n=[],i=Math.sqrt(t);for(e=1;e<i;e++)t%e==0&&(n.push(e),n.push(t/e));return i===(0|i)&&n.push(i),n.sort((function(t,e){return t-e})).pop(),n},log10:Math.log10||function(t){var e=Math.log(t)*Math.LOG10E,n=Math.round(e);return t===Math.pow(10,n)?n:e}},W=E;M.log10=E.log10;var V=M,H=C,j=O,q=B,U=W,Y={getRtlAdapter:function(t,e,n){return t?function(t,e){return{x:function(n){return t+t+e-n},setWidth:function(t){e=t},textAlign:function(t){return"center"===t?t:"right"===t?"left":"right"},xPlus:function(t,e){return t-e},leftForLtr:function(t,e){return t-e}}}(e,n):{x:function(t){return t},setWidth:function(t){},textAlign:function(t){return t},xPlus:function(t,e){return t+e},leftForLtr:function(t,e){return t}}},overrideTextDirection:function(t,e){var n,i;"ltr"!==e&&"rtl"!==e||(i=[(n=t.canvas.style).getPropertyValue("direction"),n.getPropertyPriority("direction")],n.setProperty("direction",e,"important"),t.prevTextDirection=i)},restoreTextDirection:function(t){var e=t.prevTextDirection;void 0!==e&&(delete t.prevTextDirection,t.canvas.style.setProperty("direction",e[0],e[1]))}};V.easing=H,V.canvas=j,V.options=q,V.math=U,V.rtl=Y;var G=function(t){V.extend(this,t),this.initialize.apply(this,arguments)};V.extend(G.prototype,{_type:void 0,initialize:function(){this.hidden=!1},pivot:function(){var t=this;return t._view||(t._view=V.extend({},t._model)),t._start={},t},transition:function(t){var e=this,n=e._model,i=e._start,a=e._view;return n&&1!==t?(a||(a=e._view={}),i||(i=e._start={}),function(t,e,n,i){var a,r,o,s,l,u,d,h,c,f=Object.keys(n);for(a=0,r=f.length;a<r;++a)if(u=n[o=f[a]],e.hasOwnProperty(o)||(e[o]=u),(s=e[o])!==u&&"_"!==o[0]){if(t.hasOwnProperty(o)||(t[o]=s),(d=typeof u)===typeof(l=t[o]))if("string"===d){if((h=k(l)).valid&&(c=k(u)).valid){e[o]=c.mix(h,i).rgbString();continue}}else if(V.isFinite(l)&&V.isFinite(u)){e[o]=l+(u-l)*i;continue}e[o]=u}}(i,a,n,t),e):(e._view=V.extend({},n),e._start=null,e)},tooltipPosition:function(){return{x:this._model.x,y:this._model.y}},hasValue:function(){return V.isNumber(this._model.x)&&V.isNumber(this._model.y)}}),G.extend=V.inherits;var X=G,K=X.extend({chart:null,currentStep:0,numSteps:60,easing:"",render:null,onAnimationProgress:null,onAnimationComplete:null}),Z=K;Object.defineProperty(K.prototype,"animationObject",{get:function(){return this}}),Object.defineProperty(K.prototype,"chartInstance",{get:function(){return this.chart},set:function(t){this.chart=t}}),z._set("global",{animation:{duration:1e3,easing:"easeOutQuart",onProgress:V.noop,onComplete:V.noop}});var $={animations:[],request:null,addAnimation:function(t,e,n,i){var a,r,o=this.animations;for(e.chart=t,e.startTime=Date.now(),e.duration=n,i||(t.animating=!0),a=0,r=o.length;a<r;++a)if(o[a].chart===t)return void(o[a]=e);o.push(e),1===o.length&&this.requestAnimationFrame()},cancelAnimation:function(t){var e=V.findIndex(this.animations,(function(e){return e.chart===t}));-1!==e&&(this.animations.splice(e,1),t.animating=!1)},requestAnimationFrame:function(){var t=this;null===t.request&&(t.request=V.requestAnimFrame.call(window,(function(){t.request=null,t.startDigest()})))},startDigest:function(){this.advance(),this.animations.length>0&&this.requestAnimationFrame()},advance:function(){for(var t,e,n,i,a=this.animations,r=0;r<a.length;)e=(t=a[r]).chart,n=t.numSteps,i=Math.floor((Date.now()-t.startTime)/t.duration*n)+1,t.currentStep=Math.min(i,n),V.callback(t.render,[e,t],e),V.callback(t.onAnimationProgress,[t],e),t.currentStep>=n?(V.callback(t.onAnimationComplete,[t],e),e.animating=!1,a.splice(r,1)):++r}},J=V.options.resolve,Q=["push","pop","shift","splice","unshift"];function tt(t,e){var n=t._chartjs;if(n){var i=n.listeners,a=i.indexOf(e);-1!==a&&i.splice(a,1),i.length>0||(Q.forEach((function(e){delete t[e]})),delete t._chartjs)}}var et=function(t,e){this.initialize(t,e)};V.extend(et.prototype,{datasetElementType:null,dataElementType:null,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth"],_dataElementOptions:["backgroundColor","borderColor","borderWidth","pointStyle"],initialize:function(t,e){var n=this;n.chart=t,n.index=e,n.linkScales(),n.addElements(),n._type=n.getMeta().type},updateIndex:function(t){this.index=t},linkScales:function(){var t=this.getMeta(),e=this.chart,n=e.scales,i=this.getDataset(),a=e.options.scales;null!==t.xAxisID&&t.xAxisID in n&&!i.xAxisID||(t.xAxisID=i.xAxisID||a.xAxes[0].id),null!==t.yAxisID&&t.yAxisID in n&&!i.yAxisID||(t.yAxisID=i.yAxisID||a.yAxes[0].id)},getDataset:function(){return this.chart.data.datasets[this.index]},getMeta:function(){return this.chart.getDatasetMeta(this.index)},getScaleForId:function(t){return this.chart.scales[t]},_getValueScaleId:function(){return this.getMeta().yAxisID},_getIndexScaleId:function(){return this.getMeta().xAxisID},_getValueScale:function(){return this.getScaleForId(this._getValueScaleId())},_getIndexScale:function(){return this.getScaleForId(this._getIndexScaleId())},reset:function(){this._update(!0)},destroy:function(){this._data&&tt(this._data,this)},createMetaDataset:function(){var t=this.datasetElementType;return t&&new t({_chart:this.chart,_datasetIndex:this.index})},createMetaData:function(t){var e=this.dataElementType;return e&&new e({_chart:this.chart,_datasetIndex:this.index,_index:t})},addElements:function(){var t,e,n=this.getMeta(),i=this.getDataset().data||[],a=n.data;for(t=0,e=i.length;t<e;++t)a[t]=a[t]||this.createMetaData(t);n.dataset=n.dataset||this.createMetaDataset()},addElementAndReset:function(t){var e=this.createMetaData(t);this.getMeta().data.splice(t,0,e),this.updateElement(e,t,!0)},buildOrUpdateElements:function(){var t,e,n=this,i=n.getDataset(),a=i.data||(i.data=[]);n._data!==a&&(n._data&&tt(n._data,n),a&&Object.isExtensible(a)&&(e=n,(t=a)._chartjs?t._chartjs.listeners.push(e):(Object.defineProperty(t,"_chartjs",{configurable:!0,enumerable:!1,value:{listeners:[e]}}),Q.forEach((function(e){var n="onData"+e.charAt(0).toUpperCase()+e.slice(1),i=t[e];Object.defineProperty(t,e,{configurable:!0,enumerable:!1,value:function(){var e=Array.prototype.slice.call(arguments),a=i.apply(this,e);return V.each(t._chartjs.listeners,(function(t){"function"==typeof t[n]&&t[n].apply(t,e)})),a}})})))),n._data=a),n.resyncElements()},_configure:function(){this._config=V.merge({},[this.chart.options.datasets[this._type],this.getDataset()],{merger:function(t,e,n){"_meta"!==t&&"data"!==t&&V._merger(t,e,n)}})},_update:function(t){this._configure(),this._cachedDataOpts=null,this.update(t)},update:V.noop,transition:function(t){for(var e=this.getMeta(),n=e.data||[],i=n.length,a=0;a<i;++a)n[a].transition(t);e.dataset&&e.dataset.transition(t)},draw:function(){var t=this.getMeta(),e=t.data||[],n=e.length,i=0;for(t.dataset&&t.dataset.draw();i<n;++i)e[i].draw()},getStyle:function(t){var e,n=this.getMeta(),i=n.dataset;return this._configure(),i&&void 0===t?e=this._resolveDatasetElementOptions(i||{}):(t=t||0,e=this._resolveDataElementOptions(n.data[t]||{},t)),!1!==e.fill&&null!==e.fill||(e.backgroundColor="rgba(0,0,0,0)"),e},_resolveDatasetElementOptions:function(t,e){var n,i,a,r,o=this,s=o.chart,l=o._config,u=t.custom||{},d=s.options.elements[o.datasetElementType.prototype._type]||{},h=o._datasetElementOptions,c={},f={chart:s,dataset:o.getDataset(),datasetIndex:o.index,hover:e};for(n=0,i=h.length;n<i;++n)a=h[n],r=e?"hover"+a.charAt(0).toUpperCase()+a.slice(1):a,c[a]=J([u[r],l[r],d[r]],f);return c},_resolveDataElementOptions:function(t,e){var n=this,i=t&&t.custom,a=n._cachedDataOpts;if(a&&!i)return a;var r,o,s,l,u=n.chart,d=n._config,h=u.options.elements[n.dataElementType.prototype._type]||{},c=n._dataElementOptions,f={},g={chart:u,dataIndex:e,dataset:n.getDataset(),datasetIndex:n.index},p={cacheable:!i};if(i=i||{},V.isArray(c))for(o=0,s=c.length;o<s;++o)f[l=c[o]]=J([i[l],d[l],h[l]],g,e,p);else for(o=0,s=(r=Object.keys(c)).length;o<s;++o)f[l=r[o]]=J([i[l],d[c[l]],d[l],h[l]],g,e,p);return p.cacheable&&(n._cachedDataOpts=Object.freeze(f)),f},removeHoverStyle:function(t){V.merge(t._model,t.$previousStyle||{}),delete t.$previousStyle},setHoverStyle:function(t){var e=this.chart.data.datasets[t._datasetIndex],n=t._index,i=t.custom||{},a=t._model,r=V.getHoverColor;t.$previousStyle={backgroundColor:a.backgroundColor,borderColor:a.borderColor,borderWidth:a.borderWidth},a.backgroundColor=J([i.hoverBackgroundColor,e.hoverBackgroundColor,r(a.backgroundColor)],void 0,n),a.borderColor=J([i.hoverBorderColor,e.hoverBorderColor,r(a.borderColor)],void 0,n),a.borderWidth=J([i.hoverBorderWidth,e.hoverBorderWidth,a.borderWidth],void 0,n)},_removeDatasetHoverStyle:function(){var t=this.getMeta().dataset;t&&this.removeHoverStyle(t)},_setDatasetHoverStyle:function(){var t,e,n,i,a,r,o=this.getMeta().dataset,s={};if(o){for(r=o._model,a=this._resolveDatasetElementOptions(o,!0),t=0,e=(i=Object.keys(a)).length;t<e;++t)s[n=i[t]]=r[n],r[n]=a[n];o.$previousStyle=s}},resyncElements:function(){var t=this.getMeta(),e=this.getDataset().data,n=t.data.length,i=e.length;i<n?t.data.splice(i,n-i):i>n&&this.insertElements(n,i-n)},insertElements:function(t,e){for(var n=0;n<e;++n)this.addElementAndReset(t+n)},onDataPush:function(){var t=arguments.length;this.insertElements(this.getDataset().data.length-t,t)},onDataPop:function(){this.getMeta().data.pop()},onDataShift:function(){this.getMeta().data.shift()},onDataSplice:function(t,e){this.getMeta().data.splice(t,e),this.insertElements(t,arguments.length-2)},onDataUnshift:function(){this.insertElements(0,arguments.length)}}),et.extend=V.inherits;var nt=et,it=2*Math.PI;function at(t,e){var n=e.startAngle,i=e.endAngle,a=e.pixelMargin,r=a/e.outerRadius,o=e.x,s=e.y;t.beginPath(),t.arc(o,s,e.outerRadius,n-r,i+r),e.innerRadius>a?(r=a/e.innerRadius,t.arc(o,s,e.innerRadius-a,i+r,n-r,!0)):t.arc(o,s,a,i+Math.PI/2,n-Math.PI/2),t.closePath(),t.clip()}function rt(t,e,n){var i="inner"===e.borderAlign;i?(t.lineWidth=2*e.borderWidth,t.lineJoin="round"):(t.lineWidth=e.borderWidth,t.lineJoin="bevel"),n.fullCircles&&function(t,e,n,i){var a,r=n.endAngle;for(i&&(n.endAngle=n.startAngle+it,at(t,n),n.endAngle=r,n.endAngle===n.startAngle&&n.fullCircles&&(n.endAngle+=it,n.fullCircles--)),t.beginPath(),t.arc(n.x,n.y,n.innerRadius,n.startAngle+it,n.startAngle,!0),a=0;a<n.fullCircles;++a)t.stroke();for(t.beginPath(),t.arc(n.x,n.y,e.outerRadius,n.startAngle,n.startAngle+it),a=0;a<n.fullCircles;++a)t.stroke()}(t,e,n,i),i&&at(t,n),t.beginPath(),t.arc(n.x,n.y,e.outerRadius,n.startAngle,n.endAngle),t.arc(n.x,n.y,n.innerRadius,n.endAngle,n.startAngle,!0),t.closePath(),t.stroke()}z._set("global",{elements:{arc:{backgroundColor:z.global.defaultColor,borderColor:"#fff",borderWidth:2,borderAlign:"center"}}});var ot=X.extend({_type:"arc",inLabelRange:function(t){var e=this._view;return!!e&&Math.pow(t-e.x,2)<Math.pow(e.radius+e.hoverRadius,2)},inRange:function(t,e){var n=this._view;if(n){for(var i=V.getAngleFromPoint(n,{x:t,y:e}),a=i.angle,r=i.distance,o=n.startAngle,s=n.endAngle;s<o;)s+=it;for(;a>s;)a-=it;for(;a<o;)a+=it;var l=a>=o&&a<=s,u=r>=n.innerRadius&&r<=n.outerRadius;return l&&u}return!1},getCenterPoint:function(){var t=this._view,e=(t.startAngle+t.endAngle)/2,n=(t.innerRadius+t.outerRadius)/2;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},getArea:function(){var t=this._view;return Math.PI*((t.endAngle-t.startAngle)/(2*Math.PI))*(Math.pow(t.outerRadius,2)-Math.pow(t.innerRadius,2))},tooltipPosition:function(){var t=this._view,e=t.startAngle+(t.endAngle-t.startAngle)/2,n=(t.outerRadius-t.innerRadius)/2+t.innerRadius;return{x:t.x+Math.cos(e)*n,y:t.y+Math.sin(e)*n}},draw:function(){var t,e=this._chart.ctx,n=this._view,i="inner"===n.borderAlign?.33:0,a={x:n.x,y:n.y,innerRadius:n.innerRadius,outerRadius:Math.max(n.outerRadius-i,0),pixelMargin:i,startAngle:n.startAngle,endAngle:n.endAngle,fullCircles:Math.floor(n.circumference/it)};if(e.save(),e.fillStyle=n.backgroundColor,e.strokeStyle=n.borderColor,a.fullCircles){for(a.endAngle=a.startAngle+it,e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),t=0;t<a.fullCircles;++t)e.fill();a.endAngle=a.startAngle+n.circumference%it}e.beginPath(),e.arc(a.x,a.y,a.outerRadius,a.startAngle,a.endAngle),e.arc(a.x,a.y,a.innerRadius,a.endAngle,a.startAngle,!0),e.closePath(),e.fill(),n.borderWidth&&rt(e,n,a),e.restore()}}),st=V.valueOrDefault,lt=z.global.defaultColor;z._set("global",{elements:{line:{tension:.4,backgroundColor:lt,borderWidth:3,borderColor:lt,borderCapStyle:"butt",borderDash:[],borderDashOffset:0,borderJoinStyle:"miter",capBezierPoints:!0,fill:!0}}});var ut=X.extend({_type:"line",draw:function(){var t,e,n,i=this,a=i._view,r=i._chart.ctx,o=a.spanGaps,s=i._children.slice(),l=z.global,u=l.elements.line,d=-1,h=i._loop;if(s.length){if(i._loop){for(t=0;t<s.length;++t)if(e=V.previousItem(s,t),!s[t]._view.skip&&e._view.skip){s=s.slice(t).concat(s.slice(0,t)),h=o;break}h&&s.push(s[0])}for(r.save(),r.lineCap=a.borderCapStyle||u.borderCapStyle,r.setLineDash&&r.setLineDash(a.borderDash||u.borderDash),r.lineDashOffset=st(a.borderDashOffset,u.borderDashOffset),r.lineJoin=a.borderJoinStyle||u.borderJoinStyle,r.lineWidth=st(a.borderWidth,u.borderWidth),r.strokeStyle=a.borderColor||l.defaultColor,r.beginPath(),(n=s[0]._view).skip||(r.moveTo(n.x,n.y),d=0),t=1;t<s.length;++t)n=s[t]._view,e=-1===d?V.previousItem(s,t):s[d],n.skip||(d!==t-1&&!o||-1===d?r.moveTo(n.x,n.y):V.canvas.lineTo(r,e._view,n),d=t);h&&r.closePath(),r.stroke(),r.restore()}}}),dt=V.valueOrDefault,ht=z.global.defaultColor;function ct(t){var e=this._view;return!!e&&Math.abs(t-e.x)<e.radius+e.hitRadius}z._set("global",{elements:{point:{radius:3,pointStyle:"circle",backgroundColor:ht,borderColor:ht,borderWidth:1,hitRadius:1,hoverRadius:4,hoverBorderWidth:1}}});var ft=X.extend({_type:"point",inRange:function(t,e){var n=this._view;return!!n&&Math.pow(t-n.x,2)+Math.pow(e-n.y,2)<Math.pow(n.hitRadius+n.radius,2)},inLabelRange:ct,inXRange:ct,inYRange:function(t){var e=this._view;return!!e&&Math.abs(t-e.y)<e.radius+e.hitRadius},getCenterPoint:function(){var t=this._view;return{x:t.x,y:t.y}},getArea:function(){return Math.PI*Math.pow(this._view.radius,2)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y,padding:t.radius+t.borderWidth}},draw:function(t){var e=this._view,n=this._chart.ctx,i=e.pointStyle,a=e.rotation,r=e.radius,o=e.x,s=e.y,l=z.global,u=l.defaultColor;e.skip||(void 0===t||V.canvas._isPointInArea(e,t))&&(n.strokeStyle=e.borderColor||u,n.lineWidth=dt(e.borderWidth,l.elements.point.borderWidth),n.fillStyle=e.backgroundColor||u,V.canvas.drawPoint(n,i,r,o,s,a))}}),gt=z.global.defaultColor;function pt(t){return t&&void 0!==t.width}function mt(t){var e,n,i,a,r;return pt(t)?(r=t.width/2,e=t.x-r,n=t.x+r,i=Math.min(t.y,t.base),a=Math.max(t.y,t.base)):(r=t.height/2,e=Math.min(t.x,t.base),n=Math.max(t.x,t.base),i=t.y-r,a=t.y+r),{left:e,top:i,right:n,bottom:a}}function vt(t,e,n){return t===e?n:t===n?e:t}function bt(t,e,n){var i,a,r,o,s=t.borderWidth,l=function(t){var e=t.borderSkipped,n={};return e?(t.horizontal?t.base>t.x&&(e=vt(e,"left","right")):t.base<t.y&&(e=vt(e,"bottom","top")),n[e]=!0,n):n}(t);return V.isObject(s)?(i=+s.top||0,a=+s.right||0,r=+s.bottom||0,o=+s.left||0):i=a=r=o=+s||0,{t:l.top||i<0?0:i>n?n:i,r:l.right||a<0?0:a>e?e:a,b:l.bottom||r<0?0:r>n?n:r,l:l.left||o<0?0:o>e?e:o}}function xt(t,e,n){var i=null===e,a=null===n,r=!(!t||i&&a)&&mt(t);return r&&(i||e>=r.left&&e<=r.right)&&(a||n>=r.top&&n<=r.bottom)}z._set("global",{elements:{rectangle:{backgroundColor:gt,borderColor:gt,borderSkipped:"bottom",borderWidth:0}}});var yt=X.extend({_type:"rectangle",draw:function(){var t=this._chart.ctx,e=this._view,n=function(t){var e=mt(t),n=e.right-e.left,i=e.bottom-e.top,a=bt(t,n/2,i/2);return{outer:{x:e.left,y:e.top,w:n,h:i},inner:{x:e.left+a.l,y:e.top+a.t,w:n-a.l-a.r,h:i-a.t-a.b}}}(e),i=n.outer,a=n.inner;t.fillStyle=e.backgroundColor,t.fillRect(i.x,i.y,i.w,i.h),i.w===a.w&&i.h===a.h||(t.save(),t.beginPath(),t.rect(i.x,i.y,i.w,i.h),t.clip(),t.fillStyle=e.borderColor,t.rect(a.x,a.y,a.w,a.h),t.fill("evenodd"),t.restore())},height:function(){var t=this._view;return t.base-t.y},inRange:function(t,e){return xt(this._view,t,e)},inLabelRange:function(t,e){var n=this._view;return pt(n)?xt(n,t,null):xt(n,null,e)},inXRange:function(t){return xt(this._view,t,null)},inYRange:function(t){return xt(this._view,null,t)},getCenterPoint:function(){var t,e,n=this._view;return pt(n)?(t=n.x,e=(n.y+n.base)/2):(t=(n.x+n.base)/2,e=n.y),{x:t,y:e}},getArea:function(){var t=this._view;return pt(t)?t.width*Math.abs(t.y-t.base):t.height*Math.abs(t.x-t.base)},tooltipPosition:function(){var t=this._view;return{x:t.x,y:t.y}}}),_t={},kt=ot,wt=ut,Mt=ft,St=yt;_t.Arc=kt,_t.Line=wt,_t.Point=Mt,_t.Rectangle=St;var Ct=V._deprecated,Pt=V.valueOrDefault;function At(t,e,n){var i,a,r=n.barThickness,o=e.stackCount,s=e.pixels[t],l=V.isNullOrUndef(r)?function(t,e){var n,i,a,r,o=t._length;for(a=1,r=e.length;a<r;++a)o=Math.min(o,Math.abs(e[a]-e[a-1]));for(a=0,r=t.getTicks().length;a<r;++a)i=t.getPixelForTick(a),o=a>0?Math.min(o,Math.abs(i-n)):o,n=i;return o}(e.scale,e.pixels):-1;return V.isNullOrUndef(r)?(i=l*n.categoryPercentage,a=n.barPercentage):(i=r*o,a=1),{chunk:i/o,ratio:a,start:s-i/2}}z._set("bar",{hover:{mode:"label"},scales:{xAxes:[{type:"category",offset:!0,gridLines:{offsetGridLines:!0}}],yAxes:[{type:"linear"}]}}),z._set("global",{datasets:{bar:{categoryPercentage:.8,barPercentage:.9}}});var Dt=nt.extend({dataElementType:_t.Rectangle,_dataElementOptions:["backgroundColor","borderColor","borderSkipped","borderWidth","barPercentage","barThickness","categoryPercentage","maxBarThickness","minBarLength"],initialize:function(){var t,e,n=this;nt.prototype.initialize.apply(n,arguments),(t=n.getMeta()).stack=n.getDataset().stack,t.bar=!0,e=n._getIndexScale().options,Ct("bar chart",e.barPercentage,"scales.[x/y]Axes.barPercentage","dataset.barPercentage"),Ct("bar chart",e.barThickness,"scales.[x/y]Axes.barThickness","dataset.barThickness"),Ct("bar chart",e.categoryPercentage,"scales.[x/y]Axes.categoryPercentage","dataset.categoryPercentage"),Ct("bar chart",n._getValueScale().options.minBarLength,"scales.[x/y]Axes.minBarLength","dataset.minBarLength"),Ct("bar chart",e.maxBarThickness,"scales.[x/y]Axes.maxBarThickness","dataset.maxBarThickness")},update:function(t){var e,n,i=this.getMeta().data;for(this._ruler=this.getRuler(),e=0,n=i.length;e<n;++e)this.updateElement(i[e],e,t)},updateElement:function(t,e,n){var i=this,a=i.getMeta(),r=i.getDataset(),o=i._resolveDataElementOptions(t,e);t._xScale=i.getScaleForId(a.xAxisID),t._yScale=i.getScaleForId(a.yAxisID),t._datasetIndex=i.index,t._index=e,t._model={backgroundColor:o.backgroundColor,borderColor:o.borderColor,borderSkipped:o.borderSkipped,borderWidth:o.borderWidth,datasetLabel:r.label,label:i.chart.data.labels[e]},V.isArray(r.data[e])&&(t._model.borderSkipped=null),i._updateElementGeometry(t,e,n,o),t.pivot()},_updateElementGeometry:function(t,e,n,i){var a=this,r=t._model,o=a._getValueScale(),s=o.getBasePixel(),l=o.isHorizontal(),u=a._ruler||a.getRuler(),d=a.calculateBarValuePixels(a.index,e,i),h=a.calculateBarIndexPixels(a.index,e,u,i);r.horizontal=l,r.base=n?s:d.base,r.x=l?n?s:d.head:h.center,r.y=l?h.center:n?s:d.head,r.height=l?h.size:void 0,r.width=l?void 0:h.size},_getStacks:function(t){var e,n,i=this._getIndexScale(),a=i._getMatchingVisibleMetas(this._type),r=i.options.stacked,o=a.length,s=[];for(e=0;e<o&&(n=a[e],(!1===r||-1===s.indexOf(n.stack)||void 0===r&&void 0===n.stack)&&s.push(n.stack),n.index!==t);++e);return s},getStackCount:function(){return this._getStacks().length},getStackIndex:function(t,e){var n=this._getStacks(t),i=void 0!==e?n.indexOf(e):-1;return-1===i?n.length-1:i},getRuler:function(){var t,e,n=this._getIndexScale(),i=[];for(t=0,e=this.getMeta().data.length;t<e;++t)i.push(n.getPixelForValue(null,t,this.index));return{pixels:i,start:n._startPixel,end:n._endPixel,stackCount:this.getStackCount(),scale:n}},calculateBarValuePixels:function(t,e,n){var i,a,r,o,s,l,u,d=this.chart,h=this._getValueScale(),c=h.isHorizontal(),f=d.data.datasets,g=h._getMatchingVisibleMetas(this._type),p=h._parseValue(f[t].data[e]),m=n.minBarLength,v=h.options.stacked,b=this.getMeta().stack,x=void 0===p.start?0:p.max>=0&&p.min>=0?p.min:p.max,y=void 0===p.start?p.end:p.max>=0&&p.min>=0?p.max-p.min:p.min-p.max,_=g.length;if(v||void 0===v&&void 0!==b)for(i=0;i<_&&(a=g[i]).index!==t;++i)a.stack===b&&(r=void 0===(u=h._parseValue(f[a.index].data[e])).start?u.end:u.min>=0&&u.max>=0?u.max:u.min,(p.min<0&&r<0||p.max>=0&&r>0)&&(x+=r));return o=h.getPixelForValue(x),l=(s=h.getPixelForValue(x+y))-o,void 0!==m&&Math.abs(l)<m&&(l=m,s=y>=0&&!c||y<0&&c?o-m:o+m),{size:l,base:o,head:s,center:s+l/2}},calculateBarIndexPixels:function(t,e,n,i){var a="flex"===i.barThickness?function(t,e,n){var i,a=e.pixels,r=a[t],o=t>0?a[t-1]:null,s=t<a.length-1?a[t+1]:null,l=n.categoryPercentage;return null===o&&(o=r-(null===s?e.end-e.start:s-r)),null===s&&(s=r+r-o),i=r-(r-Math.min(o,s))/2*l,{chunk:Math.abs(s-o)/2*l/e.stackCount,ratio:n.barPercentage,start:i}}(e,n,i):At(e,n,i),r=this.getStackIndex(t,this.getMeta().stack),o=a.start+a.chunk*r+a.chunk/2,s=Math.min(Pt(i.maxBarThickness,1/0),a.chunk*a.ratio);return{base:o-s/2,head:o+s/2,center:o,size:s}},draw:function(){var t=this.chart,e=this._getValueScale(),n=this.getMeta().data,i=this.getDataset(),a=n.length,r=0;for(V.canvas.clipArea(t.ctx,t.chartArea);r<a;++r){var o=e._parseValue(i.data[r]);isNaN(o.min)||isNaN(o.max)||n[r].draw()}V.canvas.unclipArea(t.ctx)},_resolveDataElementOptions:function(){var t=this,e=V.extend({},nt.prototype._resolveDataElementOptions.apply(t,arguments)),n=t._getIndexScale().options,i=t._getValueScale().options;return e.barPercentage=Pt(n.barPercentage,e.barPercentage),e.barThickness=Pt(n.barThickness,e.barThickness),e.categoryPercentage=Pt(n.categoryPercentage,e.categoryPercentage),e.maxBarThickness=Pt(n.maxBarThickness,e.maxBarThickness),e.minBarLength=Pt(i.minBarLength,e.minBarLength),e}}),Tt=V.valueOrDefault,It=V.options.resolve;z._set("bubble",{hover:{mode:"single"},scales:{xAxes:[{type:"linear",position:"bottom",id:"x-axis-0"}],yAxes:[{type:"linear",position:"left",id:"y-axis-0"}]},tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.datasets[t.datasetIndex].label||"",i=e.datasets[t.datasetIndex].data[t.index];return n+": ("+t.xLabel+", "+t.yLabel+", "+i.r+")"}}}});var Ft=nt.extend({dataElementType:_t.Point,_dataElementOptions:["backgroundColor","borderColor","borderWidth","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth","hoverRadius","hitRadius","pointStyle","rotation"],update:function(t){var e=this,n=e.getMeta().data;V.each(n,(function(n,i){e.updateElement(n,i,t)}))},updateElement:function(t,e,n){var i=this,a=i.getMeta(),r=t.custom||{},o=i.getScaleForId(a.xAxisID),s=i.getScaleForId(a.yAxisID),l=i._resolveDataElementOptions(t,e),u=i.getDataset().data[e],d=i.index,h=n?o.getPixelForDecimal(.5):o.getPixelForValue("object"==typeof u?u:NaN,e,d),c=n?s.getBasePixel():s.getPixelForValue(u,e,d);t._xScale=o,t._yScale=s,t._options=l,t._datasetIndex=d,t._index=e,t._model={backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,hitRadius:l.hitRadius,pointStyle:l.pointStyle,rotation:l.rotation,radius:n?0:l.radius,skip:r.skip||isNaN(h)||isNaN(c),x:h,y:c},t.pivot()},setHoverStyle:function(t){var e=t._model,n=t._options,i=V.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Tt(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=Tt(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=Tt(n.hoverBorderWidth,n.borderWidth),e.radius=n.radius+n.hoverRadius},_resolveDataElementOptions:function(t,e){var n=this,i=n.chart,a=n.getDataset(),r=t.custom||{},o=a.data[e]||{},s=nt.prototype._resolveDataElementOptions.apply(n,arguments),l={chart:i,dataIndex:e,dataset:a,datasetIndex:n.index};return n._cachedDataOpts===s&&(s=V.extend({},s)),s.radius=It([r.radius,o.r,n._config.radius,i.options.elements.point.radius],l,e),s}}),Lt=V.valueOrDefault,Ot=Math.PI,Rt=2*Ot,zt=Ot/2;z._set("doughnut",{animation:{animateRotate:!0,animateScale:!1},hover:{mode:"single"},legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,n=o[0].data.length;e<n;++e)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&i.appendChild(document.createTextNode(s[e]));return a.outerHTML},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map((function(n,i){var a=t.getDatasetMeta(0),r=a.controller.getStyle(i);return{text:n,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].data[i])||a.data[i].hidden,index:i}})):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)(a=o.getDatasetMeta(n)).data[r]&&(a.data[r].hidden=!a.data[r].hidden);o.update()}},cutoutPercentage:50,rotation:-zt,circumference:Rt,tooltips:{callbacks:{title:function(){return""},label:function(t,e){var n=e.labels[t.index],i=": "+e.datasets[t.datasetIndex].data[t.index];return V.isArray(n)?(n=n.slice())[0]+=i:n+=i,n}}}});var Nt=nt.extend({dataElementType:_t.Arc,linkScales:V.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],getRingIndex:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&++e;return e},update:function(t){var e,n,i,a,r=this,o=r.chart,s=o.chartArea,l=o.options,u=1,d=1,h=0,c=0,f=r.getMeta(),g=f.data,p=l.cutoutPercentage/100||0,m=l.circumference,v=r._getRingWeight(r.index);if(m<Rt){var b=l.rotation%Rt,x=(b+=b>=Ot?-Rt:b<-Ot?Rt:0)+m,y=Math.cos(b),_=Math.sin(b),k=Math.cos(x),w=Math.sin(x),M=b<=0&&x>=0||x>=Rt,S=b<=zt&&x>=zt||x>=Rt+zt,C=b<=-zt&&x>=-zt||x>=Ot+zt,P=b===-Ot||x>=Ot?-1:Math.min(y,y*p,k,k*p),A=C?-1:Math.min(_,_*p,w,w*p),D=M?1:Math.max(y,y*p,k,k*p),T=S?1:Math.max(_,_*p,w,w*p);u=(D-P)/2,d=(T-A)/2,h=-(D+P)/2,c=-(T+A)/2}for(i=0,a=g.length;i<a;++i)g[i]._options=r._resolveDataElementOptions(g[i],i);for(o.borderWidth=r.getMaxBorderWidth(),e=(s.right-s.left-o.borderWidth)/u,n=(s.bottom-s.top-o.borderWidth)/d,o.outerRadius=Math.max(Math.min(e,n)/2,0),o.innerRadius=Math.max(o.outerRadius*p,0),o.radiusLength=(o.outerRadius-o.innerRadius)/(r._getVisibleDatasetWeightTotal()||1),o.offsetX=h*o.outerRadius,o.offsetY=c*o.outerRadius,f.total=r.calculateTotal(),r.outerRadius=o.outerRadius-o.radiusLength*r._getRingWeightOffset(r.index),r.innerRadius=Math.max(r.outerRadius-o.radiusLength*v,0),i=0,a=g.length;i<a;++i)r.updateElement(g[i],i,t)},updateElement:function(t,e,n){var i=this,a=i.chart,r=a.chartArea,o=a.options,s=o.animation,l=(r.left+r.right)/2,u=(r.top+r.bottom)/2,d=o.rotation,h=o.rotation,c=i.getDataset(),f=n&&s.animateRotate?0:t.hidden?0:i.calculateCircumference(c.data[e])*(o.circumference/Rt),g=n&&s.animateScale?0:i.innerRadius,p=n&&s.animateScale?0:i.outerRadius,m=t._options||{};V.extend(t,{_datasetIndex:i.index,_index:e,_model:{backgroundColor:m.backgroundColor,borderColor:m.borderColor,borderWidth:m.borderWidth,borderAlign:m.borderAlign,x:l+a.offsetX,y:u+a.offsetY,startAngle:d,endAngle:h,circumference:f,outerRadius:p,innerRadius:g,label:V.valueAtIndexOrDefault(c.label,e,a.data.labels[e])}});var v=t._model;n&&s.animateRotate||(v.startAngle=0===e?o.rotation:i.getMeta().data[e-1]._model.endAngle,v.endAngle=v.startAngle+v.circumference),t.pivot()},calculateTotal:function(){var t,e=this.getDataset(),n=this.getMeta(),i=0;return V.each(n.data,(function(n,a){t=e.data[a],isNaN(t)||n.hidden||(i+=Math.abs(t))})),i},calculateCircumference:function(t){var e=this.getMeta().total;return e>0&&!isNaN(t)?Rt*(Math.abs(t)/e):0},getMaxBorderWidth:function(t){var e,n,i,a,r,o,s,l,u=0,d=this.chart;if(!t)for(e=0,n=d.data.datasets.length;e<n;++e)if(d.isDatasetVisible(e)){t=(i=d.getDatasetMeta(e)).data,e!==this.index&&(r=i.controller);break}if(!t)return 0;for(e=0,n=t.length;e<n;++e)a=t[e],r?(r._configure(),o=r._resolveDataElementOptions(a,e)):o=a._options,"inner"!==o.borderAlign&&(s=o.borderWidth,u=(l=o.hoverBorderWidth)>(u=s>u?s:u)?l:u);return u},setHoverStyle:function(t){var e=t._model,n=t._options,i=V.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=Lt(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=Lt(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=Lt(n.hoverBorderWidth,n.borderWidth)},_getRingWeightOffset:function(t){for(var e=0,n=0;n<t;++n)this.chart.isDatasetVisible(n)&&(e+=this._getRingWeight(n));return e},_getRingWeight:function(t){return Math.max(Lt(this.chart.data.datasets[t].weight,1),0)},_getVisibleDatasetWeightTotal:function(){return this._getRingWeightOffset(this.chart.data.datasets.length)}});z._set("horizontalBar",{hover:{mode:"index",axis:"y"},scales:{xAxes:[{type:"linear",position:"bottom"}],yAxes:[{type:"category",position:"left",offset:!0,gridLines:{offsetGridLines:!0}}]},elements:{rectangle:{borderSkipped:"left"}},tooltips:{mode:"index",axis:"y"}}),z._set("global",{datasets:{horizontalBar:{categoryPercentage:.8,barPercentage:.9}}});var Bt=Dt.extend({_getValueScaleId:function(){return this.getMeta().xAxisID},_getIndexScaleId:function(){return this.getMeta().yAxisID}}),Et=V.valueOrDefault,Wt=V.options.resolve,Vt=V.canvas._isPointInArea;function Ht(t,e){var n=t&&t.options.ticks||{},i=n.reverse,a=void 0===n.min?e:0,r=void 0===n.max?e:0;return{start:i?r:a,end:i?a:r}}function jt(t,e,n){var i=n/2,a=Ht(t,i),r=Ht(e,i);return{top:r.end,right:a.end,bottom:r.start,left:a.start}}function qt(t){var e,n,i,a;return V.isObject(t)?(e=t.top,n=t.right,i=t.bottom,a=t.left):e=n=i=a=t,{top:e,right:n,bottom:i,left:a}}z._set("line",{showLines:!0,spanGaps:!1,hover:{mode:"label"},scales:{xAxes:[{type:"category",id:"x-axis-0"}],yAxes:[{type:"linear",id:"y-axis-0"}]}});var Ut=nt.extend({datasetElementType:_t.Line,dataElementType:_t.Point,_datasetElementOptions:["backgroundColor","borderCapStyle","borderColor","borderDash","borderDashOffset","borderJoinStyle","borderWidth","cubicInterpolationMode","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},update:function(t){var e,n,i=this,a=i.getMeta(),r=a.dataset,o=a.data||[],s=i.chart.options,l=i._config,u=i._showLine=Et(l.showLine,s.showLines);for(i._xScale=i.getScaleForId(a.xAxisID),i._yScale=i.getScaleForId(a.yAxisID),u&&(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=i._yScale,r._datasetIndex=i.index,r._children=o,r._model=i._resolveDatasetElementOptions(r),r.pivot()),e=0,n=o.length;e<n;++e)i.updateElement(o[e],e,t);for(u&&0!==r._model.tension&&i.updateBezierControlPoints(),e=0,n=o.length;e<n;++e)o[e].pivot()},updateElement:function(t,e,n){var i,a,r=this,o=r.getMeta(),s=t.custom||{},l=r.getDataset(),u=r.index,d=l.data[e],h=r._xScale,c=r._yScale,f=o.dataset._model,g=r._resolveDataElementOptions(t,e);i=h.getPixelForValue("object"==typeof d?d:NaN,e,u),a=n?c.getBasePixel():r.calculatePointY(d,e,u),t._xScale=h,t._yScale=c,t._options=g,t._datasetIndex=u,t._index=e,t._model={x:i,y:a,skip:s.skip||isNaN(i)||isNaN(a),radius:g.radius,pointStyle:g.pointStyle,rotation:g.rotation,backgroundColor:g.backgroundColor,borderColor:g.borderColor,borderWidth:g.borderWidth,tension:Et(s.tension,f?f.tension:0),steppedLine:!!f&&f.steppedLine,hitRadius:g.hitRadius}},_resolveDatasetElementOptions:function(t){var e=this,n=e._config,i=t.custom||{},a=e.chart.options,r=a.elements.line,o=nt.prototype._resolveDatasetElementOptions.apply(e,arguments);return o.spanGaps=Et(n.spanGaps,a.spanGaps),o.tension=Et(n.lineTension,r.tension),o.steppedLine=Wt([i.steppedLine,n.steppedLine,r.stepped]),o.clip=qt(Et(n.clip,jt(e._xScale,e._yScale,o.borderWidth))),o},calculatePointY:function(t,e,n){var i,a,r,o,s,l,u,d=this.chart,h=this._yScale,c=0,f=0;if(h.options.stacked){for(s=+h.getRightValue(t),u=(l=d._getSortedVisibleDatasetMetas()).length,i=0;i<u&&(r=l[i]).index!==n;++i)a=d.data.datasets[r.index],"line"===r.type&&r.yAxisID===h.id&&((o=+h.getRightValue(a.data[e]))<0?f+=o||0:c+=o||0);return s<0?h.getPixelForValue(f+s):h.getPixelForValue(c+s)}return h.getPixelForValue(t)},updateBezierControlPoints:function(){var t,e,n,i,a=this.chart,r=this.getMeta(),o=r.dataset._model,s=a.chartArea,l=r.data||[];function u(t,e,n){return Math.max(Math.min(t,n),e)}if(o.spanGaps&&(l=l.filter((function(t){return!t._model.skip}))),"monotone"===o.cubicInterpolationMode)V.splineCurveMonotone(l);else for(t=0,e=l.length;t<e;++t)n=l[t]._model,i=V.splineCurve(V.previousItem(l,t)._model,n,V.nextItem(l,t)._model,o.tension),n.controlPointPreviousX=i.previous.x,n.controlPointPreviousY=i.previous.y,n.controlPointNextX=i.next.x,n.controlPointNextY=i.next.y;if(a.options.elements.line.capBezierPoints)for(t=0,e=l.length;t<e;++t)n=l[t]._model,Vt(n,s)&&(t>0&&Vt(l[t-1]._model,s)&&(n.controlPointPreviousX=u(n.controlPointPreviousX,s.left,s.right),n.controlPointPreviousY=u(n.controlPointPreviousY,s.top,s.bottom)),t<l.length-1&&Vt(l[t+1]._model,s)&&(n.controlPointNextX=u(n.controlPointNextX,s.left,s.right),n.controlPointNextY=u(n.controlPointNextY,s.top,s.bottom)))},draw:function(){var t,e=this.chart,n=this.getMeta(),i=n.data||[],a=e.chartArea,r=e.canvas,o=0,s=i.length;for(this._showLine&&(t=n.dataset._model.clip,V.canvas.clipArea(e.ctx,{left:!1===t.left?0:a.left-t.left,right:!1===t.right?r.width:a.right+t.right,top:!1===t.top?0:a.top-t.top,bottom:!1===t.bottom?r.height:a.bottom+t.bottom}),n.dataset.draw(),V.canvas.unclipArea(e.ctx));o<s;++o)i[o].draw(a)},setHoverStyle:function(t){var e=t._model,n=t._options,i=V.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Et(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=Et(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=Et(n.hoverBorderWidth,n.borderWidth),e.radius=Et(n.hoverRadius,n.radius)}}),Yt=V.options.resolve;z._set("polarArea",{scale:{type:"radialLinear",angleLines:{display:!1},gridLines:{circular:!0},pointLabels:{display:!1},ticks:{beginAtZero:!0}},animation:{animateRotate:!0,animateScale:!0},startAngle:-.5*Math.PI,legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data,o=r.datasets,s=r.labels;if(a.setAttribute("class",t.id+"-legend"),o.length)for(e=0,n=o[0].data.length;e<n;++e)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=o[0].backgroundColor[e],s[e]&&i.appendChild(document.createTextNode(s[e]));return a.outerHTML},legend:{labels:{generateLabels:function(t){var e=t.data;return e.labels.length&&e.datasets.length?e.labels.map((function(n,i){var a=t.getDatasetMeta(0),r=a.controller.getStyle(i);return{text:n,fillStyle:r.backgroundColor,strokeStyle:r.borderColor,lineWidth:r.borderWidth,hidden:isNaN(e.datasets[0].data[i])||a.data[i].hidden,index:i}})):[]}},onClick:function(t,e){var n,i,a,r=e.index,o=this.chart;for(n=0,i=(o.data.datasets||[]).length;n<i;++n)(a=o.getDatasetMeta(n)).data[r].hidden=!a.data[r].hidden;o.update()}},tooltips:{callbacks:{title:function(){return""},label:function(t,e){return e.labels[t.index]+": "+t.yLabel}}}});var Gt=nt.extend({dataElementType:_t.Arc,linkScales:V.noop,_dataElementOptions:["backgroundColor","borderColor","borderWidth","borderAlign","hoverBackgroundColor","hoverBorderColor","hoverBorderWidth"],_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},update:function(t){var e,n,i,a=this,r=a.getDataset(),o=a.getMeta(),s=a.chart.options.startAngle||0,l=a._starts=[],u=a._angles=[],d=o.data;for(a._updateRadius(),o.count=a.countVisibleElements(),e=0,n=r.data.length;e<n;e++)l[e]=s,i=a._computeAngle(e),u[e]=i,s+=i;for(e=0,n=d.length;e<n;++e)d[e]._options=a._resolveDataElementOptions(d[e],e),a.updateElement(d[e],e,t)},_updateRadius:function(){var t=this,e=t.chart,n=e.chartArea,i=e.options,a=Math.min(n.right-n.left,n.bottom-n.top);e.outerRadius=Math.max(a/2,0),e.innerRadius=Math.max(i.cutoutPercentage?e.outerRadius/100*i.cutoutPercentage:1,0),e.radiusLength=(e.outerRadius-e.innerRadius)/e.getVisibleDatasetCount(),t.outerRadius=e.outerRadius-e.radiusLength*t.index,t.innerRadius=t.outerRadius-e.radiusLength},updateElement:function(t,e,n){var i=this,a=i.chart,r=i.getDataset(),o=a.options,s=o.animation,l=a.scale,u=a.data.labels,d=l.xCenter,h=l.yCenter,c=o.startAngle,f=t.hidden?0:l.getDistanceFromCenterForValue(r.data[e]),g=i._starts[e],p=g+(t.hidden?0:i._angles[e]),m=s.animateScale?0:l.getDistanceFromCenterForValue(r.data[e]),v=t._options||{};V.extend(t,{_datasetIndex:i.index,_index:e,_scale:l,_model:{backgroundColor:v.backgroundColor,borderColor:v.borderColor,borderWidth:v.borderWidth,borderAlign:v.borderAlign,x:d,y:h,innerRadius:0,outerRadius:n?m:f,startAngle:n&&s.animateRotate?c:g,endAngle:n&&s.animateRotate?c:p,label:V.valueAtIndexOrDefault(u,e,u[e])}}),t.pivot()},countVisibleElements:function(){var t=this.getDataset(),e=this.getMeta(),n=0;return V.each(e.data,(function(e,i){isNaN(t.data[i])||e.hidden||n++})),n},setHoverStyle:function(t){var e=t._model,n=t._options,i=V.getHoverColor,a=V.valueOrDefault;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth},e.backgroundColor=a(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=a(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=a(n.hoverBorderWidth,n.borderWidth)},_computeAngle:function(t){var e=this,n=this.getMeta().count,i=e.getDataset(),a=e.getMeta();if(isNaN(i.data[t])||a.data[t].hidden)return 0;var r={chart:e.chart,dataIndex:t,dataset:i,datasetIndex:e.index};return Yt([e.chart.options.elements.arc.angle,2*Math.PI/n],r,t)}});z._set("pie",V.clone(z.doughnut)),z._set("pie",{cutoutPercentage:0});var Xt=Nt,Kt=V.valueOrDefault;z._set("radar",{spanGaps:!1,scale:{type:"radialLinear"},elements:{line:{fill:"start",tension:0}}});var Zt=nt.extend({datasetElementType:_t.Line,dataElementType:_t.Point,linkScales:V.noop,_datasetElementOptions:["backgroundColor","borderWidth","borderColor","borderCapStyle","borderDash","borderDashOffset","borderJoinStyle","fill"],_dataElementOptions:{backgroundColor:"pointBackgroundColor",borderColor:"pointBorderColor",borderWidth:"pointBorderWidth",hitRadius:"pointHitRadius",hoverBackgroundColor:"pointHoverBackgroundColor",hoverBorderColor:"pointHoverBorderColor",hoverBorderWidth:"pointHoverBorderWidth",hoverRadius:"pointHoverRadius",pointStyle:"pointStyle",radius:"pointRadius",rotation:"pointRotation"},_getIndexScaleId:function(){return this.chart.scale.id},_getValueScaleId:function(){return this.chart.scale.id},update:function(t){var e,n,i=this,a=i.getMeta(),r=a.dataset,o=a.data||[],s=i.chart.scale,l=i._config;for(void 0!==l.tension&&void 0===l.lineTension&&(l.lineTension=l.tension),r._scale=s,r._datasetIndex=i.index,r._children=o,r._loop=!0,r._model=i._resolveDatasetElementOptions(r),r.pivot(),e=0,n=o.length;e<n;++e)i.updateElement(o[e],e,t);for(i.updateBezierControlPoints(),e=0,n=o.length;e<n;++e)o[e].pivot()},updateElement:function(t,e,n){var i=this,a=t.custom||{},r=i.getDataset(),o=i.chart.scale,s=o.getPointPositionForValue(e,r.data[e]),l=i._resolveDataElementOptions(t,e),u=i.getMeta().dataset._model,d=n?o.xCenter:s.x,h=n?o.yCenter:s.y;t._scale=o,t._options=l,t._datasetIndex=i.index,t._index=e,t._model={x:d,y:h,skip:a.skip||isNaN(d)||isNaN(h),radius:l.radius,pointStyle:l.pointStyle,rotation:l.rotation,backgroundColor:l.backgroundColor,borderColor:l.borderColor,borderWidth:l.borderWidth,tension:Kt(a.tension,u?u.tension:0),hitRadius:l.hitRadius}},_resolveDatasetElementOptions:function(){var t=this,e=t._config,n=t.chart.options,i=nt.prototype._resolveDatasetElementOptions.apply(t,arguments);return i.spanGaps=Kt(e.spanGaps,n.spanGaps),i.tension=Kt(e.lineTension,n.elements.line.tension),i},updateBezierControlPoints:function(){var t,e,n,i,a=this.getMeta(),r=this.chart.chartArea,o=a.data||[];function s(t,e,n){return Math.max(Math.min(t,n),e)}for(a.dataset._model.spanGaps&&(o=o.filter((function(t){return!t._model.skip}))),t=0,e=o.length;t<e;++t)n=o[t]._model,i=V.splineCurve(V.previousItem(o,t,!0)._model,n,V.nextItem(o,t,!0)._model,n.tension),n.controlPointPreviousX=s(i.previous.x,r.left,r.right),n.controlPointPreviousY=s(i.previous.y,r.top,r.bottom),n.controlPointNextX=s(i.next.x,r.left,r.right),n.controlPointNextY=s(i.next.y,r.top,r.bottom)},setHoverStyle:function(t){var e=t._model,n=t._options,i=V.getHoverColor;t.$previousStyle={backgroundColor:e.backgroundColor,borderColor:e.borderColor,borderWidth:e.borderWidth,radius:e.radius},e.backgroundColor=Kt(n.hoverBackgroundColor,i(n.backgroundColor)),e.borderColor=Kt(n.hoverBorderColor,i(n.borderColor)),e.borderWidth=Kt(n.hoverBorderWidth,n.borderWidth),e.radius=Kt(n.hoverRadius,n.radius)}});z._set("scatter",{hover:{mode:"single"},scales:{xAxes:[{id:"x-axis-1",type:"linear",position:"bottom"}],yAxes:[{id:"y-axis-1",type:"linear",position:"left"}]},tooltips:{callbacks:{title:function(){return""},label:function(t){return"("+t.xLabel+", "+t.yLabel+")"}}}}),z._set("global",{datasets:{scatter:{showLine:!1}}});var $t={bar:Dt,bubble:Ft,doughnut:Nt,horizontalBar:Bt,line:Ut,polarArea:Gt,pie:Xt,radar:Zt,scatter:Ut};function Jt(t,e){return t.native?{x:t.x,y:t.y}:V.getRelativePosition(t,e)}function Qt(t,e){var n,i,a,r,o,s,l=t._getSortedVisibleDatasetMetas();for(i=0,r=l.length;i<r;++i)for(a=0,o=(n=l[i].data).length;a<o;++a)(s=n[a])._view.skip||e(s)}function te(t,e){var n=[];return Qt(t,(function(t){t.inRange(e.x,e.y)&&n.push(t)})),n}function ee(t,e,n,i){var a=Number.POSITIVE_INFINITY,r=[];return Qt(t,(function(t){if(!n||t.inRange(e.x,e.y)){var o=t.getCenterPoint(),s=i(e,o);s<a?(r=[t],a=s):s===a&&r.push(t)}})),r}function ne(t){var e=-1!==t.indexOf("x"),n=-1!==t.indexOf("y");return function(t,i){var a=e?Math.abs(t.x-i.x):0,r=n?Math.abs(t.y-i.y):0;return Math.sqrt(Math.pow(a,2)+Math.pow(r,2))}}function ie(t,e,n){var i=Jt(e,t);n.axis=n.axis||"x";var a=ne(n.axis),r=n.intersect?te(t,i):ee(t,i,!1,a),o=[];return r.length?(t._getSortedVisibleDatasetMetas().forEach((function(t){var e=t.data[r[0]._index];e&&!e._view.skip&&o.push(e)})),o):[]}var ae={modes:{single:function(t,e){var n=Jt(e,t),i=[];return Qt(t,(function(t){if(t.inRange(n.x,n.y))return i.push(t),i})),i.slice(0,1)},label:ie,index:ie,dataset:function(t,e,n){var i=Jt(e,t);n.axis=n.axis||"xy";var a=ne(n.axis),r=n.intersect?te(t,i):ee(t,i,!1,a);return r.length>0&&(r=t.getDatasetMeta(r[0]._datasetIndex).data),r},"x-axis":function(t,e){return ie(t,e,{intersect:!1})},point:function(t,e){return te(t,Jt(e,t))},nearest:function(t,e,n){var i=Jt(e,t);n.axis=n.axis||"xy";var a=ne(n.axis);return ee(t,i,n.intersect,a)},x:function(t,e,n){var i=Jt(e,t),a=[],r=!1;return Qt(t,(function(t){t.inXRange(i.x)&&a.push(t),t.inRange(i.x,i.y)&&(r=!0)})),n.intersect&&!r&&(a=[]),a},y:function(t,e,n){var i=Jt(e,t),a=[],r=!1;return Qt(t,(function(t){t.inYRange(i.y)&&a.push(t),t.inRange(i.x,i.y)&&(r=!0)})),n.intersect&&!r&&(a=[]),a}}},re=V.extend;function oe(t,e){return V.where(t,(function(t){return t.pos===e}))}function se(t,e){return t.sort((function(t,n){var i=e?n:t,a=e?t:n;return i.weight===a.weight?i.index-a.index:i.weight-a.weight}))}function le(t,e,n,i){return Math.max(t[n],e[n])+Math.max(t[i],e[i])}function ue(t,e,n){var i,a,r=n.box,o=t.maxPadding;if(n.size&&(t[n.pos]-=n.size),n.size=n.horizontal?r.height:r.width,t[n.pos]+=n.size,r.getPadding){var s=r.getPadding();o.top=Math.max(o.top,s.top),o.left=Math.max(o.left,s.left),o.bottom=Math.max(o.bottom,s.bottom),o.right=Math.max(o.right,s.right)}if(i=e.outerWidth-le(o,t,"left","right"),a=e.outerHeight-le(o,t,"top","bottom"),i!==t.w||a!==t.h)return t.w=i,t.h=a,n.horizontal?i!==t.w:a!==t.h}function de(t,e){var n=e.maxPadding;function i(t){var i={left:0,top:0,right:0,bottom:0};return t.forEach((function(t){i[t]=Math.max(e[t],n[t])})),i}return i(t?["left","right"]:["top","bottom"])}function he(t,e,n){var i,a,r,o,s,l,u=[];for(i=0,a=t.length;i<a;++i)(o=(r=t[i]).box).update(r.width||e.w,r.height||e.h,de(r.horizontal,e)),ue(e,n,r)&&(l=!0,u.length&&(s=!0)),o.fullWidth||u.push(r);return s&&he(u,e,n)||l}function ce(t,e,n){var i,a,r,o,s=n.padding,l=e.x,u=e.y;for(i=0,a=t.length;i<a;++i)o=(r=t[i]).box,r.horizontal?(o.left=o.fullWidth?s.left:e.left,o.right=o.fullWidth?n.outerWidth-s.right:e.left+e.w,o.top=u,o.bottom=u+o.height,o.width=o.right-o.left,u=o.bottom):(o.left=l,o.right=l+o.width,o.top=e.top,o.bottom=e.top+e.h,o.height=o.bottom-o.top,l=o.right);e.x=l,e.y=u}z._set("global",{layout:{padding:{top:0,right:0,bottom:0,left:0}}});var fe,ge={defaults:{},addBox:function(t,e){t.boxes||(t.boxes=[]),e.fullWidth=e.fullWidth||!1,e.position=e.position||"top",e.weight=e.weight||0,e._layers=e._layers||function(){return[{z:0,draw:function(){e.draw.apply(e,arguments)}}]},t.boxes.push(e)},removeBox:function(t,e){var n=t.boxes?t.boxes.indexOf(e):-1;-1!==n&&t.boxes.splice(n,1)},configure:function(t,e,n){for(var i,a=["fullWidth","position","weight"],r=a.length,o=0;o<r;++o)i=a[o],n.hasOwnProperty(i)&&(e[i]=n[i])},update:function(t,e,n){if(t){var i=t.options.layout||{},a=V.options.toPadding(i.padding),r=e-a.width,o=n-a.height,s=function(t){var e=function(t){var e,n,i,a=[];for(e=0,n=(t||[]).length;e<n;++e)i=t[e],a.push({index:e,box:i,pos:i.position,horizontal:i.isHorizontal(),weight:i.weight});return a}(t),n=se(oe(e,"left"),!0),i=se(oe(e,"right")),a=se(oe(e,"top"),!0),r=se(oe(e,"bottom"));return{leftAndTop:n.concat(a),rightAndBottom:i.concat(r),chartArea:oe(e,"chartArea"),vertical:n.concat(i),horizontal:a.concat(r)}}(t.boxes),l=s.vertical,u=s.horizontal,d=Object.freeze({outerWidth:e,outerHeight:n,padding:a,availableWidth:r,vBoxMaxWidth:r/2/l.length,hBoxMaxHeight:o/2}),h=re({maxPadding:re({},a),w:r,h:o,x:a.left,y:a.top},a);!function(t,e){var n,i,a;for(n=0,i=t.length;n<i;++n)(a=t[n]).width=a.horizontal?a.box.fullWidth&&e.availableWidth:e.vBoxMaxWidth,a.height=a.horizontal&&e.hBoxMaxHeight}(l.concat(u),d),he(l,h,d),he(u,h,d)&&he(l,h,d),function(t){var e=t.maxPadding;function n(n){var i=Math.max(e[n]-t[n],0);return t[n]+=i,i}t.y+=n("top"),t.x+=n("left"),n("right"),n("bottom")}(h),ce(s.leftAndTop,h,d),h.x+=h.w,h.y+=h.h,ce(s.rightAndBottom,h,d),t.chartArea={left:h.left,top:h.top,right:h.left+h.w,bottom:h.top+h.h},V.each(s.chartArea,(function(e){var n=e.box;re(n,t.chartArea),n.update(h.w,h.h)}))}}},pe=(fe=Object.freeze({__proto__:null,default:"@keyframes chartjs-render-animation{from{opacity:.99}to{opacity:1}}.chartjs-render-monitor{animation:chartjs-render-animation 1ms}.chartjs-size-monitor,.chartjs-size-monitor-expand,.chartjs-size-monitor-shrink{position:absolute;direction:ltr;left:0;top:0;right:0;bottom:0;overflow:hidden;pointer-events:none;visibility:hidden;z-index:-1}.chartjs-size-monitor-expand>div{position:absolute;width:1000000px;height:1000000px;left:0;top:0}.chartjs-size-monitor-shrink>div{position:absolute;width:200%;height:200%;left:0;top:0}"}))&&fe.default||fe,me="$chartjs",ve="chartjs-size-monitor",be="chartjs-render-monitor",xe="chartjs-render-animation",ye=["animationstart","webkitAnimationStart"],_e={touchstart:"mousedown",touchmove:"mousemove",touchend:"mouseup",pointerenter:"mouseenter",pointerdown:"mousedown",pointermove:"mousemove",pointerup:"mouseup",pointerleave:"mouseout",pointerout:"mouseout"};function ke(t,e){var n=V.getStyle(t,e),i=n&&n.match(/^(\d+)(\.\d+)?px$/);return i?Number(i[1]):void 0}var we=!!function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("e",null,e)}catch(t){}return t}()&&{passive:!0};function Me(t,e,n){t.addEventListener(e,n,we)}function Se(t,e,n){t.removeEventListener(e,n,we)}function Ce(t,e,n,i,a){return{type:t,chart:e,native:a||null,x:void 0!==n?n:null,y:void 0!==i?i:null}}function Pe(t){var e=document.createElement("div");return e.className=t||"",e}function Ae(t,e,n){var i,a,r,o,s=t[me]||(t[me]={}),l=s.resizer=function(t){var e=Pe(ve),n=Pe(ve+"-expand"),i=Pe(ve+"-shrink");n.appendChild(Pe()),i.appendChild(Pe()),e.appendChild(n),e.appendChild(i),e._reset=function(){n.scrollLeft=1e6,n.scrollTop=1e6,i.scrollLeft=1e6,i.scrollTop=1e6};var a=function(){e._reset(),t()};return Me(n,"scroll",a.bind(n,"expand")),Me(i,"scroll",a.bind(i,"shrink")),e}((i=function(){if(s.resizer){var i=n.options.maintainAspectRatio&&t.parentNode,a=i?i.clientWidth:0;e(Ce("resize",n)),i&&i.clientWidth<a&&n.canvas&&e(Ce("resize",n))}},r=!1,o=[],function(){o=Array.prototype.slice.call(arguments),a=a||this,r||(r=!0,V.requestAnimFrame.call(window,(function(){r=!1,i.apply(a,o)})))}));!function(t,e){var n=t[me]||(t[me]={}),i=n.renderProxy=function(t){t.animationName===xe&&e()};V.each(ye,(function(e){Me(t,e,i)})),n.reflow=!!t.offsetParent,t.classList.add(be)}(t,(function(){if(s.resizer){var e=t.parentNode;e&&e!==l.parentNode&&e.insertBefore(l,e.firstChild),l._reset()}}))}function De(t){var e=t[me]||{},n=e.resizer;delete e.resizer,function(t){var e=t[me]||{},n=e.renderProxy;n&&(V.each(ye,(function(e){Se(t,e,n)})),delete e.renderProxy),t.classList.remove(be)}(t),n&&n.parentNode&&n.parentNode.removeChild(n)}var Te={disableCSSInjection:!1,_enabled:"undefined"!=typeof window&&"undefined"!=typeof document,_ensureLoaded:function(t){if(!this.disableCSSInjection){var e=t.getRootNode?t.getRootNode():document;!function(t,e){var n=t[me]||(t[me]={});if(!n.containsStyles){n.containsStyles=!0,e="/* Chart.js */\n"+e;var i=document.createElement("style");i.setAttribute("type","text/css"),i.appendChild(document.createTextNode(e)),t.appendChild(i)}}(e.host?e:document.head,pe)}},acquireContext:function(t,e){"string"==typeof t?t=document.getElementById(t):t.length&&(t=t[0]),t&&t.canvas&&(t=t.canvas);var n=t&&t.getContext&&t.getContext("2d");return n&&n.canvas===t?(this._ensureLoaded(t),function(t,e){var n=t.style,i=t.getAttribute("height"),a=t.getAttribute("width");if(t[me]={initial:{height:i,width:a,style:{display:n.display,height:n.height,width:n.width}}},n.display=n.display||"block",null===a||""===a){var r=ke(t,"width");void 0!==r&&(t.width=r)}if(null===i||""===i)if(""===t.style.height)t.height=t.width/(e.options.aspectRatio||2);else{var o=ke(t,"height");void 0!==r&&(t.height=o)}}(t,e),n):null},releaseContext:function(t){var e=t.canvas;if(e[me]){var n=e[me].initial;["height","width"].forEach((function(t){var i=n[t];V.isNullOrUndef(i)?e.removeAttribute(t):e.setAttribute(t,i)})),V.each(n.style||{},(function(t,n){e.style[n]=t})),e.width=e.width,delete e[me]}},addEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=n[me]||(n[me]={});Me(i,e,(a.proxies||(a.proxies={}))[t.id+"_"+e]=function(e){n(function(t,e){var n=_e[t.type]||t.type,i=V.getRelativePosition(t,e);return Ce(n,e,i.x,i.y,t)}(e,t))})}else Ae(i,n,t)},removeEventListener:function(t,e,n){var i=t.canvas;if("resize"!==e){var a=((n[me]||{}).proxies||{})[t.id+"_"+e];a&&Se(i,e,a)}else De(i)}};V.addEvent=Me,V.removeEvent=Se;var Ie=Te._enabled?Te:{acquireContext:function(t){return t&&t.canvas&&(t=t.canvas),t&&t.getContext("2d")||null}},Fe=V.extend({initialize:function(){},acquireContext:function(){},releaseContext:function(){},addEventListener:function(){},removeEventListener:function(){}},Ie);z._set("global",{plugins:{}});var Le={_plugins:[],_cacheId:0,register:function(t){var e=this._plugins;[].concat(t).forEach((function(t){-1===e.indexOf(t)&&e.push(t)})),this._cacheId++},unregister:function(t){var e=this._plugins;[].concat(t).forEach((function(t){var n=e.indexOf(t);-1!==n&&e.splice(n,1)})),this._cacheId++},clear:function(){this._plugins=[],this._cacheId++},count:function(){return this._plugins.length},getAll:function(){return this._plugins},notify:function(t,e,n){var i,a,r,o,s,l=this.descriptors(t),u=l.length;for(i=0;i<u;++i)if("function"==typeof(s=(r=(a=l[i]).plugin)[e])&&((o=[t].concat(n||[])).push(a.options),!1===s.apply(r,o)))return!1;return!0},descriptors:function(t){var e=t.$plugins||(t.$plugins={});if(e.id===this._cacheId)return e.descriptors;var n=[],i=[],a=t&&t.config||{},r=a.options&&a.options.plugins||{};return this._plugins.concat(a.plugins||[]).forEach((function(t){if(-1===n.indexOf(t)){var e=t.id,a=r[e];!1!==a&&(!0===a&&(a=V.clone(z.global.plugins[e])),n.push(t),i.push({plugin:t,options:a||{}}))}})),e.descriptors=i,e.id=this._cacheId,i},_invalidate:function(t){delete t.$plugins}},Oe={constructors:{},defaults:{},registerScaleType:function(t,e,n){this.constructors[t]=e,this.defaults[t]=V.clone(n)},getScaleConstructor:function(t){return this.constructors.hasOwnProperty(t)?this.constructors[t]:void 0},getScaleDefaults:function(t){return this.defaults.hasOwnProperty(t)?V.merge({},[z.scale,this.defaults[t]]):{}},updateScaleDefaults:function(t,e){this.defaults.hasOwnProperty(t)&&(this.defaults[t]=V.extend(this.defaults[t],e))},addScalesToLayout:function(t){V.each(t.scales,(function(e){e.fullWidth=e.options.fullWidth,e.position=e.options.position,e.weight=e.options.weight,ge.addBox(t,e)}))}},Re=V.valueOrDefault,ze=V.rtl.getRtlAdapter;z._set("global",{tooltips:{enabled:!0,custom:null,mode:"nearest",position:"average",intersect:!0,backgroundColor:"rgba(0,0,0,0.8)",titleFontStyle:"bold",titleSpacing:2,titleMarginBottom:6,titleFontColor:"#fff",titleAlign:"left",bodySpacing:2,bodyFontColor:"#fff",bodyAlign:"left",footerFontStyle:"bold",footerSpacing:2,footerMarginTop:6,footerFontColor:"#fff",footerAlign:"left",yPadding:6,xPadding:6,caretPadding:2,caretSize:5,cornerRadius:6,multiKeyBackground:"#fff",displayColors:!0,borderColor:"rgba(0,0,0,0)",borderWidth:0,callbacks:{beforeTitle:V.noop,title:function(t,e){var n="",i=e.labels,a=i?i.length:0;if(t.length>0){var r=t[0];r.label?n=r.label:r.xLabel?n=r.xLabel:a>0&&r.index<a&&(n=i[r.index])}return n},afterTitle:V.noop,beforeBody:V.noop,beforeLabel:V.noop,label:function(t,e){var n=e.datasets[t.datasetIndex].label||"";return n&&(n+=": "),V.isNullOrUndef(t.value)?n+=t.yLabel:n+=t.value,n},labelColor:function(t,e){var n=e.getDatasetMeta(t.datasetIndex).data[t.index]._view;return{borderColor:n.borderColor,backgroundColor:n.backgroundColor}},labelTextColor:function(){return this._options.bodyFontColor},afterLabel:V.noop,afterBody:V.noop,beforeFooter:V.noop,footer:V.noop,afterFooter:V.noop}}});var Ne={average:function(t){if(!t.length)return!1;var e,n,i=0,a=0,r=0;for(e=0,n=t.length;e<n;++e){var o=t[e];if(o&&o.hasValue()){var s=o.tooltipPosition();i+=s.x,a+=s.y,++r}}return{x:i/r,y:a/r}},nearest:function(t,e){var n,i,a,r=e.x,o=e.y,s=Number.POSITIVE_INFINITY;for(n=0,i=t.length;n<i;++n){var l=t[n];if(l&&l.hasValue()){var u=l.getCenterPoint(),d=V.distanceBetweenPoints(e,u);d<s&&(s=d,a=l)}}if(a){var h=a.tooltipPosition();r=h.x,o=h.y}return{x:r,y:o}}};function Be(t,e){return e&&(V.isArray(e)?Array.prototype.push.apply(t,e):t.push(e)),t}function Ee(t){return("string"==typeof t||t instanceof String)&&t.indexOf("\n")>-1?t.split("\n"):t}function We(t){var e=z.global;return{xPadding:t.xPadding,yPadding:t.yPadding,xAlign:t.xAlign,yAlign:t.yAlign,rtl:t.rtl,textDirection:t.textDirection,bodyFontColor:t.bodyFontColor,_bodyFontFamily:Re(t.bodyFontFamily,e.defaultFontFamily),_bodyFontStyle:Re(t.bodyFontStyle,e.defaultFontStyle),_bodyAlign:t.bodyAlign,bodyFontSize:Re(t.bodyFontSize,e.defaultFontSize),bodySpacing:t.bodySpacing,titleFontColor:t.titleFontColor,_titleFontFamily:Re(t.titleFontFamily,e.defaultFontFamily),_titleFontStyle:Re(t.titleFontStyle,e.defaultFontStyle),titleFontSize:Re(t.titleFontSize,e.defaultFontSize),_titleAlign:t.titleAlign,titleSpacing:t.titleSpacing,titleMarginBottom:t.titleMarginBottom,footerFontColor:t.footerFontColor,_footerFontFamily:Re(t.footerFontFamily,e.defaultFontFamily),_footerFontStyle:Re(t.footerFontStyle,e.defaultFontStyle),footerFontSize:Re(t.footerFontSize,e.defaultFontSize),_footerAlign:t.footerAlign,footerSpacing:t.footerSpacing,footerMarginTop:t.footerMarginTop,caretSize:t.caretSize,cornerRadius:t.cornerRadius,backgroundColor:t.backgroundColor,opacity:0,legendColorBackground:t.multiKeyBackground,displayColors:t.displayColors,borderColor:t.borderColor,borderWidth:t.borderWidth}}function Ve(t,e){return"center"===e?t.x+t.width/2:"right"===e?t.x+t.width-t.xPadding:t.x+t.xPadding}function He(t){return Be([],Ee(t))}var je=X.extend({initialize:function(){this._model=We(this._options),this._lastActive=[]},getTitle:function(){var t=this,e=t._options,n=e.callbacks,i=n.beforeTitle.apply(t,arguments),a=n.title.apply(t,arguments),r=n.afterTitle.apply(t,arguments),o=[];return o=Be(o,Ee(i)),o=Be(o,Ee(a)),o=Be(o,Ee(r))},getBeforeBody:function(){return He(this._options.callbacks.beforeBody.apply(this,arguments))},getBody:function(t,e){var n=this,i=n._options.callbacks,a=[];return V.each(t,(function(t){var r={before:[],lines:[],after:[]};Be(r.before,Ee(i.beforeLabel.call(n,t,e))),Be(r.lines,i.label.call(n,t,e)),Be(r.after,Ee(i.afterLabel.call(n,t,e))),a.push(r)})),a},getAfterBody:function(){return He(this._options.callbacks.afterBody.apply(this,arguments))},getFooter:function(){var t=this,e=t._options.callbacks,n=e.beforeFooter.apply(t,arguments),i=e.footer.apply(t,arguments),a=e.afterFooter.apply(t,arguments),r=[];return r=Be(r,Ee(n)),r=Be(r,Ee(i)),r=Be(r,Ee(a))},update:function(t){var e,n,i,a,r,o,s,l,u,d,h=this,c=h._options,f=h._model,g=h._model=We(c),p=h._active,m=h._data,v={xAlign:f.xAlign,yAlign:f.yAlign},b={x:f.x,y:f.y},x={width:f.width,height:f.height},y={x:f.caretX,y:f.caretY};if(p.length){g.opacity=1;var _=[],k=[];y=Ne[c.position].call(h,p,h._eventPosition);var w=[];for(e=0,n=p.length;e<n;++e)w.push((i=p[e],a=void 0,r=void 0,o=void 0,s=void 0,l=void 0,u=void 0,d=void 0,a=i._xScale,r=i._yScale||i._scale,o=i._index,s=i._datasetIndex,l=i._chart.getDatasetMeta(s).controller,u=l._getIndexScale(),d=l._getValueScale(),{xLabel:a?a.getLabelForIndex(o,s):"",yLabel:r?r.getLabelForIndex(o,s):"",label:u?""+u.getLabelForIndex(o,s):"",value:d?""+d.getLabelForIndex(o,s):"",index:o,datasetIndex:s,x:i._model.x,y:i._model.y}));c.filter&&(w=w.filter((function(t){return c.filter(t,m)}))),c.itemSort&&(w=w.sort((function(t,e){return c.itemSort(t,e,m)}))),V.each(w,(function(t){_.push(c.callbacks.labelColor.call(h,t,h._chart)),k.push(c.callbacks.labelTextColor.call(h,t,h._chart))})),g.title=h.getTitle(w,m),g.beforeBody=h.getBeforeBody(w,m),g.body=h.getBody(w,m),g.afterBody=h.getAfterBody(w,m),g.footer=h.getFooter(w,m),g.x=y.x,g.y=y.y,g.caretPadding=c.caretPadding,g.labelColors=_,g.labelTextColors=k,g.dataPoints=w,x=function(t,e){var n=t._chart.ctx,i=2*e.yPadding,a=0,r=e.body,o=r.reduce((function(t,e){return t+e.before.length+e.lines.length+e.after.length}),0);o+=e.beforeBody.length+e.afterBody.length;var s=e.title.length,l=e.footer.length,u=e.titleFontSize,d=e.bodyFontSize,h=e.footerFontSize;i+=s*u,i+=s?(s-1)*e.titleSpacing:0,i+=s?e.titleMarginBottom:0,i+=o*d,i+=o?(o-1)*e.bodySpacing:0,i+=l?e.footerMarginTop:0,i+=l*h,i+=l?(l-1)*e.footerSpacing:0;var c=0,f=function(t){a=Math.max(a,n.measureText(t).width+c)};return n.font=V.fontString(u,e._titleFontStyle,e._titleFontFamily),V.each(e.title,f),n.font=V.fontString(d,e._bodyFontStyle,e._bodyFontFamily),V.each(e.beforeBody.concat(e.afterBody),f),c=e.displayColors?d+2:0,V.each(r,(function(t){V.each(t.before,f),V.each(t.lines,f),V.each(t.after,f)})),c=0,n.font=V.fontString(h,e._footerFontStyle,e._footerFontFamily),V.each(e.footer,f),{width:a+=2*e.xPadding,height:i}}(this,g),b=function(t,e,n,i){var a=t.x,r=t.y,o=t.caretSize,s=t.caretPadding,l=t.cornerRadius,u=n.xAlign,d=n.yAlign,h=o+s,c=l+s;return"right"===u?a-=e.width:"center"===u&&((a-=e.width/2)+e.width>i.width&&(a=i.width-e.width),a<0&&(a=0)),"top"===d?r+=h:r-="bottom"===d?e.height+h:e.height/2,"center"===d?"left"===u?a+=h:"right"===u&&(a-=h):"left"===u?a-=c:"right"===u&&(a+=c),{x:a,y:r}}(g,x,v=function(t,e){var n,i,a,r,o,s=t._model,l=t._chart,u=t._chart.chartArea,d="center",h="center";s.y<e.height?h="top":s.y>l.height-e.height&&(h="bottom");var c=(u.left+u.right)/2,f=(u.top+u.bottom)/2;"center"===h?(n=function(t){return t<=c},i=function(t){return t>c}):(n=function(t){return t<=e.width/2},i=function(t){return t>=l.width-e.width/2}),a=function(t){return t+e.width+s.caretSize+s.caretPadding>l.width},r=function(t){return t-e.width-s.caretSize-s.caretPadding<0},o=function(t){return t<=f?"top":"bottom"},n(s.x)?(d="left",a(s.x)&&(d="center",h=o(s.y))):i(s.x)&&(d="right",r(s.x)&&(d="center",h=o(s.y)));var g=t._options;return{xAlign:g.xAlign?g.xAlign:d,yAlign:g.yAlign?g.yAlign:h}}(this,x),h._chart)}else g.opacity=0;return g.xAlign=v.xAlign,g.yAlign=v.yAlign,g.x=b.x,g.y=b.y,g.width=x.width,g.height=x.height,g.caretX=y.x,g.caretY=y.y,h._model=g,t&&c.custom&&c.custom.call(h,g),h},drawCaret:function(t,e){var n=this._chart.ctx,i=this._view,a=this.getCaretPosition(t,e,i);n.lineTo(a.x1,a.y1),n.lineTo(a.x2,a.y2),n.lineTo(a.x3,a.y3)},getCaretPosition:function(t,e,n){var i,a,r,o,s,l,u=n.caretSize,d=n.cornerRadius,h=n.xAlign,c=n.yAlign,f=t.x,g=t.y,p=e.width,m=e.height;if("center"===c)s=g+m/2,"left"===h?(a=(i=f)-u,r=i,o=s+u,l=s-u):(a=(i=f+p)+u,r=i,o=s-u,l=s+u);else if("left"===h?(i=(a=f+d+u)-u,r=a+u):"right"===h?(i=(a=f+p-d-u)-u,r=a+u):(i=(a=n.caretX)-u,r=a+u),"top"===c)s=(o=g)-u,l=o;else{s=(o=g+m)+u,l=o;var v=r;r=i,i=v}return{x1:i,x2:a,x3:r,y1:o,y2:s,y3:l}},drawTitle:function(t,e,n){var i,a,r,o=e.title,s=o.length;if(s){var l=ze(e.rtl,e.x,e.width);for(t.x=Ve(e,e._titleAlign),n.textAlign=l.textAlign(e._titleAlign),n.textBaseline="middle",i=e.titleFontSize,a=e.titleSpacing,n.fillStyle=e.titleFontColor,n.font=V.fontString(i,e._titleFontStyle,e._titleFontFamily),r=0;r<s;++r)n.fillText(o[r],l.x(t.x),t.y+i/2),t.y+=i+a,r+1===s&&(t.y+=e.titleMarginBottom-a)}},drawBody:function(t,e,n){var i,a,r,o,s,l,u,d,h=e.bodyFontSize,c=e.bodySpacing,f=e._bodyAlign,g=e.body,p=e.displayColors,m=0,v=p?Ve(e,"left"):0,b=ze(e.rtl,e.x,e.width),x=function(e){n.fillText(e,b.x(t.x+m),t.y+h/2),t.y+=h+c},y=b.textAlign(f);for(n.textAlign=f,n.textBaseline="middle",n.font=V.fontString(h,e._bodyFontStyle,e._bodyFontFamily),t.x=Ve(e,y),n.fillStyle=e.bodyFontColor,V.each(e.beforeBody,x),m=p&&"right"!==y?"center"===f?h/2+1:h+2:0,s=0,u=g.length;s<u;++s){for(i=g[s],a=e.labelTextColors[s],r=e.labelColors[s],n.fillStyle=a,V.each(i.before,x),l=0,d=(o=i.lines).length;l<d;++l){if(p){var _=b.x(v);n.fillStyle=e.legendColorBackground,n.fillRect(b.leftForLtr(_,h),t.y,h,h),n.lineWidth=1,n.strokeStyle=r.borderColor,n.strokeRect(b.leftForLtr(_,h),t.y,h,h),n.fillStyle=r.backgroundColor,n.fillRect(b.leftForLtr(b.xPlus(_,1),h-2),t.y+1,h-2,h-2),n.fillStyle=a}x(o[l])}V.each(i.after,x)}m=0,V.each(e.afterBody,x),t.y-=c},drawFooter:function(t,e,n){var i,a,r=e.footer,o=r.length;if(o){var s=ze(e.rtl,e.x,e.width);for(t.x=Ve(e,e._footerAlign),t.y+=e.footerMarginTop,n.textAlign=s.textAlign(e._footerAlign),n.textBaseline="middle",i=e.footerFontSize,n.fillStyle=e.footerFontColor,n.font=V.fontString(i,e._footerFontStyle,e._footerFontFamily),a=0;a<o;++a)n.fillText(r[a],s.x(t.x),t.y+i/2),t.y+=i+e.footerSpacing}},drawBackground:function(t,e,n,i){n.fillStyle=e.backgroundColor,n.strokeStyle=e.borderColor,n.lineWidth=e.borderWidth;var a=e.xAlign,r=e.yAlign,o=t.x,s=t.y,l=i.width,u=i.height,d=e.cornerRadius;n.beginPath(),n.moveTo(o+d,s),"top"===r&&this.drawCaret(t,i),n.lineTo(o+l-d,s),n.quadraticCurveTo(o+l,s,o+l,s+d),"center"===r&&"right"===a&&this.drawCaret(t,i),n.lineTo(o+l,s+u-d),n.quadraticCurveTo(o+l,s+u,o+l-d,s+u),"bottom"===r&&this.drawCaret(t,i),n.lineTo(o+d,s+u),n.quadraticCurveTo(o,s+u,o,s+u-d),"center"===r&&"left"===a&&this.drawCaret(t,i),n.lineTo(o,s+d),n.quadraticCurveTo(o,s,o+d,s),n.closePath(),n.fill(),e.borderWidth>0&&n.stroke()},draw:function(){var t=this._chart.ctx,e=this._view;if(0!==e.opacity){var n={width:e.width,height:e.height},i={x:e.x,y:e.y},a=Math.abs(e.opacity<.001)?0:e.opacity,r=e.title.length||e.beforeBody.length||e.body.length||e.afterBody.length||e.footer.length;this._options.enabled&&r&&(t.save(),t.globalAlpha=a,this.drawBackground(i,e,t,n),i.y+=e.yPadding,V.rtl.overrideTextDirection(t,e.textDirection),this.drawTitle(i,e,t),this.drawBody(i,e,t),this.drawFooter(i,e,t),V.rtl.restoreTextDirection(t,e.textDirection),t.restore())}},handleEvent:function(t){var e,n=this,i=n._options;return n._lastActive=n._lastActive||[],"mouseout"===t.type?n._active=[]:(n._active=n._chart.getElementsAtEventForMode(t,i.mode,i),i.reverse&&n._active.reverse()),(e=!V.arrayEquals(n._active,n._lastActive))&&(n._lastActive=n._active,(i.enabled||i.custom)&&(n._eventPosition={x:t.x,y:t.y},n.update(!0),n.pivot())),e}}),qe=Ne,Ue=je;Ue.positioners=qe;var Ye=V.valueOrDefault;function Ge(){return V.merge({},[].slice.call(arguments),{merger:function(t,e,n,i){if("xAxes"===t||"yAxes"===t){var a,r,o,s=n[t].length;for(e[t]||(e[t]=[]),a=0;a<s;++a)o=n[t][a],r=Ye(o.type,"xAxes"===t?"category":"linear"),a>=e[t].length&&e[t].push({}),!e[t][a].type||o.type&&o.type!==e[t][a].type?V.merge(e[t][a],[Oe.getScaleDefaults(r),o]):V.merge(e[t][a],o)}else V._merger(t,e,n,i)}})}function Xe(){return V.merge({},[].slice.call(arguments),{merger:function(t,e,n,i){var a=e[t]||{},r=n[t];"scales"===t?e[t]=Ge(a,r):"scale"===t?e[t]=V.merge(a,[Oe.getScaleDefaults(r.type),r]):V._merger(t,e,n,i)}})}function Ke(t){var e=t.options;V.each(t.scales,(function(e){ge.removeBox(t,e)})),e=Xe(z.global,z[t.config.type],e),t.options=t.config.options=e,t.ensureScalesHaveIDs(),t.buildOrUpdateScales(),t.tooltip._options=e.tooltips,t.tooltip.initialize()}function Ze(t,e,n){var i,a=function(t){return t.id===i};do{i=e+n++}while(V.findIndex(t,a)>=0);return i}function $e(t){return"top"===t||"bottom"===t}function Je(t,e){return function(n,i){return n[t]===i[t]?n[e]-i[e]:n[t]-i[t]}}z._set("global",{elements:{},events:["mousemove","mouseout","click","touchstart","touchmove"],hover:{onHover:null,mode:"nearest",intersect:!0,animationDuration:400},onClick:null,maintainAspectRatio:!0,responsive:!0,responsiveAnimationDuration:0});var Qe=function(t,e){return this.construct(t,e),this};V.extend(Qe.prototype,{construct:function(t,e){var n=this;e=function(t){var e=(t=t||{}).data=t.data||{};return e.datasets=e.datasets||[],e.labels=e.labels||[],t.options=Xe(z.global,z[t.type],t.options||{}),t}(e);var i=Fe.acquireContext(t,e),a=i&&i.canvas,r=a&&a.height,o=a&&a.width;n.id=V.uid(),n.ctx=i,n.canvas=a,n.config=e,n.width=o,n.height=r,n.aspectRatio=r?o/r:null,n.options=e.options,n._bufferedRender=!1,n._layers=[],n.chart=n,n.controller=n,Qe.instances[n.id]=n,Object.defineProperty(n,"data",{get:function(){return n.config.data},set:function(t){n.config.data=t}}),i&&a?(n.initialize(),n.update()):console.error("Failed to create chart: can't acquire context from the given item")},initialize:function(){var t=this;return Le.notify(t,"beforeInit"),V.retinaScale(t,t.options.devicePixelRatio),t.bindEvents(),t.options.responsive&&t.resize(!0),t.initToolTip(),Le.notify(t,"afterInit"),t},clear:function(){return V.canvas.clear(this),this},stop:function(){return $.cancelAnimation(this),this},resize:function(t){var e=this,n=e.options,i=e.canvas,a=n.maintainAspectRatio&&e.aspectRatio||null,r=Math.max(0,Math.floor(V.getMaximumWidth(i))),o=Math.max(0,Math.floor(a?r/a:V.getMaximumHeight(i)));if((e.width!==r||e.height!==o)&&(i.width=e.width=r,i.height=e.height=o,i.style.width=r+"px",i.style.height=o+"px",V.retinaScale(e,n.devicePixelRatio),!t)){var s={width:r,height:o};Le.notify(e,"resize",[s]),n.onResize&&n.onResize(e,s),e.stop(),e.update({duration:n.responsiveAnimationDuration})}},ensureScalesHaveIDs:function(){var t=this.options,e=t.scales||{},n=t.scale;V.each(e.xAxes,(function(t,n){t.id||(t.id=Ze(e.xAxes,"x-axis-",n))})),V.each(e.yAxes,(function(t,n){t.id||(t.id=Ze(e.yAxes,"y-axis-",n))})),n&&(n.id=n.id||"scale")},buildOrUpdateScales:function(){var t=this,e=t.options,n=t.scales||{},i=[],a=Object.keys(n).reduce((function(t,e){return t[e]=!1,t}),{});e.scales&&(i=i.concat((e.scales.xAxes||[]).map((function(t){return{options:t,dtype:"category",dposition:"bottom"}})),(e.scales.yAxes||[]).map((function(t){return{options:t,dtype:"linear",dposition:"left"}})))),e.scale&&i.push({options:e.scale,dtype:"radialLinear",isDefault:!0,dposition:"chartArea"}),V.each(i,(function(e){var i=e.options,r=i.id,o=Ye(i.type,e.dtype);$e(i.position)!==$e(e.dposition)&&(i.position=e.dposition),a[r]=!0;var s=null;if(r in n&&n[r].type===o)(s=n[r]).options=i,s.ctx=t.ctx,s.chart=t;else{var l=Oe.getScaleConstructor(o);if(!l)return;s=new l({id:r,type:o,options:i,ctx:t.ctx,chart:t}),n[s.id]=s}s.mergeTicksOptions(),e.isDefault&&(t.scale=s)})),V.each(a,(function(t,e){t||delete n[e]})),t.scales=n,Oe.addScalesToLayout(this)},buildOrUpdateControllers:function(){var t,e,n=this,i=[],a=n.data.datasets;for(t=0,e=a.length;t<e;t++){var r=a[t],o=n.getDatasetMeta(t),s=r.type||n.config.type;if(o.type&&o.type!==s&&(n.destroyDatasetMeta(t),o=n.getDatasetMeta(t)),o.type=s,o.order=r.order||0,o.index=t,o.controller)o.controller.updateIndex(t),o.controller.linkScales();else{var l=$t[o.type];if(void 0===l)throw new Error('"'+o.type+'" is not a chart type.');o.controller=new l(n,t),i.push(o.controller)}}return i},resetElements:function(){var t=this;V.each(t.data.datasets,(function(e,n){t.getDatasetMeta(n).controller.reset()}),t)},reset:function(){this.resetElements(),this.tooltip.initialize()},update:function(t){var e,n,i=this;if(t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]}),Ke(i),Le._invalidate(i),!1!==Le.notify(i,"beforeUpdate")){i.tooltip._data=i.data;var a=i.buildOrUpdateControllers();for(e=0,n=i.data.datasets.length;e<n;e++)i.getDatasetMeta(e).controller.buildOrUpdateElements();i.updateLayout(),i.options.animation&&i.options.animation.duration&&V.each(a,(function(t){t.reset()})),i.updateDatasets(),i.tooltip.initialize(),i.lastActive=[],Le.notify(i,"afterUpdate"),i._layers.sort(Je("z","_idx")),i._bufferedRender?i._bufferedRequest={duration:t.duration,easing:t.easing,lazy:t.lazy}:i.render(t)}},updateLayout:function(){var t=this;!1!==Le.notify(t,"beforeLayout")&&(ge.update(this,this.width,this.height),t._layers=[],V.each(t.boxes,(function(e){e._configure&&e._configure(),t._layers.push.apply(t._layers,e._layers())}),t),t._layers.forEach((function(t,e){t._idx=e})),Le.notify(t,"afterScaleUpdate"),Le.notify(t,"afterLayout"))},updateDatasets:function(){if(!1!==Le.notify(this,"beforeDatasetsUpdate")){for(var t=0,e=this.data.datasets.length;t<e;++t)this.updateDataset(t);Le.notify(this,"afterDatasetsUpdate")}},updateDataset:function(t){var e=this.getDatasetMeta(t),n={meta:e,index:t};!1!==Le.notify(this,"beforeDatasetUpdate",[n])&&(e.controller._update(),Le.notify(this,"afterDatasetUpdate",[n]))},render:function(t){var e=this;t&&"object"==typeof t||(t={duration:t,lazy:arguments[1]});var n=e.options.animation,i=Ye(t.duration,n&&n.duration),a=t.lazy;if(!1!==Le.notify(e,"beforeRender")){var r=function(t){Le.notify(e,"afterRender"),V.callback(n&&n.onComplete,[t],e)};if(n&&i){var o=new Z({numSteps:i/16.66,easing:t.easing||n.easing,render:function(t,e){var n=V.easing.effects[e.easing],i=e.currentStep,a=i/e.numSteps;t.draw(n(a),a,i)},onAnimationProgress:n.onProgress,onAnimationComplete:r});$.addAnimation(e,o,i,a)}else e.draw(),r(new Z({numSteps:0,chart:e}));return e}},draw:function(t){var e,n,i=this;if(i.clear(),V.isNullOrUndef(t)&&(t=1),i.transition(t),!(i.width<=0||i.height<=0)&&!1!==Le.notify(i,"beforeDraw",[t])){for(n=i._layers,e=0;e<n.length&&n[e].z<=0;++e)n[e].draw(i.chartArea);for(i.drawDatasets(t);e<n.length;++e)n[e].draw(i.chartArea);i._drawTooltip(t),Le.notify(i,"afterDraw",[t])}},transition:function(t){for(var e=0,n=(this.data.datasets||[]).length;e<n;++e)this.isDatasetVisible(e)&&this.getDatasetMeta(e).controller.transition(t);this.tooltip.transition(t)},_getSortedDatasetMetas:function(t){var e,n,i=[];for(e=0,n=(this.data.datasets||[]).length;e<n;++e)t&&!this.isDatasetVisible(e)||i.push(this.getDatasetMeta(e));return i.sort(Je("order","index")),i},_getSortedVisibleDatasetMetas:function(){return this._getSortedDatasetMetas(!0)},drawDatasets:function(t){var e,n;if(!1!==Le.notify(this,"beforeDatasetsDraw",[t])){for(n=(e=this._getSortedVisibleDatasetMetas()).length-1;n>=0;--n)this.drawDataset(e[n],t);Le.notify(this,"afterDatasetsDraw",[t])}},drawDataset:function(t,e){var n={meta:t,index:t.index,easingValue:e};!1!==Le.notify(this,"beforeDatasetDraw",[n])&&(t.controller.draw(e),Le.notify(this,"afterDatasetDraw",[n]))},_drawTooltip:function(t){var e=this.tooltip,n={tooltip:e,easingValue:t};!1!==Le.notify(this,"beforeTooltipDraw",[n])&&(e.draw(),Le.notify(this,"afterTooltipDraw",[n]))},getElementAtEvent:function(t){return ae.modes.single(this,t)},getElementsAtEvent:function(t){return ae.modes.label(this,t,{intersect:!0})},getElementsAtXAxis:function(t){return ae.modes["x-axis"](this,t,{intersect:!0})},getElementsAtEventForMode:function(t,e,n){var i=ae.modes[e];return"function"==typeof i?i(this,t,n):[]},getDatasetAtEvent:function(t){return ae.modes.dataset(this,t,{intersect:!0})},getDatasetMeta:function(t){var e=this.data.datasets[t];e._meta||(e._meta={});var n=e._meta[this.id];return n||(n=e._meta[this.id]={type:null,data:[],dataset:null,controller:null,hidden:null,xAxisID:null,yAxisID:null,order:e.order||0,index:t}),n},getVisibleDatasetCount:function(){for(var t=0,e=0,n=this.data.datasets.length;e<n;++e)this.isDatasetVisible(e)&&t++;return t},isDatasetVisible:function(t){var e=this.getDatasetMeta(t);return"boolean"==typeof e.hidden?!e.hidden:!this.data.datasets[t].hidden},generateLegend:function(){return this.options.legendCallback(this)},destroyDatasetMeta:function(t){var e=this.id,n=this.data.datasets[t],i=n._meta&&n._meta[e];i&&(i.controller.destroy(),delete n._meta[e])},destroy:function(){var t,e,n=this,i=n.canvas;for(n.stop(),t=0,e=n.data.datasets.length;t<e;++t)n.destroyDatasetMeta(t);i&&(n.unbindEvents(),V.canvas.clear(n),Fe.releaseContext(n.ctx),n.canvas=null,n.ctx=null),Le.notify(n,"destroy"),delete Qe.instances[n.id]},toBase64Image:function(){return this.canvas.toDataURL.apply(this.canvas,arguments)},initToolTip:function(){var t=this;t.tooltip=new Ue({_chart:t,_chartInstance:t,_data:t.data,_options:t.options.tooltips},t)},bindEvents:function(){var t=this,e=t._listeners={},n=function(){t.eventHandler.apply(t,arguments)};V.each(t.options.events,(function(i){Fe.addEventListener(t,i,n),e[i]=n})),t.options.responsive&&(n=function(){t.resize()},Fe.addEventListener(t,"resize",n),e.resize=n)},unbindEvents:function(){var t=this,e=t._listeners;e&&(delete t._listeners,V.each(e,(function(e,n){Fe.removeEventListener(t,n,e)})))},updateHoverStyle:function(t,e,n){var i,a,r,o=n?"set":"remove";for(a=0,r=t.length;a<r;++a)(i=t[a])&&this.getDatasetMeta(i._datasetIndex).controller[o+"HoverStyle"](i);"dataset"===e&&this.getDatasetMeta(t[0]._datasetIndex).controller["_"+o+"DatasetHoverStyle"]()},eventHandler:function(t){var e=this,n=e.tooltip;if(!1!==Le.notify(e,"beforeEvent",[t])){e._bufferedRender=!0,e._bufferedRequest=null;var i=e.handleEvent(t);n&&(i=n._start?n.handleEvent(t):i|n.handleEvent(t)),Le.notify(e,"afterEvent",[t]);var a=e._bufferedRequest;return a?e.render(a):i&&!e.animating&&(e.stop(),e.render({duration:e.options.hover.animationDuration,lazy:!0})),e._bufferedRender=!1,e._bufferedRequest=null,e}},handleEvent:function(t){var e,n=this,i=n.options||{},a=i.hover;return n.lastActive=n.lastActive||[],"mouseout"===t.type?n.active=[]:n.active=n.getElementsAtEventForMode(t,a.mode,a),V.callback(i.onHover||i.hover.onHover,[t.native,n.active],n),"mouseup"!==t.type&&"click"!==t.type||i.onClick&&i.onClick.call(n,t.native,n.active),n.lastActive.length&&n.updateHoverStyle(n.lastActive,a.mode,!1),n.active.length&&a.mode&&n.updateHoverStyle(n.active,a.mode,!0),e=!V.arrayEquals(n.active,n.lastActive),n.lastActive=n.active,e}}),Qe.instances={};var tn=Qe;Qe.Controller=Qe,Qe.types={},V.configMerge=Xe,V.scaleMerge=Ge;function en(){throw new Error("This method is not implemented: either no adapter can be found or an incomplete integration was provided.")}function nn(t){this.options=t||{}}V.extend(nn.prototype,{formats:en,parse:en,format:en,add:en,diff:en,startOf:en,endOf:en,_create:function(t){return t}}),nn.override=function(t){V.extend(nn.prototype,t)};var an={_date:nn},rn={formatters:{values:function(t){return V.isArray(t)?t:""+t},linear:function(t,e,n){var i=n.length>3?n[2]-n[1]:n[1]-n[0];Math.abs(i)>1&&t!==Math.floor(t)&&(i=t-Math.floor(t));var a=V.log10(Math.abs(i)),r="";if(0!==t)if(Math.max(Math.abs(n[0]),Math.abs(n[n.length-1]))<1e-4){var o=V.log10(Math.abs(t)),s=Math.floor(o)-Math.floor(a);s=Math.max(Math.min(s,20),0),r=t.toExponential(s)}else{var l=-1*Math.floor(a);l=Math.max(Math.min(l,20),0),r=t.toFixed(l)}else r="0";return r},logarithmic:function(t,e,n){var i=t/Math.pow(10,Math.floor(V.log10(t)));return 0===t?"0":1===i||2===i||5===i||0===e||e===n.length-1?t.toExponential():""}}},on=V.isArray,sn=V.isNullOrUndef,ln=V.valueOrDefault,un=V.valueAtIndexOrDefault;function dn(t,e,n){var i,a=t.getTicks().length,r=Math.min(e,a-1),o=t.getPixelForTick(r),s=t._startPixel,l=t._endPixel;if(!(n&&(i=1===a?Math.max(o-s,l-o):0===e?(t.getPixelForTick(1)-o)/2:(o-t.getPixelForTick(r-1))/2,(o+=r<e?i:-i)<s-1e-6||o>l+1e-6)))return o}function hn(t,e,n,i){var a,r,o,s,l,u,d,h,c,f,g,p,m,v=n.length,b=[],x=[],y=[];for(a=0;a<v;++a){if(s=n[a].label,l=n[a].major?e.major:e.minor,t.font=u=l.string,d=i[u]=i[u]||{data:{},gc:[]},h=l.lineHeight,c=f=0,sn(s)||on(s)){if(on(s))for(r=0,o=s.length;r<o;++r)g=s[r],sn(g)||on(g)||(c=V.measureText(t,d.data,d.gc,c,g),f+=h)}else c=V.measureText(t,d.data,d.gc,c,s),f=h;b.push(c),x.push(f),y.push(h/2)}function _(t){return{width:b[t]||0,height:x[t]||0,offset:y[t]||0}}return function(t,e){V.each(t,(function(t){var n,i=t.gc,a=i.length/2;if(a>e){for(n=0;n<a;++n)delete t.data[i[n]];i.splice(0,a)}}))}(i,v),p=b.indexOf(Math.max.apply(null,b)),m=x.indexOf(Math.max.apply(null,x)),{first:_(0),last:_(v-1),widest:_(p),highest:_(m)}}function cn(t){return t.drawTicks?t.tickMarkLength:0}function fn(t){var e,n;return t.display?(e=V.options._parseFont(t),n=V.options.toPadding(t.padding),e.lineHeight+n.height):0}function gn(t,e){return V.extend(V.options._parseFont({fontFamily:ln(e.fontFamily,t.fontFamily),fontSize:ln(e.fontSize,t.fontSize),fontStyle:ln(e.fontStyle,t.fontStyle),lineHeight:ln(e.lineHeight,t.lineHeight)}),{color:V.options.resolve([e.fontColor,t.fontColor,z.global.defaultFontColor])})}function pn(t){var e=gn(t,t.minor);return{minor:e,major:t.major.enabled?gn(t,t.major):e}}function mn(t){var e,n,i,a=[];for(n=0,i=t.length;n<i;++n)void 0!==(e=t[n])._index&&a.push(e);return a}function vn(t,e,n,i){var a,r,o,s,l=ln(n,0),u=Math.min(ln(i,t.length),t.length),d=0;for(e=Math.ceil(e),i&&(e=(a=i-n)/Math.floor(a/e)),s=l;s<0;)d++,s=Math.round(l+d*e);for(r=Math.max(l,0);r<u;r++)o=t[r],r===s?(o._index=r,d++,s=Math.round(l+d*e)):delete o.label}z._set("scale",{display:!0,position:"left",offset:!1,gridLines:{display:!0,color:"rgba(0,0,0,0.1)",lineWidth:1,drawBorder:!0,drawOnChartArea:!0,drawTicks:!0,tickMarkLength:10,zeroLineWidth:1,zeroLineColor:"rgba(0,0,0,0.25)",zeroLineBorderDash:[],zeroLineBorderDashOffset:0,offsetGridLines:!1,borderDash:[],borderDashOffset:0},scaleLabel:{display:!1,labelString:"",padding:{top:4,bottom:4}},ticks:{beginAtZero:!1,minRotation:0,maxRotation:50,mirror:!1,padding:0,reverse:!1,display:!0,autoSkip:!0,autoSkipPadding:0,labelOffset:0,callback:rn.formatters.values,minor:{},major:{}}});var bn=X.extend({zeroLineIndex:0,getPadding:function(){return{left:this.paddingLeft||0,top:this.paddingTop||0,right:this.paddingRight||0,bottom:this.paddingBottom||0}},getTicks:function(){return this._ticks},_getLabels:function(){var t=this.chart.data;return this.options.labels||(this.isHorizontal()?t.xLabels:t.yLabels)||t.labels},mergeTicksOptions:function(){},beforeUpdate:function(){V.callback(this.options.beforeUpdate,[this])},update:function(t,e,n){var i,a,r,o,s,l=this,u=l.options.ticks,d=u.sampleSize;if(l.beforeUpdate(),l.maxWidth=t,l.maxHeight=e,l.margins=V.extend({left:0,right:0,top:0,bottom:0},n),l._ticks=null,l.ticks=null,l._labelSizes=null,l._maxLabelLines=0,l.longestLabelWidth=0,l.longestTextCache=l.longestTextCache||{},l._gridLineItems=null,l._labelItems=null,l.beforeSetDimensions(),l.setDimensions(),l.afterSetDimensions(),l.beforeDataLimits(),l.determineDataLimits(),l.afterDataLimits(),l.beforeBuildTicks(),o=l.buildTicks()||[],(!(o=l.afterBuildTicks(o)||o)||!o.length)&&l.ticks)for(o=[],i=0,a=l.ticks.length;i<a;++i)o.push({value:l.ticks[i],major:!1});return l._ticks=o,s=d<o.length,r=l._convertTicksToLabels(s?function(t,e){for(var n=[],i=t.length/e,a=0,r=t.length;a<r;a+=i)n.push(t[Math.floor(a)]);return n}(o,d):o),l._configure(),l.beforeCalculateTickRotation(),l.calculateTickRotation(),l.afterCalculateTickRotation(),l.beforeFit(),l.fit(),l.afterFit(),l._ticksToDraw=u.display&&(u.autoSkip||"auto"===u.source)?l._autoSkip(o):o,s&&(r=l._convertTicksToLabels(l._ticksToDraw)),l.ticks=r,l.afterUpdate(),l.minSize},_configure:function(){var t,e,n=this,i=n.options.ticks.reverse;n.isHorizontal()?(t=n.left,e=n.right):(t=n.top,e=n.bottom,i=!i),n._startPixel=t,n._endPixel=e,n._reversePixels=i,n._length=e-t},afterUpdate:function(){V.callback(this.options.afterUpdate,[this])},beforeSetDimensions:function(){V.callback(this.options.beforeSetDimensions,[this])},setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0},afterSetDimensions:function(){V.callback(this.options.afterSetDimensions,[this])},beforeDataLimits:function(){V.callback(this.options.beforeDataLimits,[this])},determineDataLimits:V.noop,afterDataLimits:function(){V.callback(this.options.afterDataLimits,[this])},beforeBuildTicks:function(){V.callback(this.options.beforeBuildTicks,[this])},buildTicks:V.noop,afterBuildTicks:function(t){var e=this;return on(t)&&t.length?V.callback(e.options.afterBuildTicks,[e,t]):(e.ticks=V.callback(e.options.afterBuildTicks,[e,e.ticks])||e.ticks,t)},beforeTickToLabelConversion:function(){V.callback(this.options.beforeTickToLabelConversion,[this])},convertTicksToLabels:function(){var t=this.options.ticks;this.ticks=this.ticks.map(t.userCallback||t.callback,this)},afterTickToLabelConversion:function(){V.callback(this.options.afterTickToLabelConversion,[this])},beforeCalculateTickRotation:function(){V.callback(this.options.beforeCalculateTickRotation,[this])},calculateTickRotation:function(){var t,e,n,i,a,r,o,s=this,l=s.options,u=l.ticks,d=s.getTicks().length,h=u.minRotation||0,c=u.maxRotation,f=h;!s._isVisible()||!u.display||h>=c||d<=1||!s.isHorizontal()?s.labelRotation=h:(e=(t=s._getLabelSizes()).widest.width,n=t.highest.height-t.highest.offset,i=Math.min(s.maxWidth,s.chart.width-e),e+6>(a=l.offset?s.maxWidth/d:i/(d-1))&&(a=i/(d-(l.offset?.5:1)),r=s.maxHeight-cn(l.gridLines)-u.padding-fn(l.scaleLabel),o=Math.sqrt(e*e+n*n),f=V.toDegrees(Math.min(Math.asin(Math.min((t.highest.height+6)/a,1)),Math.asin(Math.min(r/o,1))-Math.asin(n/o))),f=Math.max(h,Math.min(c,f))),s.labelRotation=f)},afterCalculateTickRotation:function(){V.callback(this.options.afterCalculateTickRotation,[this])},beforeFit:function(){V.callback(this.options.beforeFit,[this])},fit:function(){var t=this,e=t.minSize={width:0,height:0},n=t.chart,i=t.options,a=i.ticks,r=i.scaleLabel,o=i.gridLines,s=t._isVisible(),l="bottom"===i.position,u=t.isHorizontal();if(u?e.width=t.maxWidth:s&&(e.width=cn(o)+fn(r)),u?s&&(e.height=cn(o)+fn(r)):e.height=t.maxHeight,a.display&&s){var d=pn(a),h=t._getLabelSizes(),c=h.first,f=h.last,g=h.widest,p=h.highest,m=.4*d.minor.lineHeight,v=a.padding;if(u){var b=0!==t.labelRotation,x=V.toRadians(t.labelRotation),y=Math.cos(x),_=Math.sin(x),k=_*g.width+y*(p.height-(b?p.offset:0))+(b?0:m);e.height=Math.min(t.maxHeight,e.height+k+v);var w,M,S=t.getPixelForTick(0)-t.left,C=t.right-t.getPixelForTick(t.getTicks().length-1);b?(w=l?y*c.width+_*c.offset:_*(c.height-c.offset),M=l?_*(f.height-f.offset):y*f.width+_*f.offset):(w=c.width/2,M=f.width/2),t.paddingLeft=Math.max((w-S)*t.width/(t.width-S),0)+3,t.paddingRight=Math.max((M-C)*t.width/(t.width-C),0)+3}else{var P=a.mirror?0:g.width+v+m;e.width=Math.min(t.maxWidth,e.width+P),t.paddingTop=c.height/2,t.paddingBottom=f.height/2}}t.handleMargins(),u?(t.width=t._length=n.width-t.margins.left-t.margins.right,t.height=e.height):(t.width=e.width,t.height=t._length=n.height-t.margins.top-t.margins.bottom)},handleMargins:function(){var t=this;t.margins&&(t.margins.left=Math.max(t.paddingLeft,t.margins.left),t.margins.top=Math.max(t.paddingTop,t.margins.top),t.margins.right=Math.max(t.paddingRight,t.margins.right),t.margins.bottom=Math.max(t.paddingBottom,t.margins.bottom))},afterFit:function(){V.callback(this.options.afterFit,[this])},isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},isFullWidth:function(){return this.options.fullWidth},getRightValue:function(t){if(sn(t))return NaN;if(("number"==typeof t||t instanceof Number)&&!isFinite(t))return NaN;if(t)if(this.isHorizontal()){if(void 0!==t.x)return this.getRightValue(t.x)}else if(void 0!==t.y)return this.getRightValue(t.y);return t},_convertTicksToLabels:function(t){var e,n,i,a=this;for(a.ticks=t.map((function(t){return t.value})),a.beforeTickToLabelConversion(),e=a.convertTicksToLabels(t)||a.ticks,a.afterTickToLabelConversion(),n=0,i=t.length;n<i;++n)t[n].label=e[n];return e},_getLabelSizes:function(){var t=this,e=t._labelSizes;return e||(t._labelSizes=e=hn(t.ctx,pn(t.options.ticks),t.getTicks(),t.longestTextCache),t.longestLabelWidth=e.widest.width),e},_parseValue:function(t){var e,n,i,a;return on(t)?(e=+this.getRightValue(t[0]),n=+this.getRightValue(t[1]),i=Math.min(e,n),a=Math.max(e,n)):(e=void 0,n=t=+this.getRightValue(t),i=t,a=t),{min:i,max:a,start:e,end:n}},_getScaleLabel:function(t){var e=this._parseValue(t);return void 0!==e.start?"["+e.start+", "+e.end+"]":+this.getRightValue(t)},getLabelForIndex:V.noop,getPixelForValue:V.noop,getValueForPixel:V.noop,getPixelForTick:function(t){var e=this.options.offset,n=this._ticks.length,i=1/Math.max(n-(e?0:1),1);return t<0||t>n-1?null:this.getPixelForDecimal(t*i+(e?i/2:0))},getPixelForDecimal:function(t){return this._reversePixels&&(t=1-t),this._startPixel+t*this._length},getDecimalForPixel:function(t){var e=(t-this._startPixel)/this._length;return this._reversePixels?1-e:e},getBasePixel:function(){return this.getPixelForValue(this.getBaseValue())},getBaseValue:function(){var t=this.min,e=this.max;return this.beginAtZero?0:t<0&&e<0?e:t>0&&e>0?t:0},_autoSkip:function(t){var e,n,i,a,r=this.options.ticks,o=this._length,s=r.maxTicksLimit||o/this._tickSize()+1,l=r.major.enabled?function(t){var e,n,i=[];for(e=0,n=t.length;e<n;e++)t[e].major&&i.push(e);return i}(t):[],u=l.length,d=l[0],h=l[u-1];if(u>s)return function(t,e,n){var i,a,r=0,o=e[0];for(n=Math.ceil(n),i=0;i<t.length;i++)a=t[i],i===o?(a._index=i,o=e[++r*n]):delete a.label}(t,l,u/s),mn(t);if(i=function(t,e,n,i){var a,r,o,s,l=function(t){var e,n,i=t.length;if(i<2)return!1;for(n=t[0],e=1;e<i;++e)if(t[e]-t[e-1]!==n)return!1;return n}(t),u=(e.length-1)/i;if(!l)return Math.max(u,1);for(o=0,s=(a=V.math._factorize(l)).length-1;o<s;o++)if((r=a[o])>u)return r;return Math.max(u,1)}(l,t,0,s),u>0){for(e=0,n=u-1;e<n;e++)vn(t,i,l[e],l[e+1]);return a=u>1?(h-d)/(u-1):null,vn(t,i,V.isNullOrUndef(a)?0:d-a,d),vn(t,i,h,V.isNullOrUndef(a)?t.length:h+a),mn(t)}return vn(t,i),mn(t)},_tickSize:function(){var t=this.options.ticks,e=V.toRadians(this.labelRotation),n=Math.abs(Math.cos(e)),i=Math.abs(Math.sin(e)),a=this._getLabelSizes(),r=t.autoSkipPadding||0,o=a?a.widest.width+r:0,s=a?a.highest.height+r:0;return this.isHorizontal()?s*n>o*i?o/n:s/i:s*i<o*n?s/n:o/i},_isVisible:function(){var t,e,n,i=this.chart,a=this.options.display;if("auto"!==a)return!!a;for(t=0,e=i.data.datasets.length;t<e;++t)if(i.isDatasetVisible(t)&&((n=i.getDatasetMeta(t)).xAxisID===this.id||n.yAxisID===this.id))return!0;return!1},_computeGridLineItems:function(t){var e,n,i,a,r,o,s,l,u,d,h,c,f,g,p,m,v,b=this,x=b.chart,y=b.options,_=y.gridLines,k=y.position,w=_.offsetGridLines,M=b.isHorizontal(),S=b._ticksToDraw,C=S.length+(w?1:0),P=cn(_),A=[],D=_.drawBorder?un(_.lineWidth,0,0):0,T=D/2,I=V._alignPixel,F=function(t){return I(x,t,D)};for("top"===k?(e=F(b.bottom),s=b.bottom-P,u=e-T,h=F(t.top)+T,f=t.bottom):"bottom"===k?(e=F(b.top),h=t.top,f=F(t.bottom)-T,s=e+T,u=b.top+P):"left"===k?(e=F(b.right),o=b.right-P,l=e-T,d=F(t.left)+T,c=t.right):(e=F(b.left),d=t.left,c=F(t.right)-T,o=e+T,l=b.left+P),n=0;n<C;++n)i=S[n]||{},sn(i.label)&&n<S.length||(n===b.zeroLineIndex&&y.offset===w?(g=_.zeroLineWidth,p=_.zeroLineColor,m=_.zeroLineBorderDash||[],v=_.zeroLineBorderDashOffset||0):(g=un(_.lineWidth,n,1),p=un(_.color,n,"rgba(0,0,0,0.1)"),m=_.borderDash||[],v=_.borderDashOffset||0),void 0!==(a=dn(b,i._index||n,w))&&(r=I(x,a,g),M?o=l=d=c=r:s=u=h=f=r,A.push({tx1:o,ty1:s,tx2:l,ty2:u,x1:d,y1:h,x2:c,y2:f,width:g,color:p,borderDash:m,borderDashOffset:v})));return A.ticksLength=C,A.borderValue=e,A},_computeLabelItems:function(){var t,e,n,i,a,r,o,s,l,u,d,h,c=this,f=c.options,g=f.ticks,p=f.position,m=g.mirror,v=c.isHorizontal(),b=c._ticksToDraw,x=pn(g),y=g.padding,_=cn(f.gridLines),k=-V.toRadians(c.labelRotation),w=[];for("top"===p?(r=c.bottom-_-y,o=k?"left":"center"):"bottom"===p?(r=c.top+_+y,o=k?"right":"center"):"left"===p?(a=c.right-(m?0:_)-y,o=m?"left":"right"):(a=c.left+(m?0:_)+y,o=m?"right":"left"),t=0,e=b.length;t<e;++t)i=(n=b[t]).label,sn(i)||(s=c.getPixelForTick(n._index||t)+g.labelOffset,u=(l=n.major?x.major:x.minor).lineHeight,d=on(i)?i.length:1,v?(a=s,h="top"===p?((k?1:.5)-d)*u:(k?0:.5)*u):(r=s,h=(1-d)*u/2),w.push({x:a,y:r,rotation:k,label:i,font:l,textOffset:h,textAlign:o}));return w},_drawGrid:function(t){var e=this,n=e.options.gridLines;if(n.display){var i,a,r,o,s,l=e.ctx,u=e.chart,d=V._alignPixel,h=n.drawBorder?un(n.lineWidth,0,0):0,c=e._gridLineItems||(e._gridLineItems=e._computeGridLineItems(t));for(r=0,o=c.length;r<o;++r)i=(s=c[r]).width,a=s.color,i&&a&&(l.save(),l.lineWidth=i,l.strokeStyle=a,l.setLineDash&&(l.setLineDash(s.borderDash),l.lineDashOffset=s.borderDashOffset),l.beginPath(),n.drawTicks&&(l.moveTo(s.tx1,s.ty1),l.lineTo(s.tx2,s.ty2)),n.drawOnChartArea&&(l.moveTo(s.x1,s.y1),l.lineTo(s.x2,s.y2)),l.stroke(),l.restore());if(h){var f,g,p,m,v=h,b=un(n.lineWidth,c.ticksLength-1,1),x=c.borderValue;e.isHorizontal()?(f=d(u,e.left,v)-v/2,g=d(u,e.right,b)+b/2,p=m=x):(p=d(u,e.top,v)-v/2,m=d(u,e.bottom,b)+b/2,f=g=x),l.lineWidth=h,l.strokeStyle=un(n.color,0),l.beginPath(),l.moveTo(f,p),l.lineTo(g,m),l.stroke()}}},_drawLabels:function(){var t=this;if(t.options.ticks.display){var e,n,i,a,r,o,s,l,u=t.ctx,d=t._labelItems||(t._labelItems=t._computeLabelItems());for(e=0,i=d.length;e<i;++e){if(o=(r=d[e]).font,u.save(),u.translate(r.x,r.y),u.rotate(r.rotation),u.font=o.string,u.fillStyle=o.color,u.textBaseline="middle",u.textAlign=r.textAlign,s=r.label,l=r.textOffset,on(s))for(n=0,a=s.length;n<a;++n)u.fillText(""+s[n],0,l),l+=o.lineHeight;else u.fillText(s,0,l);u.restore()}}},_drawTitle:function(){var t=this,e=t.ctx,n=t.options,i=n.scaleLabel;if(i.display){var a,r,o=ln(i.fontColor,z.global.defaultFontColor),s=V.options._parseFont(i),l=V.options.toPadding(i.padding),u=s.lineHeight/2,d=n.position,h=0;if(t.isHorizontal())a=t.left+t.width/2,r="bottom"===d?t.bottom-u-l.bottom:t.top+u+l.top;else{var c="left"===d;a=c?t.left+u+l.top:t.right-u-l.top,r=t.top+t.height/2,h=c?-.5*Math.PI:.5*Math.PI}e.save(),e.translate(a,r),e.rotate(h),e.textAlign="center",e.textBaseline="middle",e.fillStyle=o,e.font=s.string,e.fillText(i.labelString,0,0),e.restore()}},draw:function(t){this._isVisible()&&(this._drawGrid(t),this._drawTitle(),this._drawLabels())},_layers:function(){var t=this,e=t.options,n=e.ticks&&e.ticks.z||0,i=e.gridLines&&e.gridLines.z||0;return t._isVisible()&&n!==i&&t.draw===t._draw?[{z:i,draw:function(){t._drawGrid.apply(t,arguments),t._drawTitle.apply(t,arguments)}},{z:n,draw:function(){t._drawLabels.apply(t,arguments)}}]:[{z:n,draw:function(){t.draw.apply(t,arguments)}}]},_getMatchingVisibleMetas:function(t){var e=this,n=e.isHorizontal();return e.chart._getSortedVisibleDatasetMetas().filter((function(i){return(!t||i.type===t)&&(n?i.xAxisID===e.id:i.yAxisID===e.id)}))}});bn.prototype._draw=bn.prototype.draw;var xn=bn,yn=V.isNullOrUndef,_n=xn.extend({determineDataLimits:function(){var t,e=this,n=e._getLabels(),i=e.options.ticks,a=i.min,r=i.max,o=0,s=n.length-1;void 0!==a&&(t=n.indexOf(a))>=0&&(o=t),void 0!==r&&(t=n.indexOf(r))>=0&&(s=t),e.minIndex=o,e.maxIndex=s,e.min=n[o],e.max=n[s]},buildTicks:function(){var t=this._getLabels(),e=this.minIndex,n=this.maxIndex;this.ticks=0===e&&n===t.length-1?t:t.slice(e,n+1)},getLabelForIndex:function(t,e){var n=this.chart;return n.getDatasetMeta(e).controller._getValueScaleId()===this.id?this.getRightValue(n.data.datasets[e].data[t]):this._getLabels()[t]},_configure:function(){var t=this,e=t.options.offset,n=t.ticks;xn.prototype._configure.call(t),t.isHorizontal()||(t._reversePixels=!t._reversePixels),n&&(t._startValue=t.minIndex-(e?.5:0),t._valueRange=Math.max(n.length-(e?0:1),1))},getPixelForValue:function(t,e,n){var i,a,r,o=this;return yn(e)||yn(n)||(t=o.chart.data.datasets[n].data[e]),yn(t)||(i=o.isHorizontal()?t.x:t.y),(void 0!==i||void 0!==t&&isNaN(e))&&(a=o._getLabels(),t=V.valueOrDefault(i,t),e=-1!==(r=a.indexOf(t))?r:e,isNaN(e)&&(e=t)),o.getPixelForDecimal((e-o._startValue)/o._valueRange)},getPixelForTick:function(t){var e=this.ticks;return t<0||t>e.length-1?null:this.getPixelForValue(e[t],t+this.minIndex)},getValueForPixel:function(t){var e=Math.round(this._startValue+this.getDecimalForPixel(t)*this._valueRange);return Math.min(Math.max(e,0),this.ticks.length-1)},getBasePixel:function(){return this.bottom}}),kn={position:"bottom"};_n._defaults=kn;var wn=V.noop,Mn=V.isNullOrUndef;var Sn=xn.extend({getRightValue:function(t){return"string"==typeof t?+t:xn.prototype.getRightValue.call(this,t)},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;if(e.beginAtZero){var n=V.sign(t.min),i=V.sign(t.max);n<0&&i<0?t.max=0:n>0&&i>0&&(t.min=0)}var a=void 0!==e.min||void 0!==e.suggestedMin,r=void 0!==e.max||void 0!==e.suggestedMax;void 0!==e.min?t.min=e.min:void 0!==e.suggestedMin&&(null===t.min?t.min=e.suggestedMin:t.min=Math.min(t.min,e.suggestedMin)),void 0!==e.max?t.max=e.max:void 0!==e.suggestedMax&&(null===t.max?t.max=e.suggestedMax:t.max=Math.max(t.max,e.suggestedMax)),a!==r&&t.min>=t.max&&(a?t.max=t.min+1:t.min=t.max-1),t.min===t.max&&(t.max++,e.beginAtZero||t.min--)},getTickLimit:function(){var t,e=this.options.ticks,n=e.stepSize,i=e.maxTicksLimit;return n?t=Math.ceil(this.max/n)-Math.floor(this.min/n)+1:(t=this._computeTickLimit(),i=i||11),i&&(t=Math.min(i,t)),t},_computeTickLimit:function(){return Number.POSITIVE_INFINITY},handleDirectionalChanges:wn,buildTicks:function(){var t=this,e=t.options.ticks,n=t.getTickLimit(),i={maxTicks:n=Math.max(2,n),min:e.min,max:e.max,precision:e.precision,stepSize:V.valueOrDefault(e.fixedStepSize,e.stepSize)},a=t.ticks=function(t,e){var n,i,a,r,o=[],s=t.stepSize,l=s||1,u=t.maxTicks-1,d=t.min,h=t.max,c=t.precision,f=e.min,g=e.max,p=V.niceNum((g-f)/u/l)*l;if(p<1e-14&&Mn(d)&&Mn(h))return[f,g];(r=Math.ceil(g/p)-Math.floor(f/p))>u&&(p=V.niceNum(r*p/u/l)*l),s||Mn(c)?n=Math.pow(10,V._decimalPlaces(p)):(n=Math.pow(10,c),p=Math.ceil(p*n)/n),i=Math.floor(f/p)*p,a=Math.ceil(g/p)*p,s&&(!Mn(d)&&V.almostWhole(d/p,p/1e3)&&(i=d),!Mn(h)&&V.almostWhole(h/p,p/1e3)&&(a=h)),r=(a-i)/p,r=V.almostEquals(r,Math.round(r),p/1e3)?Math.round(r):Math.ceil(r),i=Math.round(i*n)/n,a=Math.round(a*n)/n,o.push(Mn(d)?i:d);for(var m=1;m<r;++m)o.push(Math.round((i+m*p)*n)/n);return o.push(Mn(h)?a:h),o}(i,t);t.handleDirectionalChanges(),t.max=V.max(a),t.min=V.min(a),e.reverse?(a.reverse(),t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max)},convertTicksToLabels:function(){var t=this;t.ticksAsNumbers=t.ticks.slice(),t.zeroLineIndex=t.ticks.indexOf(0),xn.prototype.convertTicksToLabels.call(t)},_configure:function(){var t,e=this,n=e.getTicks(),i=e.min,a=e.max;xn.prototype._configure.call(e),e.options.offset&&n.length&&(i-=t=(a-i)/Math.max(n.length-1,1)/2,a+=t),e._startValue=i,e._endValue=a,e._valueRange=a-i}}),Cn={position:"left",ticks:{callback:rn.formatters.linear}};function Pn(t,e,n,i){var a,r,o=t.options,s=function(t,e,n){var i=[n.type,void 0===e&&void 0===n.stack?n.index:"",n.stack].join(".");return void 0===t[i]&&(t[i]={pos:[],neg:[]}),t[i]}(e,o.stacked,n),l=s.pos,u=s.neg,d=i.length;for(a=0;a<d;++a)r=t._parseValue(i[a]),isNaN(r.min)||isNaN(r.max)||n.data[a].hidden||(l[a]=l[a]||0,u[a]=u[a]||0,o.relativePoints?l[a]=100:r.min<0||r.max<0?u[a]+=r.min:l[a]+=r.max)}function An(t,e,n){var i,a,r=n.length;for(i=0;i<r;++i)a=t._parseValue(n[i]),isNaN(a.min)||isNaN(a.max)||e.data[i].hidden||(t.min=Math.min(t.min,a.min),t.max=Math.max(t.max,a.max))}var Dn=Sn.extend({determineDataLimits:function(){var t,e,n,i,a=this,r=a.options,o=a.chart.data.datasets,s=a._getMatchingVisibleMetas(),l=r.stacked,u={},d=s.length;if(a.min=Number.POSITIVE_INFINITY,a.max=Number.NEGATIVE_INFINITY,void 0===l)for(t=0;!l&&t<d;++t)l=void 0!==(e=s[t]).stack;for(t=0;t<d;++t)n=o[(e=s[t]).index].data,l?Pn(a,u,e,n):An(a,e,n);V.each(u,(function(t){i=t.pos.concat(t.neg),a.min=Math.min(a.min,V.min(i)),a.max=Math.max(a.max,V.max(i))})),a.min=V.isFinite(a.min)&&!isNaN(a.min)?a.min:0,a.max=V.isFinite(a.max)&&!isNaN(a.max)?a.max:1,a.handleTickRangeOptions()},_computeTickLimit:function(){var t;return this.isHorizontal()?Math.ceil(this.width/40):(t=V.options._parseFont(this.options.ticks),Math.ceil(this.height/t.lineHeight))},handleDirectionalChanges:function(){this.isHorizontal()||this.ticks.reverse()},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForValue:function(t){return this.getPixelForDecimal((+this.getRightValue(t)-this._startValue)/this._valueRange)},getValueForPixel:function(t){return this._startValue+this.getDecimalForPixel(t)*this._valueRange},getPixelForTick:function(t){var e=this.ticksAsNumbers;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])}}),Tn=Cn;Dn._defaults=Tn;var In=V.valueOrDefault,Fn=V.math.log10;var Ln={position:"left",ticks:{callback:rn.formatters.logarithmic}};function On(t,e){return V.isFinite(t)&&t>=0?t:e}var Rn=xn.extend({determineDataLimits:function(){var t,e,n,i,a,r,o=this,s=o.options,l=o.chart,u=l.data.datasets,d=o.isHorizontal();function h(t){return d?t.xAxisID===o.id:t.yAxisID===o.id}o.min=Number.POSITIVE_INFINITY,o.max=Number.NEGATIVE_INFINITY,o.minNotZero=Number.POSITIVE_INFINITY;var c=s.stacked;if(void 0===c)for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e)&&void 0!==e.stack){c=!0;break}if(s.stacked||c){var f={};for(t=0;t<u.length;t++){var g=[(e=l.getDatasetMeta(t)).type,void 0===s.stacked&&void 0===e.stack?t:"",e.stack].join(".");if(l.isDatasetVisible(t)&&h(e))for(void 0===f[g]&&(f[g]=[]),a=0,r=(i=u[t].data).length;a<r;a++){var p=f[g];n=o._parseValue(i[a]),isNaN(n.min)||isNaN(n.max)||e.data[a].hidden||n.min<0||n.max<0||(p[a]=p[a]||0,p[a]+=n.max)}}V.each(f,(function(t){if(t.length>0){var e=V.min(t),n=V.max(t);o.min=Math.min(o.min,e),o.max=Math.max(o.max,n)}}))}else for(t=0;t<u.length;t++)if(e=l.getDatasetMeta(t),l.isDatasetVisible(t)&&h(e))for(a=0,r=(i=u[t].data).length;a<r;a++)n=o._parseValue(i[a]),isNaN(n.min)||isNaN(n.max)||e.data[a].hidden||n.min<0||n.max<0||(o.min=Math.min(n.min,o.min),o.max=Math.max(n.max,o.max),0!==n.min&&(o.minNotZero=Math.min(n.min,o.minNotZero)));o.min=V.isFinite(o.min)?o.min:null,o.max=V.isFinite(o.max)?o.max:null,o.minNotZero=V.isFinite(o.minNotZero)?o.minNotZero:null,this.handleTickRangeOptions()},handleTickRangeOptions:function(){var t=this,e=t.options.ticks;t.min=On(e.min,t.min),t.max=On(e.max,t.max),t.min===t.max&&(0!==t.min&&null!==t.min?(t.min=Math.pow(10,Math.floor(Fn(t.min))-1),t.max=Math.pow(10,Math.floor(Fn(t.max))+1)):(t.min=1,t.max=10)),null===t.min&&(t.min=Math.pow(10,Math.floor(Fn(t.max))-1)),null===t.max&&(t.max=0!==t.min?Math.pow(10,Math.floor(Fn(t.min))+1):10),null===t.minNotZero&&(t.min>0?t.minNotZero=t.min:t.max<1?t.minNotZero=Math.pow(10,Math.floor(Fn(t.max))):t.minNotZero=1)},buildTicks:function(){var t=this,e=t.options.ticks,n=!t.isHorizontal(),i={min:On(e.min),max:On(e.max)},a=t.ticks=function(t,e){var n,i,a=[],r=In(t.min,Math.pow(10,Math.floor(Fn(e.min)))),o=Math.floor(Fn(e.max)),s=Math.ceil(e.max/Math.pow(10,o));0===r?(n=Math.floor(Fn(e.minNotZero)),i=Math.floor(e.minNotZero/Math.pow(10,n)),a.push(r),r=i*Math.pow(10,n)):(n=Math.floor(Fn(r)),i=Math.floor(r/Math.pow(10,n)));var l=n<0?Math.pow(10,Math.abs(n)):1;do{a.push(r),10===++i&&(i=1,l=++n>=0?1:l),r=Math.round(i*Math.pow(10,n)*l)/l}while(n<o||n===o&&i<s);var u=In(t.max,r);return a.push(u),a}(i,t);t.max=V.max(a),t.min=V.min(a),e.reverse?(n=!n,t.start=t.max,t.end=t.min):(t.start=t.min,t.end=t.max),n&&a.reverse()},convertTicksToLabels:function(){this.tickValues=this.ticks.slice(),xn.prototype.convertTicksToLabels.call(this)},getLabelForIndex:function(t,e){return this._getScaleLabel(this.chart.data.datasets[e].data[t])},getPixelForTick:function(t){var e=this.tickValues;return t<0||t>e.length-1?null:this.getPixelForValue(e[t])},_getFirstTickValue:function(t){var e=Math.floor(Fn(t));return Math.floor(t/Math.pow(10,e))*Math.pow(10,e)},_configure:function(){var t=this,e=t.min,n=0;xn.prototype._configure.call(t),0===e&&(e=t._getFirstTickValue(t.minNotZero),n=In(t.options.ticks.fontSize,z.global.defaultFontSize)/t._length),t._startValue=Fn(e),t._valueOffset=n,t._valueRange=(Fn(t.max)-Fn(e))/(1-n)},getPixelForValue:function(t){var e=this,n=0;return(t=+e.getRightValue(t))>e.min&&t>0&&(n=(Fn(t)-e._startValue)/e._valueRange+e._valueOffset),e.getPixelForDecimal(n)},getValueForPixel:function(t){var e=this,n=e.getDecimalForPixel(t);return 0===n&&0===e.min?0:Math.pow(10,e._startValue+(n-e._valueOffset)*e._valueRange)}}),zn=Ln;Rn._defaults=zn;var Nn=V.valueOrDefault,Bn=V.valueAtIndexOrDefault,En=V.options.resolve,Wn={display:!0,animate:!0,position:"chartArea",angleLines:{display:!0,color:"rgba(0,0,0,0.1)",lineWidth:1,borderDash:[],borderDashOffset:0},gridLines:{circular:!1},ticks:{showLabelBackdrop:!0,backdropColor:"rgba(255,255,255,0.75)",backdropPaddingY:2,backdropPaddingX:2,callback:rn.formatters.linear},pointLabels:{display:!0,fontSize:10,callback:function(t){return t}}};function Vn(t){var e=t.ticks;return e.display&&t.display?Nn(e.fontSize,z.global.defaultFontSize)+2*e.backdropPaddingY:0}function Hn(t,e,n,i,a){return t===i||t===a?{start:e-n/2,end:e+n/2}:t<i||t>a?{start:e-n,end:e}:{start:e,end:e+n}}function jn(t){return 0===t||180===t?"center":t<180?"left":"right"}function qn(t,e,n,i){var a,r,o=n.y+i/2;if(V.isArray(e))for(a=0,r=e.length;a<r;++a)t.fillText(e[a],n.x,o),o+=i;else t.fillText(e,n.x,o)}function Un(t,e,n){90===t||270===t?n.y-=e.h/2:(t>270||t<90)&&(n.y-=e.h)}function Yn(t){return V.isNumber(t)?t:0}var Gn=Sn.extend({setDimensions:function(){var t=this;t.width=t.maxWidth,t.height=t.maxHeight,t.paddingTop=Vn(t.options)/2,t.xCenter=Math.floor(t.width/2),t.yCenter=Math.floor((t.height-t.paddingTop)/2),t.drawingArea=Math.min(t.height-t.paddingTop,t.width)/2},determineDataLimits:function(){var t=this,e=t.chart,n=Number.POSITIVE_INFINITY,i=Number.NEGATIVE_INFINITY;V.each(e.data.datasets,(function(a,r){if(e.isDatasetVisible(r)){var o=e.getDatasetMeta(r);V.each(a.data,(function(e,a){var r=+t.getRightValue(e);isNaN(r)||o.data[a].hidden||(n=Math.min(r,n),i=Math.max(r,i))}))}})),t.min=n===Number.POSITIVE_INFINITY?0:n,t.max=i===Number.NEGATIVE_INFINITY?0:i,t.handleTickRangeOptions()},_computeTickLimit:function(){return Math.ceil(this.drawingArea/Vn(this.options))},convertTicksToLabels:function(){var t=this;Sn.prototype.convertTicksToLabels.call(t),t.pointLabels=t.chart.data.labels.map((function(){var e=V.callback(t.options.pointLabels.callback,arguments,t);return e||0===e?e:""}))},getLabelForIndex:function(t,e){return+this.getRightValue(this.chart.data.datasets[e].data[t])},fit:function(){var t=this.options;t.display&&t.pointLabels.display?function(t){var e,n,i,a=V.options._parseFont(t.options.pointLabels),r={l:0,r:t.width,t:0,b:t.height-t.paddingTop},o={};t.ctx.font=a.string,t._pointLabelSizes=[];var s,l,u,d=t.chart.data.labels.length;for(e=0;e<d;e++){i=t.getPointPosition(e,t.drawingArea+5),s=t.ctx,l=a.lineHeight,u=t.pointLabels[e],n=V.isArray(u)?{w:V.longestText(s,s.font,u),h:u.length*l}:{w:s.measureText(u).width,h:l},t._pointLabelSizes[e]=n;var h=t.getIndexAngle(e),c=V.toDegrees(h)%360,f=Hn(c,i.x,n.w,0,180),g=Hn(c,i.y,n.h,90,270);f.start<r.l&&(r.l=f.start,o.l=h),f.end>r.r&&(r.r=f.end,o.r=h),g.start<r.t&&(r.t=g.start,o.t=h),g.end>r.b&&(r.b=g.end,o.b=h)}t.setReductions(t.drawingArea,r,o)}(this):this.setCenterPoint(0,0,0,0)},setReductions:function(t,e,n){var i=this,a=e.l/Math.sin(n.l),r=Math.max(e.r-i.width,0)/Math.sin(n.r),o=-e.t/Math.cos(n.t),s=-Math.max(e.b-(i.height-i.paddingTop),0)/Math.cos(n.b);a=Yn(a),r=Yn(r),o=Yn(o),s=Yn(s),i.drawingArea=Math.min(Math.floor(t-(a+r)/2),Math.floor(t-(o+s)/2)),i.setCenterPoint(a,r,o,s)},setCenterPoint:function(t,e,n,i){var a=this,r=a.width-e-a.drawingArea,o=t+a.drawingArea,s=n+a.drawingArea,l=a.height-a.paddingTop-i-a.drawingArea;a.xCenter=Math.floor((o+r)/2+a.left),a.yCenter=Math.floor((s+l)/2+a.top+a.paddingTop)},getIndexAngle:function(t){var e=this.chart,n=(t*(360/e.data.labels.length)+((e.options||{}).startAngle||0))%360;return(n<0?n+360:n)*Math.PI*2/360},getDistanceFromCenterForValue:function(t){var e=this;if(V.isNullOrUndef(t))return NaN;var n=e.drawingArea/(e.max-e.min);return e.options.ticks.reverse?(e.max-t)*n:(t-e.min)*n},getPointPosition:function(t,e){var n=this.getIndexAngle(t)-Math.PI/2;return{x:Math.cos(n)*e+this.xCenter,y:Math.sin(n)*e+this.yCenter}},getPointPositionForValue:function(t,e){return this.getPointPosition(t,this.getDistanceFromCenterForValue(e))},getBasePosition:function(t){var e=this.min,n=this.max;return this.getPointPositionForValue(t||0,this.beginAtZero?0:e<0&&n<0?n:e>0&&n>0?e:0)},_drawGrid:function(){var t,e,n,i=this,a=i.ctx,r=i.options,o=r.gridLines,s=r.angleLines,l=Nn(s.lineWidth,o.lineWidth),u=Nn(s.color,o.color);if(r.pointLabels.display&&function(t){var e=t.ctx,n=t.options,i=n.pointLabels,a=Vn(n),r=t.getDistanceFromCenterForValue(n.ticks.reverse?t.min:t.max),o=V.options._parseFont(i);e.save(),e.font=o.string,e.textBaseline="middle";for(var s=t.chart.data.labels.length-1;s>=0;s--){var l=0===s?a/2:0,u=t.getPointPosition(s,r+l+5),d=Bn(i.fontColor,s,z.global.defaultFontColor);e.fillStyle=d;var h=t.getIndexAngle(s),c=V.toDegrees(h);e.textAlign=jn(c),Un(c,t._pointLabelSizes[s],u),qn(e,t.pointLabels[s],u,o.lineHeight)}e.restore()}(i),o.display&&V.each(i.ticks,(function(t,n){0!==n&&(e=i.getDistanceFromCenterForValue(i.ticksAsNumbers[n]),function(t,e,n,i){var a,r=t.ctx,o=e.circular,s=t.chart.data.labels.length,l=Bn(e.color,i-1),u=Bn(e.lineWidth,i-1);if((o||s)&&l&&u){if(r.save(),r.strokeStyle=l,r.lineWidth=u,r.setLineDash&&(r.setLineDash(e.borderDash||[]),r.lineDashOffset=e.borderDashOffset||0),r.beginPath(),o)r.arc(t.xCenter,t.yCenter,n,0,2*Math.PI);else{a=t.getPointPosition(0,n),r.moveTo(a.x,a.y);for(var d=1;d<s;d++)a=t.getPointPosition(d,n),r.lineTo(a.x,a.y)}r.closePath(),r.stroke(),r.restore()}}(i,o,e,n))})),s.display&&l&&u){for(a.save(),a.lineWidth=l,a.strokeStyle=u,a.setLineDash&&(a.setLineDash(En([s.borderDash,o.borderDash,[]])),a.lineDashOffset=En([s.borderDashOffset,o.borderDashOffset,0])),t=i.chart.data.labels.length-1;t>=0;t--)e=i.getDistanceFromCenterForValue(r.ticks.reverse?i.min:i.max),n=i.getPointPosition(t,e),a.beginPath(),a.moveTo(i.xCenter,i.yCenter),a.lineTo(n.x,n.y),a.stroke();a.restore()}},_drawLabels:function(){var t=this,e=t.ctx,n=t.options.ticks;if(n.display){var i,a,r=t.getIndexAngle(0),o=V.options._parseFont(n),s=Nn(n.fontColor,z.global.defaultFontColor);e.save(),e.font=o.string,e.translate(t.xCenter,t.yCenter),e.rotate(r),e.textAlign="center",e.textBaseline="middle",V.each(t.ticks,(function(r,l){(0!==l||n.reverse)&&(i=t.getDistanceFromCenterForValue(t.ticksAsNumbers[l]),n.showLabelBackdrop&&(a=e.measureText(r).width,e.fillStyle=n.backdropColor,e.fillRect(-a/2-n.backdropPaddingX,-i-o.size/2-n.backdropPaddingY,a+2*n.backdropPaddingX,o.size+2*n.backdropPaddingY)),e.fillStyle=s,e.fillText(r,0,-i))})),e.restore()}},_drawTitle:V.noop}),Xn=Wn;Gn._defaults=Xn;var Kn=V._deprecated,Zn=V.options.resolve,$n=V.valueOrDefault,Jn=Number.MIN_SAFE_INTEGER||-9007199254740991,Qn=Number.MAX_SAFE_INTEGER||9007199254740991,ti={millisecond:{common:!0,size:1,steps:1e3},second:{common:!0,size:1e3,steps:60},minute:{common:!0,size:6e4,steps:60},hour:{common:!0,size:36e5,steps:24},day:{common:!0,size:864e5,steps:30},week:{common:!1,size:6048e5,steps:4},month:{common:!0,size:2628e6,steps:12},quarter:{common:!1,size:7884e6,steps:4},year:{common:!0,size:3154e7}},ei=Object.keys(ti);function ni(t,e){return t-e}function ii(t){return V.valueOrDefault(t.time.min,t.ticks.min)}function ai(t){return V.valueOrDefault(t.time.max,t.ticks.max)}function ri(t,e,n,i){var a=function(t,e,n){for(var i,a,r,o=0,s=t.length-1;o>=0&&o<=s;){if(a=t[(i=o+s>>1)-1]||null,r=t[i],!a)return{lo:null,hi:r};if(r[e]<n)o=i+1;else{if(!(a[e]>n))return{lo:a,hi:r};s=i-1}}return{lo:r,hi:null}}(t,e,n),r=a.lo?a.hi?a.lo:t[t.length-2]:t[0],o=a.lo?a.hi?a.hi:t[t.length-1]:t[1],s=o[e]-r[e],l=s?(n-r[e])/s:0,u=(o[i]-r[i])*l;return r[i]+u}function oi(t,e){var n=t._adapter,i=t.options.time,a=i.parser,r=a||i.format,o=e;return"function"==typeof a&&(o=a(o)),V.isFinite(o)||(o="string"==typeof r?n.parse(o,r):n.parse(o)),null!==o?+o:(a||"function"!=typeof r||(o=r(e),V.isFinite(o)||(o=n.parse(o))),o)}function si(t,e){if(V.isNullOrUndef(e))return null;var n=t.options.time,i=oi(t,t.getRightValue(e));return null===i?i:(n.round&&(i=+t._adapter.startOf(i,n.round)),i)}function li(t,e,n,i){var a,r,o,s=ei.length;for(a=ei.indexOf(t);a<s-1;++a)if(o=(r=ti[ei[a]]).steps?r.steps:Qn,r.common&&Math.ceil((n-e)/(o*r.size))<=i)return ei[a];return ei[s-1]}function ui(t,e,n){var i,a,r=[],o={},s=e.length;for(i=0;i<s;++i)o[a=e[i]]=i,r.push({value:a,major:!1});return 0!==s&&n?function(t,e,n,i){var a,r,o=t._adapter,s=+o.startOf(e[0].value,i),l=e[e.length-1].value;for(a=s;a<=l;a=+o.add(a,1,i))(r=n[a])>=0&&(e[r].major=!0);return e}(t,r,o,n):r}var di=xn.extend({initialize:function(){this.mergeTicksOptions(),xn.prototype.initialize.call(this)},update:function(){var t=this,e=t.options,n=e.time||(e.time={}),i=t._adapter=new an._date(e.adapters.date);return Kn("time scale",n.format,"time.format","time.parser"),Kn("time scale",n.min,"time.min","ticks.min"),Kn("time scale",n.max,"time.max","ticks.max"),V.mergeIf(n.displayFormats,i.formats()),xn.prototype.update.apply(t,arguments)},getRightValue:function(t){return t&&void 0!==t.t&&(t=t.t),xn.prototype.getRightValue.call(this,t)},determineDataLimits:function(){var t,e,n,i,a,r,o,s=this,l=s.chart,u=s._adapter,d=s.options,h=d.time.unit||"day",c=Qn,f=Jn,g=[],p=[],m=[],v=s._getLabels();for(t=0,n=v.length;t<n;++t)m.push(si(s,v[t]));for(t=0,n=(l.data.datasets||[]).length;t<n;++t)if(l.isDatasetVisible(t))if(a=l.data.datasets[t].data,V.isObject(a[0]))for(p[t]=[],e=0,i=a.length;e<i;++e)r=si(s,a[e]),g.push(r),p[t][e]=r;else p[t]=m.slice(0),o||(g=g.concat(m),o=!0);else p[t]=[];m.length&&(c=Math.min(c,m[0]),f=Math.max(f,m[m.length-1])),g.length&&(g=n>1?function(t){var e,n,i,a={},r=[];for(e=0,n=t.length;e<n;++e)a[i=t[e]]||(a[i]=!0,r.push(i));return r}(g).sort(ni):g.sort(ni),c=Math.min(c,g[0]),f=Math.max(f,g[g.length-1])),c=si(s,ii(d))||c,f=si(s,ai(d))||f,c=c===Qn?+u.startOf(Date.now(),h):c,f=f===Jn?+u.endOf(Date.now(),h)+1:f,s.min=Math.min(c,f),s.max=Math.max(c+1,f),s._table=[],s._timestamps={data:g,datasets:p,labels:m}},buildTicks:function(){var t,e,n,i=this,a=i.min,r=i.max,o=i.options,s=o.ticks,l=o.time,u=i._timestamps,d=[],h=i.getLabelCapacity(a),c=s.source,f=o.distribution;for(u="data"===c||"auto"===c&&"series"===f?u.data:"labels"===c?u.labels:function(t,e,n,i){var a,r=t._adapter,o=t.options,s=o.time,l=s.unit||li(s.minUnit,e,n,i),u=Zn([s.stepSize,s.unitStepSize,1]),d="week"===l&&s.isoWeekday,h=e,c=[];if(d&&(h=+r.startOf(h,"isoWeek",d)),h=+r.startOf(h,d?"day":l),r.diff(n,e,l)>1e5*u)throw e+" and "+n+" are too far apart with stepSize of "+u+" "+l;for(a=h;a<n;a=+r.add(a,u,l))c.push(a);return a!==n&&"ticks"!==o.bounds||c.push(a),c}(i,a,r,h),"ticks"===o.bounds&&u.length&&(a=u[0],r=u[u.length-1]),a=si(i,ii(o))||a,r=si(i,ai(o))||r,t=0,e=u.length;t<e;++t)(n=u[t])>=a&&n<=r&&d.push(n);return i.min=a,i.max=r,i._unit=l.unit||(s.autoSkip?li(l.minUnit,i.min,i.max,h):function(t,e,n,i,a){var r,o;for(r=ei.length-1;r>=ei.indexOf(n);r--)if(o=ei[r],ti[o].common&&t._adapter.diff(a,i,o)>=e-1)return o;return ei[n?ei.indexOf(n):0]}(i,d.length,l.minUnit,i.min,i.max)),i._majorUnit=s.major.enabled&&"year"!==i._unit?function(t){for(var e=ei.indexOf(t)+1,n=ei.length;e<n;++e)if(ti[ei[e]].common)return ei[e]}(i._unit):void 0,i._table=function(t,e,n,i){if("linear"===i||!t.length)return[{time:e,pos:0},{time:n,pos:1}];var a,r,o,s,l,u=[],d=[e];for(a=0,r=t.length;a<r;++a)(s=t[a])>e&&s<n&&d.push(s);for(d.push(n),a=0,r=d.length;a<r;++a)l=d[a+1],o=d[a-1],s=d[a],void 0!==o&&void 0!==l&&Math.round((l+o)/2)===s||u.push({time:s,pos:a/(r-1)});return u}(i._timestamps.data,a,r,f),i._offsets=function(t,e,n,i,a){var r,o,s=0,l=0;return a.offset&&e.length&&(r=ri(t,"time",e[0],"pos"),s=1===e.length?1-r:(ri(t,"time",e[1],"pos")-r)/2,o=ri(t,"time",e[e.length-1],"pos"),l=1===e.length?o:(o-ri(t,"time",e[e.length-2],"pos"))/2),{start:s,end:l,factor:1/(s+1+l)}}(i._table,d,0,0,o),s.reverse&&d.reverse(),ui(i,d,i._majorUnit)},getLabelForIndex:function(t,e){var n=this,i=n._adapter,a=n.chart.data,r=n.options.time,o=a.labels&&t<a.labels.length?a.labels[t]:"",s=a.datasets[e].data[t];return V.isObject(s)&&(o=n.getRightValue(s)),r.tooltipFormat?i.format(oi(n,o),r.tooltipFormat):"string"==typeof o?o:i.format(oi(n,o),r.displayFormats.datetime)},tickFormatFunction:function(t,e,n,i){var a=this._adapter,r=this.options,o=r.time.displayFormats,s=o[this._unit],l=this._majorUnit,u=o[l],d=n[e],h=r.ticks,c=l&&u&&d&&d.major,f=a.format(t,i||(c?u:s)),g=c?h.major:h.minor,p=Zn([g.callback,g.userCallback,h.callback,h.userCallback]);return p?p(f,e,n):f},convertTicksToLabels:function(t){var e,n,i=[];for(e=0,n=t.length;e<n;++e)i.push(this.tickFormatFunction(t[e].value,e,t));return i},getPixelForOffset:function(t){var e=this._offsets,n=ri(this._table,"time",t,"pos");return this.getPixelForDecimal((e.start+n)*e.factor)},getPixelForValue:function(t,e,n){var i=null;if(void 0!==e&&void 0!==n&&(i=this._timestamps.datasets[n][e]),null===i&&(i=si(this,t)),null!==i)return this.getPixelForOffset(i)},getPixelForTick:function(t){var e=this.getTicks();return t>=0&&t<e.length?this.getPixelForOffset(e[t].value):null},getValueForPixel:function(t){var e=this._offsets,n=this.getDecimalForPixel(t)/e.factor-e.end,i=ri(this._table,"pos",n,"time");return this._adapter._create(i)},_getLabelSize:function(t){var e=this.options.ticks,n=this.ctx.measureText(t).width,i=V.toRadians(this.isHorizontal()?e.maxRotation:e.minRotation),a=Math.cos(i),r=Math.sin(i),o=$n(e.fontSize,z.global.defaultFontSize);return{w:n*a+o*r,h:n*r+o*a}},getLabelWidth:function(t){return this._getLabelSize(t).w},getLabelCapacity:function(t){var e=this,n=e.options.time,i=n.displayFormats,a=i[n.unit]||i.millisecond,r=e.tickFormatFunction(t,0,ui(e,[t],e._majorUnit),a),o=e._getLabelSize(r),s=Math.floor(e.isHorizontal()?e.width/o.w:e.height/o.h);return e.options.offset&&s--,s>0?s:1}}),hi={position:"bottom",distribution:"linear",bounds:"data",adapters:{},time:{parser:!1,unit:!1,round:!1,displayFormat:!1,isoWeekday:!1,minUnit:"millisecond",displayFormats:{}},ticks:{autoSkip:!1,source:"auto",major:{enabled:!1}}};di._defaults=hi;var ci={category:_n,linear:Dn,logarithmic:Rn,radialLinear:Gn,time:di},fi={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};an._date.override("function"==typeof t?{_id:"moment",formats:function(){return fi},parse:function(e,n){return"string"==typeof e&&"string"==typeof n?e=t(e,n):e instanceof t||(e=t(e)),e.isValid()?e.valueOf():null},format:function(e,n){return t(e).format(n)},add:function(e,n,i){return t(e).add(n,i).valueOf()},diff:function(e,n,i){return t(e).diff(t(n),i)},startOf:function(e,n,i){return e=t(e),"isoWeek"===n?e.isoWeekday(i).valueOf():e.startOf(n).valueOf()},endOf:function(e,n){return t(e).endOf(n).valueOf()},_create:function(e){return t(e)}}:{}),z._set("global",{plugins:{filler:{propagate:!0}}});var gi={dataset:function(t){var e=t.fill,n=t.chart,i=n.getDatasetMeta(e),a=i&&n.isDatasetVisible(e)&&i.dataset._children||[],r=a.length||0;return r?function(t,e){return e<r&&a[e]._view||null}:null},boundary:function(t){var e=t.boundary,n=e?e.x:null,i=e?e.y:null;return V.isArray(e)?function(t,n){return e[n]}:function(t){return{x:null===n?t.x:n,y:null===i?t.y:i}}}};function pi(t,e,n){var i,a=t._model||{},r=a.fill;if(void 0===r&&(r=!!a.backgroundColor),!1===r||null===r)return!1;if(!0===r)return"origin";if(i=parseFloat(r,10),isFinite(i)&&Math.floor(i)===i)return"-"!==r[0]&&"+"!==r[0]||(i=e+i),!(i===e||i<0||i>=n)&&i;switch(r){case"bottom":return"start";case"top":return"end";case"zero":return"origin";case"origin":case"start":case"end":return r;default:return!1}}function mi(t){return(t.el._scale||{}).getPointPositionForValue?function(t){var e,n,i,a,r,o=t.el._scale,s=o.options,l=o.chart.data.labels.length,u=t.fill,d=[];if(!l)return null;for(e=s.ticks.reverse?o.max:o.min,n=s.ticks.reverse?o.min:o.max,i=o.getPointPositionForValue(0,e),a=0;a<l;++a)r="start"===u||"end"===u?o.getPointPositionForValue(a,"start"===u?e:n):o.getBasePosition(a),s.gridLines.circular&&(r.cx=i.x,r.cy=i.y,r.angle=o.getIndexAngle(a)-Math.PI/2),d.push(r);return d}(t):function(t){var e,n=t.el._model||{},i=t.el._scale||{},a=t.fill,r=null;if(isFinite(a))return null;if("start"===a?r=void 0===n.scaleBottom?i.bottom:n.scaleBottom:"end"===a?r=void 0===n.scaleTop?i.top:n.scaleTop:void 0!==n.scaleZero?r=n.scaleZero:i.getBasePixel&&(r=i.getBasePixel()),null!=r){if(void 0!==r.x&&void 0!==r.y)return r;if(V.isFinite(r))return{x:(e=i.isHorizontal())?r:null,y:e?null:r}}return null}(t)}function vi(t,e,n){var i,a=t[e].fill,r=[e];if(!n)return a;for(;!1!==a&&-1===r.indexOf(a);){if(!isFinite(a))return a;if(!(i=t[a]))return!1;if(i.visible)return a;r.push(a),a=i.fill}return!1}function bi(t){var e=t.fill,n="dataset";return!1===e?null:(isFinite(e)||(n="boundary"),gi[n](t))}function xi(t){return t&&!t.skip}function yi(t,e,n,i,a){var r,o,s,l;if(i&&a){for(t.moveTo(e[0].x,e[0].y),r=1;r<i;++r)V.canvas.lineTo(t,e[r-1],e[r]);if(void 0===n[0].angle)for(t.lineTo(n[a-1].x,n[a-1].y),r=a-1;r>0;--r)V.canvas.lineTo(t,n[r],n[r-1],!0);else for(o=n[0].cx,s=n[0].cy,l=Math.sqrt(Math.pow(n[0].x-o,2)+Math.pow(n[0].y-s,2)),r=a-1;r>0;--r)t.arc(o,s,l,n[r].angle,n[r-1].angle,!0)}}function _i(t,e,n,i,a,r){var o,s,l,u,d,h,c,f,g=e.length,p=i.spanGaps,m=[],v=[],b=0,x=0;for(t.beginPath(),o=0,s=g;o<s;++o)d=n(u=e[l=o%g]._view,l,i),h=xi(u),c=xi(d),r&&void 0===f&&h&&(s=g+(f=o+1)),h&&c?(b=m.push(u),x=v.push(d)):b&&x&&(p?(h&&m.push(u),c&&v.push(d)):(yi(t,m,v,b,x),b=x=0,m=[],v=[]));yi(t,m,v,b,x),t.closePath(),t.fillStyle=a,t.fill()}var ki={id:"filler",afterDatasetsUpdate:function(t,e){var n,i,a,r,o=(t.data.datasets||[]).length,s=e.propagate,l=[];for(i=0;i<o;++i)r=null,(a=(n=t.getDatasetMeta(i)).dataset)&&a._model&&a instanceof _t.Line&&(r={visible:t.isDatasetVisible(i),fill:pi(a,i,o),chart:t,el:a}),n.$filler=r,l.push(r);for(i=0;i<o;++i)(r=l[i])&&(r.fill=vi(l,i,s),r.boundary=mi(r),r.mapper=bi(r))},beforeDatasetsDraw:function(t){var e,n,i,a,r,o,s,l=t._getSortedVisibleDatasetMetas(),u=t.ctx;for(n=l.length-1;n>=0;--n)(e=l[n].$filler)&&e.visible&&(a=(i=e.el)._view,r=i._children||[],o=e.mapper,s=a.backgroundColor||z.global.defaultColor,o&&s&&r.length&&(V.canvas.clipArea(u,t.chartArea),_i(u,r,o,a,s,i._loop),V.canvas.unclipArea(u)))}},wi=V.rtl.getRtlAdapter,Mi=V.noop,Si=V.valueOrDefault;function Ci(t,e){return t.usePointStyle&&t.boxWidth>e?e:t.boxWidth}z._set("global",{legend:{display:!0,position:"top",align:"center",fullWidth:!0,reverse:!1,weight:1e3,onClick:function(t,e){var n=e.datasetIndex,i=this.chart,a=i.getDatasetMeta(n);a.hidden=null===a.hidden?!i.data.datasets[n].hidden:null,i.update()},onHover:null,onLeave:null,labels:{boxWidth:40,padding:10,generateLabels:function(t){var e=t.data.datasets,n=t.options.legend||{},i=n.labels&&n.labels.usePointStyle;return t._getSortedDatasetMetas().map((function(n){var a=n.controller.getStyle(i?0:void 0);return{text:e[n.index].label,fillStyle:a.backgroundColor,hidden:!t.isDatasetVisible(n.index),lineCap:a.borderCapStyle,lineDash:a.borderDash,lineDashOffset:a.borderDashOffset,lineJoin:a.borderJoinStyle,lineWidth:a.borderWidth,strokeStyle:a.borderColor,pointStyle:a.pointStyle,rotation:a.rotation,datasetIndex:n.index}}),this)}}},legendCallback:function(t){var e,n,i,a=document.createElement("ul"),r=t.data.datasets;for(a.setAttribute("class",t.id+"-legend"),e=0,n=r.length;e<n;e++)(i=a.appendChild(document.createElement("li"))).appendChild(document.createElement("span")).style.backgroundColor=r[e].backgroundColor,r[e].label&&i.appendChild(document.createTextNode(r[e].label));return a.outerHTML}});var Pi=X.extend({initialize:function(t){V.extend(this,t),this.legendHitBoxes=[],this._hoveredItem=null,this.doughnutMode=!1},beforeUpdate:Mi,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:Mi,beforeSetDimensions:Mi,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:Mi,beforeBuildLabels:Mi,buildLabels:function(){var t=this,e=t.options.labels||{},n=V.callback(e.generateLabels,[t.chart],t)||[];e.filter&&(n=n.filter((function(n){return e.filter(n,t.chart.data)}))),t.options.reverse&&n.reverse(),t.legendItems=n},afterBuildLabels:Mi,beforeFit:Mi,fit:function(){var t=this,e=t.options,n=e.labels,i=e.display,a=t.ctx,r=V.options._parseFont(n),o=r.size,s=t.legendHitBoxes=[],l=t.minSize,u=t.isHorizontal();if(u?(l.width=t.maxWidth,l.height=i?10:0):(l.width=i?10:0,l.height=t.maxHeight),i){if(a.font=r.string,u){var d=t.lineWidths=[0],h=0;a.textAlign="left",a.textBaseline="middle",V.each(t.legendItems,(function(t,e){var i=Ci(n,o)+o/2+a.measureText(t.text).width;(0===e||d[d.length-1]+i+2*n.padding>l.width)&&(h+=o+n.padding,d[d.length-(e>0?0:1)]=0),s[e]={left:0,top:0,width:i,height:o},d[d.length-1]+=i+n.padding})),l.height+=h}else{var c=n.padding,f=t.columnWidths=[],g=t.columnHeights=[],p=n.padding,m=0,v=0;V.each(t.legendItems,(function(t,e){var i=Ci(n,o)+o/2+a.measureText(t.text).width;e>0&&v+o+2*c>l.height&&(p+=m+n.padding,f.push(m),g.push(v),m=0,v=0),m=Math.max(m,i),v+=o+c,s[e]={left:0,top:0,width:i,height:o}})),p+=m,f.push(m),g.push(v),l.width+=p}t.width=l.width,t.height=l.height}else t.width=l.width=t.height=l.height=0},afterFit:Mi,isHorizontal:function(){return"top"===this.options.position||"bottom"===this.options.position},draw:function(){var t=this,e=t.options,n=e.labels,i=z.global,a=i.defaultColor,r=i.elements.line,o=t.height,s=t.columnHeights,l=t.width,u=t.lineWidths;if(e.display){var d,h=wi(e.rtl,t.left,t.minSize.width),c=t.ctx,f=Si(n.fontColor,i.defaultFontColor),g=V.options._parseFont(n),p=g.size;c.textAlign=h.textAlign("left"),c.textBaseline="middle",c.lineWidth=.5,c.strokeStyle=f,c.fillStyle=f,c.font=g.string;var m=Ci(n,p),v=t.legendHitBoxes,b=function(t,i){switch(e.align){case"start":return n.padding;case"end":return t-i;default:return(t-i+n.padding)/2}},x=t.isHorizontal();d=x?{x:t.left+b(l,u[0]),y:t.top+n.padding,line:0}:{x:t.left+n.padding,y:t.top+b(o,s[0]),line:0},V.rtl.overrideTextDirection(t.ctx,e.textDirection);var y=p+n.padding;V.each(t.legendItems,(function(e,i){var f=c.measureText(e.text).width,g=m+p/2+f,_=d.x,k=d.y;h.setWidth(t.minSize.width),x?i>0&&_+g+n.padding>t.left+t.minSize.width&&(k=d.y+=y,d.line++,_=d.x=t.left+b(l,u[d.line])):i>0&&k+y>t.top+t.minSize.height&&(_=d.x=_+t.columnWidths[d.line]+n.padding,d.line++,k=d.y=t.top+b(o,s[d.line]));var w=h.x(_);!function(t,e,i){if(!(isNaN(m)||m<=0)){c.save();var o=Si(i.lineWidth,r.borderWidth);if(c.fillStyle=Si(i.fillStyle,a),c.lineCap=Si(i.lineCap,r.borderCapStyle),c.lineDashOffset=Si(i.lineDashOffset,r.borderDashOffset),c.lineJoin=Si(i.lineJoin,r.borderJoinStyle),c.lineWidth=o,c.strokeStyle=Si(i.strokeStyle,a),c.setLineDash&&c.setLineDash(Si(i.lineDash,r.borderDash)),n&&n.usePointStyle){var s=m*Math.SQRT2/2,l=h.xPlus(t,m/2),u=e+p/2;V.canvas.drawPoint(c,i.pointStyle,s,l,u,i.rotation)}else c.fillRect(h.leftForLtr(t,m),e,m,p),0!==o&&c.strokeRect(h.leftForLtr(t,m),e,m,p);c.restore()}}(w,k,e),v[i].left=h.leftForLtr(w,v[i].width),v[i].top=k,function(t,e,n,i){var a=p/2,r=h.xPlus(t,m+a),o=e+a;c.fillText(n.text,r,o),n.hidden&&(c.beginPath(),c.lineWidth=2,c.moveTo(r,o),c.lineTo(h.xPlus(r,i),o),c.stroke())}(w,k,e,f),x?d.x+=g+n.padding:d.y+=y})),V.rtl.restoreTextDirection(t.ctx,e.textDirection)}},_getLegendItemAt:function(t,e){var n,i,a,r=this;if(t>=r.left&&t<=r.right&&e>=r.top&&e<=r.bottom)for(a=r.legendHitBoxes,n=0;n<a.length;++n)if(t>=(i=a[n]).left&&t<=i.left+i.width&&e>=i.top&&e<=i.top+i.height)return r.legendItems[n];return null},handleEvent:function(t){var e,n=this,i=n.options,a="mouseup"===t.type?"click":t.type;if("mousemove"===a){if(!i.onHover&&!i.onLeave)return}else{if("click"!==a)return;if(!i.onClick)return}e=n._getLegendItemAt(t.x,t.y),"click"===a?e&&i.onClick&&i.onClick.call(n,t.native,e):(i.onLeave&&e!==n._hoveredItem&&(n._hoveredItem&&i.onLeave.call(n,t.native,n._hoveredItem),n._hoveredItem=e),i.onHover&&e&&i.onHover.call(n,t.native,e))}});function Ai(t,e){var n=new Pi({ctx:t.ctx,options:e,chart:t});ge.configure(t,n,e),ge.addBox(t,n),t.legend=n}var Di={id:"legend",_element:Pi,beforeInit:function(t){var e=t.options.legend;e&&Ai(t,e)},beforeUpdate:function(t){var e=t.options.legend,n=t.legend;e?(V.mergeIf(e,z.global.legend),n?(ge.configure(t,n,e),n.options=e):Ai(t,e)):n&&(ge.removeBox(t,n),delete t.legend)},afterEvent:function(t,e){var n=t.legend;n&&n.handleEvent(e)}},Ti=V.noop;z._set("global",{title:{display:!1,fontStyle:"bold",fullWidth:!0,padding:10,position:"top",text:"",weight:2e3}});var Ii=X.extend({initialize:function(t){V.extend(this,t),this.legendHitBoxes=[]},beforeUpdate:Ti,update:function(t,e,n){var i=this;return i.beforeUpdate(),i.maxWidth=t,i.maxHeight=e,i.margins=n,i.beforeSetDimensions(),i.setDimensions(),i.afterSetDimensions(),i.beforeBuildLabels(),i.buildLabels(),i.afterBuildLabels(),i.beforeFit(),i.fit(),i.afterFit(),i.afterUpdate(),i.minSize},afterUpdate:Ti,beforeSetDimensions:Ti,setDimensions:function(){var t=this;t.isHorizontal()?(t.width=t.maxWidth,t.left=0,t.right=t.width):(t.height=t.maxHeight,t.top=0,t.bottom=t.height),t.paddingLeft=0,t.paddingTop=0,t.paddingRight=0,t.paddingBottom=0,t.minSize={width:0,height:0}},afterSetDimensions:Ti,beforeBuildLabels:Ti,buildLabels:Ti,afterBuildLabels:Ti,beforeFit:Ti,fit:function(){var t,e=this,n=e.options,i=e.minSize={},a=e.isHorizontal();n.display?(t=(V.isArray(n.text)?n.text.length:1)*V.options._parseFont(n).lineHeight+2*n.padding,e.width=i.width=a?e.maxWidth:t,e.height=i.height=a?t:e.maxHeight):e.width=i.width=e.height=i.height=0},afterFit:Ti,isHorizontal:function(){var t=this.options.position;return"top"===t||"bottom"===t},draw:function(){var t=this,e=t.ctx,n=t.options;if(n.display){var i,a,r,o=V.options._parseFont(n),s=o.lineHeight,l=s/2+n.padding,u=0,d=t.top,h=t.left,c=t.bottom,f=t.right;e.fillStyle=V.valueOrDefault(n.fontColor,z.global.defaultFontColor),e.font=o.string,t.isHorizontal()?(a=h+(f-h)/2,r=d+l,i=f-h):(a="left"===n.position?h+l:f-l,r=d+(c-d)/2,i=c-d,u=Math.PI*("left"===n.position?-.5:.5)),e.save(),e.translate(a,r),e.rotate(u),e.textAlign="center",e.textBaseline="middle";var g=n.text;if(V.isArray(g))for(var p=0,m=0;m<g.length;++m)e.fillText(g[m],0,p,i),p+=s;else e.fillText(g,0,0,i);e.restore()}}});function Fi(t,e){var n=new Ii({ctx:t.ctx,options:e,chart:t});ge.configure(t,n,e),ge.addBox(t,n),t.titleBlock=n}var Li={},Oi=ki,Ri=Di,zi={id:"title",_element:Ii,beforeInit:function(t){var e=t.options.title;e&&Fi(t,e)},beforeUpdate:function(t){var e=t.options.title,n=t.titleBlock;e?(V.mergeIf(e,z.global.title),n?(ge.configure(t,n,e),n.options=e):Fi(t,e)):n&&(ge.removeBox(t,n),delete t.titleBlock)}};for(var Ni in Li.filler=Oi,Li.legend=Ri,Li.title=zi,tn.helpers=V,function(){function t(t,e,n){var i;return"string"==typeof t?(i=parseInt(t,10),-1!==t.indexOf("%")&&(i=i/100*e.parentNode[n])):i=t,i}function e(t){return null!=t&&"none"!==t}function n(n,i,a){var r=document.defaultView,o=V._getParentNode(n),s=r.getComputedStyle(n)[i],l=r.getComputedStyle(o)[i],u=e(s),d=e(l),h=Number.POSITIVE_INFINITY;return u||d?Math.min(u?t(s,n,a):h,d?t(l,o,a):h):"none"}V.where=function(t,e){if(V.isArray(t)&&Array.prototype.filter)return t.filter(e);var n=[];return V.each(t,(function(t){e(t)&&n.push(t)})),n},V.findIndex=Array.prototype.findIndex?function(t,e,n){return t.findIndex(e,n)}:function(t,e,n){n=void 0===n?t:n;for(var i=0,a=t.length;i<a;++i)if(e.call(n,t[i],i,t))return i;return-1},V.findNextWhere=function(t,e,n){V.isNullOrUndef(n)&&(n=-1);for(var i=n+1;i<t.length;i++){var a=t[i];if(e(a))return a}},V.findPreviousWhere=function(t,e,n){V.isNullOrUndef(n)&&(n=t.length);for(var i=n-1;i>=0;i--){var a=t[i];if(e(a))return a}},V.isNumber=function(t){return!isNaN(parseFloat(t))&&isFinite(t)},V.almostEquals=function(t,e,n){return Math.abs(t-e)<n},V.almostWhole=function(t,e){var n=Math.round(t);return n-e<=t&&n+e>=t},V.max=function(t){return t.reduce((function(t,e){return isNaN(e)?t:Math.max(t,e)}),Number.NEGATIVE_INFINITY)},V.min=function(t){return t.reduce((function(t,e){return isNaN(e)?t:Math.min(t,e)}),Number.POSITIVE_INFINITY)},V.sign=Math.sign?function(t){return Math.sign(t)}:function(t){return 0===(t=+t)||isNaN(t)?t:t>0?1:-1},V.toRadians=function(t){return t*(Math.PI/180)},V.toDegrees=function(t){return t*(180/Math.PI)},V._decimalPlaces=function(t){if(V.isFinite(t)){for(var e=1,n=0;Math.round(t*e)/e!==t;)e*=10,n++;return n}},V.getAngleFromPoint=function(t,e){var n=e.x-t.x,i=e.y-t.y,a=Math.sqrt(n*n+i*i),r=Math.atan2(i,n);return r<-.5*Math.PI&&(r+=2*Math.PI),{angle:r,distance:a}},V.distanceBetweenPoints=function(t,e){return Math.sqrt(Math.pow(e.x-t.x,2)+Math.pow(e.y-t.y,2))},V.aliasPixel=function(t){return t%2==0?0:.5},V._alignPixel=function(t,e,n){var i=t.currentDevicePixelRatio,a=n/2;return Math.round((e-a)*i)/i+a},V.splineCurve=function(t,e,n,i){var a=t.skip?e:t,r=e,o=n.skip?e:n,s=Math.sqrt(Math.pow(r.x-a.x,2)+Math.pow(r.y-a.y,2)),l=Math.sqrt(Math.pow(o.x-r.x,2)+Math.pow(o.y-r.y,2)),u=s/(s+l),d=l/(s+l),h=i*(u=isNaN(u)?0:u),c=i*(d=isNaN(d)?0:d);return{previous:{x:r.x-h*(o.x-a.x),y:r.y-h*(o.y-a.y)},next:{x:r.x+c*(o.x-a.x),y:r.y+c*(o.y-a.y)}}},V.EPSILON=Number.EPSILON||1e-14,V.splineCurveMonotone=function(t){var e,n,i,a,r,o,s,l,u,d=(t||[]).map((function(t){return{model:t._model,deltaK:0,mK:0}})),h=d.length;for(e=0;e<h;++e)if(!(i=d[e]).model.skip){if(n=e>0?d[e-1]:null,(a=e<h-1?d[e+1]:null)&&!a.model.skip){var c=a.model.x-i.model.x;i.deltaK=0!==c?(a.model.y-i.model.y)/c:0}!n||n.model.skip?i.mK=i.deltaK:!a||a.model.skip?i.mK=n.deltaK:this.sign(n.deltaK)!==this.sign(i.deltaK)?i.mK=0:i.mK=(n.deltaK+i.deltaK)/2}for(e=0;e<h-1;++e)i=d[e],a=d[e+1],i.model.skip||a.model.skip||(V.almostEquals(i.deltaK,0,this.EPSILON)?i.mK=a.mK=0:(r=i.mK/i.deltaK,o=a.mK/i.deltaK,(l=Math.pow(r,2)+Math.pow(o,2))<=9||(s=3/Math.sqrt(l),i.mK=r*s*i.deltaK,a.mK=o*s*i.deltaK)));for(e=0;e<h;++e)(i=d[e]).model.skip||(n=e>0?d[e-1]:null,a=e<h-1?d[e+1]:null,n&&!n.model.skip&&(u=(i.model.x-n.model.x)/3,i.model.controlPointPreviousX=i.model.x-u,i.model.controlPointPreviousY=i.model.y-u*i.mK),a&&!a.model.skip&&(u=(a.model.x-i.model.x)/3,i.model.controlPointNextX=i.model.x+u,i.model.controlPointNextY=i.model.y+u*i.mK))},V.nextItem=function(t,e,n){return n?e>=t.length-1?t[0]:t[e+1]:e>=t.length-1?t[t.length-1]:t[e+1]},V.previousItem=function(t,e,n){return n?e<=0?t[t.length-1]:t[e-1]:e<=0?t[0]:t[e-1]},V.niceNum=function(t,e){var n=Math.floor(V.log10(t)),i=t/Math.pow(10,n);return(e?i<1.5?1:i<3?2:i<7?5:10:i<=1?1:i<=2?2:i<=5?5:10)*Math.pow(10,n)},V.requestAnimFrame="undefined"==typeof window?function(t){t()}:window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(t){return window.setTimeout(t,1e3/60)},V.getRelativePosition=function(t,e){var n,i,a=t.originalEvent||t,r=t.target||t.srcElement,o=r.getBoundingClientRect(),s=a.touches;s&&s.length>0?(n=s[0].clientX,i=s[0].clientY):(n=a.clientX,i=a.clientY);var l=parseFloat(V.getStyle(r,"padding-left")),u=parseFloat(V.getStyle(r,"padding-top")),d=parseFloat(V.getStyle(r,"padding-right")),h=parseFloat(V.getStyle(r,"padding-bottom")),c=o.right-o.left-l-d,f=o.bottom-o.top-u-h;return{x:n=Math.round((n-o.left-l)/c*r.width/e.currentDevicePixelRatio),y:i=Math.round((i-o.top-u)/f*r.height/e.currentDevicePixelRatio)}},V.getConstraintWidth=function(t){return n(t,"max-width","clientWidth")},V.getConstraintHeight=function(t){return n(t,"max-height","clientHeight")},V._calculatePadding=function(t,e,n){return(e=V.getStyle(t,e)).indexOf("%")>-1?n*parseInt(e,10)/100:parseInt(e,10)},V._getParentNode=function(t){var e=t.parentNode;return e&&"[object ShadowRoot]"===e.toString()&&(e=e.host),e},V.getMaximumWidth=function(t){var e=V._getParentNode(t);if(!e)return t.clientWidth;var n=e.clientWidth,i=n-V._calculatePadding(e,"padding-left",n)-V._calculatePadding(e,"padding-right",n),a=V.getConstraintWidth(t);return isNaN(a)?i:Math.min(i,a)},V.getMaximumHeight=function(t){var e=V._getParentNode(t);if(!e)return t.clientHeight;var n=e.clientHeight,i=n-V._calculatePadding(e,"padding-top",n)-V._calculatePadding(e,"padding-bottom",n),a=V.getConstraintHeight(t);return isNaN(a)?i:Math.min(i,a)},V.getStyle=function(t,e){return t.currentStyle?t.currentStyle[e]:document.defaultView.getComputedStyle(t,null).getPropertyValue(e)},V.retinaScale=function(t,e){var n=t.currentDevicePixelRatio=e||"undefined"!=typeof window&&window.devicePixelRatio||1;if(1!==n){var i=t.canvas,a=t.height,r=t.width;i.height=a*n,i.width=r*n,t.ctx.scale(n,n),i.style.height||i.style.width||(i.style.height=a+"px",i.style.width=r+"px")}},V.fontString=function(t,e,n){return e+" "+t+"px "+n},V.longestText=function(t,e,n,i){var a=(i=i||{}).data=i.data||{},r=i.garbageCollect=i.garbageCollect||[];i.font!==e&&(a=i.data={},r=i.garbageCollect=[],i.font=e),t.font=e;var o,s,l,u,d,h=0,c=n.length;for(o=0;o<c;o++)if(null!=(u=n[o])&&!0!==V.isArray(u))h=V.measureText(t,a,r,h,u);else if(V.isArray(u))for(s=0,l=u.length;s<l;s++)null==(d=u[s])||V.isArray(d)||(h=V.measureText(t,a,r,h,d));var f=r.length/2;if(f>n.length){for(o=0;o<f;o++)delete a[r[o]];r.splice(0,f)}return h},V.measureText=function(t,e,n,i,a){var r=e[a];return r||(r=e[a]=t.measureText(a).width,n.push(a)),r>i&&(i=r),i},V.numberOfLabelLines=function(t){var e=1;return V.each(t,(function(t){V.isArray(t)&&t.length>e&&(e=t.length)})),e},V.color=k?function(t){return t instanceof CanvasGradient&&(t=z.global.defaultColor),k(t)}:function(t){return console.error("Color.js not found!"),t},V.getHoverColor=function(t){return t instanceof CanvasPattern||t instanceof CanvasGradient?t:V.color(t).saturate(.5).darken(.1).rgbString()}}(),tn._adapters=an,tn.Animation=Z,tn.animationService=$,tn.controllers=$t,tn.DatasetController=nt,tn.defaults=z,tn.Element=X,tn.elements=_t,tn.Interaction=ae,tn.layouts=ge,tn.platform=Fe,tn.plugins=Le,tn.Scale=xn,tn.scaleService=Oe,tn.Ticks=rn,tn.Tooltip=Ue,tn.helpers.each(ci,(function(t,e){tn.scaleService.registerScaleType(e,t,t._defaults)})),Li)Li.hasOwnProperty(Ni)&&tn.plugins.register(Li[Ni]);tn.platform.initialize();var Bi=tn;return"undefined"!=typeof window&&(window.Chart=tn),tn.Chart=tn,tn.Legend=Li.legend._element,tn.Title=Li.title._element,tn.pluginService=tn.plugins,tn.PluginBase=tn.Element.extend({}),tn.canvasHelpers=tn.helpers.canvas,tn.layoutService=tn.layouts,tn.LinearScaleBase=Sn,tn.helpers.each(["Bar","Bubble","Doughnut","Line","PolarArea","Radar","Scatter"],(function(t){tn[t]=function(e,n){return new tn(e,tn.helpers.merge(n||{},{type:t.charAt(0).toLowerCase()+t.slice(1)}))}})),Bi}));
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chartjs-plugin-datalabels.js b/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chartjs-plugin-datalabels.js
deleted file mode 100644
index 75eb420..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/008-Chartjs-plugin-datalabels.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/*!
- * chartjs-plugin-datalabels v0.7.0
- * https://chartjs-plugin-datalabels.netlify.com
- * (c) 2019 Chart.js Contributors
- * Released under the MIT license
- */
-!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js"],e):(t=t||self).ChartDataLabels=e(t.Chart)}(this,function(t){"use strict";var e=(t=t&&t.hasOwnProperty("default")?t.default:t).helpers,r=function(){if("undefined"!=typeof window){if(window.devicePixelRatio)return window.devicePixelRatio;var t=window.screen;if(t)return(t.deviceXDPI||1)/(t.logicalXDPI||1)}return 1}(),n={toTextLines:function(t){var r,n=[];for(t=[].concat(t);t.length;)"string"==typeof(r=t.pop())?n.unshift.apply(n,r.split("\n")):Array.isArray(r)?t.push.apply(t,r):e.isNullOrUndef(t)||n.unshift(""+r);return n},toFontString:function(t){return!t||e.isNullOrUndef(t.size)||e.isNullOrUndef(t.family)?null:(t.style?t.style+" ":"")+(t.weight?t.weight+" ":"")+t.size+"px "+t.family},textSize:function(t,e,r){var n,i=[].concat(e),o=i.length,a=t.font,l=0;for(t.font=r.string,n=0;n<o;++n)l=Math.max(t.measureText(i[n]).width,l);return t.font=a,{height:o*r.lineHeight,width:l}},parseFont:function(r){var i=t.defaults.global,o=e.valueOrDefault(r.size,i.defaultFontSize),a={family:e.valueOrDefault(r.family,i.defaultFontFamily),lineHeight:e.options.toLineHeight(r.lineHeight,o),size:o,style:e.valueOrDefault(r.style,i.defaultFontStyle),weight:e.valueOrDefault(r.weight,null),string:""};return a.string=n.toFontString(a),a},bound:function(t,e,r){return Math.max(t,Math.min(e,r))},arrayDiff:function(t,e){var r,n,i,o,a=t.slice(),l=[];for(r=0,i=e.length;r<i;++r)o=e[r],-1===(n=a.indexOf(o))?l.push([o,1]):a.splice(n,1);for(r=0,i=a.length;r<i;++r)l.push([a[r],-1]);return l},rasterize:function(t){return Math.round(t*r)/r}};function i(t,e){var r=e.x,n=e.y;if(null===r)return{x:0,y:-1};if(null===n)return{x:1,y:0};var i=t.x-r,o=t.y-n,a=Math.sqrt(i*i+o*o);return{x:a?i/a:0,y:a?o/a:-1}}var o=0,a=1,l=2,s=4,u=8;function f(t,e,r){var n=o;return t<r.left?n|=a:t>r.right&&(n|=l),e<r.top?n|=u:e>r.bottom&&(n|=s),n}function d(t,e){var r,n,i=e.anchor,o=t;return e.clamp&&(o=function(t,e){for(var r,n,i,o=t.x0,d=t.y0,c=t.x1,h=t.y1,x=f(o,d,e),y=f(c,h,e);x|y&&!(x&y);)(r=x||y)&u?(n=o+(c-o)*(e.top-d)/(h-d),i=e.top):r&s?(n=o+(c-o)*(e.bottom-d)/(h-d),i=e.bottom):r&l?(i=d+(h-d)*(e.right-o)/(c-o),n=e.right):r&a&&(i=d+(h-d)*(e.left-o)/(c-o),n=e.left),r===x?x=f(o=n,d=i,e):y=f(c=n,h=i,e);return{x0:o,x1:c,y0:d,y1:h}}(o,e.area)),"start"===i?(r=o.x0,n=o.y0):"end"===i?(r=o.x1,n=o.y1):(r=(o.x0+o.x1)/2,n=(o.y0+o.y1)/2),function(t,e,r,n,i){switch(i){case"center":r=n=0;break;case"bottom":r=0,n=1;break;case"right":r=1,n=0;break;case"left":r=-1,n=0;break;case"top":r=0,n=-1;break;case"start":r=-r,n=-n;break;case"end":break;default:i*=Math.PI/180,r=Math.cos(i),n=Math.sin(i)}return{x:t,y:e,vx:r,vy:n}}(r,n,t.vx,t.vy,e.align)}var c={arc:function(t,e){var r=(t.startAngle+t.endAngle)/2,n=Math.cos(r),i=Math.sin(r),o=t.innerRadius,a=t.outerRadius;return d({x0:t.x+n*o,y0:t.y+i*o,x1:t.x+n*a,y1:t.y+i*a,vx:n,vy:i},e)},point:function(t,e){var r=i(t,e.origin),n=r.x*t.radius,o=r.y*t.radius;return d({x0:t.x-n,y0:t.y-o,x1:t.x+n,y1:t.y+o,vx:r.x,vy:r.y},e)},rect:function(t,e){var r=i(t,e.origin),n=t.x,o=t.y,a=0,l=0;return t.horizontal?(n=Math.min(t.x,t.base),a=Math.abs(t.base-t.x)):(o=Math.min(t.y,t.base),l=Math.abs(t.base-t.y)),d({x0:n,y0:o+l,x1:n+a,y1:o,vx:r.x,vy:r.y},e)},fallback:function(t,e){var r=i(t,e.origin);return d({x0:t.x,y0:t.y,x1:t.x,y1:t.y,vx:r.x,vy:r.y},e)}},h=t.helpers,x=n.rasterize;function y(t){var e=t._model.horizontal,r=t._scale||e&&t._xScale||t._yScale;if(!r)return null;if(void 0!==r.xCenter&&void 0!==r.yCenter)return{x:r.xCenter,y:r.yCenter};var n=r.getBasePixel();return e?{x:n,y:null}:{x:null,y:n}}function v(t,e,r){var n=t.shadowBlur,i=r.stroked,o=x(r.x),a=x(r.y),l=x(r.w);i&&t.strokeText(e,o,a,l),r.filled&&(n&&i&&(t.shadowBlur=0),t.fillText(e,o,a,l),n&&i&&(t.shadowBlur=n))}var _=function(t,e,r,n){var i=this;i._config=t,i._index=n,i._model=null,i._rects=null,i._ctx=e,i._el=r};h.extend(_.prototype,{_modelize:function(e,r,i,o){var a,l=this._index,s=h.options.resolve,u=n.parseFont(s([i.font,{}],o,l)),f=s([i.color,t.defaults.global.defaultFontColor],o,l);return{align:s([i.align,"center"],o,l),anchor:s([i.anchor,"center"],o,l),area:o.chart.chartArea,backgroundColor:s([i.backgroundColor,null],o,l),borderColor:s([i.borderColor,null],o,l),borderRadius:s([i.borderRadius,0],o,l),borderWidth:s([i.borderWidth,0],o,l),clamp:s([i.clamp,!1],o,l),clip:s([i.clip,!1],o,l),color:f,display:e,font:u,lines:r,offset:s([i.offset,0],o,l),opacity:s([i.opacity,1],o,l),origin:y(this._el),padding:h.options.toPadding(s([i.padding,0],o,l)),positioner:(a=this._el,a instanceof t.elements.Arc?c.arc:a instanceof t.elements.Point?c.point:a instanceof t.elements.Rectangle?c.rect:c.fallback),rotation:s([i.rotation,0],o,l)*(Math.PI/180),size:n.textSize(this._ctx,r,u),textAlign:s([i.textAlign,"start"],o,l),textShadowBlur:s([i.textShadowBlur,0],o,l),textShadowColor:s([i.textShadowColor,f],o,l),textStrokeColor:s([i.textStrokeColor,f],o,l),textStrokeWidth:s([i.textStrokeWidth,0],o,l)}},update:function(t){var e,r,i,o=this,a=null,l=null,s=o._index,u=o._config,f=h.options.resolve([u.display,!0],t,s);f&&(e=t.dataset.data[s],r=h.valueOrDefault(h.callback(u.formatter,[e,t]),e),(i=h.isNullOrUndef(r)?[]:n.toTextLines(r)).length&&(l=function(t){var e=t.borderWidth||0,r=t.padding,n=t.size.height,i=t.size.width,o=-i/2,a=-n/2;return{frame:{x:o-r.left-e,y:a-r.top-e,w:i+r.width+2*e,h:n+r.height+2*e},text:{x:o,y:a,w:i,h:n}}}(a=o._modelize(f,i,u,t)))),o._model=a,o._rects=l},geometry:function(){return this._rects?this._rects.frame:{}},rotation:function(){return this._model?this._model.rotation:0},visible:function(){return this._model&&this._model.opacity},model:function(){return this._model},draw:function(t,e){var r,i=t.ctx,o=this._model,a=this._rects;this.visible()&&(i.save(),o.clip&&(r=o.area,i.beginPath(),i.rect(r.left,r.top,r.right-r.left,r.bottom-r.top),i.clip()),i.globalAlpha=n.bound(0,o.opacity,1),i.translate(x(e.x),x(e.y)),i.rotate(o.rotation),function(t,e,r){var n=r.backgroundColor,i=r.borderColor,o=r.borderWidth;(n||i&&o)&&(t.beginPath(),h.canvas.roundedRect(t,x(e.x)+o/2,x(e.y)+o/2,x(e.w)-o,x(e.h)-o,r.borderRadius),t.closePath(),n&&(t.fillStyle=n,t.fill()),i&&o&&(t.strokeStyle=i,t.lineWidth=o,t.lineJoin="miter",t.stroke()))}(i,a.frame,o),function(t,e,r,n){var i,o=n.textAlign,a=n.color,l=!!a,s=n.font,u=e.length,f=n.textStrokeColor,d=n.textStrokeWidth,c=f&&d;if(u&&(l||c))for(r=function(t,e,r){var n=r.lineHeight,i=t.w,o=t.x;return"center"===e?o+=i/2:"end"!==e&&"right"!==e||(o+=i),{h:n,w:i,x:o,y:t.y+n/2}}(r,o,s),t.font=s.string,t.textAlign=o,t.textBaseline="middle",t.shadowBlur=n.textShadowBlur,t.shadowColor=n.textShadowColor,l&&(t.fillStyle=a),c&&(t.lineJoin="round",t.lineWidth=d,t.strokeStyle=f),i=0,u=e.length;i<u;++i)v(t,e[i],{stroked:c,filled:l,w:r.w,x:r.x,y:r.y+r.h*i})}(i,o.lines,a.text,o),i.restore())}});var b=t.helpers,p=Number.MIN_SAFE_INTEGER||-9007199254740991,g=Number.MAX_SAFE_INTEGER||9007199254740991;function m(t,e,r){var n=Math.cos(r),i=Math.sin(r),o=e.x,a=e.y;return{x:o+n*(t.x-o)-i*(t.y-a),y:a+i*(t.x-o)+n*(t.y-a)}}function w(t,e){var r,n,i,o,a,l=g,s=p,u=e.origin;for(r=0;r<t.length;++r)i=(n=t[r]).x-u.x,o=n.y-u.y,a=e.vx*i+e.vy*o,l=Math.min(l,a),s=Math.max(s,a);return{min:l,max:s}}function k(t,e){var r=e.x-t.x,n=e.y-t.y,i=Math.sqrt(r*r+n*n);return{vx:(e.x-t.x)/i,vy:(e.y-t.y)/i,origin:t,ln:i}}var M=function(){this._rotation=0,this._rect={x:0,y:0,w:0,h:0}};function S(t,e,r){var n=e.positioner(t,e),i=n.vx,o=n.vy;if(!i&&!o)return{x:n.x,y:n.y};var a=r.w,l=r.h,s=e.rotation,u=Math.abs(a/2*Math.cos(s))+Math.abs(l/2*Math.sin(s)),f=Math.abs(a/2*Math.sin(s))+Math.abs(l/2*Math.cos(s)),d=1/Math.max(Math.abs(i),Math.abs(o));return u*=i*d,f*=o*d,u+=e.offset*i,f+=e.offset*o,{x:n.x+u,y:n.y+f}}b.extend(M.prototype,{center:function(){var t=this._rect;return{x:t.x+t.w/2,y:t.y+t.h/2}},update:function(t,e,r){this._rotation=r,this._rect={x:e.x+t.x,y:e.y+t.y,w:e.w,h:e.h}},contains:function(t){var e=this._rect;return!((t=m(t,this.center(),-this._rotation)).x<e.x-1||t.y<e.y-1||t.x>e.x+e.w+2||t.y>e.y+e.h+2)},intersects:function(t){var e,r,n,i=this._points(),o=t._points(),a=[k(i[0],i[1]),k(i[0],i[3])];for(this._rotation!==t._rotation&&a.push(k(o[0],o[1]),k(o[0],o[3])),e=0;e<a.length;++e)if(r=w(i,a[e]),n=w(o,a[e]),r.max<n.min||n.max<r.min)return!1;return!0},_points:function(){var t=this._rect,e=this._rotation,r=this.center();return[m({x:t.x,y:t.y},r,e),m({x:t.x+t.w,y:t.y},r,e),m({x:t.x+t.w,y:t.y+t.h},r,e),m({x:t.x,y:t.y+t.h},r,e)]}});var C={prepare:function(t){var e,r,n,i,o,a=[];for(e=0,n=t.length;e<n;++e)for(r=0,i=t[e].length;r<i;++r)o=t[e][r],a.push(o),o.$layout={_box:new M,_hidable:!1,_visible:!0,_set:e,_idx:r};return a.sort(function(t,e){var r=t.$layout,n=e.$layout;return r._idx===n._idx?n._set-r._set:n._idx-r._idx}),this.update(a),a},update:function(t){var e,r,n,i,o,a=!1;for(e=0,r=t.length;e<r;++e)i=(n=t[e]).model(),(o=n.$layout)._hidable=i&&"auto"===i.display,o._visible=n.visible(),a|=o._hidable;a&&function(t){var e,r,n,i,o,a;for(e=0,r=t.length;e<r;++e)(i=(n=t[e]).$layout)._visible&&(o=n.geometry(),a=S(n._el._model,n.model(),o),i._box.update(a,o,n.rotation()));(function(t,e){var r,n,i,o;for(r=t.length-1;r>=0;--r)for(i=t[r].$layout,n=r-1;n>=0&&i._visible;--n)(o=t[n].$layout)._visible&&i._box.intersects(o._box)&&e(i,o)})(t,function(t,e){var r=t._hidable,n=e._hidable;r&&n||n?e._visible=!1:r&&(t._visible=!1)})}(t)},lookup:function(t,e){var r,n;for(r=t.length-1;r>=0;--r)if((n=t[r].$layout)&&n._visible&&n._box.contains(e))return t[r];return null},draw:function(t,e){var r,n,i,o,a,l;for(r=0,n=e.length;r<n;++r)(o=(i=e[r]).$layout)._visible&&(a=i.geometry(),l=S(i._el._view,i.model(),a),o._box.update(l,a,i.rotation()),i.draw(t,l))}},z=t.helpers,$={align:"center",anchor:"center",backgroundColor:null,borderColor:null,borderRadius:0,borderWidth:0,clamp:!1,clip:!1,color:void 0,display:!0,font:{family:void 0,lineHeight:1.2,size:void 0,style:void 0,weight:null},formatter:function(t){if(z.isNullOrUndef(t))return null;var e,r,n,i=t;if(z.isObject(t))if(z.isNullOrUndef(t.label))if(z.isNullOrUndef(t.r))for(i="",n=0,r=(e=Object.keys(t)).length;n<r;++n)i+=(0!==n?", ":"")+e[n]+": "+t[e[n]];else i=t.r;else i=t.label;return""+i},labels:void 0,listeners:{},offset:4,opacity:1,padding:{top:4,right:4,bottom:4,left:4},rotation:0,textAlign:"start",textStrokeColor:void 0,textStrokeWidth:0,textShadowBlur:0,textShadowColor:void 0},O=t.helpers,A="$datalabels",D="$default";function P(t,e,r){if(e){var n,i=r.$context,o=r.$groups;e[o._set]&&(n=e[o._set][o._key])&&!0===O.callback(n,[i])&&(t[A]._dirty=!0,r.update(i))}}function N(t,e){var r,n,i=t[A],o=i._listeners;if(o.enter||o.leave){if("mousemove"===e.type)n=C.lookup(i._labels,e);else if("mouseout"!==e.type)return;r=i._hovered,i._hovered=n,function(t,e,r,n){var i,o;(r||n)&&(r?n?r!==n&&(o=i=!0):o=!0:i=!0,o&&P(t,e.leave,r),i&&P(t,e.enter,n))}(t,o,r,n)}}t.defaults.global.plugins.datalabels=$;var R={id:"datalabels",beforeInit:function(t){t[A]={_actives:[]}},beforeUpdate:function(t){var e=t[A];e._listened=!1,e._listeners={},e._datasets=[],e._labels=[]},afterDatasetUpdate:function(t,e,r){var n,i,o,a,l,s,u,f,d=e.index,c=t[A],h=c._datasets[d]=[],x=t.isDatasetVisible(d),y=t.data.datasets[d],v=function(t,e){var r,n,i,o=t.datalabels,a=[];return!1===o?null:(!0===o&&(o={}),e=O.merge({},[e,o]),n=e.labels||{},i=Object.keys(n),delete e.labels,i.length?i.forEach(function(t){n[t]&&a.push(O.merge({},[e,n[t],{_key:t}]))}):a.push(e),r=a.reduce(function(t,e){return O.each(e.listeners||{},function(r,n){t[n]=t[n]||{},t[n][e._key||D]=r}),delete e.listeners,t},{}),{labels:a,listeners:r})}(y,r),b=e.meta.data||[],p=t.ctx;for(p.save(),n=0,o=b.length;n<o;++n)if((u=b[n])[A]=[],x&&u&&!u.hidden&&!u._model.skip)for(i=0,a=v.labels.length;i<a;++i)s=(l=v.labels[i])._key,(f=new _(l,p,u,n)).$groups={_set:d,_key:s||D},f.$context={active:!1,chart:t,dataIndex:n,dataset:y,datasetIndex:d},f.update(f.$context),u[A].push(f),h.push(f);p.restore(),O.merge(c._listeners,v.listeners,{merger:function(t,r,n){r[t]=r[t]||{},r[t][e.index]=n[t],c._listened=!0}})},afterUpdate:function(t,e){t[A]._labels=C.prepare(t[A]._datasets,e)},afterDatasetsDraw:function(t){C.draw(t,t[A]._labels)},beforeEvent:function(t,e){if(t[A]._listened)switch(e.type){case"mousemove":case"mouseout":N(t,e);break;case"click":!function(t,e){var r=t[A],n=r._listeners.click,i=n&&C.lookup(r._labels,e);i&&P(t,n,i)}(t,e)}},afterEvent:function(e){var r,i,o,a,l,s,u,f=e[A],d=f._actives,c=f._actives=e.lastActive||[],h=n.arrayDiff(d,c);for(r=0,i=h.length;r<i;++r)if((l=h[r])[1])for(o=0,a=(u=l[0][A]||[]).length;o<a;++o)(s=u[o]).$context.active=1===l[1],s.update(s.$context);(f._dirty||h.length)&&(C.update(f._labels),function(e){if(!e.animating){for(var r=t.animationService.animations,n=0,i=r.length;n<i;++n)if(r[n].chart===e)return;e.render({duration:1,lazy:!0})}}(e)),delete f._dirty}};return t.plugins.register(R),R});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/008-chartjs-plugin-datalabels.js b/mailcow/src/mailcow-dockerized/data/web/js/build/008-chartjs-plugin-datalabels.js
new file mode 100644
index 0000000..c662fcf
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/008-chartjs-plugin-datalabels.js
@@ -0,0 +1,7 @@
+/*!
+ * chartjs-plugin-datalabels v2.0.0
+ * https://chartjs-plugin-datalabels.netlify.app
+ * (c) 2017-2021 chartjs-plugin-datalabels contributors
+ * Released under the MIT license
+ */
+!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("chart.js/helpers"),require("chart.js")):"function"==typeof define&&define.amd?define(["chart.js/helpers","chart.js"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).ChartDataLabels=e(t.Chart.helpers,t.Chart)}(this,(function(t,e){"use strict";var r=function(){if("undefined"!=typeof window){if(window.devicePixelRatio)return window.devicePixelRatio;var t=window.screen;if(t)return(t.deviceXDPI||1)/(t.logicalXDPI||1)}return 1}(),a=function(e){var r,a=[];for(e=[].concat(e);e.length;)"string"==typeof(r=e.pop())?a.unshift.apply(a,r.split("\n")):Array.isArray(r)?e.push.apply(e,r):t.isNullOrUndef(e)||a.unshift(""+r);return a},o=function(t,e,r){var a,o=[].concat(e),n=o.length,i=t.font,l=0;for(t.font=r.string,a=0;a<n;++a)l=Math.max(t.measureText(o[a]).width,l);return t.font=i,{height:n*r.lineHeight,width:l}},n=function(t,e,r){return Math.max(t,Math.min(e,r))},i=function(t,e){var r,a,o,n,i=t.slice(),l=[];for(r=0,o=e.length;r<o;++r)n=e[r],-1===(a=i.indexOf(n))?l.push([n,1]):i.splice(a,1);for(r=0,o=i.length;r<o;++r)l.push([i[r],-1]);return l};function l(t,e){var r=e.x,a=e.y;if(null===r)return{x:0,y:-1};if(null===a)return{x:1,y:0};var o=t.x-r,n=t.y-a,i=Math.sqrt(o*o+n*n);return{x:i?o/i:0,y:i?n/i:-1}}function s(t,e,r){var a=0;return t<r.left?a|=1:t>r.right&&(a|=2),e<r.top?a|=8:e>r.bottom&&(a|=4),a}function u(t,e){var r,a,o=e.anchor,n=t;return e.clamp&&(n=function(t,e){for(var r,a,o,n=t.x0,i=t.y0,l=t.x1,u=t.y1,d=s(n,i,e),c=s(l,u,e);d|c&&!(d&c);)8&(r=d||c)?(a=n+(l-n)*(e.top-i)/(u-i),o=e.top):4&r?(a=n+(l-n)*(e.bottom-i)/(u-i),o=e.bottom):2&r?(o=i+(u-i)*(e.right-n)/(l-n),a=e.right):1&r&&(o=i+(u-i)*(e.left-n)/(l-n),a=e.left),r===d?d=s(n=a,i=o,e):c=s(l=a,u=o,e);return{x0:n,x1:l,y0:i,y1:u}}(n,e.area)),"start"===o?(r=n.x0,a=n.y0):"end"===o?(r=n.x1,a=n.y1):(r=(n.x0+n.x1)/2,a=(n.y0+n.y1)/2),function(t,e,r,a,o){switch(o){case"center":r=a=0;break;case"bottom":r=0,a=1;break;case"right":r=1,a=0;break;case"left":r=-1,a=0;break;case"top":r=0,a=-1;break;case"start":r=-r,a=-a;break;case"end":break;default:o*=Math.PI/180,r=Math.cos(o),a=Math.sin(o)}return{x:t,y:e,vx:r,vy:a}}(r,a,t.vx,t.vy,e.align)}var d=function(t,e){var r=(t.startAngle+t.endAngle)/2,a=Math.cos(r),o=Math.sin(r),n=t.innerRadius,i=t.outerRadius;return u({x0:t.x+a*n,y0:t.y+o*n,x1:t.x+a*i,y1:t.y+o*i,vx:a,vy:o},e)},c=function(t,e){var r=l(t,e.origin),a=r.x*t.options.radius,o=r.y*t.options.radius;return u({x0:t.x-a,y0:t.y-o,x1:t.x+a,y1:t.y+o,vx:r.x,vy:r.y},e)},h=function(t,e){var r=l(t,e.origin),a=t.x,o=t.y,n=0,i=0;return t.horizontal?(a=Math.min(t.x,t.base),n=Math.abs(t.base-t.x)):(o=Math.min(t.y,t.base),i=Math.abs(t.base-t.y)),u({x0:a,y0:o+i,x1:a+n,y1:o,vx:r.x,vy:r.y},e)},f=function(t,e){var r=l(t,e.origin);return u({x0:t.x,y0:t.y,x1:t.x,y1:t.y,vx:r.x,vy:r.y},e)},x=function(t){return Math.round(t*r)/r};function y(t,e){var r=e.chart.getDatasetMeta(e.datasetIndex).vScale;if(!r)return null;if(void 0!==r.xCenter&&void 0!==r.yCenter)return{x:r.xCenter,y:r.yCenter};var a=r.getBasePixel();return t.horizontal?{x:a,y:null}:{x:null,y:a}}function v(t,e,r){var a=r.backgroundColor,o=r.borderColor,n=r.borderWidth;(a||o&&n)&&(t.beginPath(),function(t,e,r,a,o,n){var i=Math.PI/2;if(n){var l=Math.min(n,o/2,a/2),s=e+l,u=r+l,d=e+a-l,c=r+o-l;t.moveTo(e,u),s<d&&u<c?(t.arc(s,u,l,-Math.PI,-i),t.arc(d,u,l,-i,0),t.arc(d,c,l,0,i),t.arc(s,c,l,i,Math.PI)):s<d?(t.moveTo(s,r),t.arc(d,u,l,-i,i),t.arc(s,u,l,i,Math.PI+i)):u<c?(t.arc(s,u,l,-Math.PI,0),t.arc(s,c,l,0,Math.PI)):t.arc(s,u,l,-Math.PI,Math.PI),t.closePath(),t.moveTo(e,r)}else t.rect(e,r,a,o)}(t,x(e.x)+n/2,x(e.y)+n/2,x(e.w)-n,x(e.h)-n,r.borderRadius),t.closePath(),a&&(t.fillStyle=a,t.fill()),o&&n&&(t.strokeStyle=o,t.lineWidth=n,t.lineJoin="miter",t.stroke()))}function b(t,e,r){var a=t.shadowBlur,o=r.stroked,n=x(r.x),i=x(r.y),l=x(r.w);o&&t.strokeText(e,n,i,l),r.filled&&(a&&o&&(t.shadowBlur=0),t.fillText(e,n,i,l),a&&o&&(t.shadowBlur=a))}var _=function(t,e,r,a){var o=this;o._config=t,o._index=a,o._model=null,o._rects=null,o._ctx=e,o._el=r};t.merge(_.prototype,{_modelize:function(r,a,n,i){var l,s=this,u=s._index,x=t.toFont(t.resolve([n.font,{}],i,u)),v=t.resolve([n.color,e.defaults.color],i,u);return{align:t.resolve([n.align,"center"],i,u),anchor:t.resolve([n.anchor,"center"],i,u),area:i.chart.chartArea,backgroundColor:t.resolve([n.backgroundColor,null],i,u),borderColor:t.resolve([n.borderColor,null],i,u),borderRadius:t.resolve([n.borderRadius,0],i,u),borderWidth:t.resolve([n.borderWidth,0],i,u),clamp:t.resolve([n.clamp,!1],i,u),clip:t.resolve([n.clip,!1],i,u),color:v,display:r,font:x,lines:a,offset:t.resolve([n.offset,0],i,u),opacity:t.resolve([n.opacity,1],i,u),origin:y(s._el,i),padding:t.toPadding(t.resolve([n.padding,0],i,u)),positioner:(l=s._el,l instanceof e.ArcElement?d:l instanceof e.PointElement?c:l instanceof e.BarElement?h:f),rotation:t.resolve([n.rotation,0],i,u)*(Math.PI/180),size:o(s._ctx,a,x),textAlign:t.resolve([n.textAlign,"start"],i,u),textShadowBlur:t.resolve([n.textShadowBlur,0],i,u),textShadowColor:t.resolve([n.textShadowColor,v],i,u),textStrokeColor:t.resolve([n.textStrokeColor,v],i,u),textStrokeWidth:t.resolve([n.textStrokeWidth,0],i,u)}},update:function(e){var r,o,n,i=this,l=null,s=null,u=i._index,d=i._config,c=t.resolve([d.display,!0],e,u);c&&(r=e.dataset.data[u],o=t.valueOrDefault(t.callback(d.formatter,[r,e]),r),(n=t.isNullOrUndef(o)?[]:a(o)).length&&(s=function(t){var e=t.borderWidth||0,r=t.padding,a=t.size.height,o=t.size.width,n=-o/2,i=-a/2;return{frame:{x:n-r.left-e,y:i-r.top-e,w:o+r.width+2*e,h:a+r.height+2*e},text:{x:n,y:i,w:o,h:a}}}(l=i._modelize(c,n,d,e)))),i._model=l,i._rects=s},geometry:function(){return this._rects?this._rects.frame:{}},rotation:function(){return this._model?this._model.rotation:0},visible:function(){return this._model&&this._model.opacity},model:function(){return this._model},draw:function(t,e){var r,a=t.ctx,o=this._model,i=this._rects;this.visible()&&(a.save(),o.clip&&(r=o.area,a.beginPath(),a.rect(r.left,r.top,r.right-r.left,r.bottom-r.top),a.clip()),a.globalAlpha=n(0,o.opacity,1),a.translate(x(e.x),x(e.y)),a.rotate(o.rotation),v(a,i.frame,o),function(t,e,r,a){var o,n=a.textAlign,i=a.color,l=!!i,s=a.font,u=e.length,d=a.textStrokeColor,c=a.textStrokeWidth,h=d&&c;if(u&&(l||h))for(r=function(t,e,r){var a=r.lineHeight,o=t.w,n=t.x;return"center"===e?n+=o/2:"end"!==e&&"right"!==e||(n+=o),{h:a,w:o,x:n,y:t.y+a/2}}(r,n,s),t.font=s.string,t.textAlign=n,t.textBaseline="middle",t.shadowBlur=a.textShadowBlur,t.shadowColor=a.textShadowColor,l&&(t.fillStyle=i),h&&(t.lineJoin="round",t.lineWidth=c,t.strokeStyle=d),o=0,u=e.length;o<u;++o)b(t,e[o],{stroked:h,filled:l,w:r.w,x:r.x,y:r.y+r.h*o})}(a,o.lines,i.text,o),a.restore())}});var p=Number.MIN_SAFE_INTEGER||-9007199254740991,g=Number.MAX_SAFE_INTEGER||9007199254740991;function m(t,e,r){var a=Math.cos(r),o=Math.sin(r),n=e.x,i=e.y;return{x:n+a*(t.x-n)-o*(t.y-i),y:i+o*(t.x-n)+a*(t.y-i)}}function w(t,e){var r,a,o,n,i,l=g,s=p,u=e.origin;for(r=0;r<t.length;++r)o=(a=t[r]).x-u.x,n=a.y-u.y,i=e.vx*o+e.vy*n,l=Math.min(l,i),s=Math.max(s,i);return{min:l,max:s}}function M(t,e){var r=e.x-t.x,a=e.y-t.y,o=Math.sqrt(r*r+a*a);return{vx:(e.x-t.x)/o,vy:(e.y-t.y)/o,origin:t,ln:o}}var k=function(){this._rotation=0,this._rect={x:0,y:0,w:0,h:0}};function $(t,e,r){var a=e.positioner(t,e),o=a.vx,n=a.vy;if(!o&&!n)return{x:a.x,y:a.y};var i=r.w,l=r.h,s=e.rotation,u=Math.abs(i/2*Math.cos(s))+Math.abs(l/2*Math.sin(s)),d=Math.abs(i/2*Math.sin(s))+Math.abs(l/2*Math.cos(s)),c=1/Math.max(Math.abs(o),Math.abs(n));return u*=o*c,d*=n*c,u+=e.offset*o,d+=e.offset*n,{x:a.x+u,y:a.y+d}}t.merge(k.prototype,{center:function(){var t=this._rect;return{x:t.x+t.w/2,y:t.y+t.h/2}},update:function(t,e,r){this._rotation=r,this._rect={x:e.x+t.x,y:e.y+t.y,w:e.w,h:e.h}},contains:function(t){var e=this,r=e._rect;return!((t=m(t,e.center(),-e._rotation)).x<r.x-1||t.y<r.y-1||t.x>r.x+r.w+2||t.y>r.y+r.h+2)},intersects:function(t){var e,r,a,o=this._points(),n=t._points(),i=[M(o[0],o[1]),M(o[0],o[3])];for(this._rotation!==t._rotation&&i.push(M(n[0],n[1]),M(n[0],n[3])),e=0;e<i.length;++e)if(r=w(o,i[e]),a=w(n,i[e]),r.max<a.min||a.max<r.min)return!1;return!0},_points:function(){var t=this,e=t._rect,r=t._rotation,a=t.center();return[m({x:e.x,y:e.y},a,r),m({x:e.x+e.w,y:e.y},a,r),m({x:e.x+e.w,y:e.y+e.h},a,r),m({x:e.x,y:e.y+e.h},a,r)]}});var C={prepare:function(t){var e,r,a,o,n,i=[];for(e=0,a=t.length;e<a;++e)for(r=0,o=t[e].length;r<o;++r)n=t[e][r],i.push(n),n.$layout={_box:new k,_hidable:!1,_visible:!0,_set:e,_idx:r};return i.sort((function(t,e){var r=t.$layout,a=e.$layout;return r._idx===a._idx?a._set-r._set:a._idx-r._idx})),this.update(i),i},update:function(t){var e,r,a,o,n,i=!1;for(e=0,r=t.length;e<r;++e)o=(a=t[e]).model(),(n=a.$layout)._hidable=o&&"auto"===o.display,n._visible=a.visible(),i|=n._hidable;i&&function(t){var e,r,a,o,n,i,l;for(e=0,r=t.length;e<r;++e)(o=(a=t[e]).$layout)._visible&&(l=new Proxy(a._el,{get:(t,e)=>t.getProps([e],!0)[e]}),n=a.geometry(),i=$(l,a.model(),n),o._box.update(i,n,a.rotation()));(function(t,e){var r,a,o,n;for(r=t.length-1;r>=0;--r)for(o=t[r].$layout,a=r-1;a>=0&&o._visible;--a)(n=t[a].$layout)._visible&&o._box.intersects(n._box)&&e(o,n)})(t,(function(t,e){var r=t._hidable,a=e._hidable;r&&a||a?e._visible=!1:r&&(t._visible=!1)}))}(t)},lookup:function(t,e){var r,a;for(r=t.length-1;r>=0;--r)if((a=t[r].$layout)&&a._visible&&a._box.contains(e))return t[r];return null},draw:function(t,e){var r,a,o,n,i,l;for(r=0,a=e.length;r<a;++r)(n=(o=e[r]).$layout)._visible&&(i=o.geometry(),l=$(o._el,o.model(),i),n._box.update(l,i,o.rotation()),o.draw(t,l))}},P="$default";function S(e,r,a){if(r){var o,n=a.$context,i=a.$groups;r[i._set]&&(o=r[i._set][i._key])&&!0===t.callback(o,[n])&&(e.$datalabels._dirty=!0,a.update(n))}}function I(t,e){var r,a,o=t.$datalabels,n=o._listeners;if(n.enter||n.leave){if("mousemove"===e.type)a=C.lookup(o._labels,e);else if("mouseout"!==e.type)return;r=o._hovered,o._hovered=a,function(t,e,r,a){var o,n;(r||a)&&(r?a?r!==a&&(n=o=!0):n=!0:o=!0,n&&S(t,e.leave,r),o&&S(t,e.enter,a))}(t,n,r,a)}}return{id:"datalabels",defaults:{align:"center",anchor:"center",backgroundColor:null,borderColor:null,borderRadius:0,borderWidth:0,clamp:!1,clip:!1,color:void 0,display:!0,font:{family:void 0,lineHeight:1.2,size:void 0,style:void 0,weight:null},formatter:function(e){if(t.isNullOrUndef(e))return null;var r,a,o,n=e;if(t.isObject(e))if(t.isNullOrUndef(e.label))if(t.isNullOrUndef(e.r))for(n="",o=0,a=(r=Object.keys(e)).length;o<a;++o)n+=(0!==o?", ":"")+r[o]+": "+e[r[o]];else n=e.r;else n=e.label;return""+n},labels:void 0,listeners:{},offset:4,opacity:1,padding:{top:4,right:4,bottom:4,left:4},rotation:0,textAlign:"start",textStrokeColor:void 0,textStrokeWidth:0,textShadowBlur:0,textShadowColor:void 0},beforeInit:function(t){t.$datalabels={_actives:[]}},beforeUpdate:function(t){var e=t.$datalabels;e._listened=!1,e._listeners={},e._datasets=[],e._labels=[]},afterDatasetUpdate:function(e,r,a){var o,n,i,l,s,u,d,c,h=r.index,f=e.$datalabels,x=f._datasets[h]=[],y=e.isDatasetVisible(h),v=e.data.datasets[h],b=function(e,r){var a,o,n,i=e.datalabels,l=[];return!1===i?null:(!0===i&&(i={}),r=t.merge({},[r,i]),o=r.labels||{},n=Object.keys(o),delete r.labels,n.length?n.forEach((function(e){o[e]&&l.push(t.merge({},[r,o[e],{_key:e}]))})):l.push(r),a=l.reduce((function(e,r){return t.each(r.listeners||{},(function(t,a){e[a]=e[a]||{},e[a][r._key||P]=t})),delete r.listeners,e}),{}),{labels:l,listeners:a})}(v,a),p=r.meta.data||[],g=e.ctx;for(g.save(),o=0,i=p.length;o<i;++o)if((d=p[o]).$datalabels=[],y&&d&&e.getDataVisibility(o)&&!d.skip)for(n=0,l=b.labels.length;n<l;++n)u=(s=b.labels[n])._key,(c=new _(s,g,d,o)).$groups={_set:h,_key:u||P},c.$context={active:!1,chart:e,dataIndex:o,dataset:v,datasetIndex:h},c.update(c.$context),d.$datalabels.push(c),x.push(c);g.restore(),t.merge(f._listeners,b.listeners,{merger:function(t,e,a){e[t]=e[t]||{},e[t][r.index]=a[t],f._listened=!0}})},afterUpdate:function(t,e){t.$datalabels._labels=C.prepare(t.$datalabels._datasets,e)},afterDatasetsDraw:function(t){C.draw(t,t.$datalabels._labels)},beforeEvent:function(t,e){if(t.$datalabels._listened){var r=e.event;switch(r.type){case"mousemove":case"mouseout":I(t,r);break;case"click":!function(t,e){var r=t.$datalabels,a=r._listeners.click,o=a&&C.lookup(r._labels,e);o&&S(t,a,o)}(t,r)}}},afterEvent:function(t){var e,r,a,o,n,l,s,u=t.$datalabels,d=u._actives,c=u._actives=t.getActiveElements(),h=i(d,c);for(e=0,r=h.length;e<r;++e)if((n=h[e])[1])for(a=0,o=(s=n[0].element.$datalabels||[]).length;a<o;++a)(l=s[a]).$context.active=1===n[1],l.update(l.$context);(u._dirty||h.length)&&(C.update(u._labels),t.render()),delete u._dirty}}}));
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/012-api.js b/mailcow/src/mailcow-dockerized/data/web/js/build/011-api.js
similarity index 90%
rename from mailcow/src/mailcow-dockerized/data/web/js/build/012-api.js
rename to mailcow/src/mailcow-dockerized/data/web/js/build/011-api.js
index d979a9b..c657c13 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/012-api.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/011-api.js
@@ -11,7 +11,7 @@
} else {
var parent_btn_grp = $(elem).parentsUntil(".btn-group").parent();
if (parent_btn_grp.hasClass('btn-group')) {
- parent_btn_grp.replaceWith('<button class="btn btn-default btn-sm" disabled>' + lang_footer.loading + '</a>');
+ parent_btn_grp.replaceWith('<button class="btn btn-secondary btn-sm" disabled>' + lang_footer.loading + '</a>');
}
$(elem).text(lang_footer.loading);
$(elem).attr('data-submitted', '1');
@@ -156,6 +156,12 @@
});
if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject();
+ // parse possible JSON Strings
+ for (var [key, value] of Object.entries(attr_to_merge)) {
+ try {
+ attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
+ } catch {}
+ }
var api_attr = $.extend(api_attr, attr_to_merge)
} else {
return false;
@@ -263,6 +269,12 @@
});
if (!invalid) {
var attr_to_merge = $(this).closest("form").serializeObject();
+ // parse possible JSON Strings
+ for (var [key, value] of Object.entries(attr_to_merge)) {
+ try {
+ attr_to_merge[key] = JSON.parse(attr_to_merge[key]);
+ } catch {}
+ }
var api_attr = $.extend(api_attr, attr_to_merge)
} else {
return false;
@@ -329,6 +341,7 @@
multi_data[id].splice($.inArray($(this).data('item'), multi_data[id]), 1);
multi_data[id].push($(this).data('item'));
}
+
if (typeof $(this).data('text') !== 'undefined') {
$("#DeleteText").empty();
$("#DeleteText").text($(this).data('text'));
@@ -340,13 +353,10 @@
$("#ItemsToDelete").empty();
for (var i in data_array) {
data_array[i] = decodeURIComponent(data_array[i]);
- $("#ItemsToDelete").append("<li>" + data_array[i] + "</li>");
+ $("#ItemsToDelete").append("<li>" + escapeHtml(data_array[i]) + "</li>");
}
})
- $('#ConfirmDeleteModal').modal({
- backdrop: 'static',
- keyboard: false
- })
+ $('#ConfirmDeleteModal').modal('show')
.one('click', '#IsConfirmed', function(e) {
if (is_active($('#IsConfirmed'))) { return false; }
$.ajax({
@@ -370,4 +380,18 @@
$('#ConfirmDeleteModal').modal('hide');
});
});
+
+ // toggle jquery datatables child rows
+ $('button[data-datatables-expand], a[data-datatables-expand]').on('click', function (e) {
+ e.preventDefault();
+ var tableId = e.target.getAttribute("data-datatables-expand");
+ var table = $("#" + tableId).DataTable();
+ table.rows(':not(.parent)').nodes().to$().find('td:first-child').trigger('click');
+ });
+ $('button[data-datatables-collapse], a[data-datatables-collapse]').on('click', function (e) {
+ e.preventDefault();
+ var tableId = e.target.getAttribute("data-datatables-collapse");
+ var table = $("#" + tableId).DataTable();
+ table.rows('.parent').nodes().to$().find('td:first-child').trigger('click');
+ });
});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/011-u2f-api.js b/mailcow/src/mailcow-dockerized/data/web/js/build/011-u2f-api.js
deleted file mode 100644
index e8e653b..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/011-u2f-api.js
+++ /dev/null
@@ -1,778 +0,0 @@
-//Copyright 2014-2015 Google Inc. All rights reserved.
-
-//Use of this source code is governed by a BSD-style
-//license that can be found in the LICENSE file or at
-//https://developers.google.com/open-source/licenses/bsd
-
-// ref: https://github.com/google/u2f-ref-code/blob/master/u2f-gae-demo/war/js/u2f-api.js
-
-/**
- * @fileoverview The U2F api.
- */
-'use strict';
-
-/**
- * Modification:
- * Wrap implementation so that we can exit if window.u2f is already supplied by the browser (see below).
- */
-(function (root) {
- /**
- * Modification:
- * Only continue load this library if window.u2f is not already supplied by the browser.
- */
- var browserImplementsU2f = !!((typeof root.u2f !== 'undefined') && root.u2f.register);
-
- if (browserImplementsU2f) {
- root.u2f.isSupported = true;
- return;
- }
-
- /**
- * Namespace for the U2F api.
- * @type {Object}
- */
- var u2f = root.u2f || {};
-
- /**
- * Modification:
- * Check if browser supports U2F API before this wrapper was added.
- */
- u2f.isSupported = !!(((typeof u2f !== 'undefined') && u2f.register) || ((typeof chrome !== 'undefined') && chrome.runtime));
-
- /**
- * FIDO U2F Javascript API Version
- * @number
- */
- var js_api_version;
-
- /**
- * The U2F extension id
- * @const {string}
- */
- // The Chrome packaged app extension ID.
- // Uncomment this if you want to deploy a server instance that uses
- // the package Chrome app and does not require installing the U2F Chrome extension.
- u2f.EXTENSION_ID = 'kmendfapggjehodndflmmgagdbamhnfd';
- // The U2F Chrome extension ID.
- // Uncomment this if you want to deploy a server instance that uses
- // the U2F Chrome extension to authenticate.
- // u2f.EXTENSION_ID = 'pfboblefjcgdjicmnffhdgionmgcdmne';
-
-
- /**
- * Message types for messsages to/from the extension
- * @const
- * @enum {string}
- */
- u2f.MessageTypes = {
- 'U2F_REGISTER_REQUEST': 'u2f_register_request',
- 'U2F_REGISTER_RESPONSE': 'u2f_register_response',
- 'U2F_SIGN_REQUEST': 'u2f_sign_request',
- 'U2F_SIGN_RESPONSE': 'u2f_sign_response',
- 'U2F_GET_API_VERSION_REQUEST': 'u2f_get_api_version_request',
- 'U2F_GET_API_VERSION_RESPONSE': 'u2f_get_api_version_response'
- };
-
-
- /**
- * Response status codes
- * @const
- * @enum {number}
- */
- u2f.ErrorCodes = {
- 'OK': 0,
- 'OTHER_ERROR': 1,
- 'BAD_REQUEST': 2,
- 'CONFIGURATION_UNSUPPORTED': 3,
- 'DEVICE_INELIGIBLE': 4,
- 'TIMEOUT': 5
- };
-
-
- /**
- * A message for registration requests
- * @typedef {{
- * type: u2f.MessageTypes,
- * appId: ?string,
- * timeoutSeconds: ?number,
- * requestId: ?number
- * }}
- */
- u2f.U2fRequest;
-
-
- /**
- * A message for registration responses
- * @typedef {{
- * type: u2f.MessageTypes,
- * responseData: (u2f.Error | u2f.RegisterResponse | u2f.SignResponse),
- * requestId: ?number
- * }}
- */
- u2f.U2fResponse;
-
-
- /**
- * An error object for responses
- * @typedef {{
- * errorCode: u2f.ErrorCodes,
- * errorMessage: ?string
- * }}
- */
- u2f.Error;
-
- /**
- * Data object for a single sign request.
- * @typedef {enum {BLUETOOTH_RADIO, BLUETOOTH_LOW_ENERGY, USB, NFC}}
- */
- u2f.Transport;
-
-
- /**
- * Data object for a single sign request.
- * @typedef {Array<u2f.Transport>}
- */
- u2f.Transports;
-
- /**
- * Data object for a single sign request.
- * @typedef {{
- * version: string,
- * challenge: string,
- * keyHandle: string,
- * appId: string
- * }}
- */
- u2f.SignRequest;
-
-
- /**
- * Data object for a sign response.
- * @typedef {{
- * keyHandle: string,
- * signatureData: string,
- * clientData: string
- * }}
- */
- u2f.SignResponse;
-
-
- /**
- * Data object for a registration request.
- * @typedef {{
- * version: string,
- * challenge: string
- * }}
- */
- u2f.RegisterRequest;
-
-
- /**
- * Data object for a registration response.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: Transports,
- * appId: string
- * }}
- */
- u2f.RegisterResponse;
-
-
- /**
- * Data object for a registered key.
- * @typedef {{
- * version: string,
- * keyHandle: string,
- * transports: ?Transports,
- * appId: ?string
- * }}
- */
- u2f.RegisteredKey;
-
-
- /**
- * Data object for a get API register response.
- * @typedef {{
- * js_api_version: number
- * }}
- */
- u2f.GetJsApiVersionResponse;
-
-
- //Low level MessagePort API support
-
- /**
- * Sets up a MessagePort to the U2F extension using the
- * available mechanisms.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- */
- u2f.getMessagePort = function (callback) {
- if (typeof chrome != 'undefined' && chrome.runtime) {
- // The actual message here does not matter, but we need to get a reply
- // for the callback to run. Thus, send an empty signature request
- // in order to get a failure response.
- var msg = {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: []
- };
- chrome.runtime.sendMessage(u2f.EXTENSION_ID, msg, function () {
- if (!chrome.runtime.lastError) {
- // We are on a whitelisted origin and can talk directly
- // with the extension.
- u2f.getChromeRuntimePort_(callback);
- } else {
- // chrome.runtime was available, but we couldn't message
- // the extension directly, use iframe
- u2f.getIframePort_(callback);
- }
- });
- } else if (u2f.isAndroidChrome_()) {
- u2f.getAuthenticatorPort_(callback);
- } else if (u2f.isIosChrome_()) {
- u2f.getIosPort_(callback);
- } else {
- // chrome.runtime was not available at all, which is normal
- // when this origin doesn't have access to any extensions.
- u2f.getIframePort_(callback);
- }
- };
-
- /**
- * Detect chrome running on android based on the browser's useragent.
- * @private
- */
- u2f.isAndroidChrome_ = function () {
- var userAgent = navigator.userAgent;
- return userAgent.indexOf('Chrome') != -1 &&
- userAgent.indexOf('Android') != -1;
- };
-
- /**
- * Detect chrome running on iOS based on the browser's platform.
- * @private
- */
- u2f.isIosChrome_ = function () {
- return ["iPhone", "iPad", "iPod"].indexOf(navigator.platform) > -1;
- };
-
- /**
- * Connects directly to the extension via chrome.runtime.connect.
- * @param {function(u2f.WrappedChromeRuntimePort_)} callback
- * @private
- */
- u2f.getChromeRuntimePort_ = function (callback) {
- var port = chrome.runtime.connect(u2f.EXTENSION_ID,
- { 'includeTlsChannelId': true });
- setTimeout(function () {
- callback(new u2f.WrappedChromeRuntimePort_(port));
- }, 0);
- };
-
- /**
- * Return a 'port' abstraction to the Authenticator app.
- * @param {function(u2f.WrappedAuthenticatorPort_)} callback
- * @private
- */
- u2f.getAuthenticatorPort_ = function (callback) {
- setTimeout(function () {
- callback(new u2f.WrappedAuthenticatorPort_());
- }, 0);
- };
-
- /**
- * Return a 'port' abstraction to the iOS client app.
- * @param {function(u2f.WrappedIosPort_)} callback
- * @private
- */
- u2f.getIosPort_ = function (callback) {
- setTimeout(function () {
- callback(new u2f.WrappedIosPort_());
- }, 0);
- };
-
- /**
- * A wrapper for chrome.runtime.Port that is compatible with MessagePort.
- * @param {Port} port
- * @constructor
- * @private
- */
- u2f.WrappedChromeRuntimePort_ = function (port) {
- this.port_ = port;
- };
-
- /**
- * Format and return a sign request compliant with the JS API version supported by the extension.
- * @param {Array<u2f.SignRequest>} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
- u2f.formatSignRequest_ =
- function (appId, challenge, registeredKeys, timeoutSeconds, reqId) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: challenge,
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId
- };
- }
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- signRequests: signRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_SIGN_REQUEST,
- appId: appId,
- challenge: challenge,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- };
-
- /**
- * Format and return a register request compliant with the JS API version supported by the extension..
- * @param {Array<u2f.SignRequest>} signRequests
- * @param {Array<u2f.RegisterRequest>} signRequests
- * @param {number} timeoutSeconds
- * @param {number} reqId
- * @return {Object}
- */
- u2f.formatRegisterRequest_ =
- function (appId, registeredKeys, registerRequests, timeoutSeconds, reqId) {
- if (js_api_version === undefined || js_api_version < 1.1) {
- // Adapt request to the 1.0 JS API
- for (var i = 0; i < registerRequests.length; i++) {
- registerRequests[i].appId = appId;
- }
- var signRequests = [];
- for (var i = 0; i < registeredKeys.length; i++) {
- signRequests[i] = {
- version: registeredKeys[i].version,
- challenge: registerRequests[0],
- keyHandle: registeredKeys[i].keyHandle,
- appId: appId
- };
- }
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- signRequests: signRequests,
- registerRequests: registerRequests,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- }
- // JS 1.1 API
- return {
- type: u2f.MessageTypes.U2F_REGISTER_REQUEST,
- appId: appId,
- registerRequests: registerRequests,
- registeredKeys: registeredKeys,
- timeoutSeconds: timeoutSeconds,
- requestId: reqId
- };
- };
-
-
- /**
- * Posts a message on the underlying channel.
- * @param {Object} message
- */
- u2f.WrappedChromeRuntimePort_.prototype.postMessage = function (message) {
- this.port_.postMessage(message);
- };
-
-
- /**
- * Emulates the HTML 5 addEventListener interface. Works only for the
- * onmessage event, which is hooked up to the chrome.runtime.Port.onMessage.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedChromeRuntimePort_.prototype.addEventListener =
- function (eventName, handler) {
- var name = eventName.toLowerCase();
- if (name == 'message' || name == 'onmessage') {
- this.port_.onMessage.addListener(function (message) {
- // Emulate a minimal MessageEvent object
- handler({ 'data': message });
- });
- } else {
- console.error('WrappedChromeRuntimePort only supports onMessage');
- }
- };
-
- /**
- * Wrap the Authenticator app with a MessagePort interface.
- * @constructor
- * @private
- */
- u2f.WrappedAuthenticatorPort_ = function () {
- this.requestId_ = -1;
- this.requestObject_ = null;
- }
-
- /**
- * Launch the Authenticator intent.
- * @param {Object} message
- */
- u2f.WrappedAuthenticatorPort_.prototype.postMessage = function (message) {
- var intentUrl =
- u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ +
- ';S.request=' + encodeURIComponent(JSON.stringify(message)) +
- ';end';
- document.location = intentUrl;
- };
-
- /**
- * Tells what type of port this is.
- * @return {String} port type
- */
- u2f.WrappedAuthenticatorPort_.prototype.getPortType = function () {
- return "WrappedAuthenticatorPort_";
- };
-
-
- /**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedAuthenticatorPort_.prototype.addEventListener = function (eventName, handler) {
- var name = eventName.toLowerCase();
- if (name == 'message') {
- var self = this;
- /* Register a callback to that executes when
- * chrome injects the response. */
- window.addEventListener(
- 'message', self.onRequestUpdate_.bind(self, handler), false);
- } else {
- console.error('WrappedAuthenticatorPort only supports message');
- }
- };
-
- /**
- * Callback invoked when a response is received from the Authenticator.
- * @param function({data: Object}) callback
- * @param {Object} message message Object
- */
- u2f.WrappedAuthenticatorPort_.prototype.onRequestUpdate_ =
- function (callback, message) {
- var messageObject = JSON.parse(message.data);
- var intentUrl = messageObject['intentURL'];
-
- var errorCode = messageObject['errorCode'];
- var responseObject = null;
- if (messageObject.hasOwnProperty('data')) {
- responseObject = /** @type {Object} */ (
- JSON.parse(messageObject['data']));
- }
-
- callback({ 'data': responseObject });
- };
-
- /**
- * Base URL for intents to Authenticator.
- * @const
- * @private
- */
- u2f.WrappedAuthenticatorPort_.INTENT_URL_BASE_ =
- 'intent:#Intent;action=com.google.android.apps.authenticator.AUTHENTICATE';
-
- /**
- * Wrap the iOS client app with a MessagePort interface.
- * @constructor
- * @private
- */
- u2f.WrappedIosPort_ = function () { };
-
- /**
- * Launch the iOS client app request
- * @param {Object} message
- */
- u2f.WrappedIosPort_.prototype.postMessage = function (message) {
- var str = JSON.stringify(message);
- var url = "u2f://auth?" + encodeURI(str);
- location.replace(url);
- };
-
- /**
- * Tells what type of port this is.
- * @return {String} port type
- */
- u2f.WrappedIosPort_.prototype.getPortType = function () {
- return "WrappedIosPort_";
- };
-
- /**
- * Emulates the HTML 5 addEventListener interface.
- * @param {string} eventName
- * @param {function({data: Object})} handler
- */
- u2f.WrappedIosPort_.prototype.addEventListener = function (eventName, handler) {
- var name = eventName.toLowerCase();
- if (name !== 'message') {
- console.error('WrappedIosPort only supports message');
- }
- };
-
- /**
- * Sets up an embedded trampoline iframe, sourced from the extension.
- * @param {function(MessagePort)} callback
- * @private
- */
- u2f.getIframePort_ = function (callback) {
- // Create the iframe
- var iframeOrigin = 'chrome-extension://' + u2f.EXTENSION_ID;
- var iframe = document.createElement('iframe');
- iframe.src = iframeOrigin + '/u2f-comms.html';
- iframe.setAttribute('style', 'display:none');
- document.body.appendChild(iframe);
-
- var channel = new MessageChannel();
- var ready = function (message) {
- if (message.data == 'ready') {
- channel.port1.removeEventListener('message', ready);
- callback(channel.port1);
- } else {
- console.error('First event on iframe port was not "ready"');
- }
- };
- channel.port1.addEventListener('message', ready);
- channel.port1.start();
-
- iframe.addEventListener('load', function () {
- // Deliver the port to the iframe and initialize
- iframe.contentWindow.postMessage('init', iframeOrigin, [channel.port2]);
- });
- };
-
-
- //High-level JS API
-
- /**
- * Default extension response timeout in seconds.
- * @const
- */
- u2f.EXTENSION_TIMEOUT_SEC = 30;
-
- /**
- * A singleton instance for a MessagePort to the extension.
- * @type {MessagePort|u2f.WrappedChromeRuntimePort_}
- * @private
- */
- u2f.port_ = null;
-
- /**
- * Callbacks waiting for a port
- * @type {Array<function((MessagePort|u2f.WrappedChromeRuntimePort_))>}
- * @private
- */
- u2f.waitingForPort_ = [];
-
- /**
- * A counter for requestIds.
- * @type {number}
- * @private
- */
- u2f.reqCounter_ = 0;
-
- /**
- * A map from requestIds to client callbacks
- * @type {Object.<number,(function((u2f.Error|u2f.RegisterResponse))
- * |function((u2f.Error|u2f.SignResponse)))>}
- * @private
- */
- u2f.callbackMap_ = {};
-
- /**
- * Creates or retrieves the MessagePort singleton to use.
- * @param {function((MessagePort|u2f.WrappedChromeRuntimePort_))} callback
- * @private
- */
- u2f.getPortSingleton_ = function (callback) {
- if (u2f.port_) {
- callback(u2f.port_);
- } else {
- if (u2f.waitingForPort_.length == 0) {
- u2f.getMessagePort(function (port) {
- u2f.port_ = port;
- u2f.port_.addEventListener('message',
- /** @type {function(Event)} */(u2f.responseHandler_));
-
- // Careful, here be async callbacks. Maybe.
- while (u2f.waitingForPort_.length)
- u2f.waitingForPort_.shift()(u2f.port_);
- });
- }
- u2f.waitingForPort_.push(callback);
- }
- };
-
- /**
- * Handles response messages from the extension.
- * @param {MessageEvent.<u2f.Response>} message
- * @private
- */
- u2f.responseHandler_ = function (message) {
- var response = message.data;
- var reqId = response['requestId'];
- if (!reqId || !u2f.callbackMap_[reqId]) {
- console.error('Unknown or missing requestId in response.');
- return;
- }
- var cb = u2f.callbackMap_[reqId];
- delete u2f.callbackMap_[reqId];
- cb(response['responseData']);
- };
-
- /**
- * Dispatches an array of sign requests to available U2F tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the sign request.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sign = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual sign request.
- u2f.getApiVersion(
- function (response) {
- js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
- });
- } else {
- // We know the JS API version. Send the actual sign request in the supported API version.
- u2f.sendSignRequest(appId, challenge, registeredKeys, callback, opt_timeoutSeconds);
- }
- };
-
- /**
- * Dispatches an array of sign requests to available U2F tokens.
- * @param {string=} appId
- * @param {string=} challenge
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.SignResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sendSignRequest = function (appId, challenge, registeredKeys, callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function (port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
- var req = u2f.formatSignRequest_(appId, challenge, registeredKeys, timeoutSeconds, reqId);
- port.postMessage(req);
- });
- };
-
- /**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * If the JS API version supported by the extension is unknown, it first sends a
- * message to the extension to find out the supported API version and then it sends
- * the register request.
- * @param {string=} appId
- * @param {Array<u2f.RegisterRequest>} registerRequests
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.register = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
- if (js_api_version === undefined) {
- // Send a message to get the extension to JS API version, then send the actual register request.
- u2f.getApiVersion(
- function (response) {
- js_api_version = response['js_api_version'] === undefined ? 0 : response['js_api_version'];
- console.log("Extension JS API Version: ", js_api_version);
- u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
- callback, opt_timeoutSeconds);
- });
- } else {
- // We know the JS API version. Send the actual register request in the supported API version.
- u2f.sendRegisterRequest(appId, registerRequests, registeredKeys,
- callback, opt_timeoutSeconds);
- }
- };
-
- /**
- * Dispatches register requests to available U2F tokens. An array of sign
- * requests identifies already registered tokens.
- * @param {string=} appId
- * @param {Array<u2f.RegisterRequest>} registerRequests
- * @param {Array<u2f.RegisteredKey>} registeredKeys
- * @param {function((u2f.Error|u2f.RegisterResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.sendRegisterRequest = function (appId, registerRequests, registeredKeys, callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function (port) {
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var timeoutSeconds = (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC);
- var req = u2f.formatRegisterRequest_(
- appId, registeredKeys, registerRequests, timeoutSeconds, reqId);
- port.postMessage(req);
- });
- };
-
-
- /**
- * Dispatches a message to the extension to find out the supported
- * JS API version.
- * If the user is on a mobile phone and is thus using Google Authenticator instead
- * of the Chrome extension, don't send the request and simply return 0.
- * @param {function((u2f.Error|u2f.GetJsApiVersionResponse))} callback
- * @param {number=} opt_timeoutSeconds
- */
- u2f.getApiVersion = function (callback, opt_timeoutSeconds) {
- u2f.getPortSingleton_(function (port) {
- // If we are using Android Google Authenticator or iOS client app,
- // do not fire an intent to ask which JS API version to use.
- if (port.getPortType) {
- var apiVersion;
- switch (port.getPortType()) {
- case 'WrappedIosPort_':
- case 'WrappedAuthenticatorPort_':
- apiVersion = 1.1;
- break;
-
- default:
- apiVersion = 0;
- break;
- }
- callback({ 'js_api_version': apiVersion });
- return;
- }
- var reqId = ++u2f.reqCounter_;
- u2f.callbackMap_[reqId] = callback;
- var req = {
- type: u2f.MessageTypes.U2F_GET_API_VERSION_REQUEST,
- timeoutSeconds: (typeof opt_timeoutSeconds !== 'undefined' ?
- opt_timeoutSeconds : u2f.EXTENSION_TIMEOUT_SEC),
- requestId: reqId
- };
- port.postMessage(req);
- });
- };
-
- /**
- * Modification:
- * Assign u2f back to window (root) scope.
- */
- root.u2f = u2f;
-}(this));
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/012-markdown-it.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/012-markdown-it.min.js
new file mode 100644
index 0000000..34201f4
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/012-markdown-it.min.js
@@ -0,0 +1,3 @@
+/*! markdown-it 13.0.1 https://github.com/markdown-it/markdown-it @license MIT */
+!function(e,r){"object"==typeof exports&&"undefined"!=typeof module?module.exports=r():"function"==typeof define&&define.amd?define(r):(e="undefined"!=typeof globalThis?globalThis:e||self).markdownit=r()}(this,(function(){"use strict";function e(e){if(e.__esModule)return e;var r=Object.defineProperty({},"__esModule",{value:!0});return Object.keys(e).forEach((function(t){var n=Object.getOwnPropertyDescriptor(e,t);Object.defineProperty(r,t,n.get?n:{enumerable:!0,get:function(){return e[t]}})})),r}var r={Aacute:"\xc1",aacute:"\xe1",Abreve:"\u0102",abreve:"\u0103",ac:"\u223e",acd:"\u223f",acE:"\u223e\u0333",Acirc:"\xc2",acirc:"\xe2",acute:"\xb4",Acy:"\u0410",acy:"\u0430",AElig:"\xc6",aelig:"\xe6",af:"\u2061",Afr:"\ud835\udd04",afr:"\ud835\udd1e",Agrave:"\xc0",agrave:"\xe0",alefsym:"\u2135",aleph:"\u2135",Alpha:"\u0391",alpha:"\u03b1",Amacr:"\u0100",amacr:"\u0101",amalg:"\u2a3f",amp:"&",AMP:"&",andand:"\u2a55",And:"\u2a53",and:"\u2227",andd:"\u2a5c",andslope:"\u2a58",andv:"\u2a5a",ang:"\u2220",ange:"\u29a4",angle:"\u2220",angmsdaa:"\u29a8",angmsdab:"\u29a9",angmsdac:"\u29aa",angmsdad:"\u29ab",angmsdae:"\u29ac",angmsdaf:"\u29ad",angmsdag:"\u29ae",angmsdah:"\u29af",angmsd:"\u2221",angrt:"\u221f",angrtvb:"\u22be",angrtvbd:"\u299d",angsph:"\u2222",angst:"\xc5",angzarr:"\u237c",Aogon:"\u0104",aogon:"\u0105",Aopf:"\ud835\udd38",aopf:"\ud835\udd52",apacir:"\u2a6f",ap:"\u2248",apE:"\u2a70",ape:"\u224a",apid:"\u224b",apos:"'",ApplyFunction:"\u2061",approx:"\u2248",approxeq:"\u224a",Aring:"\xc5",aring:"\xe5",Ascr:"\ud835\udc9c",ascr:"\ud835\udcb6",Assign:"\u2254",ast:"*",asymp:"\u2248",asympeq:"\u224d",Atilde:"\xc3",atilde:"\xe3",Auml:"\xc4",auml:"\xe4",awconint:"\u2233",awint:"\u2a11",backcong:"\u224c",backepsilon:"\u03f6",backprime:"\u2035",backsim:"\u223d",backsimeq:"\u22cd",Backslash:"\u2216",Barv:"\u2ae7",barvee:"\u22bd",barwed:"\u2305",Barwed:"\u2306",barwedge:"\u2305",bbrk:"\u23b5",bbrktbrk:"\u23b6",bcong:"\u224c",Bcy:"\u0411",bcy:"\u0431",bdquo:"\u201e",becaus:"\u2235",because:"\u2235",Because:"\u2235",bemptyv:"\u29b0",bepsi:"\u03f6",bernou:"\u212c",Bernoullis:"\u212c",Beta:"\u0392",beta:"\u03b2",beth:"\u2136",between:"\u226c",Bfr:"\ud835\udd05",bfr:"\ud835\udd1f",bigcap:"\u22c2",bigcirc:"\u25ef",bigcup:"\u22c3",bigodot:"\u2a00",bigoplus:"\u2a01",bigotimes:"\u2a02",bigsqcup:"\u2a06",bigstar:"\u2605",bigtriangledown:"\u25bd",bigtriangleup:"\u25b3",biguplus:"\u2a04",bigvee:"\u22c1",bigwedge:"\u22c0",bkarow:"\u290d",blacklozenge:"\u29eb",blacksquare:"\u25aa",blacktriangle:"\u25b4",blacktriangledown:"\u25be",blacktriangleleft:"\u25c2",blacktriangleright:"\u25b8",blank:"\u2423",blk12:"\u2592",blk14:"\u2591",blk34:"\u2593",block:"\u2588",bne:"=\u20e5",bnequiv:"\u2261\u20e5",bNot:"\u2aed",bnot:"\u2310",Bopf:"\ud835\udd39",bopf:"\ud835\udd53",bot:"\u22a5",bottom:"\u22a5",bowtie:"\u22c8",boxbox:"\u29c9",boxdl:"\u2510",boxdL:"\u2555",boxDl:"\u2556",boxDL:"\u2557",boxdr:"\u250c",boxdR:"\u2552",boxDr:"\u2553",boxDR:"\u2554",boxh:"\u2500",boxH:"\u2550",boxhd:"\u252c",boxHd:"\u2564",boxhD:"\u2565",boxHD:"\u2566",boxhu:"\u2534",boxHu:"\u2567",boxhU:"\u2568",boxHU:"\u2569",boxminus:"\u229f",boxplus:"\u229e",boxtimes:"\u22a0",boxul:"\u2518",boxuL:"\u255b",boxUl:"\u255c",boxUL:"\u255d",boxur:"\u2514",boxuR:"\u2558",boxUr:"\u2559",boxUR:"\u255a",boxv:"\u2502",boxV:"\u2551",boxvh:"\u253c",boxvH:"\u256a",boxVh:"\u256b",boxVH:"\u256c",boxvl:"\u2524",boxvL:"\u2561",boxVl:"\u2562",boxVL:"\u2563",boxvr:"\u251c",boxvR:"\u255e",boxVr:"\u255f",boxVR:"\u2560",bprime:"\u2035",breve:"\u02d8",Breve:"\u02d8",brvbar:"\xa6",bscr:"\ud835\udcb7",Bscr:"\u212c",bsemi:"\u204f",bsim:"\u223d",bsime:"\u22cd",bsolb:"\u29c5",bsol:"\\",bsolhsub:"\u27c8",bull:"\u2022",bullet:"\u2022",bump:"\u224e",bumpE:"\u2aae",bumpe:"\u224f",Bumpeq:"\u224e",bumpeq:"\u224f",Cacute:"\u0106",cacute:"\u0107",capand:"\u2a44",capbrcup:"\u2a49",capcap:"\u2a4b",cap:"\u2229",Cap:"\u22d2",capcup:"\u2a47",capdot:"\u2a40",CapitalDifferentialD:"\u2145",caps:"\u2229\ufe00",caret:"\u2041",caron:"\u02c7",Cayleys:"\u212d",ccaps:"\u2a4d",Ccaron:"\u010c",ccaron:"\u010d",Ccedil:"\xc7",ccedil:"\xe7",Ccirc:"\u0108",ccirc:"\u0109",Cconint:"\u2230",ccups:"\u2a4c",ccupssm:"\u2a50",Cdot:"\u010a",cdot:"\u010b",cedil:"\xb8",Cedilla:"\xb8",cemptyv:"\u29b2",cent:"\xa2",centerdot:"\xb7",CenterDot:"\xb7",cfr:"\ud835\udd20",Cfr:"\u212d",CHcy:"\u0427",chcy:"\u0447",check:"\u2713",checkmark:"\u2713",Chi:"\u03a7",chi:"\u03c7",circ:"\u02c6",circeq:"\u2257",circlearrowleft:"\u21ba",circlearrowright:"\u21bb",circledast:"\u229b",circledcirc:"\u229a",circleddash:"\u229d",CircleDot:"\u2299",circledR:"\xae",circledS:"\u24c8",CircleMinus:"\u2296",CirclePlus:"\u2295",CircleTimes:"\u2297",cir:"\u25cb",cirE:"\u29c3",cire:"\u2257",cirfnint:"\u2a10",cirmid:"\u2aef",cirscir:"\u29c2",ClockwiseContourIntegral:"\u2232",CloseCurlyDoubleQuote:"\u201d",CloseCurlyQuote:"\u2019",clubs:"\u2663",clubsuit:"\u2663",colon:":",Colon:"\u2237",Colone:"\u2a74",colone:"\u2254",coloneq:"\u2254",comma:",",commat:"@",comp:"\u2201",compfn:"\u2218",complement:"\u2201",complexes:"\u2102",cong:"\u2245",congdot:"\u2a6d",Congruent:"\u2261",conint:"\u222e",Conint:"\u222f",ContourIntegral:"\u222e",copf:"\ud835\udd54",Copf:"\u2102",coprod:"\u2210",Coproduct:"\u2210",copy:"\xa9",COPY:"\xa9",copysr:"\u2117",CounterClockwiseContourIntegral:"\u2233",crarr:"\u21b5",cross:"\u2717",Cross:"\u2a2f",Cscr:"\ud835\udc9e",cscr:"\ud835\udcb8",csub:"\u2acf",csube:"\u2ad1",csup:"\u2ad0",csupe:"\u2ad2",ctdot:"\u22ef",cudarrl:"\u2938",cudarrr:"\u2935",cuepr:"\u22de",cuesc:"\u22df",cularr:"\u21b6",cularrp:"\u293d",cupbrcap:"\u2a48",cupcap:"\u2a46",CupCap:"\u224d",cup:"\u222a",Cup:"\u22d3",cupcup:"\u2a4a",cupdot:"\u228d",cupor:"\u2a45",cups:"\u222a\ufe00",curarr:"\u21b7",curarrm:"\u293c",curlyeqprec:"\u22de",curlyeqsucc:"\u22df",curlyvee:"\u22ce",curlywedge:"\u22cf",curren:"\xa4",curvearrowleft:"\u21b6",curvearrowright:"\u21b7",cuvee:"\u22ce",cuwed:"\u22cf",cwconint:"\u2232",cwint:"\u2231",cylcty:"\u232d",dagger:"\u2020",Dagger:"\u2021",daleth:"\u2138",darr:"\u2193",Darr:"\u21a1",dArr:"\u21d3",dash:"\u2010",Dashv:"\u2ae4",dashv:"\u22a3",dbkarow:"\u290f",dblac:"\u02dd",Dcaron:"\u010e",dcaron:"\u010f",Dcy:"\u0414",dcy:"\u0434",ddagger:"\u2021",ddarr:"\u21ca",DD:"\u2145",dd:"\u2146",DDotrahd:"\u2911",ddotseq:"\u2a77",deg:"\xb0",Del:"\u2207",Delta:"\u0394",delta:"\u03b4",demptyv:"\u29b1",dfisht:"\u297f",Dfr:"\ud835\udd07",dfr:"\ud835\udd21",dHar:"\u2965",dharl:"\u21c3",dharr:"\u21c2",DiacriticalAcute:"\xb4",DiacriticalDot:"\u02d9",DiacriticalDoubleAcute:"\u02dd",DiacriticalGrave:"`",DiacriticalTilde:"\u02dc",diam:"\u22c4",diamond:"\u22c4",Diamond:"\u22c4",diamondsuit:"\u2666",diams:"\u2666",die:"\xa8",DifferentialD:"\u2146",digamma:"\u03dd",disin:"\u22f2",div:"\xf7",divide:"\xf7",divideontimes:"\u22c7",divonx:"\u22c7",DJcy:"\u0402",djcy:"\u0452",dlcorn:"\u231e",dlcrop:"\u230d",dollar:"$",Dopf:"\ud835\udd3b",dopf:"\ud835\udd55",Dot:"\xa8",dot:"\u02d9",DotDot:"\u20dc",doteq:"\u2250",doteqdot:"\u2251",DotEqual:"\u2250",dotminus:"\u2238",dotplus:"\u2214",dotsquare:"\u22a1",doublebarwedge:"\u2306",DoubleContourIntegral:"\u222f",DoubleDot:"\xa8",DoubleDownArrow:"\u21d3",DoubleLeftArrow:"\u21d0",DoubleLeftRightArrow:"\u21d4",DoubleLeftTee:"\u2ae4",DoubleLongLeftArrow:"\u27f8",DoubleLongLeftRightArrow:"\u27fa",DoubleLongRightArrow:"\u27f9",DoubleRightArrow:"\u21d2",DoubleRightTee:"\u22a8",DoubleUpArrow:"\u21d1",DoubleUpDownArrow:"\u21d5",DoubleVerticalBar:"\u2225",DownArrowBar:"\u2913",downarrow:"\u2193",DownArrow:"\u2193",Downarrow:"\u21d3",DownArrowUpArrow:"\u21f5",DownBreve:"\u0311",downdownarrows:"\u21ca",downharpoonleft:"\u21c3",downharpoonright:"\u21c2",DownLeftRightVector:"\u2950",DownLeftTeeVector:"\u295e",DownLeftVectorBar:"\u2956",DownLeftVector:"\u21bd",DownRightTeeVector:"\u295f",DownRightVectorBar:"\u2957",DownRightVector:"\u21c1",DownTeeArrow:"\u21a7",DownTee:"\u22a4",drbkarow:"\u2910",drcorn:"\u231f",drcrop:"\u230c",Dscr:"\ud835\udc9f",dscr:"\ud835\udcb9",DScy:"\u0405",dscy:"\u0455",dsol:"\u29f6",Dstrok:"\u0110",dstrok:"\u0111",dtdot:"\u22f1",dtri:"\u25bf",dtrif:"\u25be",duarr:"\u21f5",duhar:"\u296f",dwangle:"\u29a6",DZcy:"\u040f",dzcy:"\u045f",dzigrarr:"\u27ff",Eacute:"\xc9",eacute:"\xe9",easter:"\u2a6e",Ecaron:"\u011a",ecaron:"\u011b",Ecirc:"\xca",ecirc:"\xea",ecir:"\u2256",ecolon:"\u2255",Ecy:"\u042d",ecy:"\u044d",eDDot:"\u2a77",Edot:"\u0116",edot:"\u0117",eDot:"\u2251",ee:"\u2147",efDot:"\u2252",Efr:"\ud835\udd08",efr:"\ud835\udd22",eg:"\u2a9a",Egrave:"\xc8",egrave:"\xe8",egs:"\u2a96",egsdot:"\u2a98",el:"\u2a99",Element:"\u2208",elinters:"\u23e7",ell:"\u2113",els:"\u2a95",elsdot:"\u2a97",Emacr:"\u0112",emacr:"\u0113",empty:"\u2205",emptyset:"\u2205",EmptySmallSquare:"\u25fb",emptyv:"\u2205",EmptyVerySmallSquare:"\u25ab",emsp13:"\u2004",emsp14:"\u2005",emsp:"\u2003",ENG:"\u014a",eng:"\u014b",ensp:"\u2002",Eogon:"\u0118",eogon:"\u0119",Eopf:"\ud835\udd3c",eopf:"\ud835\udd56",epar:"\u22d5",eparsl:"\u29e3",eplus:"\u2a71",epsi:"\u03b5",Epsilon:"\u0395",epsilon:"\u03b5",epsiv:"\u03f5",eqcirc:"\u2256",eqcolon:"\u2255",eqsim:"\u2242",eqslantgtr:"\u2a96",eqslantless:"\u2a95",Equal:"\u2a75",equals:"=",EqualTilde:"\u2242",equest:"\u225f",Equilibrium:"\u21cc",equiv:"\u2261",equivDD:"\u2a78",eqvparsl:"\u29e5",erarr:"\u2971",erDot:"\u2253",escr:"\u212f",Escr:"\u2130",esdot:"\u2250",Esim:"\u2a73",esim:"\u2242",Eta:"\u0397",eta:"\u03b7",ETH:"\xd0",eth:"\xf0",Euml:"\xcb",euml:"\xeb",euro:"\u20ac",excl:"!",exist:"\u2203",Exists:"\u2203",expectation:"\u2130",exponentiale:"\u2147",ExponentialE:"\u2147",fallingdotseq:"\u2252",Fcy:"\u0424",fcy:"\u0444",female:"\u2640",ffilig:"\ufb03",fflig:"\ufb00",ffllig:"\ufb04",Ffr:"\ud835\udd09",ffr:"\ud835\udd23",filig:"\ufb01",FilledSmallSquare:"\u25fc",FilledVerySmallSquare:"\u25aa",fjlig:"fj",flat:"\u266d",fllig:"\ufb02",fltns:"\u25b1",fnof:"\u0192",Fopf:"\ud835\udd3d",fopf:"\ud835\udd57",forall:"\u2200",ForAll:"\u2200",fork:"\u22d4",forkv:"\u2ad9",Fouriertrf:"\u2131",fpartint:"\u2a0d",frac12:"\xbd",frac13:"\u2153",frac14:"\xbc",frac15:"\u2155",frac16:"\u2159",frac18:"\u215b",frac23:"\u2154",frac25:"\u2156",frac34:"\xbe",frac35:"\u2157",frac38:"\u215c",frac45:"\u2158",frac56:"\u215a",frac58:"\u215d",frac78:"\u215e",frasl:"\u2044",frown:"\u2322",fscr:"\ud835\udcbb",Fscr:"\u2131",gacute:"\u01f5",Gamma:"\u0393",gamma:"\u03b3",Gammad:"\u03dc",gammad:"\u03dd",gap:"\u2a86",Gbreve:"\u011e",gbreve:"\u011f",Gcedil:"\u0122",Gcirc:"\u011c",gcirc:"\u011d",Gcy:"\u0413",gcy:"\u0433",Gdot:"\u0120",gdot:"\u0121",ge:"\u2265",gE:"\u2267",gEl:"\u2a8c",gel:"\u22db",geq:"\u2265",geqq:"\u2267",geqslant:"\u2a7e",gescc:"\u2aa9",ges:"\u2a7e",gesdot:"\u2a80",gesdoto:"\u2a82",gesdotol:"\u2a84",gesl:"\u22db\ufe00",gesles:"\u2a94",Gfr:"\ud835\udd0a",gfr:"\ud835\udd24",gg:"\u226b",Gg:"\u22d9",ggg:"\u22d9",gimel:"\u2137",GJcy:"\u0403",gjcy:"\u0453",gla:"\u2aa5",gl:"\u2277",glE:"\u2a92",glj:"\u2aa4",gnap:"\u2a8a",gnapprox:"\u2a8a",gne:"\u2a88",gnE:"\u2269",gneq:"\u2a88",gneqq:"\u2269",gnsim:"\u22e7",Gopf:"\ud835\udd3e",gopf:"\ud835\udd58",grave:"`",GreaterEqual:"\u2265",GreaterEqualLess:"\u22db",GreaterFullEqual:"\u2267",GreaterGreater:"\u2aa2",GreaterLess:"\u2277",GreaterSlantEqual:"\u2a7e",GreaterTilde:"\u2273",Gscr:"\ud835\udca2",gscr:"\u210a",gsim:"\u2273",gsime:"\u2a8e",gsiml:"\u2a90",gtcc:"\u2aa7",gtcir:"\u2a7a",gt:">",GT:">",Gt:"\u226b",gtdot:"\u22d7",gtlPar:"\u2995",gtquest:"\u2a7c",gtrapprox:"\u2a86",gtrarr:"\u2978",gtrdot:"\u22d7",gtreqless:"\u22db",gtreqqless:"\u2a8c",gtrless:"\u2277",gtrsim:"\u2273",gvertneqq:"\u2269\ufe00",gvnE:"\u2269\ufe00",Hacek:"\u02c7",hairsp:"\u200a",half:"\xbd",hamilt:"\u210b",HARDcy:"\u042a",hardcy:"\u044a",harrcir:"\u2948",harr:"\u2194",hArr:"\u21d4",harrw:"\u21ad",Hat:"^",hbar:"\u210f",Hcirc:"\u0124",hcirc:"\u0125",hearts:"\u2665",heartsuit:"\u2665",hellip:"\u2026",hercon:"\u22b9",hfr:"\ud835\udd25",Hfr:"\u210c",HilbertSpace:"\u210b",hksearow:"\u2925",hkswarow:"\u2926",hoarr:"\u21ff",homtht:"\u223b",hookleftarrow:"\u21a9",hookrightarrow:"\u21aa",hopf:"\ud835\udd59",Hopf:"\u210d",horbar:"\u2015",HorizontalLine:"\u2500",hscr:"\ud835\udcbd",Hscr:"\u210b",hslash:"\u210f",Hstrok:"\u0126",hstrok:"\u0127",HumpDownHump:"\u224e",HumpEqual:"\u224f",hybull:"\u2043",hyphen:"\u2010",Iacute:"\xcd",iacute:"\xed",ic:"\u2063",Icirc:"\xce",icirc:"\xee",Icy:"\u0418",icy:"\u0438",Idot:"\u0130",IEcy:"\u0415",iecy:"\u0435",iexcl:"\xa1",iff:"\u21d4",ifr:"\ud835\udd26",Ifr:"\u2111",Igrave:"\xcc",igrave:"\xec",ii:"\u2148",iiiint:"\u2a0c",iiint:"\u222d",iinfin:"\u29dc",iiota:"\u2129",IJlig:"\u0132",ijlig:"\u0133",Imacr:"\u012a",imacr:"\u012b",image:"\u2111",ImaginaryI:"\u2148",imagline:"\u2110",imagpart:"\u2111",imath:"\u0131",Im:"\u2111",imof:"\u22b7",imped:"\u01b5",Implies:"\u21d2",incare:"\u2105",in:"\u2208",infin:"\u221e",infintie:"\u29dd",inodot:"\u0131",intcal:"\u22ba",int:"\u222b",Int:"\u222c",integers:"\u2124",Integral:"\u222b",intercal:"\u22ba",Intersection:"\u22c2",intlarhk:"\u2a17",intprod:"\u2a3c",InvisibleComma:"\u2063",InvisibleTimes:"\u2062",IOcy:"\u0401",iocy:"\u0451",Iogon:"\u012e",iogon:"\u012f",Iopf:"\ud835\udd40",iopf:"\ud835\udd5a",Iota:"\u0399",iota:"\u03b9",iprod:"\u2a3c",iquest:"\xbf",iscr:"\ud835\udcbe",Iscr:"\u2110",isin:"\u2208",isindot:"\u22f5",isinE:"\u22f9",isins:"\u22f4",isinsv:"\u22f3",isinv:"\u2208",it:"\u2062",Itilde:"\u0128",itilde:"\u0129",Iukcy:"\u0406",iukcy:"\u0456",Iuml:"\xcf",iuml:"\xef",Jcirc:"\u0134",jcirc:"\u0135",Jcy:"\u0419",jcy:"\u0439",Jfr:"\ud835\udd0d",jfr:"\ud835\udd27",jmath:"\u0237",Jopf:"\ud835\udd41",jopf:"\ud835\udd5b",Jscr:"\ud835\udca5",jscr:"\ud835\udcbf",Jsercy:"\u0408",jsercy:"\u0458",Jukcy:"\u0404",jukcy:"\u0454",Kappa:"\u039a",kappa:"\u03ba",kappav:"\u03f0",Kcedil:"\u0136",kcedil:"\u0137",Kcy:"\u041a",kcy:"\u043a",Kfr:"\ud835\udd0e",kfr:"\ud835\udd28",kgreen:"\u0138",KHcy:"\u0425",khcy:"\u0445",KJcy:"\u040c",kjcy:"\u045c",Kopf:"\ud835\udd42",kopf:"\ud835\udd5c",Kscr:"\ud835\udca6",kscr:"\ud835\udcc0",lAarr:"\u21da",Lacute:"\u0139",lacute:"\u013a",laemptyv:"\u29b4",lagran:"\u2112",Lambda:"\u039b",lambda:"\u03bb",lang:"\u27e8",Lang:"\u27ea",langd:"\u2991",langle:"\u27e8",lap:"\u2a85",Laplacetrf:"\u2112",laquo:"\xab",larrb:"\u21e4",larrbfs:"\u291f",larr:"\u2190",Larr:"\u219e",lArr:"\u21d0",larrfs:"\u291d",larrhk:"\u21a9",larrlp:"\u21ab",larrpl:"\u2939",larrsim:"\u2973",larrtl:"\u21a2",latail:"\u2919",lAtail:"\u291b",lat:"\u2aab",late:"\u2aad",lates:"\u2aad\ufe00",lbarr:"\u290c",lBarr:"\u290e",lbbrk:"\u2772",lbrace:"{",lbrack:"[",lbrke:"\u298b",lbrksld:"\u298f",lbrkslu:"\u298d",Lcaron:"\u013d",lcaron:"\u013e",Lcedil:"\u013b",lcedil:"\u013c",lceil:"\u2308",lcub:"{",Lcy:"\u041b",lcy:"\u043b",ldca:"\u2936",ldquo:"\u201c",ldquor:"\u201e",ldrdhar:"\u2967",ldrushar:"\u294b",ldsh:"\u21b2",le:"\u2264",lE:"\u2266",LeftAngleBracket:"\u27e8",LeftArrowBar:"\u21e4",leftarrow:"\u2190",LeftArrow:"\u2190",Leftarrow:"\u21d0",LeftArrowRightArrow:"\u21c6",leftarrowtail:"\u21a2",LeftCeiling:"\u2308",LeftDoubleBracket:"\u27e6",LeftDownTeeVector:"\u2961",LeftDownVectorBar:"\u2959",LeftDownVector:"\u21c3",LeftFloor:"\u230a",leftharpoondown:"\u21bd",leftharpoonup:"\u21bc",leftleftarrows:"\u21c7",leftrightarrow:"\u2194",LeftRightArrow:"\u2194",Leftrightarrow:"\u21d4",leftrightarrows:"\u21c6",leftrightharpoons:"\u21cb",leftrightsquigarrow:"\u21ad",LeftRightVector:"\u294e",LeftTeeArrow:"\u21a4",LeftTee:"\u22a3",LeftTeeVector:"\u295a",leftthreetimes:"\u22cb",LeftTriangleBar:"\u29cf",LeftTriangle:"\u22b2",LeftTriangleEqual:"\u22b4",LeftUpDownVector:"\u2951",LeftUpTeeVector:"\u2960",LeftUpVectorBar:"\u2958",LeftUpVector:"\u21bf",LeftVectorBar:"\u2952",LeftVector:"\u21bc",lEg:"\u2a8b",leg:"\u22da",leq:"\u2264",leqq:"\u2266",leqslant:"\u2a7d",lescc:"\u2aa8",les:"\u2a7d",lesdot:"\u2a7f",lesdoto:"\u2a81",lesdotor:"\u2a83",lesg:"\u22da\ufe00",lesges:"\u2a93",lessapprox:"\u2a85",lessdot:"\u22d6",lesseqgtr:"\u22da",lesseqqgtr:"\u2a8b",LessEqualGreater:"\u22da",LessFullEqual:"\u2266",LessGreater:"\u2276",lessgtr:"\u2276",LessLess:"\u2aa1",lesssim:"\u2272",LessSlantEqual:"\u2a7d",LessTilde:"\u2272",lfisht:"\u297c",lfloor:"\u230a",Lfr:"\ud835\udd0f",lfr:"\ud835\udd29",lg:"\u2276",lgE:"\u2a91",lHar:"\u2962",lhard:"\u21bd",lharu:"\u21bc",lharul:"\u296a",lhblk:"\u2584",LJcy:"\u0409",ljcy:"\u0459",llarr:"\u21c7",ll:"\u226a",Ll:"\u22d8",llcorner:"\u231e",Lleftarrow:"\u21da",llhard:"\u296b",lltri:"\u25fa",Lmidot:"\u013f",lmidot:"\u0140",lmoustache:"\u23b0",lmoust:"\u23b0",lnap:"\u2a89",lnapprox:"\u2a89",lne:"\u2a87",lnE:"\u2268",lneq:"\u2a87",lneqq:"\u2268",lnsim:"\u22e6",loang:"\u27ec",loarr:"\u21fd",lobrk:"\u27e6",longleftarrow:"\u27f5",LongLeftArrow:"\u27f5",Longleftarrow:"\u27f8",longleftrightarrow:"\u27f7",LongLeftRightArrow:"\u27f7",Longleftrightarrow:"\u27fa",longmapsto:"\u27fc",longrightarrow:"\u27f6",LongRightArrow:"\u27f6",Longrightarrow:"\u27f9",looparrowleft:"\u21ab",looparrowright:"\u21ac",lopar:"\u2985",Lopf:"\ud835\udd43",lopf:"\ud835\udd5d",loplus:"\u2a2d",lotimes:"\u2a34",lowast:"\u2217",lowbar:"_",LowerLeftArrow:"\u2199",LowerRightArrow:"\u2198",loz:"\u25ca",lozenge:"\u25ca",lozf:"\u29eb",lpar:"(",lparlt:"\u2993",lrarr:"\u21c6",lrcorner:"\u231f",lrhar:"\u21cb",lrhard:"\u296d",lrm:"\u200e",lrtri:"\u22bf",lsaquo:"\u2039",lscr:"\ud835\udcc1",Lscr:"\u2112",lsh:"\u21b0",Lsh:"\u21b0",lsim:"\u2272",lsime:"\u2a8d",lsimg:"\u2a8f",lsqb:"[",lsquo:"\u2018",lsquor:"\u201a",Lstrok:"\u0141",lstrok:"\u0142",ltcc:"\u2aa6",ltcir:"\u2a79",lt:"<",LT:"<",Lt:"\u226a",ltdot:"\u22d6",lthree:"\u22cb",ltimes:"\u22c9",ltlarr:"\u2976",ltquest:"\u2a7b",ltri:"\u25c3",ltrie:"\u22b4",ltrif:"\u25c2",ltrPar:"\u2996",lurdshar:"\u294a",luruhar:"\u2966",lvertneqq:"\u2268\ufe00",lvnE:"\u2268\ufe00",macr:"\xaf",male:"\u2642",malt:"\u2720",maltese:"\u2720",Map:"\u2905",map:"\u21a6",mapsto:"\u21a6",mapstodown:"\u21a7",mapstoleft:"\u21a4",mapstoup:"\u21a5",marker:"\u25ae",mcomma:"\u2a29",Mcy:"\u041c",mcy:"\u043c",mdash:"\u2014",mDDot:"\u223a",measuredangle:"\u2221",MediumSpace:"\u205f",Mellintrf:"\u2133",Mfr:"\ud835\udd10",mfr:"\ud835\udd2a",mho:"\u2127",micro:"\xb5",midast:"*",midcir:"\u2af0",mid:"\u2223",middot:"\xb7",minusb:"\u229f",minus:"\u2212",minusd:"\u2238",minusdu:"\u2a2a",MinusPlus:"\u2213",mlcp:"\u2adb",mldr:"\u2026",mnplus:"\u2213",models:"\u22a7",Mopf:"\ud835\udd44",mopf:"\ud835\udd5e",mp:"\u2213",mscr:"\ud835\udcc2",Mscr:"\u2133",mstpos:"\u223e",Mu:"\u039c",mu:"\u03bc",multimap:"\u22b8",mumap:"\u22b8",nabla:"\u2207",Nacute:"\u0143",nacute:"\u0144",nang:"\u2220\u20d2",nap:"\u2249",napE:"\u2a70\u0338",napid:"\u224b\u0338",napos:"\u0149",napprox:"\u2249",natural:"\u266e",naturals:"\u2115",natur:"\u266e",nbsp:"\xa0",nbump:"\u224e\u0338",nbumpe:"\u224f\u0338",ncap:"\u2a43",Ncaron:"\u0147",ncaron:"\u0148",Ncedil:"\u0145",ncedil:"\u0146",ncong:"\u2247",ncongdot:"\u2a6d\u0338",ncup:"\u2a42",Ncy:"\u041d",ncy:"\u043d",ndash:"\u2013",nearhk:"\u2924",nearr:"\u2197",neArr:"\u21d7",nearrow:"\u2197",ne:"\u2260",nedot:"\u2250\u0338",NegativeMediumSpace:"\u200b",NegativeThickSpace:"\u200b",NegativeThinSpace:"\u200b",NegativeVeryThinSpace:"\u200b",nequiv:"\u2262",nesear:"\u2928",nesim:"\u2242\u0338",NestedGreaterGreater:"\u226b",NestedLessLess:"\u226a",NewLine:"\n",nexist:"\u2204",nexists:"\u2204",Nfr:"\ud835\udd11",nfr:"\ud835\udd2b",ngE:"\u2267\u0338",nge:"\u2271",ngeq:"\u2271",ngeqq:"\u2267\u0338",ngeqslant:"\u2a7e\u0338",nges:"\u2a7e\u0338",nGg:"\u22d9\u0338",ngsim:"\u2275",nGt:"\u226b\u20d2",ngt:"\u226f",ngtr:"\u226f",nGtv:"\u226b\u0338",nharr:"\u21ae",nhArr:"\u21ce",nhpar:"\u2af2",ni:"\u220b",nis:"\u22fc",nisd:"\u22fa",niv:"\u220b",NJcy:"\u040a",njcy:"\u045a",nlarr:"\u219a",nlArr:"\u21cd",nldr:"\u2025",nlE:"\u2266\u0338",nle:"\u2270",nleftarrow:"\u219a",nLeftarrow:"\u21cd",nleftrightarrow:"\u21ae",nLeftrightarrow:"\u21ce",nleq:"\u2270",nleqq:"\u2266\u0338",nleqslant:"\u2a7d\u0338",nles:"\u2a7d\u0338",nless:"\u226e",nLl:"\u22d8\u0338",nlsim:"\u2274",nLt:"\u226a\u20d2",nlt:"\u226e",nltri:"\u22ea",nltrie:"\u22ec",nLtv:"\u226a\u0338",nmid:"\u2224",NoBreak:"\u2060",NonBreakingSpace:"\xa0",nopf:"\ud835\udd5f",Nopf:"\u2115",Not:"\u2aec",not:"\xac",NotCongruent:"\u2262",NotCupCap:"\u226d",NotDoubleVerticalBar:"\u2226",NotElement:"\u2209",NotEqual:"\u2260",NotEqualTilde:"\u2242\u0338",NotExists:"\u2204",NotGreater:"\u226f",NotGreaterEqual:"\u2271",NotGreaterFullEqual:"\u2267\u0338",NotGreaterGreater:"\u226b\u0338",NotGreaterLess:"\u2279",NotGreaterSlantEqual:"\u2a7e\u0338",NotGreaterTilde:"\u2275",NotHumpDownHump:"\u224e\u0338",NotHumpEqual:"\u224f\u0338",notin:"\u2209",notindot:"\u22f5\u0338",notinE:"\u22f9\u0338",notinva:"\u2209",notinvb:"\u22f7",notinvc:"\u22f6",NotLeftTriangleBar:"\u29cf\u0338",NotLeftTriangle:"\u22ea",NotLeftTriangleEqual:"\u22ec",NotLess:"\u226e",NotLessEqual:"\u2270",NotLessGreater:"\u2278",NotLessLess:"\u226a\u0338",NotLessSlantEqual:"\u2a7d\u0338",NotLessTilde:"\u2274",NotNestedGreaterGreater:"\u2aa2\u0338",NotNestedLessLess:"\u2aa1\u0338",notni:"\u220c",notniva:"\u220c",notnivb:"\u22fe",notnivc:"\u22fd",NotPrecedes:"\u2280",NotPrecedesEqual:"\u2aaf\u0338",NotPrecedesSlantEqual:"\u22e0",NotReverseElement:"\u220c",NotRightTriangleBar:"\u29d0\u0338",NotRightTriangle:"\u22eb",NotRightTriangleEqual:"\u22ed",NotSquareSubset:"\u228f\u0338",NotSquareSubsetEqual:"\u22e2",NotSquareSuperset:"\u2290\u0338",NotSquareSupersetEqual:"\u22e3",NotSubset:"\u2282\u20d2",NotSubsetEqual:"\u2288",NotSucceeds:"\u2281",NotSucceedsEqual:"\u2ab0\u0338",NotSucceedsSlantEqual:"\u22e1",NotSucceedsTilde:"\u227f\u0338",NotSuperset:"\u2283\u20d2",NotSupersetEqual:"\u2289",NotTilde:"\u2241",NotTildeEqual:"\u2244",NotTildeFullEqual:"\u2247",NotTildeTilde:"\u2249",NotVerticalBar:"\u2224",nparallel:"\u2226",npar:"\u2226",nparsl:"\u2afd\u20e5",npart:"\u2202\u0338",npolint:"\u2a14",npr:"\u2280",nprcue:"\u22e0",nprec:"\u2280",npreceq:"\u2aaf\u0338",npre:"\u2aaf\u0338",nrarrc:"\u2933\u0338",nrarr:"\u219b",nrArr:"\u21cf",nrarrw:"\u219d\u0338",nrightarrow:"\u219b",nRightarrow:"\u21cf",nrtri:"\u22eb",nrtrie:"\u22ed",nsc:"\u2281",nsccue:"\u22e1",nsce:"\u2ab0\u0338",Nscr:"\ud835\udca9",nscr:"\ud835\udcc3",nshortmid:"\u2224",nshortparallel:"\u2226",nsim:"\u2241",nsime:"\u2244",nsimeq:"\u2244",nsmid:"\u2224",nspar:"\u2226",nsqsube:"\u22e2",nsqsupe:"\u22e3",nsub:"\u2284",nsubE:"\u2ac5\u0338",nsube:"\u2288",nsubset:"\u2282\u20d2",nsubseteq:"\u2288",nsubseteqq:"\u2ac5\u0338",nsucc:"\u2281",nsucceq:"\u2ab0\u0338",nsup:"\u2285",nsupE:"\u2ac6\u0338",nsupe:"\u2289",nsupset:"\u2283\u20d2",nsupseteq:"\u2289",nsupseteqq:"\u2ac6\u0338",ntgl:"\u2279",Ntilde:"\xd1",ntilde:"\xf1",ntlg:"\u2278",ntriangleleft:"\u22ea",ntrianglelefteq:"\u22ec",ntriangleright:"\u22eb",ntrianglerighteq:"\u22ed",Nu:"\u039d",nu:"\u03bd",num:"#",numero:"\u2116",numsp:"\u2007",nvap:"\u224d\u20d2",nvdash:"\u22ac",nvDash:"\u22ad",nVdash:"\u22ae",nVDash:"\u22af",nvge:"\u2265\u20d2",nvgt:">\u20d2",nvHarr:"\u2904",nvinfin:"\u29de",nvlArr:"\u2902",nvle:"\u2264\u20d2",nvlt:"<\u20d2",nvltrie:"\u22b4\u20d2",nvrArr:"\u2903",nvrtrie:"\u22b5\u20d2",nvsim:"\u223c\u20d2",nwarhk:"\u2923",nwarr:"\u2196",nwArr:"\u21d6",nwarrow:"\u2196",nwnear:"\u2927",Oacute:"\xd3",oacute:"\xf3",oast:"\u229b",Ocirc:"\xd4",ocirc:"\xf4",ocir:"\u229a",Ocy:"\u041e",ocy:"\u043e",odash:"\u229d",Odblac:"\u0150",odblac:"\u0151",odiv:"\u2a38",odot:"\u2299",odsold:"\u29bc",OElig:"\u0152",oelig:"\u0153",ofcir:"\u29bf",Ofr:"\ud835\udd12",ofr:"\ud835\udd2c",ogon:"\u02db",Ograve:"\xd2",ograve:"\xf2",ogt:"\u29c1",ohbar:"\u29b5",ohm:"\u03a9",oint:"\u222e",olarr:"\u21ba",olcir:"\u29be",olcross:"\u29bb",oline:"\u203e",olt:"\u29c0",Omacr:"\u014c",omacr:"\u014d",Omega:"\u03a9",omega:"\u03c9",Omicron:"\u039f",omicron:"\u03bf",omid:"\u29b6",ominus:"\u2296",Oopf:"\ud835\udd46",oopf:"\ud835\udd60",opar:"\u29b7",OpenCurlyDoubleQuote:"\u201c",OpenCurlyQuote:"\u2018",operp:"\u29b9",oplus:"\u2295",orarr:"\u21bb",Or:"\u2a54",or:"\u2228",ord:"\u2a5d",order:"\u2134",orderof:"\u2134",ordf:"\xaa",ordm:"\xba",origof:"\u22b6",oror:"\u2a56",orslope:"\u2a57",orv:"\u2a5b",oS:"\u24c8",Oscr:"\ud835\udcaa",oscr:"\u2134",Oslash:"\xd8",oslash:"\xf8",osol:"\u2298",Otilde:"\xd5",otilde:"\xf5",otimesas:"\u2a36",Otimes:"\u2a37",otimes:"\u2297",Ouml:"\xd6",ouml:"\xf6",ovbar:"\u233d",OverBar:"\u203e",OverBrace:"\u23de",OverBracket:"\u23b4",OverParenthesis:"\u23dc",para:"\xb6",parallel:"\u2225",par:"\u2225",parsim:"\u2af3",parsl:"\u2afd",part:"\u2202",PartialD:"\u2202",Pcy:"\u041f",pcy:"\u043f",percnt:"%",period:".",permil:"\u2030",perp:"\u22a5",pertenk:"\u2031",Pfr:"\ud835\udd13",pfr:"\ud835\udd2d",Phi:"\u03a6",phi:"\u03c6",phiv:"\u03d5",phmmat:"\u2133",phone:"\u260e",Pi:"\u03a0",pi:"\u03c0",pitchfork:"\u22d4",piv:"\u03d6",planck:"\u210f",planckh:"\u210e",plankv:"\u210f",plusacir:"\u2a23",plusb:"\u229e",pluscir:"\u2a22",plus:"+",plusdo:"\u2214",plusdu:"\u2a25",pluse:"\u2a72",PlusMinus:"\xb1",plusmn:"\xb1",plussim:"\u2a26",plustwo:"\u2a27",pm:"\xb1",Poincareplane:"\u210c",pointint:"\u2a15",popf:"\ud835\udd61",Popf:"\u2119",pound:"\xa3",prap:"\u2ab7",Pr:"\u2abb",pr:"\u227a",prcue:"\u227c",precapprox:"\u2ab7",prec:"\u227a",preccurlyeq:"\u227c",Precedes:"\u227a",PrecedesEqual:"\u2aaf",PrecedesSlantEqual:"\u227c",PrecedesTilde:"\u227e",preceq:"\u2aaf",precnapprox:"\u2ab9",precneqq:"\u2ab5",precnsim:"\u22e8",pre:"\u2aaf",prE:"\u2ab3",precsim:"\u227e",prime:"\u2032",Prime:"\u2033",primes:"\u2119",prnap:"\u2ab9",prnE:"\u2ab5",prnsim:"\u22e8",prod:"\u220f",Product:"\u220f",profalar:"\u232e",profline:"\u2312",profsurf:"\u2313",prop:"\u221d",Proportional:"\u221d",Proportion:"\u2237",propto:"\u221d",prsim:"\u227e",prurel:"\u22b0",Pscr:"\ud835\udcab",pscr:"\ud835\udcc5",Psi:"\u03a8",psi:"\u03c8",puncsp:"\u2008",Qfr:"\ud835\udd14",qfr:"\ud835\udd2e",qint:"\u2a0c",qopf:"\ud835\udd62",Qopf:"\u211a",qprime:"\u2057",Qscr:"\ud835\udcac",qscr:"\ud835\udcc6",quaternions:"\u210d",quatint:"\u2a16",quest:"?",questeq:"\u225f",quot:'"',QUOT:'"',rAarr:"\u21db",race:"\u223d\u0331",Racute:"\u0154",racute:"\u0155",radic:"\u221a",raemptyv:"\u29b3",rang:"\u27e9",Rang:"\u27eb",rangd:"\u2992",range:"\u29a5",rangle:"\u27e9",raquo:"\xbb",rarrap:"\u2975",rarrb:"\u21e5",rarrbfs:"\u2920",rarrc:"\u2933",rarr:"\u2192",Rarr:"\u21a0",rArr:"\u21d2",rarrfs:"\u291e",rarrhk:"\u21aa",rarrlp:"\u21ac",rarrpl:"\u2945",rarrsim:"\u2974",Rarrtl:"\u2916",rarrtl:"\u21a3",rarrw:"\u219d",ratail:"\u291a",rAtail:"\u291c",ratio:"\u2236",rationals:"\u211a",rbarr:"\u290d",rBarr:"\u290f",RBarr:"\u2910",rbbrk:"\u2773",rbrace:"}",rbrack:"]",rbrke:"\u298c",rbrksld:"\u298e",rbrkslu:"\u2990",Rcaron:"\u0158",rcaron:"\u0159",Rcedil:"\u0156",rcedil:"\u0157",rceil:"\u2309",rcub:"}",Rcy:"\u0420",rcy:"\u0440",rdca:"\u2937",rdldhar:"\u2969",rdquo:"\u201d",rdquor:"\u201d",rdsh:"\u21b3",real:"\u211c",realine:"\u211b",realpart:"\u211c",reals:"\u211d",Re:"\u211c",rect:"\u25ad",reg:"\xae",REG:"\xae",ReverseElement:"\u220b",ReverseEquilibrium:"\u21cb",ReverseUpEquilibrium:"\u296f",rfisht:"\u297d",rfloor:"\u230b",rfr:"\ud835\udd2f",Rfr:"\u211c",rHar:"\u2964",rhard:"\u21c1",rharu:"\u21c0",rharul:"\u296c",Rho:"\u03a1",rho:"\u03c1",rhov:"\u03f1",RightAngleBracket:"\u27e9",RightArrowBar:"\u21e5",rightarrow:"\u2192",RightArrow:"\u2192",Rightarrow:"\u21d2",RightArrowLeftArrow:"\u21c4",rightarrowtail:"\u21a3",RightCeiling:"\u2309",RightDoubleBracket:"\u27e7",RightDownTeeVector:"\u295d",RightDownVectorBar:"\u2955",RightDownVector:"\u21c2",RightFloor:"\u230b",rightharpoondown:"\u21c1",rightharpoonup:"\u21c0",rightleftarrows:"\u21c4",rightleftharpoons:"\u21cc",rightrightarrows:"\u21c9",rightsquigarrow:"\u219d",RightTeeArrow:"\u21a6",RightTee:"\u22a2",RightTeeVector:"\u295b",rightthreetimes:"\u22cc",RightTriangleBar:"\u29d0",RightTriangle:"\u22b3",RightTriangleEqual:"\u22b5",RightUpDownVector:"\u294f",RightUpTeeVector:"\u295c",RightUpVectorBar:"\u2954",RightUpVector:"\u21be",RightVectorBar:"\u2953",RightVector:"\u21c0",ring:"\u02da",risingdotseq:"\u2253",rlarr:"\u21c4",rlhar:"\u21cc",rlm:"\u200f",rmoustache:"\u23b1",rmoust:"\u23b1",rnmid:"\u2aee",roang:"\u27ed",roarr:"\u21fe",robrk:"\u27e7",ropar:"\u2986",ropf:"\ud835\udd63",Ropf:"\u211d",roplus:"\u2a2e",rotimes:"\u2a35",RoundImplies:"\u2970",rpar:")",rpargt:"\u2994",rppolint:"\u2a12",rrarr:"\u21c9",Rrightarrow:"\u21db",rsaquo:"\u203a",rscr:"\ud835\udcc7",Rscr:"\u211b",rsh:"\u21b1",Rsh:"\u21b1",rsqb:"]",rsquo:"\u2019",rsquor:"\u2019",rthree:"\u22cc",rtimes:"\u22ca",rtri:"\u25b9",rtrie:"\u22b5",rtrif:"\u25b8",rtriltri:"\u29ce",RuleDelayed:"\u29f4",ruluhar:"\u2968",rx:"\u211e",Sacute:"\u015a",sacute:"\u015b",sbquo:"\u201a",scap:"\u2ab8",Scaron:"\u0160",scaron:"\u0161",Sc:"\u2abc",sc:"\u227b",sccue:"\u227d",sce:"\u2ab0",scE:"\u2ab4",Scedil:"\u015e",scedil:"\u015f",Scirc:"\u015c",scirc:"\u015d",scnap:"\u2aba",scnE:"\u2ab6",scnsim:"\u22e9",scpolint:"\u2a13",scsim:"\u227f",Scy:"\u0421",scy:"\u0441",sdotb:"\u22a1",sdot:"\u22c5",sdote:"\u2a66",searhk:"\u2925",searr:"\u2198",seArr:"\u21d8",searrow:"\u2198",sect:"\xa7",semi:";",seswar:"\u2929",setminus:"\u2216",setmn:"\u2216",sext:"\u2736",Sfr:"\ud835\udd16",sfr:"\ud835\udd30",sfrown:"\u2322",sharp:"\u266f",SHCHcy:"\u0429",shchcy:"\u0449",SHcy:"\u0428",shcy:"\u0448",ShortDownArrow:"\u2193",ShortLeftArrow:"\u2190",shortmid:"\u2223",shortparallel:"\u2225",ShortRightArrow:"\u2192",ShortUpArrow:"\u2191",shy:"\xad",Sigma:"\u03a3",sigma:"\u03c3",sigmaf:"\u03c2",sigmav:"\u03c2",sim:"\u223c",simdot:"\u2a6a",sime:"\u2243",simeq:"\u2243",simg:"\u2a9e",simgE:"\u2aa0",siml:"\u2a9d",simlE:"\u2a9f",simne:"\u2246",simplus:"\u2a24",simrarr:"\u2972",slarr:"\u2190",SmallCircle:"\u2218",smallsetminus:"\u2216",smashp:"\u2a33",smeparsl:"\u29e4",smid:"\u2223",smile:"\u2323",smt:"\u2aaa",smte:"\u2aac",smtes:"\u2aac\ufe00",SOFTcy:"\u042c",softcy:"\u044c",solbar:"\u233f",solb:"\u29c4",sol:"/",Sopf:"\ud835\udd4a",sopf:"\ud835\udd64",spades:"\u2660",spadesuit:"\u2660",spar:"\u2225",sqcap:"\u2293",sqcaps:"\u2293\ufe00",sqcup:"\u2294",sqcups:"\u2294\ufe00",Sqrt:"\u221a",sqsub:"\u228f",sqsube:"\u2291",sqsubset:"\u228f",sqsubseteq:"\u2291",sqsup:"\u2290",sqsupe:"\u2292",sqsupset:"\u2290",sqsupseteq:"\u2292",square:"\u25a1",Square:"\u25a1",SquareIntersection:"\u2293",SquareSubset:"\u228f",SquareSubsetEqual:"\u2291",SquareSuperset:"\u2290",SquareSupersetEqual:"\u2292",SquareUnion:"\u2294",squarf:"\u25aa",squ:"\u25a1",squf:"\u25aa",srarr:"\u2192",Sscr:"\ud835\udcae",sscr:"\ud835\udcc8",ssetmn:"\u2216",ssmile:"\u2323",sstarf:"\u22c6",Star:"\u22c6",star:"\u2606",starf:"\u2605",straightepsilon:"\u03f5",straightphi:"\u03d5",strns:"\xaf",sub:"\u2282",Sub:"\u22d0",subdot:"\u2abd",subE:"\u2ac5",sube:"\u2286",subedot:"\u2ac3",submult:"\u2ac1",subnE:"\u2acb",subne:"\u228a",subplus:"\u2abf",subrarr:"\u2979",subset:"\u2282",Subset:"\u22d0",subseteq:"\u2286",subseteqq:"\u2ac5",SubsetEqual:"\u2286",subsetneq:"\u228a",subsetneqq:"\u2acb",subsim:"\u2ac7",subsub:"\u2ad5",subsup:"\u2ad3",succapprox:"\u2ab8",succ:"\u227b",succcurlyeq:"\u227d",Succeeds:"\u227b",SucceedsEqual:"\u2ab0",SucceedsSlantEqual:"\u227d",SucceedsTilde:"\u227f",succeq:"\u2ab0",succnapprox:"\u2aba",succneqq:"\u2ab6",succnsim:"\u22e9",succsim:"\u227f",SuchThat:"\u220b",sum:"\u2211",Sum:"\u2211",sung:"\u266a",sup1:"\xb9",sup2:"\xb2",sup3:"\xb3",sup:"\u2283",Sup:"\u22d1",supdot:"\u2abe",supdsub:"\u2ad8",supE:"\u2ac6",supe:"\u2287",supedot:"\u2ac4",Superset:"\u2283",SupersetEqual:"\u2287",suphsol:"\u27c9",suphsub:"\u2ad7",suplarr:"\u297b",supmult:"\u2ac2",supnE:"\u2acc",supne:"\u228b",supplus:"\u2ac0",supset:"\u2283",Supset:"\u22d1",supseteq:"\u2287",supseteqq:"\u2ac6",supsetneq:"\u228b",supsetneqq:"\u2acc",supsim:"\u2ac8",supsub:"\u2ad4",supsup:"\u2ad6",swarhk:"\u2926",swarr:"\u2199",swArr:"\u21d9",swarrow:"\u2199",swnwar:"\u292a",szlig:"\xdf",Tab:"\t",target:"\u2316",Tau:"\u03a4",tau:"\u03c4",tbrk:"\u23b4",Tcaron:"\u0164",tcaron:"\u0165",Tcedil:"\u0162",tcedil:"\u0163",Tcy:"\u0422",tcy:"\u0442",tdot:"\u20db",telrec:"\u2315",Tfr:"\ud835\udd17",tfr:"\ud835\udd31",there4:"\u2234",therefore:"\u2234",Therefore:"\u2234",Theta:"\u0398",theta:"\u03b8",thetasym:"\u03d1",thetav:"\u03d1",thickapprox:"\u2248",thicksim:"\u223c",ThickSpace:"\u205f\u200a",ThinSpace:"\u2009",thinsp:"\u2009",thkap:"\u2248",thksim:"\u223c",THORN:"\xde",thorn:"\xfe",tilde:"\u02dc",Tilde:"\u223c",TildeEqual:"\u2243",TildeFullEqual:"\u2245",TildeTilde:"\u2248",timesbar:"\u2a31",timesb:"\u22a0",times:"\xd7",timesd:"\u2a30",tint:"\u222d",toea:"\u2928",topbot:"\u2336",topcir:"\u2af1",top:"\u22a4",Topf:"\ud835\udd4b",topf:"\ud835\udd65",topfork:"\u2ada",tosa:"\u2929",tprime:"\u2034",trade:"\u2122",TRADE:"\u2122",triangle:"\u25b5",triangledown:"\u25bf",triangleleft:"\u25c3",trianglelefteq:"\u22b4",triangleq:"\u225c",triangleright:"\u25b9",trianglerighteq:"\u22b5",tridot:"\u25ec",trie:"\u225c",triminus:"\u2a3a",TripleDot:"\u20db",triplus:"\u2a39",trisb:"\u29cd",tritime:"\u2a3b",trpezium:"\u23e2",Tscr:"\ud835\udcaf",tscr:"\ud835\udcc9",TScy:"\u0426",tscy:"\u0446",TSHcy:"\u040b",tshcy:"\u045b",Tstrok:"\u0166",tstrok:"\u0167",twixt:"\u226c",twoheadleftarrow:"\u219e",twoheadrightarrow:"\u21a0",Uacute:"\xda",uacute:"\xfa",uarr:"\u2191",Uarr:"\u219f",uArr:"\u21d1",Uarrocir:"\u2949",Ubrcy:"\u040e",ubrcy:"\u045e",Ubreve:"\u016c",ubreve:"\u016d",Ucirc:"\xdb",ucirc:"\xfb",Ucy:"\u0423",ucy:"\u0443",udarr:"\u21c5",Udblac:"\u0170",udblac:"\u0171",udhar:"\u296e",ufisht:"\u297e",Ufr:"\ud835\udd18",ufr:"\ud835\udd32",Ugrave:"\xd9",ugrave:"\xf9",uHar:"\u2963",uharl:"\u21bf",uharr:"\u21be",uhblk:"\u2580",ulcorn:"\u231c",ulcorner:"\u231c",ulcrop:"\u230f",ultri:"\u25f8",Umacr:"\u016a",umacr:"\u016b",uml:"\xa8",UnderBar:"_",UnderBrace:"\u23df",UnderBracket:"\u23b5",UnderParenthesis:"\u23dd",Union:"\u22c3",UnionPlus:"\u228e",Uogon:"\u0172",uogon:"\u0173",Uopf:"\ud835\udd4c",uopf:"\ud835\udd66",UpArrowBar:"\u2912",uparrow:"\u2191",UpArrow:"\u2191",Uparrow:"\u21d1",UpArrowDownArrow:"\u21c5",updownarrow:"\u2195",UpDownArrow:"\u2195",Updownarrow:"\u21d5",UpEquilibrium:"\u296e",upharpoonleft:"\u21bf",upharpoonright:"\u21be",uplus:"\u228e",UpperLeftArrow:"\u2196",UpperRightArrow:"\u2197",upsi:"\u03c5",Upsi:"\u03d2",upsih:"\u03d2",Upsilon:"\u03a5",upsilon:"\u03c5",UpTeeArrow:"\u21a5",UpTee:"\u22a5",upuparrows:"\u21c8",urcorn:"\u231d",urcorner:"\u231d",urcrop:"\u230e",Uring:"\u016e",uring:"\u016f",urtri:"\u25f9",Uscr:"\ud835\udcb0",uscr:"\ud835\udcca",utdot:"\u22f0",Utilde:"\u0168",utilde:"\u0169",utri:"\u25b5",utrif:"\u25b4",uuarr:"\u21c8",Uuml:"\xdc",uuml:"\xfc",uwangle:"\u29a7",vangrt:"\u299c",varepsilon:"\u03f5",varkappa:"\u03f0",varnothing:"\u2205",varphi:"\u03d5",varpi:"\u03d6",varpropto:"\u221d",varr:"\u2195",vArr:"\u21d5",varrho:"\u03f1",varsigma:"\u03c2",varsubsetneq:"\u228a\ufe00",varsubsetneqq:"\u2acb\ufe00",varsupsetneq:"\u228b\ufe00",varsupsetneqq:"\u2acc\ufe00",vartheta:"\u03d1",vartriangleleft:"\u22b2",vartriangleright:"\u22b3",vBar:"\u2ae8",Vbar:"\u2aeb",vBarv:"\u2ae9",Vcy:"\u0412",vcy:"\u0432",vdash:"\u22a2",vDash:"\u22a8",Vdash:"\u22a9",VDash:"\u22ab",Vdashl:"\u2ae6",veebar:"\u22bb",vee:"\u2228",Vee:"\u22c1",veeeq:"\u225a",vellip:"\u22ee",verbar:"|",Verbar:"\u2016",vert:"|",Vert:"\u2016",VerticalBar:"\u2223",VerticalLine:"|",VerticalSeparator:"\u2758",VerticalTilde:"\u2240",VeryThinSpace:"\u200a",Vfr:"\ud835\udd19",vfr:"\ud835\udd33",vltri:"\u22b2",vnsub:"\u2282\u20d2",vnsup:"\u2283\u20d2",Vopf:"\ud835\udd4d",vopf:"\ud835\udd67",vprop:"\u221d",vrtri:"\u22b3",Vscr:"\ud835\udcb1",vscr:"\ud835\udccb",vsubnE:"\u2acb\ufe00",vsubne:"\u228a\ufe00",vsupnE:"\u2acc\ufe00",vsupne:"\u228b\ufe00",Vvdash:"\u22aa",vzigzag:"\u299a",Wcirc:"\u0174",wcirc:"\u0175",wedbar:"\u2a5f",wedge:"\u2227",Wedge:"\u22c0",wedgeq:"\u2259",weierp:"\u2118",Wfr:"\ud835\udd1a",wfr:"\ud835\udd34",Wopf:"\ud835\udd4e",wopf:"\ud835\udd68",wp:"\u2118",wr:"\u2240",wreath:"\u2240",Wscr:"\ud835\udcb2",wscr:"\ud835\udccc",xcap:"\u22c2",xcirc:"\u25ef",xcup:"\u22c3",xdtri:"\u25bd",Xfr:"\ud835\udd1b",xfr:"\ud835\udd35",xharr:"\u27f7",xhArr:"\u27fa",Xi:"\u039e",xi:"\u03be",xlarr:"\u27f5",xlArr:"\u27f8",xmap:"\u27fc",xnis:"\u22fb",xodot:"\u2a00",Xopf:"\ud835\udd4f",xopf:"\ud835\udd69",xoplus:"\u2a01",xotime:"\u2a02",xrarr:"\u27f6",xrArr:"\u27f9",Xscr:"\ud835\udcb3",xscr:"\ud835\udccd",xsqcup:"\u2a06",xuplus:"\u2a04",xutri:"\u25b3",xvee:"\u22c1",xwedge:"\u22c0",Yacute:"\xdd",yacute:"\xfd",YAcy:"\u042f",yacy:"\u044f",Ycirc:"\u0176",ycirc:"\u0177",Ycy:"\u042b",ycy:"\u044b",yen:"\xa5",Yfr:"\ud835\udd1c",yfr:"\ud835\udd36",YIcy:"\u0407",yicy:"\u0457",Yopf:"\ud835\udd50",yopf:"\ud835\udd6a",Yscr:"\ud835\udcb4",yscr:"\ud835\udcce",YUcy:"\u042e",yucy:"\u044e",yuml:"\xff",Yuml:"\u0178",Zacute:"\u0179",zacute:"\u017a",Zcaron:"\u017d",zcaron:"\u017e",Zcy:"\u0417",zcy:"\u0437",Zdot:"\u017b",zdot:"\u017c",zeetrf:"\u2128",ZeroWidthSpace:"\u200b",Zeta:"\u0396",zeta:"\u03b6",zfr:"\ud835\udd37",Zfr:"\u2128",ZHcy:"\u0416",zhcy:"\u0436",zigrarr:"\u21dd",zopf:"\ud835\udd6b",Zopf:"\u2124",Zscr:"\ud835\udcb5",zscr:"\ud835\udccf",zwj:"\u200d",zwnj:"\u200c"},t=/[!-#%-\*,-\/:;\?@\[-\]_\{\}\xA1\xA7\xAB\xB6\xB7\xBB\xBF\u037E\u0387\u055A-\u055F\u0589\u058A\u05BE\u05C0\u05C3\u05C6\u05F3\u05F4\u0609\u060A\u060C\u060D\u061B\u061E\u061F\u066A-\u066D\u06D4\u0700-\u070D\u07F7-\u07F9\u0830-\u083E\u085E\u0964\u0965\u0970\u09FD\u0A76\u0AF0\u0C84\u0DF4\u0E4F\u0E5A\u0E5B\u0F04-\u0F12\u0F14\u0F3A-\u0F3D\u0F85\u0FD0-\u0FD4\u0FD9\u0FDA\u104A-\u104F\u10FB\u1360-\u1368\u1400\u166D\u166E\u169B\u169C\u16EB-\u16ED\u1735\u1736\u17D4-\u17D6\u17D8-\u17DA\u1800-\u180A\u1944\u1945\u1A1E\u1A1F\u1AA0-\u1AA6\u1AA8-\u1AAD\u1B5A-\u1B60\u1BFC-\u1BFF\u1C3B-\u1C3F\u1C7E\u1C7F\u1CC0-\u1CC7\u1CD3\u2010-\u2027\u2030-\u2043\u2045-\u2051\u2053-\u205E\u207D\u207E\u208D\u208E\u2308-\u230B\u2329\u232A\u2768-\u2775\u27C5\u27C6\u27E6-\u27EF\u2983-\u2998\u29D8-\u29DB\u29FC\u29FD\u2CF9-\u2CFC\u2CFE\u2CFF\u2D70\u2E00-\u2E2E\u2E30-\u2E4E\u3001-\u3003\u3008-\u3011\u3014-\u301F\u3030\u303D\u30A0\u30FB\uA4FE\uA4FF\uA60D-\uA60F\uA673\uA67E\uA6F2-\uA6F7\uA874-\uA877\uA8CE\uA8CF\uA8F8-\uA8FA\uA8FC\uA92E\uA92F\uA95F\uA9C1-\uA9CD\uA9DE\uA9DF\uAA5C-\uAA5F\uAADE\uAADF\uAAF0\uAAF1\uABEB\uFD3E\uFD3F\uFE10-\uFE19\uFE30-\uFE52\uFE54-\uFE61\uFE63\uFE68\uFE6A\uFE6B\uFF01-\uFF03\uFF05-\uFF0A\uFF0C-\uFF0F\uFF1A\uFF1B\uFF1F\uFF20\uFF3B-\uFF3D\uFF3F\uFF5B\uFF5D\uFF5F-\uFF65]|\uD800[\uDD00-\uDD02\uDF9F\uDFD0]|\uD801\uDD6F|\uD802[\uDC57\uDD1F\uDD3F\uDE50-\uDE58\uDE7F\uDEF0-\uDEF6\uDF39-\uDF3F\uDF99-\uDF9C]|\uD803[\uDF55-\uDF59]|\uD804[\uDC47-\uDC4D\uDCBB\uDCBC\uDCBE-\uDCC1\uDD40-\uDD43\uDD74\uDD75\uDDC5-\uDDC8\uDDCD\uDDDB\uDDDD-\uDDDF\uDE38-\uDE3D\uDEA9]|\uD805[\uDC4B-\uDC4F\uDC5B\uDC5D\uDCC6\uDDC1-\uDDD7\uDE41-\uDE43\uDE60-\uDE6C\uDF3C-\uDF3E]|\uD806[\uDC3B\uDE3F-\uDE46\uDE9A-\uDE9C\uDE9E-\uDEA2]|\uD807[\uDC41-\uDC45\uDC70\uDC71\uDEF7\uDEF8]|\uD809[\uDC70-\uDC74]|\uD81A[\uDE6E\uDE6F\uDEF5\uDF37-\uDF3B\uDF44]|\uD81B[\uDE97-\uDE9A]|\uD82F\uDC9F|\uD836[\uDE87-\uDE8B]|\uD83A[\uDD5E\uDD5F]/,n={};function s(e,r,t){var o,i,a,c,l,u="";for("string"!=typeof r&&(t=r,r=s.defaultChars),void 0===t&&(t=!0),l=function(e){var r,t,s=n[e];if(s)return s;for(s=n[e]=[],r=0;r<128;r++)t=String.fromCharCode(r),/^[0-9a-z]$/i.test(t)?s.push(t):s.push("%"+("0"+r.toString(16).toUpperCase()).slice(-2));for(r=0;r<e.length;r++)s[e.charCodeAt(r)]=e[r];return s}(r),o=0,i=e.length;o<i;o++)if(a=e.charCodeAt(o),t&&37===a&&o+2<i&&/^[0-9a-f]{2}$/i.test(e.slice(o+1,o+3)))u+=e.slice(o,o+3),o+=2;else if(a<128)u+=l[a];else if(a>=55296&&a<=57343){if(a>=55296&&a<=56319&&o+1<i&&(c=e.charCodeAt(o+1))>=56320&&c<=57343){u+=encodeURIComponent(e[o]+e[o+1]),o++;continue}u+="%EF%BF%BD"}else u+=encodeURIComponent(e[o]);return u}s.defaultChars=";/?:@&=+$,-_.!~*'()#",s.componentChars="-_.!~*'()";var o=s,i={};function a(e,r){var t;return"string"!=typeof r&&(r=a.defaultChars),t=function(e){var r,t,n=i[e];if(n)return n;for(n=i[e]=[],r=0;r<128;r++)t=String.fromCharCode(r),n.push(t);for(r=0;r<e.length;r++)n[t=e.charCodeAt(r)]="%"+("0"+t.toString(16).toUpperCase()).slice(-2);return n}(r),e.replace(/(%[a-f0-9]{2})+/gi,(function(e){var r,n,s,o,i,a,c,l="";for(r=0,n=e.length;r<n;r+=3)(s=parseInt(e.slice(r+1,r+3),16))<128?l+=t[s]:192==(224&s)&&r+3<n&&128==(192&(o=parseInt(e.slice(r+4,r+6),16)))?(l+=(c=s<<6&1984|63&o)<128?"\ufffd\ufffd":String.fromCharCode(c),r+=3):224==(240&s)&&r+6<n&&(o=parseInt(e.slice(r+4,r+6),16),i=parseInt(e.slice(r+7,r+9),16),128==(192&o)&&128==(192&i))?(l+=(c=s<<12&61440|o<<6&4032|63&i)<2048||c>=55296&&c<=57343?"\ufffd\ufffd\ufffd":String.fromCharCode(c),r+=6):240==(248&s)&&r+9<n&&(o=parseInt(e.slice(r+4,r+6),16),i=parseInt(e.slice(r+7,r+9),16),a=parseInt(e.slice(r+10,r+12),16),128==(192&o)&&128==(192&i)&&128==(192&a))?((c=s<<18&1835008|o<<12&258048|i<<6&4032|63&a)<65536||c>1114111?l+="\ufffd\ufffd\ufffd\ufffd":(c-=65536,l+=String.fromCharCode(55296+(c>>10),56320+(1023&c))),r+=9):l+="\ufffd";return l}))}a.defaultChars=";/?:@&=+$,#",a.componentChars="";var c=a;function l(){this.protocol=null,this.slashes=null,this.auth=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.pathname=null}var u=/^([a-z0-9.+-]+:)/i,p=/:[0-9]*$/,h=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,f=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),d=["'"].concat(f),m=["%","/","?",";","#"].concat(d),g=["/","?","#"],_=/^[+a-z0-9A-Z_-]{0,63}$/,k=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,b={javascript:!0,"javascript:":!0},v={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};l.prototype.parse=function(e,r){var t,n,s,o,i,a=e;if(a=a.trim(),!r&&1===e.split("#").length){var c=h.exec(a);if(c)return this.pathname=c[1],c[2]&&(this.search=c[2]),this}var l=u.exec(a);if(l&&(s=(l=l[0]).toLowerCase(),this.protocol=l,a=a.substr(l.length)),(r||l||a.match(/^\/\/[^@\/]+@[^@\/]+/))&&(!(i="//"===a.substr(0,2))||l&&b[l]||(a=a.substr(2),this.slashes=!0)),!b[l]&&(i||l&&!v[l])){var p,f,d=-1;for(t=0;t<g.length;t++)-1!==(o=a.indexOf(g[t]))&&(-1===d||o<d)&&(d=o);for(-1!==(f=-1===d?a.lastIndexOf("@"):a.lastIndexOf("@",d))&&(p=a.slice(0,f),a=a.slice(f+1),this.auth=p),d=-1,t=0;t<m.length;t++)-1!==(o=a.indexOf(m[t]))&&(-1===d||o<d)&&(d=o);-1===d&&(d=a.length),":"===a[d-1]&&d--;var C=a.slice(0,d);a=a.slice(d),this.parseHost(C),this.hostname=this.hostname||"";var y="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!y){var A=this.hostname.split(/\./);for(t=0,n=A.length;t<n;t++){var x=A[t];if(x&&!x.match(_)){for(var D="",w=0,E=x.length;w<E;w++)x.charCodeAt(w)>127?D+="x":D+=x[w];if(!D.match(_)){var q=A.slice(0,t),S=A.slice(t+1),F=x.match(k);F&&(q.push(F[1]),S.unshift(F[2])),S.length&&(a=S.join(".")+a),this.hostname=q.join(".");break}}}}this.hostname.length>255&&(this.hostname=""),y&&(this.hostname=this.hostname.substr(1,this.hostname.length-2))}var L=a.indexOf("#");-1!==L&&(this.hash=a.substr(L),a=a.slice(0,L));var z=a.indexOf("?");return-1!==z&&(this.search=a.substr(z),a=a.slice(0,z)),a&&(this.pathname=a),v[s]&&this.hostname&&!this.pathname&&(this.pathname=""),this},l.prototype.parseHost=function(e){var r=p.exec(e);r&&(":"!==(r=r[0])&&(this.port=r.substr(1)),e=e.substr(0,e.length-r.length)),e&&(this.hostname=e)};var C={encode:o,decode:c,format:function(e){var r="";return r+=e.protocol||"",r+=e.slashes?"//":"",r+=e.auth?e.auth+"@":"",e.hostname&&-1!==e.hostname.indexOf(":")?r+="["+e.hostname+"]":r+=e.hostname||"",r+=e.port?":"+e.port:"",r+=e.pathname||"",r+=e.search||"",r+=e.hash||""},parse:function(e,r){if(e&&e instanceof l)return e;var t=new l;return t.parse(e,r),t}},y=/[\0-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/,A=/[\0-\x1F\x7F-\x9F]/,x=/[ \xA0\u1680\u2000-\u200A\u2028\u2029\u202F\u205F\u3000]/,D={Any:y,Cc:A,Cf:/[\xAD\u0600-\u0605\u061C\u06DD\u070F\u08E2\u180E\u200B-\u200F\u202A-\u202E\u2060-\u2064\u2066-\u206F\uFEFF\uFFF9-\uFFFB]|\uD804[\uDCBD\uDCCD]|\uD82F[\uDCA0-\uDCA3]|\uD834[\uDD73-\uDD7A]|\uDB40[\uDC01\uDC20-\uDC7F]/,P:t,Z:x},w=function(e,r,t){return t={path:r,exports:{},require:function(e,r){return function(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}(null==r&&t.path)}},e(t,t.exports),t.exports}((function(e,n){var s=Object.prototype.hasOwnProperty;function o(e,r){return s.call(e,r)}function i(e){return!(e>=55296&&e<=57343)&&(!(e>=64976&&e<=65007)&&(65535!=(65535&e)&&65534!=(65535&e)&&(!(e>=0&&e<=8)&&(11!==e&&(!(e>=14&&e<=31)&&(!(e>=127&&e<=159)&&!(e>1114111)))))))}function a(e){if(e>65535){var r=55296+((e-=65536)>>10),t=56320+(1023&e);return String.fromCharCode(r,t)}return String.fromCharCode(e)}var c=/\\([!"#$%&'()*+,\-.\/:;<=>?@[\\\]^_`{|}~])/g,l=new RegExp(c.source+"|"+/&([a-z#][a-z0-9]{1,31});/gi.source,"gi"),u=/^#((?:x[a-f0-9]{1,8}|[0-9]{1,8}))/i;var p=/[&<>"]/,h=/[&<>"]/g,f={"&":"&","<":"<",">":">",'"':"""};function d(e){return f[e]}var m=/[.?*+^$[\]\\(){}|-]/g;n.lib={},n.lib.mdurl=C,n.lib.ucmicro=D,n.assign=function(e){var r=Array.prototype.slice.call(arguments,1);return r.forEach((function(r){if(r){if("object"!=typeof r)throw new TypeError(r+"must be object");Object.keys(r).forEach((function(t){e[t]=r[t]}))}})),e},n.isString=function(e){return"[object String]"===function(e){return Object.prototype.toString.call(e)}(e)},n.has=o,n.unescapeMd=function(e){return e.indexOf("\\")<0?e:e.replace(c,"$1")},n.unescapeAll=function(e){return e.indexOf("\\")<0&&e.indexOf("&")<0?e:e.replace(l,(function(e,t,n){return t||function(e,t){var n=0;return o(r,t)?r[t]:35===t.charCodeAt(0)&&u.test(t)&&i(n="x"===t[1].toLowerCase()?parseInt(t.slice(2),16):parseInt(t.slice(1),10))?a(n):e}(e,n)}))},n.isValidEntityCode=i,n.fromCodePoint=a,n.escapeHtml=function(e){return p.test(e)?e.replace(h,d):e},n.arrayReplaceAt=function(e,r,t){return[].concat(e.slice(0,r),t,e.slice(r+1))},n.isSpace=function(e){switch(e){case 9:case 32:return!0}return!1},n.isWhiteSpace=function(e){if(e>=8192&&e<=8202)return!0;switch(e){case 9:case 10:case 11:case 12:case 13:case 32:case 160:case 5760:case 8239:case 8287:case 12288:return!0}return!1},n.isMdAsciiPunct=function(e){switch(e){case 33:case 34:case 35:case 36:case 37:case 38:case 39:case 40:case 41:case 42:case 43:case 44:case 45:case 46:case 47:case 58:case 59:case 60:case 61:case 62:case 63:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 124:case 125:case 126:return!0;default:return!1}},n.isPunctChar=function(e){return t.test(e)},n.escapeRE=function(e){return e.replace(m,"\\$&")},n.normalizeReference=function(e){return e=e.trim().replace(/\s+/g," "),"\u1e7e"==="\u1e9e".toLowerCase()&&(e=e.replace(/\u1e9e/g,"\xdf")),e.toLowerCase().toUpperCase()}})),E=w.unescapeAll,q=w.unescapeAll,S=function(e,r,t){var n,s,o=r,i={ok:!1,pos:0,lines:0,str:""};if(60===e.charCodeAt(r)){for(r++;r<t;){if(10===(n=e.charCodeAt(r)))return i;if(60===n)return i;if(62===n)return i.pos=r+1,i.str=E(e.slice(o+1,r)),i.ok=!0,i;92===n&&r+1<t?r+=2:r++}return i}for(s=0;r<t&&32!==(n=e.charCodeAt(r))&&!(n<32||127===n);)if(92===n&&r+1<t){if(32===e.charCodeAt(r+1))break;r+=2}else{if(40===n&&++s>32)return i;if(41===n){if(0===s)break;s--}r++}return o===r||0!==s||(i.str=E(e.slice(o,r)),i.lines=0,i.pos=r,i.ok=!0),i},F=function(e,r,t){var n,s,o=0,i=r,a={ok:!1,pos:0,lines:0,str:""};if(r>=t)return a;if(34!==(s=e.charCodeAt(r))&&39!==s&&40!==s)return a;for(r++,40===s&&(s=41);r<t;){if((n=e.charCodeAt(r))===s)return a.pos=r+1,a.lines=o,a.str=q(e.slice(i+1,r)),a.ok=!0,a;if(40===n&&41===s)return a;10===n?o++:92===n&&r+1<t&&(r++,10===e.charCodeAt(r)&&o++),r++}return a},L={parseLinkLabel:function(e,r,t){var n,s,o,i,a=-1,c=e.posMax,l=e.pos;for(e.pos=r+1,n=1;e.pos<c;){if(93===(o=e.src.charCodeAt(e.pos))&&0===--n){s=!0;break}if(i=e.pos,e.md.inline.skipToken(e),91===o)if(i===e.pos-1)n++;else if(t)return e.pos=l,-1}return s&&(a=e.pos),e.pos=l,a},parseLinkDestination:S,parseLinkTitle:F},z=w.assign,T=w.unescapeAll,I=w.escapeHtml,M={};function R(){this.rules=z({},M)}M.code_inline=function(e,r,t,n,s){var o=e[r];return"<code"+s.renderAttrs(o)+">"+I(e[r].content)+"</code>"},M.code_block=function(e,r,t,n,s){var o=e[r];return"<pre"+s.renderAttrs(o)+"><code>"+I(e[r].content)+"</code></pre>\n"},M.fence=function(e,r,t,n,s){var o,i,a,c,l,u=e[r],p=u.info?T(u.info).trim():"",h="",f="";return p&&(h=(a=p.split(/(\s+)/g))[0],f=a.slice(2).join("")),0===(o=t.highlight&&t.highlight(u.content,h,f)||I(u.content)).indexOf("<pre")?o+"\n":p?(i=u.attrIndex("class"),c=u.attrs?u.attrs.slice():[],i<0?c.push(["class",t.langPrefix+h]):(c[i]=c[i].slice(),c[i][1]+=" "+t.langPrefix+h),l={attrs:c},"<pre><code"+s.renderAttrs(l)+">"+o+"</code></pre>\n"):"<pre><code"+s.renderAttrs(u)+">"+o+"</code></pre>\n"},M.image=function(e,r,t,n,s){var o=e[r];return o.attrs[o.attrIndex("alt")][1]=s.renderInlineAsText(o.children,t,n),s.renderToken(e,r,t)},M.hardbreak=function(e,r,t){return t.xhtmlOut?"<br />\n":"<br>\n"},M.softbreak=function(e,r,t){return t.breaks?t.xhtmlOut?"<br />\n":"<br>\n":"\n"},M.text=function(e,r){return I(e[r].content)},M.html_block=function(e,r){return e[r].content},M.html_inline=function(e,r){return e[r].content},R.prototype.renderAttrs=function(e){var r,t,n;if(!e.attrs)return"";for(n="",r=0,t=e.attrs.length;r<t;r++)n+=" "+I(e.attrs[r][0])+'="'+I(e.attrs[r][1])+'"';return n},R.prototype.renderToken=function(e,r,t){var n,s="",o=!1,i=e[r];return i.hidden?"":(i.block&&-1!==i.nesting&&r&&e[r-1].hidden&&(s+="\n"),s+=(-1===i.nesting?"</":"<")+i.tag,s+=this.renderAttrs(i),0===i.nesting&&t.xhtmlOut&&(s+=" /"),i.block&&(o=!0,1===i.nesting&&r+1<e.length&&("inline"===(n=e[r+1]).type||n.hidden||-1===n.nesting&&n.tag===i.tag)&&(o=!1)),s+=o?">\n":">")},R.prototype.renderInline=function(e,r,t){for(var n,s="",o=this.rules,i=0,a=e.length;i<a;i++)void 0!==o[n=e[i].type]?s+=o[n](e,i,r,t,this):s+=this.renderToken(e,i,r);return s},R.prototype.renderInlineAsText=function(e,r,t){for(var n="",s=0,o=e.length;s<o;s++)"text"===e[s].type?n+=e[s].content:"image"===e[s].type?n+=this.renderInlineAsText(e[s].children,r,t):"softbreak"===e[s].type&&(n+="\n");return n},R.prototype.render=function(e,r,t){var n,s,o,i="",a=this.rules;for(n=0,s=e.length;n<s;n++)"inline"===(o=e[n].type)?i+=this.renderInline(e[n].children,r,t):void 0!==a[o]?i+=a[e[n].type](e,n,r,t,this):i+=this.renderToken(e,n,r,t);return i};var B=R;function N(){this.__rules__=[],this.__cache__=null}N.prototype.__find__=function(e){for(var r=0;r<this.__rules__.length;r++)if(this.__rules__[r].name===e)return r;return-1},N.prototype.__compile__=function(){var e=this,r=[""];e.__rules__.forEach((function(e){e.enabled&&e.alt.forEach((function(e){r.indexOf(e)<0&&r.push(e)}))})),e.__cache__={},r.forEach((function(r){e.__cache__[r]=[],e.__rules__.forEach((function(t){t.enabled&&(r&&t.alt.indexOf(r)<0||e.__cache__[r].push(t.fn))}))}))},N.prototype.at=function(e,r,t){var n=this.__find__(e),s=t||{};if(-1===n)throw new Error("Parser rule not found: "+e);this.__rules__[n].fn=r,this.__rules__[n].alt=s.alt||[],this.__cache__=null},N.prototype.before=function(e,r,t,n){var s=this.__find__(e),o=n||{};if(-1===s)throw new Error("Parser rule not found: "+e);this.__rules__.splice(s,0,{name:r,enabled:!0,fn:t,alt:o.alt||[]}),this.__cache__=null},N.prototype.after=function(e,r,t,n){var s=this.__find__(e),o=n||{};if(-1===s)throw new Error("Parser rule not found: "+e);this.__rules__.splice(s+1,0,{name:r,enabled:!0,fn:t,alt:o.alt||[]}),this.__cache__=null},N.prototype.push=function(e,r,t){var n=t||{};this.__rules__.push({name:e,enabled:!0,fn:r,alt:n.alt||[]}),this.__cache__=null},N.prototype.enable=function(e,r){Array.isArray(e)||(e=[e]);var t=[];return e.forEach((function(e){var n=this.__find__(e);if(n<0){if(r)return;throw new Error("Rules manager: invalid rule name "+e)}this.__rules__[n].enabled=!0,t.push(e)}),this),this.__cache__=null,t},N.prototype.enableOnly=function(e,r){Array.isArray(e)||(e=[e]),this.__rules__.forEach((function(e){e.enabled=!1})),this.enable(e,r)},N.prototype.disable=function(e,r){Array.isArray(e)||(e=[e]);var t=[];return e.forEach((function(e){var n=this.__find__(e);if(n<0){if(r)return;throw new Error("Rules manager: invalid rule name "+e)}this.__rules__[n].enabled=!1,t.push(e)}),this),this.__cache__=null,t},N.prototype.getRules=function(e){return null===this.__cache__&&this.__compile__(),this.__cache__[e]||[]};var O=N,P=/\r\n?|\n/g,j=/\0/g,U=w.arrayReplaceAt;function V(e){return/^<\/a\s*>/i.test(e)}var Z=/\+-|\.\.|\?\?\?\?|!!!!|,,|--/,$=/\((c|tm|r)\)/i,G=/\((c|tm|r)\)/gi,H={c:"\xa9",r:"\xae",tm:"\u2122"};function J(e,r){return H[r.toLowerCase()]}function W(e){var r,t,n=0;for(r=e.length-1;r>=0;r--)"text"!==(t=e[r]).type||n||(t.content=t.content.replace(G,J)),"link_open"===t.type&&"auto"===t.info&&n--,"link_close"===t.type&&"auto"===t.info&&n++}function Y(e){var r,t,n=0;for(r=e.length-1;r>=0;r--)"text"!==(t=e[r]).type||n||Z.test(t.content)&&(t.content=t.content.replace(/\+-/g,"\xb1").replace(/\.{2,}/g,"\u2026").replace(/([?!])\u2026/g,"$1..").replace(/([?!]){4,}/g,"$1$1$1").replace(/,{2,}/g,",").replace(/(^|[^-])---(?=[^-]|$)/gm,"$1\u2014").replace(/(^|\s)--(?=\s|$)/gm,"$1\u2013").replace(/(^|[^-\s])--(?=[^-\s]|$)/gm,"$1\u2013")),"link_open"===t.type&&"auto"===t.info&&n--,"link_close"===t.type&&"auto"===t.info&&n++}var K=w.isWhiteSpace,Q=w.isPunctChar,X=w.isMdAsciiPunct,ee=/['"]/,re=/['"]/g;function te(e,r,t){return e.slice(0,r)+t+e.slice(r+1)}function ne(e,r){var t,n,s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b,v,C,y;for(v=[],t=0;t<e.length;t++){for(n=e[t],c=e[t].level,k=v.length-1;k>=0&&!(v[k].level<=c);k--);if(v.length=k+1,"text"===n.type){i=0,a=(s=n.content).length;e:for(;i<a&&(re.lastIndex=i,o=re.exec(s));){if(g=_=!0,i=o.index+1,b="'"===o[0],u=32,o.index-1>=0)u=s.charCodeAt(o.index-1);else for(k=t-1;k>=0&&("softbreak"!==e[k].type&&"hardbreak"!==e[k].type);k--)if(e[k].content){u=e[k].content.charCodeAt(e[k].content.length-1);break}if(p=32,i<a)p=s.charCodeAt(i);else for(k=t+1;k<e.length&&("softbreak"!==e[k].type&&"hardbreak"!==e[k].type);k++)if(e[k].content){p=e[k].content.charCodeAt(0);break}if(h=X(u)||Q(String.fromCharCode(u)),f=X(p)||Q(String.fromCharCode(p)),d=K(u),(m=K(p))?g=!1:f&&(d||h||(g=!1)),d?_=!1:h&&(m||f||(_=!1)),34===p&&'"'===o[0]&&u>=48&&u<=57&&(_=g=!1),g&&_&&(g=h,_=f),g||_){if(_)for(k=v.length-1;k>=0&&(l=v[k],!(v[k].level<c));k--)if(l.single===b&&v[k].level===c){l=v[k],b?(C=r.md.options.quotes[2],y=r.md.options.quotes[3]):(C=r.md.options.quotes[0],y=r.md.options.quotes[1]),n.content=te(n.content,o.index,y),e[l.token].content=te(e[l.token].content,l.pos,C),i+=y.length-1,l.token===t&&(i+=C.length-1),a=(s=n.content).length,v.length=k;continue e}g?v.push({token:t,pos:o.index,single:b,level:c}):_&&b&&(n.content=te(n.content,o.index,"\u2019"))}else b&&(n.content=te(n.content,o.index,"\u2019"))}}}}function se(e,r,t){this.type=e,this.tag=r,this.attrs=null,this.map=null,this.nesting=t,this.level=0,this.children=null,this.content="",this.markup="",this.info="",this.meta=null,this.block=!1,this.hidden=!1}se.prototype.attrIndex=function(e){var r,t,n;if(!this.attrs)return-1;for(t=0,n=(r=this.attrs).length;t<n;t++)if(r[t][0]===e)return t;return-1},se.prototype.attrPush=function(e){this.attrs?this.attrs.push(e):this.attrs=[e]},se.prototype.attrSet=function(e,r){var t=this.attrIndex(e),n=[e,r];t<0?this.attrPush(n):this.attrs[t]=n},se.prototype.attrGet=function(e){var r=this.attrIndex(e),t=null;return r>=0&&(t=this.attrs[r][1]),t},se.prototype.attrJoin=function(e,r){var t=this.attrIndex(e);t<0?this.attrPush([e,r]):this.attrs[t][1]=this.attrs[t][1]+" "+r};var oe=se;function ie(e,r,t){this.src=e,this.env=t,this.tokens=[],this.inlineMode=!1,this.md=r}ie.prototype.Token=oe;var ae=ie,ce=[["normalize",function(e){var r;r=(r=e.src.replace(P,"\n")).replace(j,"\ufffd"),e.src=r}],["block",function(e){var r;e.inlineMode?((r=new e.Token("inline","",0)).content=e.src,r.map=[0,1],r.children=[],e.tokens.push(r)):e.md.block.parse(e.src,e.md,e.env,e.tokens)}],["inline",function(e){var r,t,n,s=e.tokens;for(t=0,n=s.length;t<n;t++)"inline"===(r=s[t]).type&&e.md.inline.parse(r.content,e.md,e.env,r.children)}],["linkify",function(e){var r,t,n,s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b=e.tokens;if(e.md.options.linkify)for(t=0,n=b.length;t<n;t++)if("inline"===b[t].type&&e.md.linkify.pretest(b[t].content))for(f=0,r=(s=b[t].children).length-1;r>=0;r--)if("link_close"!==(i=s[r]).type){if("html_inline"===i.type&&(k=i.content,/^<a[>\s]/i.test(k)&&f>0&&f--,V(i.content)&&f++),!(f>0)&&"text"===i.type&&e.md.linkify.test(i.content)){for(l=i.content,_=e.md.linkify.match(l),a=[],h=i.level,p=0,_.length>0&&0===_[0].index&&r>0&&"text_special"===s[r-1].type&&(_=_.slice(1)),c=0;c<_.length;c++)d=_[c].url,m=e.md.normalizeLink(d),e.md.validateLink(m)&&(g=_[c].text,g=_[c].schema?"mailto:"!==_[c].schema||/^mailto:/i.test(g)?e.md.normalizeLinkText(g):e.md.normalizeLinkText("mailto:"+g).replace(/^mailto:/,""):e.md.normalizeLinkText("http://"+g).replace(/^http:\/\//,""),(u=_[c].index)>p&&((o=new e.Token("text","",0)).content=l.slice(p,u),o.level=h,a.push(o)),(o=new e.Token("link_open","a",1)).attrs=[["href",m]],o.level=h++,o.markup="linkify",o.info="auto",a.push(o),(o=new e.Token("text","",0)).content=g,o.level=h,a.push(o),(o=new e.Token("link_close","a",-1)).level=--h,o.markup="linkify",o.info="auto",a.push(o),p=_[c].lastIndex);p<l.length&&((o=new e.Token("text","",0)).content=l.slice(p),o.level=h,a.push(o)),b[t].children=s=U(s,r,a)}}else for(r--;s[r].level!==i.level&&"link_open"!==s[r].type;)r--}],["replacements",function(e){var r;if(e.md.options.typographer)for(r=e.tokens.length-1;r>=0;r--)"inline"===e.tokens[r].type&&($.test(e.tokens[r].content)&&W(e.tokens[r].children),Z.test(e.tokens[r].content)&&Y(e.tokens[r].children))}],["smartquotes",function(e){var r;if(e.md.options.typographer)for(r=e.tokens.length-1;r>=0;r--)"inline"===e.tokens[r].type&&ee.test(e.tokens[r].content)&&ne(e.tokens[r].children,e)}],["text_join",function(e){var r,t,n,s,o,i,a=e.tokens;for(r=0,t=a.length;r<t;r++)if("inline"===a[r].type){for(o=(n=a[r].children).length,s=0;s<o;s++)"text_special"===n[s].type&&(n[s].type="text");for(s=i=0;s<o;s++)"text"===n[s].type&&s+1<o&&"text"===n[s+1].type?n[s+1].content=n[s].content+n[s+1].content:(s!==i&&(n[i]=n[s]),i++);s!==i&&(n.length=i)}}]];function le(){this.ruler=new O;for(var e=0;e<ce.length;e++)this.ruler.push(ce[e][0],ce[e][1])}le.prototype.process=function(e){var r,t,n;for(r=0,t=(n=this.ruler.getRules("")).length;r<t;r++)n[r](e)},le.prototype.State=ae;var ue=le,pe=w.isSpace;function he(e,r){var t=e.bMarks[r]+e.tShift[r],n=e.eMarks[r];return e.src.slice(t,n)}function fe(e){var r,t=[],n=0,s=e.length,o=!1,i=0,a="";for(r=e.charCodeAt(n);n<s;)124===r&&(o?(a+=e.substring(i,n-1),i=n):(t.push(a+e.substring(i,n)),a="",i=n+1)),o=92===r,n++,r=e.charCodeAt(n);return t.push(a+e.substring(i)),t}var de=w.isSpace,me=w.isSpace,ge=w.isSpace;function _e(e,r){var t,n,s,o;return n=e.bMarks[r]+e.tShift[r],s=e.eMarks[r],42!==(t=e.src.charCodeAt(n++))&&45!==t&&43!==t||n<s&&(o=e.src.charCodeAt(n),!ge(o))?-1:n}function ke(e,r){var t,n=e.bMarks[r]+e.tShift[r],s=n,o=e.eMarks[r];if(s+1>=o)return-1;if((t=e.src.charCodeAt(s++))<48||t>57)return-1;for(;;){if(s>=o)return-1;if(!((t=e.src.charCodeAt(s++))>=48&&t<=57)){if(41===t||46===t)break;return-1}if(s-n>=10)return-1}return s<o&&(t=e.src.charCodeAt(s),!ge(t))?-1:s}var be=w.normalizeReference,ve=w.isSpace,Ce="<[A-Za-z][A-Za-z0-9\\-]*(?:\\s+[a-zA-Z_:][a-zA-Z0-9:._-]*(?:\\s*=\\s*(?:[^\"'=<>`\\x00-\\x20]+|'[^']*'|\"[^\"]*\"))?)*\\s*\\/?>",ye="<\\/[A-Za-z][A-Za-z0-9\\-]*\\s*>",Ae={HTML_TAG_RE:new RegExp("^(?:"+Ce+"|"+ye+"|\x3c!----\x3e|\x3c!--(?:-?[^>-])(?:-?[^-])*--\x3e|<[?][\\s\\S]*?[?]>|<![A-Z]+\\s+[^>]*>|<!\\[CDATA\\[[\\s\\S]*?\\]\\]>)"),HTML_OPEN_CLOSE_TAG_RE:new RegExp("^(?:"+Ce+"|"+ye+")")},xe=Ae.HTML_OPEN_CLOSE_TAG_RE,De=[[/^<(script|pre|style|textarea)(?=(\s|>|$))/i,/<\/(script|pre|style|textarea)>/i,!0],[/^<!--/,/-->/,!0],[/^<\?/,/\?>/,!0],[/^<![A-Z]/,/>/,!0],[/^<!\[CDATA\[/,/\]\]>/,!0],[new RegExp("^</?("+["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","section","source","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"].join("|")+")(?=(\\s|/?>|$))","i"),/^$/,!0],[new RegExp(xe.source+"\\s*$"),/^$/,!1]],we=w.isSpace,Ee=w.isSpace;function qe(e,r,t,n){var s,o,i,a,c,l,u,p;for(this.src=e,this.md=r,this.env=t,this.tokens=n,this.bMarks=[],this.eMarks=[],this.tShift=[],this.sCount=[],this.bsCount=[],this.blkIndent=0,this.line=0,this.lineMax=0,this.tight=!1,this.ddIndent=-1,this.listIndent=-1,this.parentType="root",this.level=0,this.result="",p=!1,i=a=l=u=0,c=(o=this.src).length;a<c;a++){if(s=o.charCodeAt(a),!p){if(Ee(s)){l++,9===s?u+=4-u%4:u++;continue}p=!0}10!==s&&a!==c-1||(10!==s&&a++,this.bMarks.push(i),this.eMarks.push(a),this.tShift.push(l),this.sCount.push(u),this.bsCount.push(0),p=!1,l=0,u=0,i=a+1)}this.bMarks.push(o.length),this.eMarks.push(o.length),this.tShift.push(0),this.sCount.push(0),this.bsCount.push(0),this.lineMax=this.bMarks.length-1}qe.prototype.push=function(e,r,t){var n=new oe(e,r,t);return n.block=!0,t<0&&this.level--,n.level=this.level,t>0&&this.level++,this.tokens.push(n),n},qe.prototype.isEmpty=function(e){return this.bMarks[e]+this.tShift[e]>=this.eMarks[e]},qe.prototype.skipEmptyLines=function(e){for(var r=this.lineMax;e<r&&!(this.bMarks[e]+this.tShift[e]<this.eMarks[e]);e++);return e},qe.prototype.skipSpaces=function(e){for(var r,t=this.src.length;e<t&&(r=this.src.charCodeAt(e),Ee(r));e++);return e},qe.prototype.skipSpacesBack=function(e,r){if(e<=r)return e;for(;e>r;)if(!Ee(this.src.charCodeAt(--e)))return e+1;return e},qe.prototype.skipChars=function(e,r){for(var t=this.src.length;e<t&&this.src.charCodeAt(e)===r;e++);return e},qe.prototype.skipCharsBack=function(e,r,t){if(e<=t)return e;for(;e>t;)if(r!==this.src.charCodeAt(--e))return e+1;return e},qe.prototype.getLines=function(e,r,t,n){var s,o,i,a,c,l,u,p=e;if(e>=r)return"";for(l=new Array(r-e),s=0;p<r;p++,s++){for(o=0,u=a=this.bMarks[p],c=p+1<r||n?this.eMarks[p]+1:this.eMarks[p];a<c&&o<t;){if(i=this.src.charCodeAt(a),Ee(i))9===i?o+=4-(o+this.bsCount[p])%4:o++;else{if(!(a-u<this.tShift[p]))break;o++}a++}l[s]=o>t?new Array(o-t+1).join(" ")+this.src.slice(a,c):this.src.slice(a,c)}return l.join("")},qe.prototype.Token=oe;var Se=qe,Fe=[["table",function(e,r,t,n){var s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b,v,C;if(r+2>t)return!1;if(l=r+1,e.sCount[l]<e.blkIndent)return!1;if(e.sCount[l]-e.blkIndent>=4)return!1;if((i=e.bMarks[l]+e.tShift[l])>=e.eMarks[l])return!1;if(124!==(v=e.src.charCodeAt(i++))&&45!==v&&58!==v)return!1;if(i>=e.eMarks[l])return!1;if(124!==(C=e.src.charCodeAt(i++))&&45!==C&&58!==C&&!pe(C))return!1;if(45===v&&pe(C))return!1;for(;i<e.eMarks[l];){if(124!==(s=e.src.charCodeAt(i))&&45!==s&&58!==s&&!pe(s))return!1;i++}for(u=(o=he(e,r+1)).split("|"),f=[],a=0;a<u.length;a++){if(!(d=u[a].trim())){if(0===a||a===u.length-1)continue;return!1}if(!/^:?-+:?$/.test(d))return!1;58===d.charCodeAt(d.length-1)?f.push(58===d.charCodeAt(0)?"center":"right"):58===d.charCodeAt(0)?f.push("left"):f.push("")}if(-1===(o=he(e,r).trim()).indexOf("|"))return!1;if(e.sCount[r]-e.blkIndent>=4)return!1;if((u=fe(o)).length&&""===u[0]&&u.shift(),u.length&&""===u[u.length-1]&&u.pop(),0===(p=u.length)||p!==f.length)return!1;if(n)return!0;for(_=e.parentType,e.parentType="table",b=e.md.block.ruler.getRules("blockquote"),(h=e.push("table_open","table",1)).map=m=[r,0],(h=e.push("thead_open","thead",1)).map=[r,r+1],(h=e.push("tr_open","tr",1)).map=[r,r+1],a=0;a<u.length;a++)h=e.push("th_open","th",1),f[a]&&(h.attrs=[["style","text-align:"+f[a]]]),(h=e.push("inline","",0)).content=u[a].trim(),h.children=[],h=e.push("th_close","th",-1);for(h=e.push("tr_close","tr",-1),h=e.push("thead_close","thead",-1),l=r+2;l<t&&!(e.sCount[l]<e.blkIndent);l++){for(k=!1,a=0,c=b.length;a<c;a++)if(b[a](e,l,t,!0)){k=!0;break}if(k)break;if(!(o=he(e,l).trim()))break;if(e.sCount[l]-e.blkIndent>=4)break;for((u=fe(o)).length&&""===u[0]&&u.shift(),u.length&&""===u[u.length-1]&&u.pop(),l===r+2&&((h=e.push("tbody_open","tbody",1)).map=g=[r+2,0]),(h=e.push("tr_open","tr",1)).map=[l,l+1],a=0;a<p;a++)h=e.push("td_open","td",1),f[a]&&(h.attrs=[["style","text-align:"+f[a]]]),(h=e.push("inline","",0)).content=u[a]?u[a].trim():"",h.children=[],h=e.push("td_close","td",-1);h=e.push("tr_close","tr",-1)}return g&&(h=e.push("tbody_close","tbody",-1),g[1]=l),h=e.push("table_close","table",-1),m[1]=l,e.parentType=_,e.line=l,!0},["paragraph","reference"]],["code",function(e,r,t){var n,s,o;if(e.sCount[r]-e.blkIndent<4)return!1;for(s=n=r+1;n<t;)if(e.isEmpty(n))n++;else{if(!(e.sCount[n]-e.blkIndent>=4))break;s=++n}return e.line=s,(o=e.push("code_block","code",0)).content=e.getLines(r,s,4+e.blkIndent,!1)+"\n",o.map=[r,e.line],!0}],["fence",function(e,r,t,n){var s,o,i,a,c,l,u,p=!1,h=e.bMarks[r]+e.tShift[r],f=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(h+3>f)return!1;if(126!==(s=e.src.charCodeAt(h))&&96!==s)return!1;if(c=h,(o=(h=e.skipChars(h,s))-c)<3)return!1;if(u=e.src.slice(c,h),i=e.src.slice(h,f),96===s&&i.indexOf(String.fromCharCode(s))>=0)return!1;if(n)return!0;for(a=r;!(++a>=t)&&!((h=c=e.bMarks[a]+e.tShift[a])<(f=e.eMarks[a])&&e.sCount[a]<e.blkIndent);)if(e.src.charCodeAt(h)===s&&!(e.sCount[a]-e.blkIndent>=4||(h=e.skipChars(h,s))-c<o||(h=e.skipSpaces(h))<f)){p=!0;break}return o=e.sCount[r],e.line=a+(p?1:0),(l=e.push("fence","code",0)).info=i,l.content=e.getLines(r+1,a,o,!0),l.markup=u,l.map=[r,e.line],!0},["paragraph","reference","blockquote","list"]],["blockquote",function(e,r,t,n){var s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b,v,C,y,A,x=e.lineMax,D=e.bMarks[r]+e.tShift[r],w=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(62!==e.src.charCodeAt(D++))return!1;if(n)return!0;for(a=h=e.sCount[r]+1,32===e.src.charCodeAt(D)?(D++,a++,h++,s=!1,b=!0):9===e.src.charCodeAt(D)?(b=!0,(e.bsCount[r]+h)%4==3?(D++,a++,h++,s=!1):s=!0):b=!1,f=[e.bMarks[r]],e.bMarks[r]=D;D<w&&(o=e.src.charCodeAt(D),de(o));)9===o?h+=4-(h+e.bsCount[r]+(s?1:0))%4:h++,D++;for(d=[e.bsCount[r]],e.bsCount[r]=e.sCount[r]+1+(b?1:0),l=D>=w,_=[e.sCount[r]],e.sCount[r]=h-a,k=[e.tShift[r]],e.tShift[r]=D-e.bMarks[r],C=e.md.block.ruler.getRules("blockquote"),g=e.parentType,e.parentType="blockquote",p=r+1;p<t&&(A=e.sCount[p]<e.blkIndent,!((D=e.bMarks[p]+e.tShift[p])>=(w=e.eMarks[p])));p++)if(62!==e.src.charCodeAt(D++)||A){if(l)break;for(v=!1,i=0,c=C.length;i<c;i++)if(C[i](e,p,t,!0)){v=!0;break}if(v){e.lineMax=p,0!==e.blkIndent&&(f.push(e.bMarks[p]),d.push(e.bsCount[p]),k.push(e.tShift[p]),_.push(e.sCount[p]),e.sCount[p]-=e.blkIndent);break}f.push(e.bMarks[p]),d.push(e.bsCount[p]),k.push(e.tShift[p]),_.push(e.sCount[p]),e.sCount[p]=-1}else{for(a=h=e.sCount[p]+1,32===e.src.charCodeAt(D)?(D++,a++,h++,s=!1,b=!0):9===e.src.charCodeAt(D)?(b=!0,(e.bsCount[p]+h)%4==3?(D++,a++,h++,s=!1):s=!0):b=!1,f.push(e.bMarks[p]),e.bMarks[p]=D;D<w&&(o=e.src.charCodeAt(D),de(o));)9===o?h+=4-(h+e.bsCount[p]+(s?1:0))%4:h++,D++;l=D>=w,d.push(e.bsCount[p]),e.bsCount[p]=e.sCount[p]+1+(b?1:0),_.push(e.sCount[p]),e.sCount[p]=h-a,k.push(e.tShift[p]),e.tShift[p]=D-e.bMarks[p]}for(m=e.blkIndent,e.blkIndent=0,(y=e.push("blockquote_open","blockquote",1)).markup=">",y.map=u=[r,0],e.md.block.tokenize(e,r,p),(y=e.push("blockquote_close","blockquote",-1)).markup=">",e.lineMax=x,e.parentType=g,u[1]=e.line,i=0;i<k.length;i++)e.bMarks[i+r]=f[i],e.tShift[i+r]=k[i],e.sCount[i+r]=_[i],e.bsCount[i+r]=d[i];return e.blkIndent=m,!0},["paragraph","reference","blockquote","list"]],["hr",function(e,r,t,n){var s,o,i,a,c=e.bMarks[r]+e.tShift[r],l=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(42!==(s=e.src.charCodeAt(c++))&&45!==s&&95!==s)return!1;for(o=1;c<l;){if((i=e.src.charCodeAt(c++))!==s&&!me(i))return!1;i===s&&o++}return!(o<3)&&(n||(e.line=r+1,(a=e.push("hr","hr",0)).map=[r,e.line],a.markup=Array(o+1).join(String.fromCharCode(s))),!0)},["paragraph","reference","blockquote","list"]],["list",function(e,r,t,n){var s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b,v,C,y,A,x,D,w,E,q,S,F,L,z=!1,T=!0;if(e.sCount[r]-e.blkIndent>=4)return!1;if(e.listIndent>=0&&e.sCount[r]-e.listIndent>=4&&e.sCount[r]<e.blkIndent)return!1;if(n&&"paragraph"===e.parentType&&e.sCount[r]>=e.blkIndent&&(z=!0),(w=ke(e,r))>=0){if(u=!0,q=e.bMarks[r]+e.tShift[r],g=Number(e.src.slice(q,w-1)),z&&1!==g)return!1}else{if(!((w=_e(e,r))>=0))return!1;u=!1}if(z&&e.skipSpaces(w)>=e.eMarks[r])return!1;if(m=e.src.charCodeAt(w-1),n)return!0;for(d=e.tokens.length,u?(L=e.push("ordered_list_open","ol",1),1!==g&&(L.attrs=[["start",g]])):L=e.push("bullet_list_open","ul",1),L.map=f=[r,0],L.markup=String.fromCharCode(m),k=r,E=!1,F=e.md.block.ruler.getRules("list"),C=e.parentType,e.parentType="list";k<t;){for(D=w,_=e.eMarks[k],l=b=e.sCount[k]+w-(e.bMarks[r]+e.tShift[r]);D<_;){if(9===(s=e.src.charCodeAt(D)))b+=4-(b+e.bsCount[k])%4;else{if(32!==s)break;b++}D++}if((c=(o=D)>=_?1:b-l)>4&&(c=1),a=l+c,(L=e.push("list_item_open","li",1)).markup=String.fromCharCode(m),L.map=p=[r,0],u&&(L.info=e.src.slice(q,w-1)),x=e.tight,A=e.tShift[r],y=e.sCount[r],v=e.listIndent,e.listIndent=e.blkIndent,e.blkIndent=a,e.tight=!0,e.tShift[r]=o-e.bMarks[r],e.sCount[r]=b,o>=_&&e.isEmpty(r+1)?e.line=Math.min(e.line+2,t):e.md.block.tokenize(e,r,t,!0),e.tight&&!E||(T=!1),E=e.line-r>1&&e.isEmpty(e.line-1),e.blkIndent=e.listIndent,e.listIndent=v,e.tShift[r]=A,e.sCount[r]=y,e.tight=x,(L=e.push("list_item_close","li",-1)).markup=String.fromCharCode(m),k=r=e.line,p[1]=k,o=e.bMarks[r],k>=t)break;if(e.sCount[k]<e.blkIndent)break;if(e.sCount[r]-e.blkIndent>=4)break;for(S=!1,i=0,h=F.length;i<h;i++)if(F[i](e,k,t,!0)){S=!0;break}if(S)break;if(u){if((w=ke(e,k))<0)break;q=e.bMarks[k]+e.tShift[k]}else if((w=_e(e,k))<0)break;if(m!==e.src.charCodeAt(w-1))break}return(L=u?e.push("ordered_list_close","ol",-1):e.push("bullet_list_close","ul",-1)).markup=String.fromCharCode(m),f[1]=k,e.line=k,e.parentType=C,T&&function(e,r){var t,n,s=e.level+2;for(t=r+2,n=e.tokens.length-2;t<n;t++)e.tokens[t].level===s&&"paragraph_open"===e.tokens[t].type&&(e.tokens[t+2].hidden=!0,e.tokens[t].hidden=!0,t+=2)}(e,d),!0},["paragraph","reference","blockquote"]],["reference",function(e,r,t,n){var s,o,i,a,c,l,u,p,h,f,d,m,g,_,k,b,v=0,C=e.bMarks[r]+e.tShift[r],y=e.eMarks[r],A=r+1;if(e.sCount[r]-e.blkIndent>=4)return!1;if(91!==e.src.charCodeAt(C))return!1;for(;++C<y;)if(93===e.src.charCodeAt(C)&&92!==e.src.charCodeAt(C-1)){if(C+1===y)return!1;if(58!==e.src.charCodeAt(C+1))return!1;break}for(a=e.lineMax,k=e.md.block.ruler.getRules("reference"),f=e.parentType,e.parentType="reference";A<a&&!e.isEmpty(A);A++)if(!(e.sCount[A]-e.blkIndent>3||e.sCount[A]<0)){for(_=!1,l=0,u=k.length;l<u;l++)if(k[l](e,A,a,!0)){_=!0;break}if(_)break}for(y=(g=e.getLines(r,A,e.blkIndent,!1).trim()).length,C=1;C<y;C++){if(91===(s=g.charCodeAt(C)))return!1;if(93===s){h=C;break}(10===s||92===s&&++C<y&&10===g.charCodeAt(C))&&v++}if(h<0||58!==g.charCodeAt(h+1))return!1;for(C=h+2;C<y;C++)if(10===(s=g.charCodeAt(C)))v++;else if(!ve(s))break;if(!(d=e.md.helpers.parseLinkDestination(g,C,y)).ok)return!1;if(c=e.md.normalizeLink(d.str),!e.md.validateLink(c))return!1;for(o=C=d.pos,i=v+=d.lines,m=C;C<y;C++)if(10===(s=g.charCodeAt(C)))v++;else if(!ve(s))break;for(d=e.md.helpers.parseLinkTitle(g,C,y),C<y&&m!==C&&d.ok?(b=d.str,C=d.pos,v+=d.lines):(b="",C=o,v=i);C<y&&(s=g.charCodeAt(C),ve(s));)C++;if(C<y&&10!==g.charCodeAt(C)&&b)for(b="",C=o,v=i;C<y&&(s=g.charCodeAt(C),ve(s));)C++;return!(C<y&&10!==g.charCodeAt(C))&&(!!(p=be(g.slice(1,h)))&&(n||(void 0===e.env.references&&(e.env.references={}),void 0===e.env.references[p]&&(e.env.references[p]={title:b,href:c}),e.parentType=f,e.line=r+v+1),!0))}],["html_block",function(e,r,t,n){var s,o,i,a,c=e.bMarks[r]+e.tShift[r],l=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(!e.md.options.html)return!1;if(60!==e.src.charCodeAt(c))return!1;for(a=e.src.slice(c,l),s=0;s<De.length&&!De[s][0].test(a);s++);if(s===De.length)return!1;if(n)return De[s][2];if(o=r+1,!De[s][1].test(a))for(;o<t&&!(e.sCount[o]<e.blkIndent);o++)if(c=e.bMarks[o]+e.tShift[o],l=e.eMarks[o],a=e.src.slice(c,l),De[s][1].test(a)){0!==a.length&&o++;break}return e.line=o,(i=e.push("html_block","",0)).map=[r,o],i.content=e.getLines(r,o,e.blkIndent,!0),!0},["paragraph","reference","blockquote"]],["heading",function(e,r,t,n){var s,o,i,a,c=e.bMarks[r]+e.tShift[r],l=e.eMarks[r];if(e.sCount[r]-e.blkIndent>=4)return!1;if(35!==(s=e.src.charCodeAt(c))||c>=l)return!1;for(o=1,s=e.src.charCodeAt(++c);35===s&&c<l&&o<=6;)o++,s=e.src.charCodeAt(++c);return!(o>6||c<l&&!we(s))&&(n||(l=e.skipSpacesBack(l,c),(i=e.skipCharsBack(l,35,c))>c&&we(e.src.charCodeAt(i-1))&&(l=i),e.line=r+1,(a=e.push("heading_open","h"+String(o),1)).markup="########".slice(0,o),a.map=[r,e.line],(a=e.push("inline","",0)).content=e.src.slice(c,l).trim(),a.map=[r,e.line],a.children=[],(a=e.push("heading_close","h"+String(o),-1)).markup="########".slice(0,o)),!0)},["paragraph","reference","blockquote"]],["lheading",function(e,r,t){var n,s,o,i,a,c,l,u,p,h,f=r+1,d=e.md.block.ruler.getRules("paragraph");if(e.sCount[r]-e.blkIndent>=4)return!1;for(h=e.parentType,e.parentType="paragraph";f<t&&!e.isEmpty(f);f++)if(!(e.sCount[f]-e.blkIndent>3)){if(e.sCount[f]>=e.blkIndent&&(c=e.bMarks[f]+e.tShift[f])<(l=e.eMarks[f])&&(45===(p=e.src.charCodeAt(c))||61===p)&&(c=e.skipChars(c,p),(c=e.skipSpaces(c))>=l)){u=61===p?1:2;break}if(!(e.sCount[f]<0)){for(s=!1,o=0,i=d.length;o<i;o++)if(d[o](e,f,t,!0)){s=!0;break}if(s)break}}return!!u&&(n=e.getLines(r,f,e.blkIndent,!1).trim(),e.line=f+1,(a=e.push("heading_open","h"+String(u),1)).markup=String.fromCharCode(p),a.map=[r,e.line],(a=e.push("inline","",0)).content=n,a.map=[r,e.line-1],a.children=[],(a=e.push("heading_close","h"+String(u),-1)).markup=String.fromCharCode(p),e.parentType=h,!0)}],["paragraph",function(e,r){var t,n,s,o,i,a,c=r+1,l=e.md.block.ruler.getRules("paragraph"),u=e.lineMax;for(a=e.parentType,e.parentType="paragraph";c<u&&!e.isEmpty(c);c++)if(!(e.sCount[c]-e.blkIndent>3||e.sCount[c]<0)){for(n=!1,s=0,o=l.length;s<o;s++)if(l[s](e,c,u,!0)){n=!0;break}if(n)break}return t=e.getLines(r,c,e.blkIndent,!1).trim(),e.line=c,(i=e.push("paragraph_open","p",1)).map=[r,e.line],(i=e.push("inline","",0)).content=t,i.map=[r,e.line],i.children=[],i=e.push("paragraph_close","p",-1),e.parentType=a,!0}]];function Le(){this.ruler=new O;for(var e=0;e<Fe.length;e++)this.ruler.push(Fe[e][0],Fe[e][1],{alt:(Fe[e][2]||[]).slice()})}Le.prototype.tokenize=function(e,r,t){for(var n,s=this.ruler.getRules(""),o=s.length,i=r,a=!1,c=e.md.options.maxNesting;i<t&&(e.line=i=e.skipEmptyLines(i),!(i>=t))&&!(e.sCount[i]<e.blkIndent);){if(e.level>=c){e.line=t;break}for(n=0;n<o&&!s[n](e,i,t,!1);n++);e.tight=!a,e.isEmpty(e.line-1)&&(a=!0),(i=e.line)<t&&e.isEmpty(i)&&(a=!0,i++,e.line=i)}},Le.prototype.parse=function(e,r,t,n){var s;e&&(s=new this.State(e,r,t,n),this.tokenize(s,s.line,s.lineMax))},Le.prototype.State=Se;var ze=Le;function Te(e){switch(e){case 10:case 33:case 35:case 36:case 37:case 38:case 42:case 43:case 45:case 58:case 60:case 61:case 62:case 64:case 91:case 92:case 93:case 94:case 95:case 96:case 123:case 125:case 126:return!0;default:return!1}}for(var Ie=/(?:^|[^a-z0-9.+-])([a-z][a-z0-9.+-]*)$/i,Me=w.isSpace,Re=w.isSpace,Be=[],Ne=0;Ne<256;Ne++)Be.push(0);"\\!\"#$%&'()*+,./:;<=>?@[]^_`{|}~-".split("").forEach((function(e){Be[e.charCodeAt(0)]=1}));function Oe(e,r){var t,n,s,o,i,a=[],c=r.length;for(t=0;t<c;t++)126===(s=r[t]).marker&&-1!==s.end&&(o=r[s.end],(i=e.tokens[s.token]).type="s_open",i.tag="s",i.nesting=1,i.markup="~~",i.content="",(i=e.tokens[o.token]).type="s_close",i.tag="s",i.nesting=-1,i.markup="~~",i.content="","text"===e.tokens[o.token-1].type&&"~"===e.tokens[o.token-1].content&&a.push(o.token-1));for(;a.length;){for(n=(t=a.pop())+1;n<e.tokens.length&&"s_close"===e.tokens[n].type;)n++;t!==--n&&(i=e.tokens[n],e.tokens[n]=e.tokens[t],e.tokens[t]=i)}}var Pe={tokenize:function(e,r){var t,n,s,o,i=e.pos,a=e.src.charCodeAt(i);if(r)return!1;if(126!==a)return!1;if(s=(n=e.scanDelims(e.pos,!0)).length,o=String.fromCharCode(a),s<2)return!1;for(s%2&&(e.push("text","",0).content=o,s--),t=0;t<s;t+=2)e.push("text","",0).content=o+o,e.delimiters.push({marker:a,length:0,token:e.tokens.length-1,end:-1,open:n.can_open,close:n.can_close});return e.pos+=n.length,!0},postProcess:function(e){var r,t=e.tokens_meta,n=e.tokens_meta.length;for(Oe(e,e.delimiters),r=0;r<n;r++)t[r]&&t[r].delimiters&&Oe(e,t[r].delimiters)}};function je(e,r){var t,n,s,o,i,a;for(t=r.length-1;t>=0;t--)95!==(n=r[t]).marker&&42!==n.marker||-1!==n.end&&(s=r[n.end],a=t>0&&r[t-1].end===n.end+1&&r[t-1].marker===n.marker&&r[t-1].token===n.token-1&&r[n.end+1].token===s.token+1,i=String.fromCharCode(n.marker),(o=e.tokens[n.token]).type=a?"strong_open":"em_open",o.tag=a?"strong":"em",o.nesting=1,o.markup=a?i+i:i,o.content="",(o=e.tokens[s.token]).type=a?"strong_close":"em_close",o.tag=a?"strong":"em",o.nesting=-1,o.markup=a?i+i:i,o.content="",a&&(e.tokens[r[t-1].token].content="",e.tokens[r[n.end+1].token].content="",t--))}var Ue={tokenize:function(e,r){var t,n,s=e.pos,o=e.src.charCodeAt(s);if(r)return!1;if(95!==o&&42!==o)return!1;for(n=e.scanDelims(e.pos,42===o),t=0;t<n.length;t++)e.push("text","",0).content=String.fromCharCode(o),e.delimiters.push({marker:o,length:n.length,token:e.tokens.length-1,end:-1,open:n.can_open,close:n.can_close});return e.pos+=n.length,!0},postProcess:function(e){var r,t=e.tokens_meta,n=e.tokens_meta.length;for(je(e,e.delimiters),r=0;r<n;r++)t[r]&&t[r].delimiters&&je(e,t[r].delimiters)}},Ve=w.normalizeReference,Ze=w.isSpace,$e=w.normalizeReference,Ge=w.isSpace,He=/^([a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*)$/,Je=/^([a-zA-Z][a-zA-Z0-9+.\-]{1,31}):([^<>\x00-\x20]*)$/,We=Ae.HTML_TAG_RE;var Ye=w.has,Ke=w.isValidEntityCode,Qe=w.fromCodePoint,Xe=/^&#((?:x[a-f0-9]{1,6}|[0-9]{1,7}));/i,er=/^&([a-z][a-z0-9]{1,31});/i;function rr(e,r){var t,n,s,o,i,a,c,l,u={},p=r.length;if(p){var h=0,f=-2,d=[];for(t=0;t<p;t++)if(s=r[t],d.push(0),r[h].marker===s.marker&&f===s.token-1||(h=t),f=s.token,s.length=s.length||0,s.close){for(u.hasOwnProperty(s.marker)||(u[s.marker]=[-1,-1,-1,-1,-1,-1]),i=u[s.marker][(s.open?3:0)+s.length%3],a=n=h-d[h]-1;n>i;n-=d[n]+1)if((o=r[n]).marker===s.marker&&o.open&&o.end<0&&(c=!1,(o.close||s.open)&&(o.length+s.length)%3==0&&(o.length%3==0&&s.length%3==0||(c=!0)),!c)){l=n>0&&!r[n-1].open?d[n-1]+1:0,d[t]=t-n+l,d[n]=l,s.open=!1,o.end=t,o.close=!1,a=-1,f=-2;break}-1!==a&&(u[s.marker][(s.open?3:0)+(s.length||0)%3]=a)}}}var tr=w.isWhiteSpace,nr=w.isPunctChar,sr=w.isMdAsciiPunct;function or(e,r,t,n){this.src=e,this.env=t,this.md=r,this.tokens=n,this.tokens_meta=Array(n.length),this.pos=0,this.posMax=this.src.length,this.level=0,this.pending="",this.pendingLevel=0,this.cache={},this.delimiters=[],this._prev_delimiters=[],this.backticks={},this.backticksScanned=!1,this.linkLevel=0}or.prototype.pushPending=function(){var e=new oe("text","",0);return e.content=this.pending,e.level=this.pendingLevel,this.tokens.push(e),this.pending="",e},or.prototype.push=function(e,r,t){this.pending&&this.pushPending();var n=new oe(e,r,t),s=null;return t<0&&(this.level--,this.delimiters=this._prev_delimiters.pop()),n.level=this.level,t>0&&(this.level++,this._prev_delimiters.push(this.delimiters),this.delimiters=[],s={delimiters:this.delimiters}),this.pendingLevel=this.level,this.tokens.push(n),this.tokens_meta.push(s),n},or.prototype.scanDelims=function(e,r){var t,n,s,o,i,a,c,l,u,p=e,h=!0,f=!0,d=this.posMax,m=this.src.charCodeAt(e);for(t=e>0?this.src.charCodeAt(e-1):32;p<d&&this.src.charCodeAt(p)===m;)p++;return s=p-e,n=p<d?this.src.charCodeAt(p):32,c=sr(t)||nr(String.fromCharCode(t)),u=sr(n)||nr(String.fromCharCode(n)),a=tr(t),(l=tr(n))?h=!1:u&&(a||c||(h=!1)),a?f=!1:c&&(l||u||(f=!1)),r?(o=h,i=f):(o=h&&(!f||c),i=f&&(!h||u)),{can_open:o,can_close:i,length:s}},or.prototype.Token=oe;var ir=or,ar=[["text",function(e,r){for(var t=e.pos;t<e.posMax&&!Te(e.src.charCodeAt(t));)t++;return t!==e.pos&&(r||(e.pending+=e.src.slice(e.pos,t)),e.pos=t,!0)}],["linkify",function(e,r){var t,n,s,o,i,a,c;return!!e.md.options.linkify&&(!(e.linkLevel>0)&&(!((t=e.pos)+3>e.posMax)&&(58===e.src.charCodeAt(t)&&(47===e.src.charCodeAt(t+1)&&(47===e.src.charCodeAt(t+2)&&(!!(n=e.pending.match(Ie))&&(s=n[1],!!(o=e.md.linkify.matchAtStart(e.src.slice(t-s.length)))&&(i=(i=o.url).replace(/\*+$/,""),a=e.md.normalizeLink(i),!!e.md.validateLink(a)&&(r||(e.pending=e.pending.slice(0,-s.length),(c=e.push("link_open","a",1)).attrs=[["href",a]],c.markup="linkify",c.info="auto",(c=e.push("text","",0)).content=e.md.normalizeLinkText(i),(c=e.push("link_close","a",-1)).markup="linkify",c.info="auto"),e.pos+=i.length-s.length,!0)))))))))}],["newline",function(e,r){var t,n,s,o=e.pos;if(10!==e.src.charCodeAt(o))return!1;if(t=e.pending.length-1,n=e.posMax,!r)if(t>=0&&32===e.pending.charCodeAt(t))if(t>=1&&32===e.pending.charCodeAt(t-1)){for(s=t-1;s>=1&&32===e.pending.charCodeAt(s-1);)s--;e.pending=e.pending.slice(0,s),e.push("hardbreak","br",0)}else e.pending=e.pending.slice(0,-1),e.push("softbreak","br",0);else e.push("softbreak","br",0);for(o++;o<n&&Me(e.src.charCodeAt(o));)o++;return e.pos=o,!0}],["escape",function(e,r){var t,n,s,o,i,a=e.pos,c=e.posMax;if(92!==e.src.charCodeAt(a))return!1;if(++a>=c)return!1;if(10===(t=e.src.charCodeAt(a))){for(r||e.push("hardbreak","br",0),a++;a<c&&(t=e.src.charCodeAt(a),Re(t));)a++;return e.pos=a,!0}return o=e.src[a],t>=55296&&t<=56319&&a+1<c&&(n=e.src.charCodeAt(a+1))>=56320&&n<=57343&&(o+=e.src[a+1],a++),s="\\"+o,r||(i=e.push("text_special","",0),t<256&&0!==Be[t]?i.content=o:i.content=s,i.markup=s,i.info="escape"),e.pos=a+1,!0}],["backticks",function(e,r){var t,n,s,o,i,a,c,l,u=e.pos;if(96!==e.src.charCodeAt(u))return!1;for(t=u,u++,n=e.posMax;u<n&&96===e.src.charCodeAt(u);)u++;if(c=(s=e.src.slice(t,u)).length,e.backticksScanned&&(e.backticks[c]||0)<=t)return r||(e.pending+=s),e.pos+=c,!0;for(i=a=u;-1!==(i=e.src.indexOf("`",a));){for(a=i+1;a<n&&96===e.src.charCodeAt(a);)a++;if((l=a-i)===c)return r||((o=e.push("code_inline","code",0)).markup=s,o.content=e.src.slice(u,i).replace(/\n/g," ").replace(/^ (.+) $/,"$1")),e.pos=a,!0;e.backticks[l]=i}return e.backticksScanned=!0,r||(e.pending+=s),e.pos+=c,!0}],["strikethrough",Pe.tokenize],["emphasis",Ue.tokenize],["link",function(e,r){var t,n,s,o,i,a,c,l,u="",p="",h=e.pos,f=e.posMax,d=e.pos,m=!0;if(91!==e.src.charCodeAt(e.pos))return!1;if(i=e.pos+1,(o=e.md.helpers.parseLinkLabel(e,e.pos,!0))<0)return!1;if((a=o+1)<f&&40===e.src.charCodeAt(a)){for(m=!1,a++;a<f&&(n=e.src.charCodeAt(a),Ze(n)||10===n);a++);if(a>=f)return!1;if(d=a,(c=e.md.helpers.parseLinkDestination(e.src,a,e.posMax)).ok){for(u=e.md.normalizeLink(c.str),e.md.validateLink(u)?a=c.pos:u="",d=a;a<f&&(n=e.src.charCodeAt(a),Ze(n)||10===n);a++);if(c=e.md.helpers.parseLinkTitle(e.src,a,e.posMax),a<f&&d!==a&&c.ok)for(p=c.str,a=c.pos;a<f&&(n=e.src.charCodeAt(a),Ze(n)||10===n);a++);}(a>=f||41!==e.src.charCodeAt(a))&&(m=!0),a++}if(m){if(void 0===e.env.references)return!1;if(a<f&&91===e.src.charCodeAt(a)?(d=a+1,(a=e.md.helpers.parseLinkLabel(e,a))>=0?s=e.src.slice(d,a++):a=o+1):a=o+1,s||(s=e.src.slice(i,o)),!(l=e.env.references[Ve(s)]))return e.pos=h,!1;u=l.href,p=l.title}return r||(e.pos=i,e.posMax=o,e.push("link_open","a",1).attrs=t=[["href",u]],p&&t.push(["title",p]),e.linkLevel++,e.md.inline.tokenize(e),e.linkLevel--,e.push("link_close","a",-1)),e.pos=a,e.posMax=f,!0}],["image",function(e,r){var t,n,s,o,i,a,c,l,u,p,h,f,d,m="",g=e.pos,_=e.posMax;if(33!==e.src.charCodeAt(e.pos))return!1;if(91!==e.src.charCodeAt(e.pos+1))return!1;if(a=e.pos+2,(i=e.md.helpers.parseLinkLabel(e,e.pos+1,!1))<0)return!1;if((c=i+1)<_&&40===e.src.charCodeAt(c)){for(c++;c<_&&(n=e.src.charCodeAt(c),Ge(n)||10===n);c++);if(c>=_)return!1;for(d=c,(u=e.md.helpers.parseLinkDestination(e.src,c,e.posMax)).ok&&(m=e.md.normalizeLink(u.str),e.md.validateLink(m)?c=u.pos:m=""),d=c;c<_&&(n=e.src.charCodeAt(c),Ge(n)||10===n);c++);if(u=e.md.helpers.parseLinkTitle(e.src,c,e.posMax),c<_&&d!==c&&u.ok)for(p=u.str,c=u.pos;c<_&&(n=e.src.charCodeAt(c),Ge(n)||10===n);c++);else p="";if(c>=_||41!==e.src.charCodeAt(c))return e.pos=g,!1;c++}else{if(void 0===e.env.references)return!1;if(c<_&&91===e.src.charCodeAt(c)?(d=c+1,(c=e.md.helpers.parseLinkLabel(e,c))>=0?o=e.src.slice(d,c++):c=i+1):c=i+1,o||(o=e.src.slice(a,i)),!(l=e.env.references[$e(o)]))return e.pos=g,!1;m=l.href,p=l.title}return r||(s=e.src.slice(a,i),e.md.inline.parse(s,e.md,e.env,f=[]),(h=e.push("image","img",0)).attrs=t=[["src",m],["alt",""]],h.children=f,h.content=s,p&&t.push(["title",p])),e.pos=c,e.posMax=_,!0}],["autolink",function(e,r){var t,n,s,o,i,a,c=e.pos;if(60!==e.src.charCodeAt(c))return!1;for(i=e.pos,a=e.posMax;;){if(++c>=a)return!1;if(60===(o=e.src.charCodeAt(c)))return!1;if(62===o)break}return t=e.src.slice(i+1,c),Je.test(t)?(n=e.md.normalizeLink(t),!!e.md.validateLink(n)&&(r||((s=e.push("link_open","a",1)).attrs=[["href",n]],s.markup="autolink",s.info="auto",(s=e.push("text","",0)).content=e.md.normalizeLinkText(t),(s=e.push("link_close","a",-1)).markup="autolink",s.info="auto"),e.pos+=t.length+2,!0)):!!He.test(t)&&(n=e.md.normalizeLink("mailto:"+t),!!e.md.validateLink(n)&&(r||((s=e.push("link_open","a",1)).attrs=[["href",n]],s.markup="autolink",s.info="auto",(s=e.push("text","",0)).content=e.md.normalizeLinkText(t),(s=e.push("link_close","a",-1)).markup="autolink",s.info="auto"),e.pos+=t.length+2,!0))}],["html_inline",function(e,r){var t,n,s,o,i,a=e.pos;return!!e.md.options.html&&(s=e.posMax,!(60!==e.src.charCodeAt(a)||a+2>=s)&&(!(33!==(t=e.src.charCodeAt(a+1))&&63!==t&&47!==t&&!function(e){var r=32|e;return r>=97&&r<=122}(t))&&(!!(n=e.src.slice(a).match(We))&&(r||((o=e.push("html_inline","",0)).content=e.src.slice(a,a+n[0].length),i=o.content,/^<a[>\s]/i.test(i)&&e.linkLevel++,function(e){return/^<\/a\s*>/i.test(e)}(o.content)&&e.linkLevel--),e.pos+=n[0].length,!0))))}],["entity",function(e,t){var n,s,o,i=e.pos,a=e.posMax;if(38!==e.src.charCodeAt(i))return!1;if(i+1>=a)return!1;if(35===e.src.charCodeAt(i+1)){if(s=e.src.slice(i).match(Xe))return t||(n="x"===s[1][0].toLowerCase()?parseInt(s[1].slice(1),16):parseInt(s[1],10),(o=e.push("text_special","",0)).content=Ke(n)?Qe(n):Qe(65533),o.markup=s[0],o.info="entity"),e.pos+=s[0].length,!0}else if((s=e.src.slice(i).match(er))&&Ye(r,s[1]))return t||((o=e.push("text_special","",0)).content=r[s[1]],o.markup=s[0],o.info="entity"),e.pos+=s[0].length,!0;return!1}]],cr=[["balance_pairs",function(e){var r,t=e.tokens_meta,n=e.tokens_meta.length;for(rr(0,e.delimiters),r=0;r<n;r++)t[r]&&t[r].delimiters&&rr(0,t[r].delimiters)}],["strikethrough",Pe.postProcess],["emphasis",Ue.postProcess],["fragments_join",function(e){var r,t,n=0,s=e.tokens,o=e.tokens.length;for(r=t=0;r<o;r++)s[r].nesting<0&&n--,s[r].level=n,s[r].nesting>0&&n++,"text"===s[r].type&&r+1<o&&"text"===s[r+1].type?s[r+1].content=s[r].content+s[r+1].content:(r!==t&&(s[t]=s[r]),t++);r!==t&&(s.length=t)}]];function lr(){var e;for(this.ruler=new O,e=0;e<ar.length;e++)this.ruler.push(ar[e][0],ar[e][1]);for(this.ruler2=new O,e=0;e<cr.length;e++)this.ruler2.push(cr[e][0],cr[e][1])}lr.prototype.skipToken=function(e){var r,t,n=e.pos,s=this.ruler.getRules(""),o=s.length,i=e.md.options.maxNesting,a=e.cache;if(void 0===a[n]){if(e.level<i)for(t=0;t<o&&(e.level++,r=s[t](e,!0),e.level--,!r);t++);else e.pos=e.posMax;r||e.pos++,a[n]=e.pos}else e.pos=a[n]},lr.prototype.tokenize=function(e){for(var r,t,n=this.ruler.getRules(""),s=n.length,o=e.posMax,i=e.md.options.maxNesting;e.pos<o;){if(e.level<i)for(t=0;t<s&&!(r=n[t](e,!1));t++);if(r){if(e.pos>=o)break}else e.pending+=e.src[e.pos++]}e.pending&&e.pushPending()},lr.prototype.parse=function(e,r,t,n){var s,o,i,a=new this.State(e,r,t,n);for(this.tokenize(a),i=(o=this.ruler2.getRules("")).length,s=0;s<i;s++)o[s](a)},lr.prototype.State=ir;var ur=lr;function pr(e){var r=Array.prototype.slice.call(arguments,1);return r.forEach((function(r){r&&Object.keys(r).forEach((function(t){e[t]=r[t]}))})),e}function hr(e){return Object.prototype.toString.call(e)}function fr(e){return"[object Function]"===hr(e)}function dr(e){return e.replace(/[.?*+^$[\]\\(){}|-]/g,"\\$&")}var mr={fuzzyLink:!0,fuzzyEmail:!0,fuzzyIP:!1};var gr={"http:":{validate:function(e,r,t){var n=e.slice(r);return t.re.http||(t.re.http=new RegExp("^\\/\\/"+t.re.src_auth+t.re.src_host_port_strict+t.re.src_path,"i")),t.re.http.test(n)?n.match(t.re.http)[0].length:0}},"https:":"http:","ftp:":"http:","//":{validate:function(e,r,t){var n=e.slice(r);return t.re.no_http||(t.re.no_http=new RegExp("^"+t.re.src_auth+"(?:localhost|(?:(?:"+t.re.src_domain+")\\.)+"+t.re.src_domain_root+")"+t.re.src_port+t.re.src_host_terminator+t.re.src_path,"i")),t.re.no_http.test(n)?r>=3&&":"===e[r-3]||r>=3&&"/"===e[r-3]?0:n.match(t.re.no_http)[0].length:0}},"mailto:":{validate:function(e,r,t){var n=e.slice(r);return t.re.mailto||(t.re.mailto=new RegExp("^"+t.re.src_email_name+"@"+t.re.src_host_strict,"i")),t.re.mailto.test(n)?n.match(t.re.mailto)[0].length:0}}},_r="biz|com|edu|gov|net|org|pro|web|xxx|aero|asia|coop|info|museum|name|shop|\u0440\u0444".split("|");function kr(e){var r=e.re=function(e){var r={};return e=e||{},r.src_Any=y.source,r.src_Cc=A.source,r.src_Z=x.source,r.src_P=t.source,r.src_ZPCc=[r.src_Z,r.src_P,r.src_Cc].join("|"),r.src_ZCc=[r.src_Z,r.src_Cc].join("|"),r.src_pseudo_letter="(?:(?![><\uff5c]|"+r.src_ZPCc+")"+r.src_Any+")",r.src_ip4="(?:(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)",r.src_auth="(?:(?:(?!"+r.src_ZCc+"|[@/\\[\\]()]).)+@)?",r.src_port="(?::(?:6(?:[0-4]\\d{3}|5(?:[0-4]\\d{2}|5(?:[0-2]\\d|3[0-5])))|[1-5]?\\d{1,4}))?",r.src_host_terminator="(?=$|[><\uff5c]|"+r.src_ZPCc+")(?!"+(e["---"]?"-(?!--)|":"-|")+"_|:\\d|\\.-|\\.(?!$|"+r.src_ZPCc+"))",r.src_path="(?:[/?#](?:(?!"+r.src_ZCc+"|[><\uff5c]|[()[\\]{}.,\"'?!\\-;]).|\\[(?:(?!"+r.src_ZCc+"|\\]).)*\\]|\\((?:(?!"+r.src_ZCc+"|[)]).)*\\)|\\{(?:(?!"+r.src_ZCc+'|[}]).)*\\}|\\"(?:(?!'+r.src_ZCc+'|["]).)+\\"|\\\'(?:(?!'+r.src_ZCc+"|[']).)+\\'|\\'(?="+r.src_pseudo_letter+"|[-])|\\.{2,}[a-zA-Z0-9%/&]|\\.(?!"+r.src_ZCc+"|[.]|$)|"+(e["---"]?"\\-(?!--(?:[^-]|$))(?:-*)|":"\\-+|")+",(?!"+r.src_ZCc+"|$)|;(?!"+r.src_ZCc+"|$)|\\!+(?!"+r.src_ZCc+"|[!]|$)|\\?(?!"+r.src_ZCc+"|[?]|$))+|\\/)?",r.src_email_name='[\\-;:&=\\+\\$,\\.a-zA-Z0-9_][\\-;:&=\\+\\$,\\"\\.a-zA-Z0-9_]*',r.src_xn="xn--[a-z0-9\\-]{1,59}",r.src_domain_root="(?:"+r.src_xn+"|"+r.src_pseudo_letter+"{1,63})",r.src_domain="(?:"+r.src_xn+"|(?:"+r.src_pseudo_letter+")|(?:"+r.src_pseudo_letter+"(?:-|"+r.src_pseudo_letter+"){0,61}"+r.src_pseudo_letter+"))",r.src_host="(?:(?:(?:(?:"+r.src_domain+")\\.)*"+r.src_domain+"))",r.tpl_host_fuzzy="(?:"+r.src_ip4+"|(?:(?:(?:"+r.src_domain+")\\.)+(?:%TLDS%)))",r.tpl_host_no_ip_fuzzy="(?:(?:(?:"+r.src_domain+")\\.)+(?:%TLDS%))",r.src_host_strict=r.src_host+r.src_host_terminator,r.tpl_host_fuzzy_strict=r.tpl_host_fuzzy+r.src_host_terminator,r.src_host_port_strict=r.src_host+r.src_port+r.src_host_terminator,r.tpl_host_port_fuzzy_strict=r.tpl_host_fuzzy+r.src_port+r.src_host_terminator,r.tpl_host_port_no_ip_fuzzy_strict=r.tpl_host_no_ip_fuzzy+r.src_port+r.src_host_terminator,r.tpl_host_fuzzy_test="localhost|www\\.|\\.\\d{1,3}\\.|(?:\\.(?:%TLDS%)(?:"+r.src_ZPCc+"|>|$))",r.tpl_email_fuzzy='(^|[><\uff5c]|"|\\(|'+r.src_ZCc+")("+r.src_email_name+"@"+r.tpl_host_fuzzy_strict+")",r.tpl_link_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+r.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+r.tpl_host_port_fuzzy_strict+r.src_path+")",r.tpl_link_no_ip_fuzzy="(^|(?![.:/\\-_@])(?:[$+<=>^`|\uff5c]|"+r.src_ZPCc+"))((?![$+<=>^`|\uff5c])"+r.tpl_host_port_no_ip_fuzzy_strict+r.src_path+")",r}(e.__opts__),n=e.__tlds__.slice();function s(e){return e.replace("%TLDS%",r.src_tlds)}e.onCompile(),e.__tlds_replaced__||n.push("a[cdefgilmnoqrstuwxz]|b[abdefghijmnorstvwyz]|c[acdfghiklmnoruvwxyz]|d[ejkmoz]|e[cegrstu]|f[ijkmor]|g[abdefghilmnpqrstuwy]|h[kmnrtu]|i[delmnoqrst]|j[emop]|k[eghimnprwyz]|l[abcikrstuvy]|m[acdeghklmnopqrstuvwxyz]|n[acefgilopruz]|om|p[aefghklmnrstwy]|qa|r[eosuw]|s[abcdeghijklmnortuvxyz]|t[cdfghjklmnortvwz]|u[agksyz]|v[aceginu]|w[fs]|y[et]|z[amw]"),n.push(r.src_xn),r.src_tlds=n.join("|"),r.email_fuzzy=RegExp(s(r.tpl_email_fuzzy),"i"),r.link_fuzzy=RegExp(s(r.tpl_link_fuzzy),"i"),r.link_no_ip_fuzzy=RegExp(s(r.tpl_link_no_ip_fuzzy),"i"),r.host_fuzzy_test=RegExp(s(r.tpl_host_fuzzy_test),"i");var o=[];function i(e,r){throw new Error('(LinkifyIt) Invalid schema "'+e+'": '+r)}e.__compiled__={},Object.keys(e.__schemas__).forEach((function(r){var t=e.__schemas__[r];if(null!==t){var n={validate:null,link:null};if(e.__compiled__[r]=n,"[object Object]"===hr(t))return!function(e){return"[object RegExp]"===hr(e)}(t.validate)?fr(t.validate)?n.validate=t.validate:i(r,t):n.validate=function(e){return function(r,t){var n=r.slice(t);return e.test(n)?n.match(e)[0].length:0}}(t.validate),void(fr(t.normalize)?n.normalize=t.normalize:t.normalize?i(r,t):n.normalize=function(e,r){r.normalize(e)});!function(e){return"[object String]"===hr(e)}(t)?i(r,t):o.push(r)}})),o.forEach((function(r){e.__compiled__[e.__schemas__[r]]&&(e.__compiled__[r].validate=e.__compiled__[e.__schemas__[r]].validate,e.__compiled__[r].normalize=e.__compiled__[e.__schemas__[r]].normalize)})),e.__compiled__[""]={validate:null,normalize:function(e,r){r.normalize(e)}};var a=Object.keys(e.__compiled__).filter((function(r){return r.length>0&&e.__compiled__[r]})).map(dr).join("|");e.re.schema_test=RegExp("(^|(?!_)(?:[><\uff5c]|"+r.src_ZPCc+"))("+a+")","i"),e.re.schema_search=RegExp("(^|(?!_)(?:[><\uff5c]|"+r.src_ZPCc+"))("+a+")","ig"),e.re.schema_at_start=RegExp("^"+e.re.schema_search.source,"i"),e.re.pretest=RegExp("("+e.re.schema_test.source+")|("+e.re.host_fuzzy_test.source+")|@","i"),function(e){e.__index__=-1,e.__text_cache__=""}(e)}function br(e,r){var t=e.__index__,n=e.__last_index__,s=e.__text_cache__.slice(t,n);this.schema=e.__schema__.toLowerCase(),this.index=t+r,this.lastIndex=n+r,this.raw=s,this.text=s,this.url=s}function vr(e,r){var t=new br(e,r);return e.__compiled__[t.schema].normalize(t,e),t}function Cr(e,r){if(!(this instanceof Cr))return new Cr(e,r);var t;r||(t=e,Object.keys(t||{}).reduce((function(e,r){return e||mr.hasOwnProperty(r)}),!1)&&(r=e,e={})),this.__opts__=pr({},mr,r),this.__index__=-1,this.__last_index__=-1,this.__schema__="",this.__text_cache__="",this.__schemas__=pr({},gr,e),this.__compiled__={},this.__tlds__=_r,this.__tlds_replaced__=!1,this.re={},kr(this)}Cr.prototype.add=function(e,r){return this.__schemas__[e]=r,kr(this),this},Cr.prototype.set=function(e){return this.__opts__=pr(this.__opts__,e),this},Cr.prototype.test=function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return!1;var r,t,n,s,o,i,a,c;if(this.re.schema_test.test(e))for((a=this.re.schema_search).lastIndex=0;null!==(r=a.exec(e));)if(s=this.testSchemaAt(e,r[2],a.lastIndex)){this.__schema__=r[2],this.__index__=r.index+r[1].length,this.__last_index__=r.index+r[0].length+s;break}return this.__opts__.fuzzyLink&&this.__compiled__["http:"]&&(c=e.search(this.re.host_fuzzy_test))>=0&&(this.__index__<0||c<this.__index__)&&null!==(t=e.match(this.__opts__.fuzzyIP?this.re.link_fuzzy:this.re.link_no_ip_fuzzy))&&(o=t.index+t[1].length,(this.__index__<0||o<this.__index__)&&(this.__schema__="",this.__index__=o,this.__last_index__=t.index+t[0].length)),this.__opts__.fuzzyEmail&&this.__compiled__["mailto:"]&&e.indexOf("@")>=0&&null!==(n=e.match(this.re.email_fuzzy))&&(o=n.index+n[1].length,i=n.index+n[0].length,(this.__index__<0||o<this.__index__||o===this.__index__&&i>this.__last_index__)&&(this.__schema__="mailto:",this.__index__=o,this.__last_index__=i)),this.__index__>=0},Cr.prototype.pretest=function(e){return this.re.pretest.test(e)},Cr.prototype.testSchemaAt=function(e,r,t){return this.__compiled__[r.toLowerCase()]?this.__compiled__[r.toLowerCase()].validate(e,t,this):0},Cr.prototype.match=function(e){var r=0,t=[];this.__index__>=0&&this.__text_cache__===e&&(t.push(vr(this,r)),r=this.__last_index__);for(var n=r?e.slice(r):e;this.test(n);)t.push(vr(this,r)),n=n.slice(this.__last_index__),r+=this.__last_index__;return t.length?t:null},Cr.prototype.matchAtStart=function(e){if(this.__text_cache__=e,this.__index__=-1,!e.length)return null;var r=this.re.schema_at_start.exec(e);if(!r)return null;var t=this.testSchemaAt(e,r[2],r[0].length);return t?(this.__schema__=r[2],this.__index__=r.index+r[1].length,this.__last_index__=r.index+r[0].length+t,vr(this,0)):null},Cr.prototype.tlds=function(e,r){return e=Array.isArray(e)?e:[e],r?(this.__tlds__=this.__tlds__.concat(e).sort().filter((function(e,r,t){return e!==t[r-1]})).reverse(),kr(this),this):(this.__tlds__=e.slice(),this.__tlds_replaced__=!0,kr(this),this)},Cr.prototype.normalize=function(e){e.schema||(e.url="http://"+e.url),"mailto:"!==e.schema||/^mailto:/i.test(e.url)||(e.url="mailto:"+e.url)},Cr.prototype.onCompile=function(){};var yr=Cr,Ar=2147483647,xr=36,Dr=/^xn--/,wr=/[^\x20-\x7E]/,Er=/[\x2E\u3002\uFF0E\uFF61]/g,qr={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},Sr=Math.floor,Fr=String.fromCharCode;
+/*! https://mths.be/punycode v1.4.1 by @mathias */function Lr(e){throw new RangeError(qr[e])}function zr(e,r){for(var t=e.length,n=[];t--;)n[t]=r(e[t]);return n}function Tr(e,r){var t=e.split("@"),n="";return t.length>1&&(n=t[0]+"@",e=t[1]),n+zr((e=e.replace(Er,".")).split("."),r).join(".")}function Ir(e){for(var r,t,n=[],s=0,o=e.length;s<o;)(r=e.charCodeAt(s++))>=55296&&r<=56319&&s<o?56320==(64512&(t=e.charCodeAt(s++)))?n.push(((1023&r)<<10)+(1023&t)+65536):(n.push(r),s--):n.push(r);return n}function Mr(e){return zr(e,(function(e){var r="";return e>65535&&(r+=Fr((e-=65536)>>>10&1023|55296),e=56320|1023&e),r+=Fr(e)})).join("")}function Rr(e,r){return e+22+75*(e<26)-((0!=r)<<5)}function Br(e,r,t){var n=0;for(e=t?Sr(e/700):e>>1,e+=Sr(e/r);e>455;n+=xr)e=Sr(e/35);return Sr(n+36*e/(e+38))}function Nr(e){var r,t,n,s,o,i,a,c,l,u,p,h=[],f=e.length,d=0,m=128,g=72;for((t=e.lastIndexOf("-"))<0&&(t=0),n=0;n<t;++n)e.charCodeAt(n)>=128&&Lr("not-basic"),h.push(e.charCodeAt(n));for(s=t>0?t+1:0;s<f;){for(o=d,i=1,a=xr;s>=f&&Lr("invalid-input"),((c=(p=e.charCodeAt(s++))-48<10?p-22:p-65<26?p-65:p-97<26?p-97:xr)>=xr||c>Sr((Ar-d)/i))&&Lr("overflow"),d+=c*i,!(c<(l=a<=g?1:a>=g+26?26:a-g));a+=xr)i>Sr(Ar/(u=xr-l))&&Lr("overflow"),i*=u;g=Br(d-o,r=h.length+1,0==o),Sr(d/r)>Ar-m&&Lr("overflow"),m+=Sr(d/r),d%=r,h.splice(d++,0,m)}return Mr(h)}function Or(e){var r,t,n,s,o,i,a,c,l,u,p,h,f,d,m,g=[];for(h=(e=Ir(e)).length,r=128,t=0,o=72,i=0;i<h;++i)(p=e[i])<128&&g.push(Fr(p));for(n=s=g.length,s&&g.push("-");n<h;){for(a=Ar,i=0;i<h;++i)(p=e[i])>=r&&p<a&&(a=p);for(a-r>Sr((Ar-t)/(f=n+1))&&Lr("overflow"),t+=(a-r)*f,r=a,i=0;i<h;++i)if((p=e[i])<r&&++t>Ar&&Lr("overflow"),p==r){for(c=t,l=xr;!(c<(u=l<=o?1:l>=o+26?26:l-o));l+=xr)m=c-u,d=xr-u,g.push(Fr(Rr(u+m%d,0))),c=Sr(m/d);g.push(Fr(Rr(c,0))),o=Br(t,f,n==s),t=0,++n}++t,++r}return g.join("")}function Pr(e){return Tr(e,(function(e){return Dr.test(e)?Nr(e.slice(4).toLowerCase()):e}))}function jr(e){return Tr(e,(function(e){return wr.test(e)?"xn--"+Or(e):e}))}var Ur="1.4.1",Vr={decode:Ir,encode:Mr},Zr={version:Ur,ucs2:Vr,toASCII:jr,toUnicode:Pr,encode:Or,decode:Nr},$r=e(Object.freeze({__proto__:null,decode:Nr,encode:Or,toUnicode:Pr,toASCII:jr,version:Ur,ucs2:Vr,default:Zr})),Gr={default:{options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:100},components:{core:{},block:{},inline:{}}},zero:{options:{html:!1,xhtmlOut:!1,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline","text_join"]},block:{rules:["paragraph"]},inline:{rules:["text"],rules2:["balance_pairs","fragments_join"]}}},commonmark:{options:{html:!0,xhtmlOut:!0,breaks:!1,langPrefix:"language-",linkify:!1,typographer:!1,quotes:"\u201c\u201d\u2018\u2019",highlight:null,maxNesting:20},components:{core:{rules:["normalize","block","inline","text_join"]},block:{rules:["blockquote","code","fence","heading","hr","html_block","lheading","list","reference","paragraph"]},inline:{rules:["autolink","backticks","emphasis","entity","escape","html_inline","image","link","newline","text"],rules2:["balance_pairs","emphasis","fragments_join"]}}}},Hr=/^(vbscript|javascript|file|data):/,Jr=/^data:image\/(gif|png|jpeg|webp);/;function Wr(e){var r=e.trim().toLowerCase();return!Hr.test(r)||!!Jr.test(r)}var Yr=["http:","https:","mailto:"];function Kr(e){var r=C.parse(e,!0);if(r.hostname&&(!r.protocol||Yr.indexOf(r.protocol)>=0))try{r.hostname=$r.toASCII(r.hostname)}catch(e){}return C.encode(C.format(r))}function Qr(e){var r=C.parse(e,!0);if(r.hostname&&(!r.protocol||Yr.indexOf(r.protocol)>=0))try{r.hostname=$r.toUnicode(r.hostname)}catch(e){}return C.decode(C.format(r),C.decode.defaultChars+"%")}function Xr(e,r){if(!(this instanceof Xr))return new Xr(e,r);r||w.isString(e)||(r=e||{},e="default"),this.inline=new ur,this.block=new ze,this.core=new ue,this.renderer=new B,this.linkify=new yr,this.validateLink=Wr,this.normalizeLink=Kr,this.normalizeLinkText=Qr,this.utils=w,this.helpers=w.assign({},L),this.options={},this.configure(e),r&&this.set(r)}return Xr.prototype.set=function(e){return w.assign(this.options,e),this},Xr.prototype.configure=function(e){var r,t=this;if(w.isString(e)&&!(e=Gr[r=e]))throw new Error('Wrong `markdown-it` preset "'+r+'", check name');if(!e)throw new Error("Wrong `markdown-it` preset, can't be empty");return e.options&&t.set(e.options),e.components&&Object.keys(e.components).forEach((function(r){e.components[r].rules&&t[r].ruler.enableOnly(e.components[r].rules),e.components[r].rules2&&t[r].ruler2.enableOnly(e.components[r].rules2)})),this},Xr.prototype.enable=function(e,r){var t=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(r){t=t.concat(this[r].ruler.enable(e,!0))}),this),t=t.concat(this.inline.ruler2.enable(e,!0));var n=e.filter((function(e){return t.indexOf(e)<0}));if(n.length&&!r)throw new Error("MarkdownIt. Failed to enable unknown rule(s): "+n);return this},Xr.prototype.disable=function(e,r){var t=[];Array.isArray(e)||(e=[e]),["core","block","inline"].forEach((function(r){t=t.concat(this[r].ruler.disable(e,!0))}),this),t=t.concat(this.inline.ruler2.disable(e,!0));var n=e.filter((function(e){return t.indexOf(e)<0}));if(n.length&&!r)throw new Error("MarkdownIt. Failed to disable unknown rule(s): "+n);return this},Xr.prototype.use=function(e){var r=[this].concat(Array.prototype.slice.call(arguments,1));return e.apply(e,r),this},Xr.prototype.parse=function(e,r){if("string"!=typeof e)throw new Error("Input data should be a String");var t=new this.core.State(e,this,r);return this.core.process(t),t.tokens},Xr.prototype.render=function(e,r){return r=r||{},this.renderer.render(this.parse(e,r),this.options,r)},Xr.prototype.parseInline=function(e,r){var t=new this.core.State(e,this,r);return t.inlineMode=!0,this.core.process(t),t.tokens},Xr.prototype.renderInline=function(e,r){return r=r||{},this.renderer.render(this.parseInline(e,r),this.options,r)},Xr}));
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/013-bootstrap-tabcollapse.js b/mailcow/src/mailcow-dockerized/data/web/js/build/013-bootstrap-tabcollapse.js
deleted file mode 100644
index 6a5f9b8..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/013-bootstrap-tabcollapse.js
+++ /dev/null
@@ -1,239 +0,0 @@
-!function ($) {
-
- "use strict";
-
- // TABCOLLAPSE CLASS DEFINITION
- // ======================
-
- var TabCollapse = function (el, options) {
- this.options = options;
- this.$tabs = $(el);
-
- this._accordionVisible = false; //content is attached to tabs at first
- this._initAccordion();
- this._checkStateOnResize();
-
-
- // checkState() has gone to setTimeout for making it possible to attach listeners to
- // shown-accordion.bs.tabcollapse event on page load.
- // See https://github.com/flatlogic/bootstrap-tabcollapse/issues/23
- var that = this;
- setTimeout(function() {
- that.checkState();
- }, 0);
- };
-
- TabCollapse.DEFAULTS = {
- accordionClass: 'visible-xs',
- tabsClass: 'hidden-xs',
- accordionTemplate: function(heading, groupId, parentId, active) {
- return '<div class="panel panel-default">' +
- ' <div class="panel-heading">' +
- ' <h4 class="panel-title">' +
- ' </h4>' +
- ' </div>' +
- ' <div id="' + groupId + '" class="panel-collapse collapse ' + (active ? 'in' : '') + '">' +
- ' <div class="panel-body js-tabcollapse-panel-body">' +
- ' </div>' +
- ' </div>' +
- '</div>'
-
- }
- };
-
- TabCollapse.prototype.checkState = function(){
- if (this.$tabs.is(':visible') && this._accordionVisible){
- this.showTabs();
- this._accordionVisible = false;
- } else if (this.$accordion.is(':visible') && !this._accordionVisible){
- this.showAccordion();
- this._accordionVisible = true;
- }
- };
-
- TabCollapse.prototype.showTabs = function(){
- var view = this;
- this.$tabs.trigger($.Event('show-tabs.bs.tabcollapse'));
-
- var $panelHeadings = this.$accordion.find('.js-tabcollapse-panel-heading').detach();
-
- $panelHeadings.each(function() {
- var $panelHeading = $(this),
- $parentLi = $panelHeading.data('bs.tabcollapse.parentLi');
-
- var $oldHeading = view._panelHeadingToTabHeading($panelHeading);
-
- $parentLi.removeClass('active');
- if ($parentLi.parent().hasClass('dropdown-menu') && !$parentLi.siblings('li').hasClass('active')) {
- $parentLi.parent().parent().removeClass('active');
- }
-
- if (!$oldHeading.hasClass('collapsed')) {
- $parentLi.addClass('active');
- $('.tab-pane').removeClass('active');
- $($panelHeading.attr('href')).addClass('active');
- if ($parentLi.parent().hasClass('dropdown-menu')) {
- $parentLi.parent().parent().addClass('active');
- }
- } else {
- $oldHeading.removeClass('collapsed');
- }
-
- $parentLi.append($panelHeading);
- });
-
- if (!$('li').hasClass('active')) {
- $('li').first().addClass('active')
- }
-
- var $panelBodies = this.$accordion.find('.js-tabcollapse-panel-body');
- $panelBodies.each(function(){
- var $panelBody = $(this),
- $tabPane = $panelBody.data('bs.tabcollapse.tabpane');
- $tabPane.append($panelBody.contents().detach());
- });
- this.$accordion.html('');
-
- if(this.options.updateLinks) {
- var $tabContents = this.getTabContentElement();
- $tabContents.find('[data-toggle-was="tab"], [data-toggle-was="pill"]').each(function() {
- var $el = $(this);
- var href = $el.attr('href').replace(/-collapse$/g, '');
- $el.attr({
- 'data-toggle': $el.attr('data-toggle-was'),
- 'data-toggle-was': '',
- 'data-parent': '',
- href: href
- });
- });
- }
-
- this.$tabs.trigger($.Event('shown-tabs.bs.tabcollapse'));
- };
-
- TabCollapse.prototype.getTabContentElement = function(){
- var $tabContents = $(this.options.tabContentSelector);
- if($tabContents.length === 0) {
- $tabContents = this.$tabs.siblings('.tab-content');
- }
- return $tabContents;
- };
-
- TabCollapse.prototype.showAccordion = function(){
- this.$tabs.trigger($.Event('show-accordion.bs.tabcollapse'));
-
- var $headings = this.$tabs.find('li:not(.dropdown) [data-toggle="tab"], li:not(.dropdown) [data-toggle="pill"]'),
- view = this;
- $headings.each(function(){
- var $heading = $(this),
- $parentLi = $heading.parent();
- $heading.data('bs.tabcollapse.parentLi', $parentLi);
- view.$accordion.append(view._createAccordionGroup(view.$accordion.attr('id'), $heading.detach()));
- });
-
- if(this.options.updateLinks) {
- var parentId = this.$accordion.attr('id');
- var $selector = this.$accordion.find('.js-tabcollapse-panel-body');
- $selector.find('[data-toggle="tab"], [data-toggle="pill"]').each(function() {
- var $el = $(this);
- var href = $el.attr('href') + '-collapse';
- $el.attr({
- 'data-toggle-was': $el.attr('data-toggle'),
- 'data-toggle': 'collapse',
- 'data-parent': '#' + parentId,
- href: href
- });
- });
- }
-
- this.$tabs.trigger($.Event('shown-accordion.bs.tabcollapse'));
- };
-
- TabCollapse.prototype._panelHeadingToTabHeading = function($heading) {
- var href = $heading.attr('href').replace(/-collapse$/g, '');
- $heading.attr({
- 'data-toggle': 'tab',
- 'href': href,
- 'data-parent': ''
- });
- return $heading;
- };
-
- TabCollapse.prototype._tabHeadingToPanelHeading = function($heading, groupId, parentId, active) {
- $heading.addClass('js-tabcollapse-panel-heading ' + (active ? '' : 'collapsed'));
- $heading.attr({
- 'data-toggle': 'collapse',
- 'data-parent': '#' + parentId,
- 'href': '#' + groupId
- });
- return $heading;
- };
-
- TabCollapse.prototype._checkStateOnResize = function(){
- var view = this;
- $(window).resize(function(){
- clearTimeout(view._resizeTimeout);
- view._resizeTimeout = setTimeout(function(){
- view.checkState();
- }, 100);
- });
- };
-
-
- TabCollapse.prototype._initAccordion = function(){
- var randomString = function() {
- var result = "",
- possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
- for( var i=0; i < 5; i++ ) {
- result += possible.charAt(Math.floor(Math.random() * possible.length));
- }
- return result;
- };
-
- var srcId = this.$tabs.attr('id'),
- accordionId = (srcId ? srcId : randomString()) + '-accordion';
-
- this.$accordion = $('<div class="panel-group ' + this.options.accordionClass + '" id="' + accordionId +'"></div>');
- this.$tabs.after(this.$accordion);
- this.$tabs.addClass(this.options.tabsClass);
- this.getTabContentElement().addClass(this.options.tabsClass);
- };
-
- TabCollapse.prototype._createAccordionGroup = function(parentId, $heading){
- var tabSelector = $heading.attr('data-target'),
- active = $heading.data('bs.tabcollapse.parentLi').is('.active');
-
- if (!tabSelector) {
- tabSelector = $heading.attr('href');
- tabSelector = tabSelector && tabSelector.replace(/.*(?=#[^\s]*$)/, ''); //strip for ie7
- }
-
- var $tabPane = $(tabSelector),
- groupId = $tabPane.attr('id') + '-collapse',
- $panel = $(this.options.accordionTemplate($heading, groupId, parentId, active));
- $panel.find('.panel-heading > .panel-title').append(this._tabHeadingToPanelHeading($heading, groupId, parentId, active));
- $panel.find('.panel-body').append($tabPane.contents().detach())
- .data('bs.tabcollapse.tabpane', $tabPane);
-
- return $panel;
- };
-
-
-
- // TABCOLLAPSE PLUGIN DEFINITION
- // =======================
-
- $.fn.tabCollapse = function (option) {
- return this.each(function () {
- var $this = $(this);
- var data = $this.data('bs.tabcollapse');
- var options = $.extend({}, TabCollapse.DEFAULTS, $this.data(), typeof option === 'object' && option);
-
- if (!data) $this.data('bs.tabcollapse', new TabCollapse(this, options));
- });
- };
-
- $.fn.tabCollapse.Constructor = TabCollapse;
-
-
-}(window.jQuery);
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/013-footable.min.js b/mailcow/src/mailcow-dockerized/data/web/js/build/013-footable.min.js
deleted file mode 100644
index 53398d1..0000000
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/013-footable.min.js
+++ /dev/null
@@ -1,10 +0,0 @@
-/*
-* FooTable v3 - FooTable is a jQuery plugin that aims to make HTML tables on smaller devices look awesome.
-* @version 3.1.6
-* @link http://fooplugins.com
-* @copyright Steven Usher & Brad Vincent 2015
-* @license Released under the GPLv3 license.
-*/
-!function(a,b){window.console=window.console||{log:function(){},error:function(){}},a.fn.footable=function(a,c){return a=a||{},this.filter("table").each(function(d,e){b.init(e,a,c)})};var c={events:[]};b.__debug__=JSON.parse(localStorage.getItem("footable_debug"))||!1,b.__debug_options__=JSON.parse(localStorage.getItem("footable_debug_options"))||c,b.debug=function(d,e){return b.is["boolean"](d)?(b.__debug__=d,void(b.__debug__?(localStorage.setItem("footable_debug",JSON.stringify(b.__debug__)),b.__debug_options__=a.extend(!0,{},c,e||{}),b.is.hash(e)&&localStorage.setItem("footable_debug_options",JSON.stringify(b.__debug_options__))):(localStorage.removeItem("footable_debug"),localStorage.removeItem("footable_debug_options")))):b.__debug__},b.get=function(b){return a(b).first().data("__FooTable__")},b.init=function(a,c,d){var e=b.get(a);return e instanceof b.Table&&e.destroy(),new b.Table(a,c,d)},b.getRow=function(b){var c=a(b).closest("tr");return c.hasClass("footable-detail-row")&&(c=c.prev()),c.data("__FooTableRow__")}}(jQuery,FooTable=window.FooTable||{}),function(a){var b=function(){return!0};a.arr={},a.arr.each=function(b,c){if(a.is.array(b)&&a.is.fn(c))for(var d=0,e=b.length;e>d&&c(b[d],d)!==!1;d++);},a.arr.get=function(b,c){var d=[];if(!a.is.array(b))return d;if(!a.is.fn(c))return b;for(var e=0,f=b.length;f>e;e++)c(b[e],e)&&d.push(b[e]);return d},a.arr.any=function(c,d){if(!a.is.array(c))return!1;d=a.is.fn(d)?d:b;for(var e=0,f=c.length;f>e;e++)if(d(c[e],e))return!0;return!1},a.arr.contains=function(b,c){if(!a.is.array(b)||a.is.undef(c))return!1;for(var d=0,e=b.length;e>d;d++)if(b[d]==c)return!0;return!1},a.arr.first=function(c,d){if(!a.is.array(c))return null;d=a.is.fn(d)?d:b;for(var e=0,f=c.length;f>e;e++)if(d(c[e],e))return c[e];return null},a.arr.map=function(b,c){var d=[],e=null;if(!a.is.array(b)||!a.is.fn(c))return d;for(var f=0,g=b.length;g>f;f++)null!=(e=c(b[f],f))&&d.push(e);return d},a.arr.remove=function(b,c){var d=[],e=[];if(!a.is.array(b)||!a.is.fn(c))return e;for(var f=0,g=b.length;g>f;f++)c(b[f],f,e)&&(d.push(f),e.push(b[f]));for(d.sort(function(a,b){return b-a}),f=0,g=d.length;g>f;f++){var h=d[f]-f;b.splice(h,1)}return e},a.arr["delete"]=function(b,c){var d=-1,e=null;if(!a.is.array(b)||a.is.undef(c))return e;for(var f=0,g=b.length;g>f;f++)if(b[f]==c){d=f,e=b[f];break}return-1!=d&&b.splice(d,1),e},a.arr.replace=function(a,b,c){var d=a.indexOf(b);-1!==d&&(a[d]=c)}}(FooTable),function(a){a.is={},a.is.type=function(a,b){return typeof a===b},a.is.defined=function(a){return"undefined"!=typeof a},a.is.undef=function(a){return"undefined"==typeof a},a.is.array=function(a){return"[object Array]"===Object.prototype.toString.call(a)},a.is.date=function(a){return"[object Date]"===Object.prototype.toString.call(a)&&!isNaN(a.getTime())},a.is["boolean"]=function(a){return"[object Boolean]"===Object.prototype.toString.call(a)},a.is.string=function(a){return"[object String]"===Object.prototype.toString.call(a)},a.is.number=function(a){return"[object Number]"===Object.prototype.toString.call(a)&&!isNaN(a)},a.is.fn=function(b){return a.is.defined(window)&&b===window.alert||"[object Function]"===Object.prototype.toString.call(b)},a.is.error=function(a){return"[object Error]"===Object.prototype.toString.call(a)},a.is.object=function(a){return"[object Object]"===Object.prototype.toString.call(a)},a.is.hash=function(b){return a.is.object(b)&&b.constructor===Object&&!b.nodeType&&!b.setInterval},a.is.element=function(a){return"object"==typeof HTMLElement?a instanceof HTMLElement:a&&"object"==typeof a&&null!==a&&1===a.nodeType&&"string"==typeof a.nodeName},a.is.promise=function(b){return a.is.object(b)&&a.is.fn(b.then)&&a.is.fn(b.promise)},a.is.jq=function(b){return a.is.defined(window.jQuery)&&b instanceof jQuery&&b.length>0},a.is.moment=function(b){return a.is.defined(window.moment)&&a.is.object(b)&&a.is["boolean"](b._isAMomentObject)},a.is.emptyObject=function(b){if(!a.is.hash(b))return!1;for(var c in b)if(b.hasOwnProperty(c))return!1;return!0},a.is.emptyArray=function(b){return a.is.array(b)?0===b.length:!0},a.is.emptyString=function(b){return a.is.string(b)?0===b.length:!0}}(FooTable),function(a){a.str={},a.str.contains=function(b,c,d){return a.is.emptyString(b)||a.is.emptyString(c)?!1:c.length<=b.length&&-1!==(d?b.toUpperCase().indexOf(c.toUpperCase()):b.indexOf(c))},a.str.containsExact=function(b,c,d){return a.is.emptyString(b)||a.is.emptyString(c)||c.length>b.length?!1:new RegExp("\\b"+a.str.escapeRegExp(c)+"\\b",d?"i":"").test(b)},a.str.containsWord=function(b,c,d){if(a.is.emptyString(b)||a.is.emptyString(c)||b.length<c.length)return!1;for(var e=b.split(/\W/),f=0,g=e.length;g>f;f++)if(d?e[f].toUpperCase()==c.toUpperCase():e[f]==c)return!0;return!1},a.str.from=function(b,c){return a.is.emptyString(b)?b:a.str.contains(b,c)?b.substring(b.indexOf(c)+1):b},a.str.startsWith=function(b,c){return a.is.emptyString(b)?b==c:b.slice(0,c.length)==c},a.str.toCamelCase=function(b){return a.is.emptyString(b)?b:b.toUpperCase()===b?b.toLowerCase():b.replace(/^([A-Z])|[-\s_](\w)/g,function(b,c,d){return a.is.string(d)?d.toUpperCase():c.toLowerCase()})},a.str.random=function(b){return b=a.is.emptyString(b)?"":b,b+Math.random().toString(36).substr(2,9)},a.str.escapeRegExp=function(b){return a.is.emptyString(b)?b:b.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}}(FooTable),function(a){"use strict";function b(){}Object.create||(Object.create=function(){var b=function(){};return function(c){if(arguments.length>1)throw Error("Second argument not supported");if(!a.is.object(c))throw TypeError("Argument must be an object");b.prototype=c;var d=new b;return b.prototype=null,d}}());var c=/xyz/.test(function(){xyz})?/\b_super\b/:/.*/;b.__extend__=function(b,d,e,f){b[d]=a.is.fn(f)&&c.test(e)?function(a,b){return function(){var a,c;return a=this._super,this._super=f,c=b.apply(this,arguments),this._super=a,c}}(d,e):e},b.extend=function(d,e){function f(b,d,e,f){b[d]=a.is.fn(f)&&c.test(e)?function(a,b,c){return function(){var a,d;return a=this._super,this._super=c,d=b.apply(this,arguments),this._super=a,d}}(d,e,f):e}var g=Array.prototype.slice.call(arguments);if(d=g.shift(),e=g.shift(),a.is.hash(d)){var h=Object.create(this.prototype),i=this.prototype;for(var j in d)"__ctor__"!==j&&f(h,j,d[j],i[j]);var k=a.is.fn(h.__ctor__)?h.__ctor__:function(){if(!a.is.fn(this.construct))throw new SyntaxError('FooTable class objects must be constructed with the "new" keyword.');this.construct.apply(this,arguments)};return h.construct=a.is.fn(h.construct)?h.construct:function(){},k.prototype=h,h.constructor=k,k.extend=b.extend,k}a.is.string(d)&&a.is.fn(e)&&f(this.prototype,d,e,this.prototype[d])},a.Class=b,a.ClassFactory=a.Class.extend({construct:function(){this.registered={}},contains:function(b){return a.is.defined(this.registered[b])},names:function(){var a,b=[];for(a in this.registered)this.registered.hasOwnProperty(a)&&b.push(a);return b},register:function(b,c,d){if(a.is.string(b)&&a.is.fn(c)){var e=this.registered[b];this.registered[b]={name:b,klass:c,priority:a.is.number(d)?d:a.is.defined(e)?e.priority:0}}},load:function(b,c,d){var e,f,g=this,h=Array.prototype.slice.call(arguments),i=[],j=[];b=h.shift()||{};for(e in g.registered)if(g.registered.hasOwnProperty(e)){var k=g.registered[e];b.hasOwnProperty(e)&&(f=b[e],a.is.string(f)&&(f=a.getFnPointer(b[e])),a.is.fn(f)&&(k={name:e,klass:f,priority:g.registered[e].priority})),i.push(k)}for(e in b)b.hasOwnProperty(e)&&!g.registered.hasOwnProperty(e)&&(f=b[e],a.is.string(f)&&(f=a.getFnPointer(b[e])),a.is.fn(f)&&i.push({name:e,klass:f,priority:0}));return i.sort(function(a,b){return b.priority-a.priority}),a.arr.each(i,function(b){a.is.fn(b.klass)&&j.push(g._make(b.klass,h))}),j},make:function(b,c,d){var e,f=this,g=Array.prototype.slice.call(arguments);return b=g.shift(),e=f.registered[b],a.is.fn(e.klass)?f._make(e.klass,g):null},_make:function(a,b){function c(){return a.apply(this,b)}return c.prototype=a.prototype,new c}})}(FooTable),function(a,b){b.css2json=function(c){if(b.is.emptyString(c))return{};for(var d,e,f,g={},h=c.split(";"),i=0,j=h.length;j>i;i++)b.is.emptyString(h[i])||(d=h[i].split(":"),b.is.emptyString(d[0])||b.is.emptyString(d[1])||(e=b.str.toCamelCase(a.trim(d[0])),f=a.trim(d[1]),g[e]=f));return g},b.getFnPointer=function(a){if(b.is.emptyString(a))return null;var c=window,d=a.split(".");return b.arr.each(d,function(a){c[a]&&(c=c[a])}),b.is.fn(c)?c:null},b.checkFnValue=function(a,c,d){function e(a,c,d){return b.is.fn(c)?function(){return c.apply(a,arguments)}:d}return d=b.is.fn(d)?d:null,b.is.fn(c)?e(a,c,d):b.is.type(c,"string")?e(a,b.getFnPointer(c),d):d}}(jQuery,FooTable),function(a,b){b.Cell=b.Class.extend({construct:function(a,b,c,d){this.ft=a,this.row=b,this.column=c,this.created=!1,this.define(d)},define:function(c){this.$el=b.is.element(c)||b.is.jq(c)?a(c):null,this.$detail=null;var d=b.is.hash(c)&&b.is.hash(c.options)&&b.is.defined(c.value);this.value=this.column.parser.call(this.column,b.is.jq(this.$el)?this.$el:d?c.value:c,this.ft.o),this.o=a.extend(!0,{classes:null,style:null},d?c.options:{}),this.classes=b.is.jq(this.$el)&&this.$el.attr("class")?this.$el.attr("class").match(/\S+/g):b.is.array(this.o.classes)?this.o.classes:b.is.string(this.o.classes)?this.o.classes.match(/\S+/g):[],this.style=b.is.jq(this.$el)&&this.$el.attr("style")?b.css2json(this.$el.attr("style")):b.is.hash(this.o.style)?this.o.style:b.is.string(this.o.style)?b.css2json(this.o.style):{}},$create:function(){this.created||((this.$el=b.is.jq(this.$el)?this.$el:a("<td/>")).data("value",this.value).contents().detach().end().append(this.format(this.value)),this._setClasses(this.$el),this._setStyle(this.$el),this.$detail=a("<tr/>").addClass(this.row.classes.join(" ")).data("__FooTableCell__",this).append(a("<th/>")).append(a("<td/>")),this.created=!0)},collapse:function(){this.created&&(this.$detail.children("th").html(this.column.title),this.$el.clone().attr("id",this.$el.attr("id")?this.$el.attr("id")+"-detail":void 0).css("display","table-cell").html("").append(this.$el.contents().detach()).replaceAll(this.$detail.children("td").first()),b.is.jq(this.$detail.parent())||this.$detail.appendTo(this.row.$details.find(".footable-details > tbody")))},restore:function(){if(this.created){if(b.is.jq(this.$detail.parent())){var a=this.$detail.children("td").first();this.$el.attr("class",a.attr("class")).attr("style",a.attr("style")).css("display",this.column.hidden||!this.column.visible?"none":"table-cell").append(a.contents().detach())}this.$detail.detach()}},parse:function(){return this.column.parser.call(this.column,this.$el,this.ft.o)},format:function(a){return this.column.formatter.call(this.column,a,this.ft.o,this.row.value)},val:function(c,d,e){if(b.is.undef(c))return this.value;var f=this,g=b.is.hash(c)&&b.is.hash(c.options)&&b.is.defined(c.value);if(this.o=a.extend(!0,{classes:f.classes,style:f.style},g?c.options:{}),this.value=g?c.value:c,this.classes=b.is.array(this.o.classes)?this.o.classes:b.is.string(this.o.classes)?this.o.classes.match(/\S+/g):[],this.style=b.is.hash(this.o.style)?this.o.style:b.is.string(this.o.style)?b.css2json(this.o.style):{},e=b.is["boolean"](e)?e:!0,this.created&&e){this.$el.data("value",this.value).empty();var h=this.$detail.children("td").first().empty(),i=b.is.jq(this.$detail.parent())?h:this.$el;i.append(this.format(this.value)),this._setClasses(i),this._setStyle(i),(b.is["boolean"](d)?d:!0)&&this.row.draw()}},_setClasses:function(a){var c=!b.is.emptyArray(this.column.classes),d=!b.is.emptyArray(this.classes),e=null;a.removeAttr("class"),(c||d)&&(c&&d?e=this.classes.concat(this.column.classes).join(" "):c?e=this.column.classes.join(" "):d&&(e=this.classes.join(" ")),b.is.emptyString(e)||a.addClass(e))},_setStyle:function(c){var d=!b.is.emptyObject(this.column.style),e=!b.is.emptyObject(this.style),f=null;c.removeAttr("style"),(d||e)&&(d&&e?f=a.extend({},this.column.style,this.style):d?f=this.column.style:e&&(f=this.style),b.is.hash(f)&&c.css(f))}})}(jQuery,FooTable),function(a,b){b.Column=b.Class.extend({construct:function(a,c,d){this.ft=a,this.type=b.is.emptyString(d)?"text":d,this.virtual=b.is["boolean"](c.virtual)?c.virtual:!1,this.$el=b.is.jq(c.$el)?c.$el:null,this.index=b.is.number(c.index)?c.index:-1,this.internal=!1,this.define(c),this.$create()},define:function(a){this.hidden=b.is["boolean"](a.hidden)?a.hidden:!1,this.visible=b.is["boolean"](a.visible)?a.visible:!0,this.name=b.is.string(a.name)?a.name:null,null==this.name&&(this.name="col"+(a.index+1)),this.title=b.is.string(a.title)?a.title:null,!this.virtual&&null==this.title&&b.is.jq(this.$el)&&(this.title=this.$el.html()),null==this.title&&(this.title="Column "+(a.index+1)),this.style=b.is.hash(a.style)?a.style:b.is.string(a.style)?b.css2json(a.style):{},this.classes=b.is.array(a.classes)?a.classes:b.is.string(a.classes)?a.classes.match(/\S+/g):[],this.parser=b.checkFnValue(this,a.parser,this.parser),this.formatter=b.checkFnValue(this,a.formatter,this.formatter)},$create:function(){(this.$el=!this.virtual&&b.is.jq(this.$el)?this.$el:a("<th/>")).html(this.title).addClass(this.classes.join(" ")).css(this.style)},parser:function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("value");return b.is.defined(d)?d:a(c).html()}return b.is.defined(c)&&null!=c?c+"":null},formatter:function(a,b,c){return null==a?"":a},createCell:function(a){var c=b.is.jq(a.$el)?a.$el.children("td,th").get(this.index):null,d=b.is.hash(a.value)?a.value[this.name]:null;return new b.Cell(this.ft,a,this,c||d)}}),b.columns=new b.ClassFactory,b.columns.register("text",b.Column)}(jQuery,FooTable),function(a,b){b.Component=b.Class.extend({construct:function(a,c){if(!(a instanceof b.Table))throw new TypeError("The instance parameter must be an instance of FooTable.Table.");this.ft=a,this.enabled=b.is["boolean"](c)?c:!1},preinit:function(a){},init:function(){},destroy:function(){},predraw:function(){},draw:function(){},postdraw:function(){}}),b.components=new b.ClassFactory}(jQuery,FooTable),function(a,b){b.Defaults=function(){this.stopPropagation=!1,this.on=null},b.defaults=new b.Defaults}(jQuery,FooTable),function(a,b){b.Row=b.Class.extend({construct:function(a,b,c){this.ft=a,this.columns=b,this.created=!1,this.define(c)},define:function(c){this.$el=b.is.element(c)||b.is.jq(c)?a(c):null,this.$toggle=a("<span/>",{"class":"footable-toggle fooicon fooicon-plus"});var d=b.is.hash(c),e=d&&b.is.hash(c.options)&&b.is.hash(c.value);this.value=d?e?c.value:c:null,this.o=a.extend(!0,{expanded:!1,classes:null,style:null},e?c.options:{}),this.expanded=b.is.jq(this.$el)?this.$el.data("expanded")||this.o.expanded:this.o.expanded,this.classes=b.is.jq(this.$el)&&this.$el.attr("class")?this.$el.attr("class").match(/\S+/g):b.is.array(this.o.classes)?this.o.classes:b.is.string(this.o.classes)?this.o.classes.match(/\S+/g):[],this.style=b.is.jq(this.$el)&&this.$el.attr("style")?b.css2json(this.$el.attr("style")):b.is.hash(this.o.style)?this.o.style:b.is.string(this.o.style)?b.css2json(this.o.style):{},this.cells=this.createCells();var f=this;f.value={},b.arr.each(f.cells,function(a){f.value[a.column.name]=a.val()})},$create:function(){if(!this.created){(this.$el=b.is.jq(this.$el)?this.$el:a("<tr/>")).data("__FooTableRow__",this),this._setClasses(this.$el),this._setStyle(this.$el),"last"==this.ft.rows.toggleColumn&&this.$toggle.addClass("last-column"),this.$details=a("<tr/>",{"class":"footable-detail-row"}).append(a("<td/>",{colspan:this.ft.columns.visibleColspan}).append(a("<table/>",{"class":"footable-details "+this.ft.classes.join(" ")}).append("<tbody/>")));var c=this;b.arr.each(c.cells,function(a){a.created||a.$create(),c.$el.append(a.$el)}),c.$el.off("click.ft.row").on("click.ft.row",{self:c},c._onToggle),this.created=!0}},createCells:function(){var a=this;return b.arr.map(a.columns,function(b){return b.createCell(a)})},val:function(c,d,e){var f=this;if(!b.is.hash(c))return b.is.hash(this.value)&&!b.is.emptyObject(this.value)||(this.value={},b.arr.each(this.cells,function(a){a.column.internal||(f.value[a.column.name]=a.val())})),this.value;this.collapse(!1);var g=b.is.hash(c),h=g&&b.is.hash(c.options)&&b.is.hash(c.value);if(this.o=a.extend(!0,{expanded:f.expanded,classes:f.classes,style:f.style},h?c.options:{}),this.expanded=this.o.expanded,this.classes=b.is.array(this.o.classes)?this.o.classes:b.is.string(this.o.classes)?this.o.classes.match(/\S+/g):[],this.style=b.is.hash(this.o.style)?this.o.style:b.is.string(this.o.style)?b.css2json(this.o.style):{},g)if(h&&(c=c.value),b.is.hash(this.value))for(var i in c)c.hasOwnProperty(i)&&(this.value[i]=c[i]);else this.value=c;else this.value=null;e=b.is["boolean"](e)?e:!0,b.arr.each(this.cells,function(a){!a.column.internal&&b.is.defined(f.value[a.column.name])&&a.val(f.value[a.column.name],!1,e)}),this.created&&e&&(this._setClasses(this.$el),this._setStyle(this.$el),(b.is["boolean"](d)?d:!0)&&this.draw())},_setClasses:function(a){var c=!b.is.emptyArray(this.classes),d=null;a.removeAttr("class"),c&&(d=this.classes.join(" "),b.is.emptyString(d)||a.addClass(d))},_setStyle:function(a){var c=!b.is.emptyObject(this.style),d=null;a.removeAttr("style"),c&&(d=this.style,b.is.hash(d)&&a.css(d))},expand:function(){if(this.created){var a=this;a.ft.raise("expand.ft.row",[a]).then(function(){a.__hidden__=b.arr.map(a.cells,function(a){return a.column.hidden&&a.column.visible?a:null}),a.__hidden__.length>0&&(a.$details.insertAfter(a.$el).children("td").first().attr("colspan",a.ft.columns.visibleColspan),b.arr.each(a.__hidden__,function(a){a.collapse()})),a.$el.attr("data-expanded",!0),a.$toggle.removeClass("fooicon-plus").addClass("fooicon-minus"),a.expanded=!0,a.ft.raise("expanded.ft.row",[a])})}},collapse:function(a){if(this.created){var c=this;c.ft.raise("collapse.ft.row",[c]).then(function(){b.arr.each(c.__hidden__,function(a){a.restore()}),c.$details.detach(),c.$el.removeAttr("data-expanded"),c.$toggle.removeClass("fooicon-minus").addClass("fooicon-plus"),(b.is["boolean"](a)?a:!0)&&(c.expanded=!1),c.ft.raise("collapsed.ft.row",[c])})}},predraw:function(a){this.created&&(this.expanded&&this.collapse(!1),this.$toggle.detach(),a=b.is["boolean"](a)?a:!0,a&&this.$el.detach())},draw:function(a){this.created||this.$create(),b.is.jq(a)&&a.append(this.$el);var c=this;b.arr.each(c.cells,function(a){a.$el.css("display",a.column.hidden||!a.column.visible?"none":"table-cell"),c.ft.rows.showToggle&&c.ft.columns.hasHidden&&("first"==c.ft.rows.toggleColumn&&a.column.index==c.ft.columns.firstVisibleIndex||"last"==c.ft.rows.toggleColumn&&a.column.index==c.ft.columns.lastVisibleIndex)&&a.$el.prepend(c.$toggle),a.$el.add(a.column.$el).removeClass("footable-first-visible footable-last-visible"),a.column.index==c.ft.columns.firstVisibleIndex&&a.$el.add(a.column.$el).addClass("footable-first-visible"),a.column.index==c.ft.columns.lastVisibleIndex&&a.$el.add(a.column.$el).addClass("footable-last-visible")}),this.expanded&&this.expand()},toggle:function(){this.created&&this.ft.columns.hasHidden&&(this.expanded?this.collapse():this.expand())},_onToggle:function(b){var c=b.data.self;a(b.target).is(c.ft.rows.toggleSelector)&&c.toggle()}})}(jQuery,FooTable),function(a,b){b.instances=[],b.Table=b.Class.extend({construct:function(c,d,e){this._resizeTimeout=null,this.id=b.instances.push(this),this.initialized=!1,this.$el=(b.is.jq(c)?c:a(c)).first(),this.$loader=a("<div/>",{"class":"footable-loader"}).append(a("<span/>",{"class":"fooicon fooicon-loader"})),this.o=a.extend(!0,{},b.defaults,d),this.data=this.$el.data()||{},this.classes=[],this.components=b.components.load(b.is.hash(this.data.components)?this.data.components:this.o.components,this),this.breakpoints=this.use(FooTable.Breakpoints),this.columns=this.use(FooTable.Columns),this.rows=this.use(FooTable.Rows),this._construct(e)},_construct:function(a){var c=this;return this._preinit().then(function(){return c._init().then(function(){return c.raise("ready.ft.table").then(function(){b.is.fn(a)&&a.call(c,c)})})}).always(function(a){c.$el.show(),b.is.error(a)&&console.error("FooTable: unhandled error thrown during initialization.",a)})},_preinit:function(){var a=this;return this.raise("preinit.ft.table",[a.data]).then(function(){var c=(a.$el.attr("class")||"").match(/\S+/g)||[];a.o.ajax=b.checkFnValue(a,a.data.ajax,a.o.ajax),a.o.stopPropagation=b.is["boolean"](a.data.stopPropagation)?a.data.stopPropagation:a.o.stopPropagation;for(var d=0,e=c.length;e>d;d++)b.str.startsWith(c[d],"footable")||a.classes.push(c[d]);return a.$el.hide().after(a.$loader),a.execute(!1,!1,"preinit",a.data)})},_init:function(){var c=this;return c.raise("init.ft.table").then(function(){var d=c.$el.children("thead"),e=c.$el.children("tbody"),f=c.$el.children("tfoot");return c.$el.addClass("footable footable-"+c.id),b.is.hash(c.o.on)&&c.$el.on(c.o.on),0==f.length&&c.$el.append(f=a("<tfoot/>")),0==e.length&&c.$el.append("<tbody/>"),0==d.length&&c.$el.prepend(d=a("<thead/>")),c.execute(!1,!0,"init").then(function(){return c.$el.data("__FooTable__",c),0==f.children("tr").length&&f.remove(),0==d.children("tr").length&&d.remove(),c.raise("postinit.ft.table").then(function(){return c.draw()}).always(function(){a(window).off("resize.ft"+c.id,c._onWindowResize).on("resize.ft"+c.id,{self:c},c._onWindowResize),c.initialized=!0})})})},destroy:function(){var c=this;return c.raise("destroy.ft.table").then(function(){return c.execute(!0,!0,"destroy").then(function(){c.$el.removeData("__FooTable__").removeClass("footable-"+c.id),b.is.hash(c.o.on)&&c.$el.off(c.o.on),a(window).off("resize.ft"+c.id,c._onWindowResize),c.initialized=!1,b.instances[c.id]=null})}).fail(function(a){b.is.error(a)&&console.error("FooTable: unhandled error thrown while destroying the plugin.",a)})},raise:function(c,d){var e=this,f=b.__debug__&&(b.is.emptyArray(b.__debug_options__.events)||b.arr.any(b.__debug_options__.events,function(a){return b.str.contains(c,a)}));return d=d||[],d.unshift(this),a.Deferred(function(b){var g=a.Event(c);1==e.o.stopPropagation&&e.$el.one(c,function(a){a.stopPropagation()}),f&&console.log("FooTable:"+c+": ",d),e.$el.trigger(g,d),g.isDefaultPrevented()?(f&&console.log('FooTable: default prevented for the "'+c+'" event.'),b.reject(g)):b.resolve(g)})},use:function(a){for(var b=0,c=this.components.length;c>b;b++)if(this.components[b]instanceof a)return this.components[b];return null},draw:function(){var a=this,c=a.$el.clone().insertBefore(a.$el);return a.$el.detach(),a.execute(!1,!0,"predraw").then(function(){return a.raise("predraw.ft.table").then(function(){return a.execute(!1,!0,"draw").then(function(){return a.raise("draw.ft.table").then(function(){return a.execute(!1,!0,"postdraw").then(function(){return a.raise("postdraw.ft.table")})})})})}).fail(function(a){b.is.error(a)&&console.error("FooTable: unhandled error thrown during a draw operation.",a)}).always(function(){c.replaceWith(a.$el),a.$loader.remove()})},execute:function(a,c,d,e,f){var g=this,h=Array.prototype.slice.call(arguments);a=h.shift(),c=h.shift();var i=c?b.arr.get(g.components,function(a){return a.enabled}):g.components.slice(0);return h.unshift(a?i.reverse():i),g._execute.apply(g,h)},_execute:function(c,d,e,f){if(!c||!c.length)return a.when();var g,h=this,i=Array.prototype.slice.call(arguments);return c=i.shift(),d=i.shift(),g=c.shift(),b.is.fn(g[d])?a.Deferred(function(a){try{var c=g[d].apply(g,i);if(b.is.promise(c))return c.then(a.resolve,a.reject);a.resolve(c)}catch(e){a.reject(e)}}).then(function(){return h._execute.apply(h,[c,d].concat(i))}):h._execute.apply(h,[c,d].concat(i))},_onWindowResize:function(a){var b=a.data.self;null!=b._resizeTimeout&&clearTimeout(b._resizeTimeout),b._resizeTimeout=setTimeout(function(){b._resizeTimeout=null,b.raise("resize.ft.table").then(function(){b.breakpoints.check()})},300)}})}(jQuery,FooTable),function(a,b){b.ArrayColumn=b.Column.extend({construct:function(a,b){this._super(a,b,"array")},parser:function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c),e=d.data("value");if(b.is.array(e))return e;e=d.html();try{e=JSON.parse(e)}catch(f){e=null}return b.is.array(e)?e:null}return b.is.array(c)?c:null},formatter:function(a,c,d){return b.is.array(a)?JSON.stringify(a):""}}),b.columns.register("array",b.ArrayColumn)}(jQuery,FooTable),function(a,b){b.is.undef(window.moment)||(b.DateColumn=b.Column.extend({construct:function(a,c){this._super(a,c,"date"),this.formatString=b.is.string(c.formatString)?c.formatString:"MM-DD-YYYY"},parser:function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("value");c=b.is.defined(d)?d:a(c).text(),b.is.string(c)&&(c=isNaN(c)?c:+c)}if(b.is.date(c))return moment(c);if(b.is.object(c)&&b.is["boolean"](c._isAMomentObject))return c;if(b.is.string(c)){if(isNaN(c))return moment(c,this.formatString);c=+c}return b.is.number(c)?moment(c):null},formatter:function(a,c,d){return b.is.object(a)&&b.is["boolean"](a._isAMomentObject)&&a.isValid()?a.format(this.formatString):""},filterValue:function(c){if((b.is.element(c)||b.is.jq(c))&&(c=a(c).data("filterValue")||a(c).text()),b.is.hash(c)&&b.is.hash(c.options)&&(b.is.string(c.options.filterValue)&&(c=c.options.filterValue),b.is.defined(c.value)&&(c=c.value)),b.is.object(c)&&b.is["boolean"](c._isAMomentObject))return c.format(this.formatString);if(b.is.string(c)){if(isNaN(c))return c;c=+c}return b.is.number(c)||b.is.date(c)?moment(c).format(this.formatString):b.is.defined(c)&&null!=c?c+"":""}}),b.columns.register("date",b.DateColumn))}(jQuery,FooTable),function(a,b){b.HTMLColumn=b.Column.extend({construct:function(a,b){this._super(a,b,"html")},parser:function(c){if(b.is.string(c)&&(c=a(a.trim(c))),b.is.element(c)&&(c=a(c)),b.is.jq(c)){var d=c.prop("tagName").toLowerCase();if("td"==d||"th"==d){var e=c.data("value");return b.is.defined(e)?e:c.contents()}return c}return null}}),b.columns.register("html",b.HTMLColumn)}(jQuery,FooTable),function(a,b){b.NumberColumn=b.Column.extend({construct:function(a,c){this._super(a,c,"number"),this.decimalSeparator=b.is.string(c.decimalSeparator)?c.decimalSeparator:".",this.thousandSeparator=b.is.string(c.thousandSeparator)?c.thousandSeparator:",",this.decimalSeparatorRegex=new RegExp(b.str.escapeRegExp(this.decimalSeparator),"g"),this.thousandSeparatorRegex=new RegExp(b.str.escapeRegExp(this.thousandSeparator),"g"),this.cleanRegex=new RegExp("[^-0-9"+b.str.escapeRegExp(this.decimalSeparator)+"]","g")},parser:function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("value");c=b.is.defined(d)?d:a(c).text().replace(this.cleanRegex,"")}return b.is.string(c)&&(c=c.replace(this.thousandSeparatorRegex,"").replace(this.decimalSeparatorRegex,"."),c=parseFloat(c)),b.is.number(c)?c:null},formatter:function(a,b,c){if(null==a)return"";var d=(a+"").split(".");return 2==d.length&&d[0].length>3&&(d[0]=d[0].replace(/\B(?=(?:\d{3})+(?!\d))/g,this.thousandSeparator)),d.join(this.decimalSeparator)}}),b.columns.register("number",b.NumberColumn)}(jQuery,FooTable),function(a,b){b.ObjectColumn=b.Column.extend({construct:function(a,b){this._super(a,b,"object")},parser:function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c),e=d.data("value");if(b.is.object(e))return e;e=d.html();try{e=JSON.parse(e)}catch(f){e=null}return b.is.object(e)?e:null}return b.is.object(c)?c:null},formatter:function(a,c,d){return b.is.object(a)?JSON.stringify(a):""}}),b.columns.register("object",b.ObjectColumn)}(jQuery,FooTable),function(a,b){b.Breakpoint=b.Class.extend({construct:function(a,b){this.name=a,this.width=b}})}(jQuery,FooTable),function(a,b){b.Breakpoints=b.Component.extend({construct:function(a){this._super(a,!0),this.o=a.o,this.current=null,this.array=[],this.cascade=this.o.cascade,this.useParentWidth=this.o.useParentWidth,this.hidden=null,this._classNames="",this.getWidth=b.checkFnValue(this,this.o.getWidth,this.getWidth)},preinit:function(a){var c=this;return this.ft.raise("preinit.ft.breakpoints",[a]).then(function(){c.cascade=b.is["boolean"](a.cascade)?a.cascade:c.cascade,c.o.breakpoints=b.is.hash(a.breakpoints)?a.breakpoints:c.o.breakpoints,c.getWidth=b.checkFnValue(c,a.getWidth,c.getWidth),null==c.o.breakpoints&&(c.o.breakpoints={xs:480,sm:768,md:992,lg:1200});for(var d in c.o.breakpoints)c.o.breakpoints.hasOwnProperty(d)&&(c.array.push(new b.Breakpoint(d,c.o.breakpoints[d])),c._classNames+="breakpoint-"+d+" ");c.array.sort(function(a,b){return b.width-a.width})})},init:function(){var a=this;return this.ft.raise("init.ft.breakpoints").then(function(){a.current=a.get()})},draw:function(){this.ft.$el.removeClass(this._classNames).addClass("breakpoint-"+this.current.name)},calculate:function(){for(var a,c=this,d=null,e=[],f=null,g=c.getWidth(),h=0,i=c.array.length;i>h;h++)a=c.array[h],(!d&&h==i-1||g>=a.width&&(f instanceof b.Breakpoint?g<f.width:!0))&&(d=a),d||e.push(a.name),f=a;return e.push(d.name),c.hidden=e.join(" "),d},visible:function(a){if(b.is.emptyString(a))return!0;if("all"===a)return!1;for(var c=a.split(" "),d=0,e=c.length;e>d;d++)if(this.cascade?b.str.containsWord(this.hidden,c[d]):c[d]==this.current.name)return!1;return!0},check:function(){var a=this,c=a.get();c instanceof b.Breakpoint&&c!=a.current&&a.ft.raise("before.ft.breakpoints",[a.current,c]).then(function(){var b=a.current;return a.current=c,a.ft.draw().then(function(){a.ft.raise("after.ft.breakpoints",[a.current,b])})})},get:function(a){return b.is.undef(a)?this.calculate():a instanceof b.Breakpoint?a:b.is.string(a)?b.arr.first(this.array,function(b){return b.name==a}):b.is.number(a)&&a>=0&&a<this.array.length?this.array[a]:null},getWidth:function(){return b.is.fn(this.o.getWidth)?this.o.getWidth(this.ft):1==this.useParentWidth?this.getParentWidth():this.getViewportWidth()},getParentWidth:function(){return this.ft.$el.parent().width()},getViewportWidth:function(){return Math.max(document.documentElement.clientWidth,window.innerWidth,0)}}),b.components.register("breakpoints",b.Breakpoints,1e3)}(jQuery,FooTable),function(a){a.Column.prototype.breakpoints=null,a.Column.prototype.__breakpoints_define__=function(b){this.breakpoints=a.is.emptyString(b.breakpoints)?null:b.breakpoints},a.Column.extend("define",function(a){this._super(a),this.__breakpoints_define__(a)})}(FooTable),function(a){a.Defaults.prototype.breakpoints=null,a.Defaults.prototype.cascade=!1,a.Defaults.prototype.useParentWidth=!1,a.Defaults.prototype.getWidth=null}(FooTable),function(a,b){b.Columns=b.Component.extend({construct:function(a){this._super(a,!0),this.o=a.o,this.array=[],this.$header=null,this.showHeader=a.o.showHeader,this._fromHTML=b.is.emptyArray(a.o.columns)&&!b.is.promise(a.o.columns)},parse:function(c){var d=this;return a.Deferred(function(c){function e(c,d){var e=[];if(0==c.length||0==d.length)e=c.concat(d);else{var f=0;b.arr.each(c.concat(d),function(a){a.index>f&&(f=a.index)}),f++;for(var g,h,i=0;f>i;i++)g={},b.arr.each(c,function(a){return a.index==i?(g=a,!1):void 0}),h={},b.arr.each(d,function(a){return a.index==i?(h=a,!1):void 0}),e.push(a.extend(!0,{},g,h))}return e}var f,g,h=[],i=[],j=d.ft.$el.find("tr.footable-header, thead > tr:last:has([data-breakpoints]), tbody > tr:first:has([data-breakpoints]), thead > tr:last, tbody > tr:first").first();if(j.length>0){var k=j.parent().is("tbody")&&j.children().length==j.children("td").length;k||(d.$header=j.addClass("footable-header")),j.children("td,th").each(function(b,c){f=a(c),g=f.data(),g.index=b,g.$el=f,g.virtual=k,i.push(g)}),k&&(d.showHeader=!1)}b.is.array(d.o.columns)&&!b.is.emptyArray(d.o.columns)?(b.arr.each(d.o.columns,function(a,b){a.index=b,h.push(a)}),d.parseFinalize(c,e(h,i))):b.is.promise(d.o.columns)?d.o.columns.then(function(a){b.arr.each(a,function(a,b){a.index=b,h.push(a)}),d.parseFinalize(c,e(h,i))},function(a){c.reject(Error("Columns ajax request error: "+a.status+" ("+a.statusText+")"))}):d.parseFinalize(c,e(h,i))})},parseFinalize:function(a,c){var d,e=this,f=[];b.arr.each(c,function(a){(d=b.columns.contains(a.type)?b.columns.make(a.type,e.ft,a):new b.Column(e.ft,a))&&f.push(d)}),b.is.emptyArray(f)?a.reject(Error("No columns supplied.")):(f.sort(function(a,b){
-return a.index-b.index}),a.resolve(f))},preinit:function(a){var c=this;return c.ft.raise("preinit.ft.columns",[a]).then(function(){return c.parse(a).then(function(d){c.array=d,c.showHeader=b.is["boolean"](a.showHeader)?a.showHeader:c.showHeader})})},init:function(){var a=this;return this.ft.raise("init.ft.columns",[a.array]).then(function(){a.$create()})},destroy:function(){var a=this;this.ft.raise("destroy.ft.columns").then(function(){a._fromHTML||a.$header.remove()})},predraw:function(){var a=this,c=!0;a.visibleColspan=0,a.firstVisibleIndex=0,a.lastVisibleIndex=0,a.hasHidden=!1,b.arr.each(a.array,function(b){b.hidden=!a.ft.breakpoints.visible(b.breakpoints),!b.hidden&&b.visible&&(c&&(a.firstVisibleIndex=b.index,c=!1),a.lastVisibleIndex=b.index,a.visibleColspan++),b.hidden&&(a.hasHidden=!0)}),a.ft.$el.toggleClass("breakpoint",a.hasHidden)},draw:function(){b.arr.each(this.array,function(a){a.$el.css("display",a.hidden||!a.visible?"none":"table-cell")}),!this.showHeader&&b.is.jq(this.$header.parent())&&this.$header.detach()},$create:function(){var c=this;c.$header=b.is.jq(c.$header)?c.$header:a("<tr/>",{"class":"footable-header"}),c.$header.children("th,td").detach(),b.arr.each(c.array,function(a){c.$header.append(a.$el)}),c.showHeader&&!b.is.jq(c.$header.parent())&&c.ft.$el.children("thead").append(c.$header)},get:function(a){return a instanceof b.Column?a:b.is.string(a)?b.arr.first(this.array,function(b){return b.name==a}):b.is.number(a)?b.arr.first(this.array,function(b){return b.index==a}):b.is.fn(a)?b.arr.get(this.array,a):null},ensure:function(a){var c=this,d=[];return b.is.array(a)?(b.arr.each(a,function(a){d.push(c.get(a))}),d):d}}),b.components.register("columns",b.Columns,900)}(jQuery,FooTable),function(a){a.Defaults.prototype.columns=[],a.Defaults.prototype.showHeader=!0}(FooTable),function(a,b){b.Rows=b.Component.extend({construct:function(a){this._super(a,!0),this.o=a.o,this.array=[],this.all=[],this.showToggle=a.o.showToggle,this.toggleSelector=a.o.toggleSelector,this.toggleColumn=a.o.toggleColumn,this.emptyString=a.o.empty,this.expandFirst=a.o.expandFirst,this.expandAll=a.o.expandAll,this.$empty=null,this._fromHTML=b.is.emptyArray(a.o.rows)&&!b.is.promise(a.o.rows)},parse:function(){var c=this;return a.Deferred(function(a){var d=c.ft.$el.children("tbody").children("tr");b.is.array(c.o.rows)&&c.o.rows.length>0?c.parseFinalize(a,c.o.rows):b.is.promise(c.o.rows)?c.o.rows.then(function(b){c.parseFinalize(a,b)},function(b){a.reject(Error("Rows ajax request error: "+b.status+" ("+b.statusText+")"))}):b.is.jq(d)?(c.parseFinalize(a,d),d.detach()):c.parseFinalize(a,[])})},parseFinalize:function(c,d){var e=this,f=a.map(d,function(a){return new b.Row(e.ft,e.ft.columns.array,a)});c.resolve(f)},preinit:function(a){var c=this;return c.ft.raise("preinit.ft.rows",[a]).then(function(){return c.parse().then(function(d){c.all=d,c.array=c.all.slice(0),c.showToggle=b.is["boolean"](a.showToggle)?a.showToggle:c.showToggle,c.toggleSelector=b.is.string(a.toggleSelector)?a.toggleSelector:c.toggleSelector,c.toggleColumn=b.is.string(a.toggleColumn)?a.toggleColumn:c.toggleColumn,"first"!=c.toggleColumn&&"last"!=c.toggleColumn&&(c.toggleColumn="first"),c.emptyString=b.is.string(a.empty)?a.empty:c.emptyString,c.expandFirst=b.is["boolean"](a.expandFirst)?a.expandFirst:c.expandFirst,c.expandAll=b.is["boolean"](a.expandAll)?a.expandAll:c.expandAll})})},init:function(){var a=this;return a.ft.raise("init.ft.rows",[a.all]).then(function(){a.$create()})},destroy:function(){var a=this;this.ft.raise("destroy.ft.rows").then(function(){b.arr.each(a.array,function(b){b.predraw(!a._fromHTML)}),a.all=a.array=[]})},predraw:function(){b.arr.each(this.array,function(a){a.predraw()}),this.array=this.all.slice(0)},$create:function(){this.$empty=a("<tr/>",{"class":"footable-empty"}).append(a("<td/>").text(this.emptyString))},draw:function(){var a=this,c=a.ft.$el.children("tbody"),d=!0;a.array.length>0?(a.$empty.detach(),b.arr.each(a.array,function(b){(a.expandFirst&&d||a.expandAll)&&(b.expanded=!0,d=!1),b.draw(c)})):(a.$empty.children("td").attr("colspan",a.ft.columns.visibleColspan),c.append(a.$empty))},load:function(c,d){var e=this,f=a.map(c,function(a){return new b.Row(e.ft,e.ft.columns.array,a)});b.arr.each(this.array,function(a){a.predraw()}),this.all=(b.is["boolean"](d)?d:!1)?this.all.concat(f):f,this.array=this.all.slice(0),this.ft.draw()},expand:function(){b.arr.each(this.array,function(a){a.expand()})},collapse:function(){b.arr.each(this.array,function(a){a.collapse()})}}),b.components.register("rows",b.Rows,800)}(jQuery,FooTable),function(a){a.Defaults.prototype.rows=[],a.Defaults.prototype.empty="No results",a.Defaults.prototype.showToggle=!0,a.Defaults.prototype.toggleSelector="tr,td,.footable-toggle",a.Defaults.prototype.toggleColumn="first",a.Defaults.prototype.expandFirst=!1,a.Defaults.prototype.expandAll=!1}(FooTable),function(a){a.Table.prototype.loadRows=function(a,b){this.rows.load(a,b)}}(FooTable),function(a){a.Filter=a.Class.extend({construct:function(b,c,d,e,f,g,h){this.name=b,this.space=!a.is.string(e)||"OR"!=e&&"AND"!=e?"AND":e,this.connectors=a.is["boolean"](f)?f:!0,this.ignoreCase=a.is["boolean"](g)?g:!0,this.hidden=a.is["boolean"](h)?h:!1,this.query=c instanceof a.Query?c:new a.Query(c,this.space,this.connectors,this.ignoreCase),this.columns=d},match:function(b){return a.is.string(b)?(a.is.string(this.query)&&(this.query=new a.Query(this.query,this.space,this.connectors,this.ignoreCase)),this.query instanceof a.Query?this.query.match(b):!1):!1},matchRow:function(b){var c=this,d=a.arr.map(b.cells,function(b){return a.arr.contains(c.columns,b.column)?b.filterValue:null}).join(" ");return c.match(d)}})}(FooTable),function(a,b){b.Filtering=b.Component.extend({construct:function(a){this._super(a,a.o.filtering.enabled),this.filters=a.o.filtering.filters,this.delay=a.o.filtering.delay,this.min=a.o.filtering.min,this.space=a.o.filtering.space,this.connectors=a.o.filtering.connectors,this.ignoreCase=a.o.filtering.ignoreCase,this.exactMatch=a.o.filtering.exactMatch,this.placeholder=a.o.filtering.placeholder,this.dropdownTitle=a.o.filtering.dropdownTitle,this.position=a.o.filtering.position,this.focus=a.o.filtering.focus,this.container=a.o.filtering.container,this.$container=null,this.$row=null,this.$cell=null,this.$form=null,this.$dropdown=null,this.$input=null,this.$button=null,this._filterTimeout=null,this._exactRegExp=/^"(.*?)"$/},preinit:function(a){var c=this;return c.ft.raise("preinit.ft.filtering").then(function(){c.ft.$el.hasClass("footable-filtering")&&(c.enabled=!0),c.enabled=b.is["boolean"](a.filtering)?a.filtering:c.enabled,c.enabled&&(c.space=b.is.string(a.filterSpace)?a.filterSpace:c.space,c.min=b.is.number(a.filterMin)?a.filterMin:c.min,c.connectors=b.is["boolean"](a.filterConnectors)?a.filterConnectors:c.connectors,c.ignoreCase=b.is["boolean"](a.filterIgnoreCase)?a.filterIgnoreCase:c.ignoreCase,c.exactMatch=b.is["boolean"](a.filterExactMatch)?a.filterExactMatch:c.exactMatch,c.focus=b.is["boolean"](a.filterFocus)?a.filterFocus:c.focus,c.delay=b.is.number(a.filterDelay)?a.filterDelay:c.delay,c.placeholder=b.is.string(a.filterPlaceholder)?a.filterPlaceholder:c.placeholder,c.dropdownTitle=b.is.string(a.filterDropdownTitle)?a.filterDropdownTitle:c.dropdownTitle,c.container=b.is.string(a.filterContainer)?a.filterContainer:c.container,c.filters=b.is.array(a.filterFilters)?c.ensure(a.filterFilters):c.ensure(c.filters),c.ft.$el.hasClass("footable-filtering-left")&&(c.position="left"),c.ft.$el.hasClass("footable-filtering-center")&&(c.position="center"),c.ft.$el.hasClass("footable-filtering-right")&&(c.position="right"),c.position=b.is.string(a.filterPosition)?a.filterPosition:c.position)},function(){c.enabled=!1})},init:function(){var a=this;return a.ft.raise("init.ft.filtering").then(function(){a.$create()},function(){a.enabled=!1})},destroy:function(){var a=this;return a.ft.raise("destroy.ft.filtering").then(function(){a.ft.$el.removeClass("footable-filtering").find("thead > tr.footable-filtering").remove()})},$create:function(){var c,d=this,e=a("<div/>",{"class":"form-group footable-filtering-search"}).append(a("<label/>",{"class":"sr-only",text:"Search"})),f=a("<div/>",{"class":"input-group"}).appendTo(e),g=a("<div/>",{"class":"input-group-btn"}),h=a("<button/>",{type:"button","class":"btn btn-default dropdown-toggle"}).on("click",{self:d},d._onDropdownToggleClicked).append(a("<span/>",{"class":"caret"}));switch(d.position){case"left":c="footable-filtering-left";break;case"center":c="footable-filtering-center";break;default:c="footable-filtering-right"}d.ft.$el.addClass("footable-filtering").addClass(c),d.$container=null===d.container?a():a(d.container).first(),d.$container.length?d.$container.addClass("footable-filtering-external").addClass(c):(d.$row=a("<tr/>",{"class":"footable-filtering"}).prependTo(d.ft.$el.children("thead")),d.$cell=a("<th/>").attr("colspan",d.ft.columns.visibleColspan).appendTo(d.$row),d.$container=d.$cell),d.$form=a("<form/>",{"class":"form-inline"}).append(e).appendTo(d.$container),d.$input=a("<input/>",{type:"text","class":"form-control",placeholder:d.placeholder}),d.$button=a("<button/>",{type:"button","class":"btn btn-primary"}).on("click",{self:d},d._onSearchButtonClicked).append(a("<span/>",{"class":"fooicon fooicon-search"})),d.$dropdown=a("<ul/>",{"class":"dropdown-menu dropdown-menu-right"}),b.is.emptyString(d.dropdownTitle)||d.$dropdown.append(a("<li/>",{"class":"dropdown-header",text:d.dropdownTitle})),d.$dropdown.append(b.arr.map(d.ft.columns.array,function(b){return b.filterable?a("<li/>").append(a("<a/>",{"class":"checkbox"}).append(a("<label/>",{html:b.title}).prepend(a("<input/>",{type:"checkbox",checked:!0}).data("__FooTableColumn__",b)))):null})),d.delay>0&&(d.$input.on("keypress keyup paste",{self:d},d._onSearchInputChanged),d.$dropdown.on("click",'input[type="checkbox"]',{self:d},d._onSearchColumnClicked)),g.append(d.$button,h,d.$dropdown),f.append(d.$input,g)},predraw:function(){if(!b.is.emptyArray(this.filters)){var c=this;c.ft.rows.array=a.grep(c.ft.rows.array,function(a){return a.filtered(c.filters)})}},draw:function(){b.is.jq(this.$cell)&&this.$cell.attr("colspan",this.ft.columns.visibleColspan);var a=this.find("search");if(a instanceof b.Filter){var c=a.query.val();this.exactMatch&&this._exactRegExp.test(c)&&(c=c.replace(this._exactRegExp,"$1")),this.$input.val(c)}else this.$input.val(null);this.setButton(!b.arr.any(this.filters,function(a){return!a.hidden}))},addFilter:function(a,c,d,e,f,g,h){var i=this.createFilter(a,c,d,e,f,g,h);i instanceof b.Filter&&(this.removeFilter(i.name),this.filters.push(i))},removeFilter:function(a){b.arr.remove(this.filters,function(b){return b.name==a})},filter:function(a){var b=this;return b.filters=b.ensure(b.filters),b.ft.raise("before.ft.filtering",[b.filters]).then(function(){if(b.filters=b.ensure(b.filters),a)var c=b.$input.prop("selectionStart"),d=b.$input.prop("selectionEnd");return b.ft.draw().then(function(){a&&b.$input.focus().prop({selectionStart:c,selectionEnd:d}),b.ft.raise("after.ft.filtering",[b.filters])})})},clear:function(){return this.filters=b.arr.get(this.filters,function(a){return a.hidden}),this.filter(this.focus)},setButton:function(a){a?this.$button.children(".fooicon").removeClass("fooicon-remove").addClass("fooicon-search"):this.$button.children(".fooicon").removeClass("fooicon-search").addClass("fooicon-remove")},find:function(a){return b.arr.first(this.filters,function(b){return b.name==a})},columns:function(){return b.is.jq(this.$dropdown)?this.$dropdown.find("input:checked").map(function(){return a(this).data("__FooTableColumn__")}).get():this.ft.columns.get(function(a){return a.filterable})},ensure:function(a){var c=this,d=[],e=c.columns();return b.is.emptyArray(a)||b.arr.each(a,function(a){a=c._ensure(a,e),a instanceof b.Filter&&d.push(a)}),d},createFilter:function(a,c,d,e,f,g,h){return b.is.string(a)&&(a={name:a,query:c,columns:d,ignoreCase:e,connectors:f,space:g,hidden:h}),this._ensure(a,this.columns())},_ensure:function(a,c){return(b.is.hash(a)||a instanceof b.Filter)&&!b.is.emptyString(a.name)&&(!b.is.emptyString(a.query)||a.query instanceof b.Query)?(a.columns=b.is.emptyArray(a.columns)?c:this.ft.columns.ensure(a.columns),a.ignoreCase=b.is["boolean"](a.ignoreCase)?a.ignoreCase:this.ignoreCase,a.connectors=b.is["boolean"](a.connectors)?a.connectors:this.connectors,a.hidden=b.is["boolean"](a.hidden)?a.hidden:!1,a.space=!b.is.string(a.space)||"AND"!==a.space&&"OR"!==a.space?this.space:a.space,a.query=b.is.string(a.query)?new b.Query(a.query,a.space,a.connectors,a.ignoreCase):a.query,a instanceof b.Filter?a:new b.Filter(a.name,a.query,a.columns,a.space,a.connectors,a.ignoreCase,a.hidden)):null},_onSearchInputChanged:function(a){var c=a.data.self,d="keypress"==a.type&&!b.is.emptyString(String.fromCharCode(a.charCode)),e="keyup"==a.type&&(8==a.which||46==a.which),f="paste"==a.type;(d||e||f)&&(13==a.which&&a.preventDefault(),null!=c._filterTimeout&&clearTimeout(c._filterTimeout),c._filterTimeout=setTimeout(function(){c._filterTimeout=null;var a=c.$input.val();a.length>=c.min?(c.exactMatch&&!c._exactRegExp.test(a)&&(a='"'+a+'"'),c.addFilter("search",a),c.filter(c.focus)):b.is.emptyString(a)&&c.clear()},c.delay))},_onSearchButtonClicked:function(a){a.preventDefault();var b=a.data.self;null!=b._filterTimeout&&clearTimeout(b._filterTimeout);var c=b.$button.children(".fooicon");if(c.hasClass("fooicon-remove"))b.clear();else{var d=b.$input.val();d.length>=b.min&&(b.exactMatch&&!b._exactRegExp.test(d)&&(d='"'+d+'"'),b.addFilter("search",d),b.filter(b.focus))}},_onSearchColumnClicked:function(a){var b=a.data.self;null!=b._filterTimeout&&clearTimeout(b._filterTimeout),b._filterTimeout=setTimeout(function(){b._filterTimeout=null;var a=b.$button.children(".fooicon");a.hasClass("fooicon-remove")&&(a.removeClass("fooicon-remove").addClass("fooicon-search"),b.addFilter("search",b.$input.val()),b.filter())},b.delay)},_onDropdownToggleClicked:function(b){b.preventDefault(),b.stopPropagation();var c=b.data.self;c.$dropdown.parent().toggleClass("open"),c.$dropdown.parent().hasClass("open")?a(document).on("click.footable",{self:c},c._onDocumentClicked):a(document).off("click.footable",c._onDocumentClicked)},_onDocumentClicked:function(b){if(0==a(b.target).closest(".dropdown-menu").length){b.preventDefault();var c=b.data.self;c.$dropdown.parent().removeClass("open"),a(document).off("click.footable",c._onDocumentClicked)}}}),b.components.register("filtering",b.Filtering,500)}(jQuery,FooTable),function(a){a.Query=a.Class.extend({construct:function(b,c,d,e){this._original=null,this._value=null,this.space=!a.is.string(c)||"OR"!=c&&"AND"!=c?"AND":c,this.connectors=a.is["boolean"](d)?d:!0,this.ignoreCase=a.is["boolean"](e)?e:!0,this.left=null,this.right=null,this.parts=[],this.operator=null,this.val(b)},val:function(b){if(a.is.emptyString(b))return this._value;if(a.is.emptyString(this._original))this._original=b;else if(this._original==b)return;this._value=b,this._parse()},match:function(b){return a.is.emptyString(this.operator)||"OR"===this.operator?this._left(b,!1)||this._match(b,!1)||this._right(b,!1):"AND"===this.operator?this._left(b,!0)&&this._match(b,!0)&&this._right(b,!0):void 0},_match:function(b,c){var d=this,e=!1,f=a.is.emptyString(b);return a.is.emptyArray(d.parts)&&d.left instanceof a.Query?c:a.is.emptyArray(d.parts)?e:("OR"===d.space?a.arr.each(d.parts,function(c){if(c.empty&&f){if(e=!0,c.negate)return e=!1}else{var g=(c.exact?a.str.containsExact:a.str.contains)(b,c.query,d.ignoreCase);if(g&&!c.negate&&(e=!0),g&&c.negate)return e=!1}}):(e=!0,a.arr.each(d.parts,function(c){if(c.empty)return(!f&&!c.negate||f&&c.negate)&&(e=!1),e;var g=(c.exact?a.str.containsExact:a.str.contains)(b,c.query,d.ignoreCase);return(!g&&!c.negate||g&&c.negate)&&(e=!1),e})),e)},_left:function(b,c){return this.left instanceof a.Query?this.left.match(b):c},_right:function(b,c){return this.right instanceof a.Query?this.right.match(b):c},_parse:function(){if(!a.is.emptyString(this._value))if(/\sOR\s/.test(this._value)){this.operator="OR";var b=this._value.split(/(?:\sOR\s)(.*)?/);this.left=new a.Query(b[0],this.space,this.connectors,this.ignoreCase),this.right=new a.Query(b[1],this.space,this.connectors,this.ignoreCase)}else if(/\sAND\s/.test(this._value)){this.operator="AND";var c=this._value.split(/(?:\sAND\s)(.*)?/);this.left=new a.Query(c[0],this.space,this.connectors,this.ignoreCase),this.right=new a.Query(c[1],this.space,this.connectors,this.ignoreCase)}else{var d=this;this.parts=a.arr.map(this._value.match(/(?:[^\s"]+|"[^"]*")+/g),function(a){return d._part(a)})}},_part:function(b){var c={query:b,negate:!1,phrase:!1,exact:!1,empty:!1};return a.str.startsWith(c.query,"-")&&(c.query=a.str.from(c.query,"-"),c.negate=!0),/^"(.*?)"$/.test(c.query)?(c.query=c.query.replace(/^"(.*?)"$/,"$1"),c.phrase=!0,c.exact=!0):this.connectors&&/(?:\w)+?([-_\+\.])(?:\w)+?/.test(c.query)&&(c.query=c.query.replace(/(?:\w)+?([-_\+\.])(?:\w)+?/g,function(a,b){return a.replace(b," ")}),c.phrase=!0),c.empty=c.phrase&&a.is.emptyString(c.query),c}})}(FooTable),function(a){a.Cell.prototype.filterValue=null,a.Cell.prototype.__filtering_define__=function(a){this.filterValue=this.column.filterValue.call(this.column,a)},a.Cell.prototype.__filtering_val__=function(b){a.is.defined(b)&&(this.filterValue=this.column.filterValue.call(this.column,b))},a.Cell.extend("define",function(a){this._super(a),this.__filtering_define__(a)}),a.Cell.extend("val",function(a,b,c){var d=this._super(a,b,c);return this.__filtering_val__(a),d})}(FooTable),function(a,b){b.Column.prototype.filterable=!0,b.Column.prototype.filterValue=function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("filterValue");return b.is.defined(d)?""+d:a(c).text()}if(b.is.hash(c)&&b.is.hash(c.options)){if(b.is.string(c.options.filterValue))return c.options.filterValue;b.is.defined(c.value)&&(c=c.value)}return b.is.defined(c)&&null!=c?c+"":""},b.Column.prototype.__filtering_define__=function(a){this.filterable=b.is["boolean"](a.filterable)?a.filterable:this.filterable,this.filterValue=b.checkFnValue(this,a.filterValue,this.filterValue)},b.Column.extend("define",function(a){this._super(a),this.__filtering_define__(a)})}(jQuery,FooTable),function(a){a.Defaults.prototype.filtering={enabled:!1,filters:[],delay:1200,min:1,space:"AND",placeholder:"Search",dropdownTitle:null,position:"right",connectors:!0,ignoreCase:!0,exactMatch:!1,focus:!0,container:null}}(FooTable),function(a){a.Row.prototype.filtered=function(b){var c=!0,d=this;return a.arr.each(b,function(a){return 0==(c=a.matchRow(d))?!1:void 0}),c}}(FooTable),function(a,b){b.Sorter=b.Class.extend({construct:function(a,b){this.column=a,this.direction=b}})}(jQuery,FooTable),function(a,b){b.Sorting=b.Component.extend({construct:function(a){this._super(a,a.o.sorting.enabled),this.o=a.o.sorting,this.column=null,this.allowed=!0,this.initial=null},preinit:function(a){var c=this;this.ft.raise("preinit.ft.sorting",[a]).then(function(){c.ft.$el.hasClass("footable-sorting")&&(c.enabled=!0),c.enabled=b.is["boolean"](a.sorting)?a.sorting:c.enabled,c.enabled&&(c.column=b.arr.first(c.ft.columns.array,function(a){return a.sorted}))},function(){c.enabled=!1})},init:function(){var c=this;this.ft.raise("init.ft.sorting").then(function(){if(!c.initial){var d=!!c.column;c.initial={isset:d,rows:c.ft.rows.all.slice(0),column:d?c.column.name:null,direction:d?c.column.direction:null}}b.arr.each(c.ft.columns.array,function(b){b.sortable&&b.$el.addClass("footable-sortable").append(a("<span/>",{"class":"fooicon fooicon-sort"}))}),c.ft.$el.on("click.footable",".footable-sortable",{self:c},c._onSortClicked)},function(){c.enabled=!1})},destroy:function(){var a=this;this.ft.raise("destroy.ft.paging").then(function(){a.ft.$el.off("click.footable",".footable-sortable",a._onSortClicked),a.ft.$el.children("thead").children("tr.footable-header").children(".footable-sortable").removeClass("footable-sortable footable-asc footable-desc").find("span.fooicon").remove()})},predraw:function(){if(this.column){var a=this,b=a.column;a.ft.rows.array.sort(function(a,c){return"DESC"==b.direction?b.sorter(c.cells[b.index].sortValue,a.cells[b.index].sortValue):b.sorter(a.cells[b.index].sortValue,c.cells[b.index].sortValue)})}},draw:function(){if(this.column){var a=this,b=a.ft.$el.find("thead > tr > .footable-sortable"),c=a.column.$el;b.removeClass("footable-asc footable-desc").children(".fooicon").removeClass("fooicon-sort fooicon-sort-asc fooicon-sort-desc"),b.not(c).children(".fooicon").addClass("fooicon-sort"),c.addClass("DESC"==a.column.direction?"footable-desc":"footable-asc").children(".fooicon").addClass("DESC"==a.column.direction?"fooicon-sort-desc":"fooicon-sort-asc")}},sort:function(a,b){return this._sort(a,b)},toggleAllowed:function(a){a=b.is["boolean"](a)?a:!this.allowed,this.allowed=a,this.ft.$el.toggleClass("footable-sorting-disabled",!this.allowed)},hasChanged:function(){return!(!this.initial||!this.column||this.column.name===this.initial.column&&(this.column.direction===this.initial.direction||null===this.initial.direction&&"ASC"===this.column.direction))},reset:function(){this.initial&&(this.initial.isset?this.sort(this.initial.column,this.initial.direction):(this.column&&(this.column.$el.removeClass("footable-asc footable-desc"),this.column=null),this.ft.rows.all=this.initial.rows,this.ft.draw()))},_sort:function(c,d){if(!this.allowed)return a.Deferred().reject("sorting disabled");var e=this,f=new b.Sorter(e.ft.columns.get(c),b.Sorting.dir(d));return e.ft.raise("before.ft.sorting",[f]).then(function(){return b.arr.each(e.ft.columns.array,function(a){a!=e.column&&(a.direction=null)}),e.column=e.ft.columns.get(f.column),e.column&&(e.column.direction=b.Sorting.dir(f.direction)),e.ft.draw().then(function(){e.ft.raise("after.ft.sorting",[f])})})},_onSortClicked:function(b){var c=b.data.self,d=a(this).closest("th,td"),e=d.is(".footable-asc, .footable-desc")?d.hasClass("footable-desc")?"ASC":"DESC":"ASC";c._sort(d.index(),e)}}),b.Sorting.dir=function(a){return!b.is.string(a)||"ASC"!=a&&"DESC"!=a?"ASC":a},b.components.register("sorting",b.Sorting,600)}(jQuery,FooTable),function(a){a.Cell.prototype.sortValue=null,a.Cell.prototype.__sorting_define__=function(a){this.sortValue=this.column.sortValue.call(this.column,a)},a.Cell.prototype.__sorting_val__=function(b){a.is.defined(b)&&(this.sortValue=this.column.sortValue.call(this.column,b))},a.Cell.extend("define",function(a){this._super(a),this.__sorting_define__(a)}),a.Cell.extend("val",function(a,b,c){var d=this._super(a,b,c);return this.__sorting_val__(a),d})}(FooTable),function(a,b){b.Column.prototype.direction=null,b.Column.prototype.sortable=!0,b.Column.prototype.sorted=!1,b.Column.prototype.sorter=function(a,b){return"string"==typeof a&&(a=a.toLowerCase()),"string"==typeof b&&(b=b.toLowerCase()),a===b?0:b>a?-1:1},b.Column.prototype.sortValue=function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("sortValue");return b.is.defined(d)?d:this.parser(c)}if(b.is.hash(c)&&b.is.hash(c.options)){if(b.is.string(c.options.sortValue))return c.options.sortValue;b.is.defined(c.value)&&(c=c.value)}return b.is.defined(c)&&null!=c?c:null},b.Column.prototype.__sorting_define__=function(a){this.sorter=b.checkFnValue(this,a.sorter,this.sorter),this.direction=b.is.type(a.direction,"string")?b.Sorting.dir(a.direction):null,this.sortable=b.is["boolean"](a.sortable)?a.sortable:!0,this.sorted=b.is["boolean"](a.sorted)?a.sorted:!1,this.sortValue=b.checkFnValue(this,a.sortValue,this.sortValue)},b.Column.extend("define",function(a){this._super(a),this.__sorting_define__(a)})}(jQuery,FooTable),function(a){a.Defaults.prototype.sorting={enabled:!1}}(FooTable),function(a,b){b.HTMLColumn.extend("__sorting_define__",function(c){this._super(c),this.sortUse=b.is.string(c.sortUse)&&-1!==a.inArray(c.sortUse,["html","text"])?c.sortUse:"html"}),b.HTMLColumn.prototype.sortValue=function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("sortValue");return b.is.defined(d)?d:this.parser(c)}if(b.is.hash(c)&&b.is.hash(c.options)){if(b.is.string(c.options.sortValue))return c.options.sortValue;b.is.defined(c.value)&&(c=c.value)}return b.is.defined(c)&&null!=c?c:null}}(jQuery,FooTable),function(a,b){b.NumberColumn.prototype.sortValue=function(c){if(b.is.element(c)||b.is.jq(c)){var d=a(c).data("sortValue");return b.is.number(d)?d:this.parser(c)}if(b.is.hash(c)&&b.is.hash(c.options)){if(b.is.string(c.options.sortValue))return this.parser(c);if(b.is.number(c.options.sortValue))return c.options.sortValue;if(b.is.number(c.value))return c.value}return b.is.string(c)?this.parser(c):b.is.number(c)?c:null}}(jQuery,FooTable),function(a){a.Table.prototype.sort=function(b,c){return this.use(a.Sorting).sort(b,c)}}(FooTable),function(a,b){b.Pager=b.Class.extend({construct:function(a,b,c,d,e){this.total=a,this.current=b,this.size=c,this.page=d,this.forward=e}})}(jQuery,FooTable),function(a,b){b.Paging=b.Component.extend({construct:function(a){this._super(a,a.o.paging.enabled),this.strings=a.o.paging.strings,this.current=a.o.paging.current,this.size=a.o.paging.size,this.limit=a.o.paging.limit,this.position=a.o.paging.position,this.countFormat=a.o.paging.countFormat,this.container=a.o.paging.container,this.total=-1,this.totalRows=0,this.previous=-1,this.formattedCount=null,this.$container=null,this.$wrapper=null,this.$row=null,this.$cell=null,this.$pagination=null,this.$count=null,this.detached=!0,this._createdLinks=0},preinit:function(a){var c=this;this.ft.raise("preinit.ft.paging",[a]).then(function(){c.ft.$el.hasClass("footable-paging")&&(c.enabled=!0),c.enabled=b.is["boolean"](a.paging)?a.paging:c.enabled,c.enabled&&(c.size=b.is.number(a.pagingSize)?a.pagingSize:c.size,c.current=b.is.number(a.pagingCurrent)?a.pagingCurrent:c.current,c.limit=b.is.number(a.pagingLimit)?a.pagingLimit:c.limit,c.ft.$el.hasClass("footable-paging-left")&&(c.position="left"),c.ft.$el.hasClass("footable-paging-center")&&(c.position="center"),c.ft.$el.hasClass("footable-paging-right")&&(c.position="right"),c.position=b.is.string(a.pagingPosition)?a.pagingPosition:c.position,c.countFormat=b.is.string(a.pagingCountFormat)?a.pagingCountFormat:c.countFormat,c.container=b.is.string(a.pagingContainer)?a.pagingContainer:c.container,c.total=Math.ceil(c.ft.rows.all.length/c.size))},function(){c.enabled=!1})},init:function(){var a=this;this.ft.raise("init.ft.paging").then(function(){a.$create()},function(){a.enabled=!1})},destroy:function(){var a=this;this.ft.raise("destroy.ft.paging").then(function(){a.ft.$el.removeClass("footable-paging").find("tfoot > tr.footable-paging").remove(),a.detached=!0,a._createdLinks=0})},predraw:function(){this.total=Math.ceil(this.ft.rows.array.length/this.size),this.current=this.current>this.total?this.total:this.current<1?1:this.current,this.totalRows=this.ft.rows.array.length,this.totalRows>this.size&&(this.ft.rows.array=this.ft.rows.array.splice((this.current-1)*this.size,this.size)),this.formattedCount=this.format(this.countFormat)},draw:function(){if(this.total<=1)this.detached||(this.$row?this.$row.detach():this.$wrapper.detach(),this.detached=!0);else{if(this.detached){if(this.$row){var c=this.ft.$el.children("tfoot");0==c.length&&(c=a("<tfoot/>"),this.ft.$el.append(c)),this.$row.appendTo(c)}else this.$wrapper.appendTo(this.$container);this.detached=!1}b.is.jq(this.$cell)&&this.$cell.attr("colspan",this.ft.columns.visibleColspan),this._createLinks(),this._setVisible(this.current,this.current>this.previous),this._setNavigation(!0),this.$count.text(this.formattedCount)}},$create:function(){this._createdLinks=0;var c="footable-paging-center";switch(this.position){case"left":c="footable-paging-left";break;case"right":c="footable-paging-right"}if(this.ft.$el.addClass("footable-paging").addClass(c),this.$container=null===this.container?null:a(this.container).first(),b.is.jq(this.$container))this.$container.addClass("footable-paging-external").addClass(c);else{var d=this.ft.$el.children("tfoot");0==d.length&&(d=a("<tfoot/>"),this.ft.$el.append(d)),this.$row=a("<tr/>",{"class":"footable-paging"}).prependTo(d),this.$container=this.$cell=a("<td/>").attr("colspan",this.ft.columns.visibleColspan).appendTo(this.$row)}this.$wrapper=a("<div/>",{"class":"footable-pagination-wrapper"}).appendTo(this.$container),this.$pagination=a("<ul/>",{"class":"pagination"}).on("click.footable","a.footable-page-link",{self:this},this._onPageClicked),this.$count=a("<span/>",{"class":"label label-default"}),this.$wrapper.append(this.$pagination,a("<div/>",{"class":"divider"}),this.$count),this.detached=!1},format:function(a){var b=this.size*(this.current-1)+1,c=this.size*this.current;return 0==this.ft.rows.array.length?(b=0,c=0):c=c>this.totalRows?this.totalRows:c,a.replace(/\{CP}/g,this.current).replace(/\{TP}/g,this.total).replace(/\{PF}/g,b).replace(/\{PL}/g,c).replace(/\{TR}/g,this.totalRows)},first:function(){return this._set(1)},prev:function(){return this._set(this.current-1>0?this.current-1:1)},next:function(){return this._set(this.current+1<this.total?this.current+1:this.total)},last:function(){return this._set(this.total)},"goto":function(a){return this._set(a>this.total?this.total:1>a?1:a)},prevPages:function(){var a=this.$pagination.children("li.footable-page.visible:first").data("page")-1;this._setVisible(a,!0),this._setNavigation(!1)},nextPages:function(){var a=this.$pagination.children("li.footable-page.visible:last").data("page")+1;this._setVisible(a,!1),this._setNavigation(!1)},pageSize:function(a){return a=parseInt(a),isNaN(a)?this.size:(this.size=a,this.total=Math.ceil(this.ft.rows.all.length/this.size),b.is.jq(this.$wrapper)&&(this.$container.is("td")?this.$row.remove():this.$wrapper.remove()),this.$create(),void this.ft.draw())},_set:function(c){var d=this,e=new b.Pager(d.total,d.current,d.size,c,c>d.current);return d.ft.raise("before.ft.paging",[e]).then(function(){return e.page=e.page>e.total?e.total:e.page,e.page=e.page<1?1:e.page,d.current==c?a.when():(d.previous=d.current,d.current=e.page,d.ft.draw().then(function(){d.ft.raise("after.ft.paging",[e])}))})},_createLinks:function(){if(this._createdLinks!==this.total){var b=this,c=b.total>1,d=function(b,c,d){return a("<li/>",{"class":d}).attr("data-page",b).append(a("<a/>",{"class":"footable-page-link",href:"#"}).data("page",b).html(c))};b.$pagination.empty(),c&&(b.$pagination.append(d("first",b.strings.first,"footable-page-nav")),b.$pagination.append(d("prev",b.strings.prev,"footable-page-nav")),b.limit>0&&b.limit<b.total&&b.$pagination.append(d("prev-limit",b.strings.prevPages,"footable-page-nav")));for(var e,f=0;f<b.total;f++)e=d(f+1,f+1,"footable-page"),b.$pagination.append(e);c&&(b.limit>0&&b.limit<b.total&&b.$pagination.append(d("next-limit",b.strings.nextPages,"footable-page-nav")),b.$pagination.append(d("next",b.strings.next,"footable-page-nav")),b.$pagination.append(d("last",b.strings.last,"footable-page-nav"))),b._createdLinks=b.total}},_setNavigation:function(a){1==this.current?this.$pagination.children('li[data-page="first"],li[data-page="prev"]').addClass("disabled"):this.$pagination.children('li[data-page="first"],li[data-page="prev"]').removeClass("disabled"),this.current==this.total?this.$pagination.children('li[data-page="next"],li[data-page="last"]').addClass("disabled"):this.$pagination.children('li[data-page="next"],li[data-page="last"]').removeClass("disabled"),1==(this.$pagination.children("li.footable-page.visible:first").data("page")||1)?this.$pagination.children('li[data-page="prev-limit"]').addClass("disabled"):this.$pagination.children('li[data-page="prev-limit"]').removeClass("disabled"),(this.$pagination.children("li.footable-page.visible:last").data("page")||this.limit)==this.total?this.$pagination.children('li[data-page="next-limit"]').addClass("disabled"):this.$pagination.children('li[data-page="next-limit"]').removeClass("disabled"),this.limit>0&&this.total<this.limit?this.$pagination.children('li[data-page="prev-limit"],li[data-page="next-limit"]').css("display","none"):this.$pagination.children('li[data-page="prev-limit"],li[data-page="next-limit"]').css("display",""),
-a&&this.$pagination.children("li.footable-page").removeClass("active").filter('li[data-page="'+this.current+'"]').addClass("active")},_setVisible:function(a,b){if(this.limit>0&&this.total>this.limit){if(!this.$pagination.children('li.footable-page[data-page="'+a+'"]').hasClass("visible")){var c=0,d=0;1==b?(d=a>this.total?this.total:a,c=d-this.limit):(c=1>a?0:a-1,d=c+this.limit),0>c&&(c=0,d=this.limit>this.total?this.total:this.limit),d>this.total&&(d=this.total,c=this.total-this.limit<0?0:this.total-this.limit),this.$pagination.children("li.footable-page").removeClass("visible").slice(c,d).addClass("visible")}}else this.$pagination.children("li.footable-page").removeClass("visible").slice(0,this.total).addClass("visible")},_onPageClicked:function(b){if(b.preventDefault(),!a(b.target).closest("li").is(".active,.disabled")){var c=b.data.self,d=a(this).data("page");switch(d){case"first":return void c.first();case"prev":return void c.prev();case"next":return void c.next();case"last":return void c.last();case"prev-limit":return void c.prevPages();case"next-limit":return void c.nextPages();default:return void c._set(d)}}}}),b.components.register("paging",b.Paging,400)}(jQuery,FooTable),function(a){a.Defaults.prototype.paging={enabled:!1,countFormat:"{CP} of {TP}",current:1,limit:5,position:"center",size:10,container:null,strings:{first:"«",prev:"‹",next:"›",last:"»",prevPages:"...",nextPages:"..."}}}(FooTable),function(a){a.Table.prototype.gotoPage=function(b){return this.use(a.Paging)["goto"](b)},a.Table.prototype.nextPage=function(){return this.use(a.Paging).next()},a.Table.prototype.prevPage=function(){return this.use(a.Paging).prev()},a.Table.prototype.firstPage=function(){return this.use(a.Paging).first()},a.Table.prototype.lastPage=function(){return this.use(a.Paging).last()},a.Table.prototype.nextPages=function(){return this.use(a.Paging).nextPages()},a.Table.prototype.prevPages=function(){return this.use(a.Paging).prevPages()},a.Table.prototype.pageSize=function(b){return this.use(a.Paging).pageSize(b)}}(FooTable),function(a,b){b.Editing=b.Component.extend({construct:function(c){this._super(c,c.o.editing.enabled),this.pageToNew=c.o.editing.pageToNew,this.alwaysShow=c.o.editing.alwaysShow,this.column=a.extend(!0,{},c.o.editing.column,{visible:this.alwaysShow}),this.position=c.o.editing.position,this.showText=c.o.editing.showText,this.hideText=c.o.editing.hideText,this.addText=c.o.editing.addText,this.editText=c.o.editing.editText,this.deleteText=c.o.editing.deleteText,this.viewText=c.o.editing.viewText,this.allowAdd=c.o.editing.allowAdd,this.allowEdit=c.o.editing.allowEdit,this.allowDelete=c.o.editing.allowDelete,this.allowView=c.o.editing.allowView,this._$buttons=null,this.callbacks={addRow:b.checkFnValue(this,c.o.editing.addRow),editRow:b.checkFnValue(this,c.o.editing.editRow),deleteRow:b.checkFnValue(this,c.o.editing.deleteRow),viewRow:b.checkFnValue(this,c.o.editing.viewRow)}},preinit:function(c){var d=this;this.ft.raise("preinit.ft.editing",[c]).then(function(){if(d.ft.$el.hasClass("footable-editing")&&(d.enabled=!0),d.enabled=b.is["boolean"](c.editing)?c.editing:d.enabled,d.enabled){if(d.pageToNew=b.is["boolean"](c.editingPageToNew)?c.editingPageToNew:d.pageToNew,d.alwaysShow=b.is["boolean"](c.editingAlwaysShow)?c.editingAlwaysShow:d.alwaysShow,d.position=b.is.string(c.editingPosition)?c.editingPosition:d.position,d.showText=b.is.string(c.editingShowText)?c.editingShowText:d.showText,d.hideText=b.is.string(c.editingHideText)?c.editingHideText:d.hideText,d.addText=b.is.string(c.editingAddText)?c.editingAddText:d.addText,d.editText=b.is.string(c.editingEditText)?c.editingEditText:d.editText,d.deleteText=b.is.string(c.editingDeleteText)?c.editingDeleteText:d.deleteText,d.viewText=b.is.string(c.editingViewText)?c.editingViewText:d.viewText,d.allowAdd=b.is["boolean"](c.editingAllowAdd)?c.editingAllowAdd:d.allowAdd,d.allowEdit=b.is["boolean"](c.editingAllowEdit)?c.editingAllowEdit:d.allowEdit,d.allowDelete=b.is["boolean"](c.editingAllowDelete)?c.editingAllowDelete:d.allowDelete,d.allowView=b.is["boolean"](c.editingAllowView)?c.editingAllowView:d.allowView,d.column=new b.EditingColumn(d.ft,d,a.extend(!0,{},d.column,c.editingColumn,{visible:d.alwaysShow})),d.ft.$el.hasClass("footable-editing-left")&&(d.position="left"),d.ft.$el.hasClass("footable-editing-right")&&(d.position="right"),"right"===d.position)d.column.index=d.ft.columns.array.length;else{d.column.index=0;for(var e=0,f=d.ft.columns.array.length;f>e;e++)d.ft.columns.array[e].index+=1}d.ft.columns.array.push(d.column),d.ft.columns.array.sort(function(a,b){return a.index-b.index}),d.callbacks.addRow=b.checkFnValue(d,c.editingAddRow,d.callbacks.addRow),d.callbacks.editRow=b.checkFnValue(d,c.editingEditRow,d.callbacks.editRow),d.callbacks.deleteRow=b.checkFnValue(d,c.editingDeleteRow,d.callbacks.deleteRow),d.callbacks.viewRow=b.checkFnValue(d,c.editingViewRow,d.callbacks.viewRow)}},function(){d.enabled=!1})},init:function(){var a=this;this.ft.raise("init.ft.editing").then(function(){a.$create()},function(){a.enabled=!1})},destroy:function(){var a=this;this.ft.raise("destroy.ft.editing").then(function(){a.ft.$el.removeClass("footable-editing footable-editing-always-show footable-editing-no-add footable-editing-no-edit footable-editing-no-delete footable-editing-no-view").off("click.ft.editing").find("tfoot > tr.footable-editing").remove()})},$create:function(){var b=this,c="right"===b.position?"footable-editing-right":"footable-editing-left";b.ft.$el.addClass("footable-editing").addClass(c).on("click.ft.editing",".footable-show",{self:b},b._onShowClick).on("click.ft.editing",".footable-hide",{self:b},b._onHideClick).on("click.ft.editing",".footable-edit",{self:b},b._onEditClick).on("click.ft.editing",".footable-delete",{self:b},b._onDeleteClick).on("click.ft.editing",".footable-view",{self:b},b._onViewClick).on("click.ft.editing",".footable-add",{self:b},b._onAddClick),b.$cell=a("<td/>").attr("colspan",b.ft.columns.visibleColspan).append(b.$buttonShow()),b.allowAdd&&b.$cell.append(b.$buttonAdd()),b.$cell.append(b.$buttonHide()),b.alwaysShow&&b.ft.$el.addClass("footable-editing-always-show"),b.allowAdd||b.ft.$el.addClass("footable-editing-no-add"),b.allowEdit||b.ft.$el.addClass("footable-editing-no-edit"),b.allowDelete||b.ft.$el.addClass("footable-editing-no-delete"),b.allowView||b.ft.$el.addClass("footable-editing-no-view");var d=b.ft.$el.children("tfoot");0==d.length&&(d=a("<tfoot/>"),b.ft.$el.append(d)),b.$row=a("<tr/>",{"class":"footable-editing"}).append(b.$cell).appendTo(d)},$buttonShow:function(){return'<button type="button" class="btn btn-primary footable-show">'+this.showText+"</button>"},$buttonHide:function(){return'<button type="button" class="btn btn-default footable-hide">'+this.hideText+"</button>"},$buttonAdd:function(){return'<button type="button" class="btn btn-primary footable-add">'+this.addText+"</button> "},$buttonEdit:function(){return'<button type="button" class="btn btn-default footable-edit">'+this.editText+"</button> "},$buttonDelete:function(){return'<button type="button" class="btn btn-default footable-delete">'+this.deleteText+"</button>"},$buttonView:function(){return'<button type="button" class="btn btn-default footable-view">'+this.viewText+"</button> "},$rowButtons:function(){return b.is.jq(this._$buttons)?this._$buttons.clone():(this._$buttons=a('<div class="btn-group btn-group-xs" role="group"></div>'),this.allowView&&this._$buttons.append(this.$buttonView()),this.allowEdit&&this._$buttons.append(this.$buttonEdit()),this.allowDelete&&this._$buttons.append(this.$buttonDelete()),this._$buttons)},draw:function(){this.$cell.attr("colspan",this.ft.columns.visibleColspan)},_onEditClick:function(c){c.preventDefault();var d=c.data.self,e=a(this).closest("tr").data("__FooTableRow__");e instanceof b.Row&&d.ft.raise("edit.ft.editing",[e]).then(function(){d.callbacks.editRow.call(d.ft,e)})},_onDeleteClick:function(c){c.preventDefault();var d=c.data.self,e=a(this).closest("tr").data("__FooTableRow__");e instanceof b.Row&&d.ft.raise("delete.ft.editing",[e]).then(function(){d.callbacks.deleteRow.call(d.ft,e)})},_onViewClick:function(c){c.preventDefault();var d=c.data.self,e=a(this).closest("tr").data("__FooTableRow__");e instanceof b.Row&&d.ft.raise("view.ft.editing",[e]).then(function(){d.callbacks.viewRow.call(d.ft,e)})},_onAddClick:function(a){a.preventDefault();var b=a.data.self;b.ft.raise("add.ft.editing").then(function(){b.callbacks.addRow.call(b.ft)})},_onShowClick:function(a){a.preventDefault();var b=a.data.self;b.ft.raise("show.ft.editing").then(function(){b.ft.$el.addClass("footable-editing-show"),b.column.visible=!0,b.ft.draw()})},_onHideClick:function(a){a.preventDefault();var b=a.data.self;b.ft.raise("hide.ft.editing").then(function(){b.ft.$el.removeClass("footable-editing-show"),b.column.visible=!1,b.ft.draw()})}}),b.components.register("editing",b.Editing,850)}(jQuery,FooTable),function(a,b){b.EditingColumn=b.Column.extend({construct:function(a,b,c){this._super(a,c,"editing"),this.editing=b,this.internal=!0},$create:function(){(this.$el=!this.virtual&&b.is.jq(this.$el)?this.$el:a("<th/>",{"class":"footable-editing"})).html(this.title)},parser:function(c){if(b.is.string(c)&&(c=a(a.trim(c))),b.is.element(c)&&(c=a(c)),b.is.jq(c)){var d=c.prop("tagName").toLowerCase();return"td"==d||"th"==d?c.data("value")||c.contents():c}return null},createCell:function(c){var d=this.editing.$rowButtons(),e=a("<td/>").append(d);return b.is.jq(c.$el)&&(0===this.index?e.prependTo(c.$el):e.insertAfter(c.$el.children().eq(this.index-1))),new b.Cell(this.ft,c,this,e||e.html())}}),b.columns.register("editing",b.EditingColumn)}(jQuery,FooTable),function(a,b){b.Defaults.prototype.editing={enabled:!1,pageToNew:!0,position:"right",alwaysShow:!1,addRow:function(){},editRow:function(a){},deleteRow:function(a){},viewRow:function(a){},showText:'<span class="fooicon fooicon-pencil" aria-hidden="true"></span> Edit rows',hideText:"Cancel",addText:"New row",editText:'<span class="fooicon fooicon-pencil" aria-hidden="true"></span>',deleteText:'<span class="fooicon fooicon-trash" aria-hidden="true"></span>',viewText:'<span class="fooicon fooicon-stats" aria-hidden="true"></span>',allowAdd:!0,allowEdit:!0,allowDelete:!0,allowView:!1,column:{classes:"footable-editing",name:"editing",title:"",filterable:!1,sortable:!1}}}(jQuery,FooTable),function(a,b){b.is.defined(b.Paging)&&(b.Paging.prototype.unpaged=[],b.Paging.extend("predraw",function(){this.unpaged=this.ft.rows.array.slice(0),this._super()}))}(jQuery,FooTable),function(a,b){b.Row.prototype.add=function(c){c=b.is["boolean"](c)?c:!0;var d=this;return a.Deferred(function(a){var b=d.ft.rows.all.push(d)-1;return c?d.ft.draw().then(function(){a.resolve(b)}):void a.resolve(b)})},b.Row.prototype["delete"]=function(c){c=b.is["boolean"](c)?c:!0;var d=this;return a.Deferred(function(a){var e=d.ft.rows.all.indexOf(d);return b.is.number(e)&&e>=0&&e<d.ft.rows.all.length&&(d.ft.rows.all.splice(e,1),c)?d.ft.draw().then(function(){a.resolve(d)}):void a.resolve(d)})},b.is.defined(b.Paging)&&b.Row.extend("add",function(a){a=b.is["boolean"](a)?a:!0;var c,d=this,e=this._super(a),f=d.ft.use(b.Editing);return f&&f.pageToNew&&(c=d.ft.use(b.Paging))&&a?e.then(function(){var a=c.unpaged.indexOf(d),b=Math.ceil((a+1)/c.size);return c.current!==b?c["goto"](b):void 0}):e}),b.is.defined(b.Sorting)&&b.Row.extend("val",function(a,c){c=b.is["boolean"](c)?c:!0;var d=this._super(a);if(!b.is.hash(a))return d;var e=this;return c&&e.ft.draw().then(function(){var a,c=e.ft.use(b.Editing);if(b.is.defined(b.Paging)&&c&&c.pageToNew&&(a=e.ft.use(b.Paging))){var d=a.unpaged.indexOf(e),f=Math.ceil((d+1)/a.size);if(a.current!==f)return a["goto"](f)}}),d})}(jQuery,FooTable),function(a){a.Rows.prototype.add=function(b,c){var d=b;a.is.hash(b)&&(d=new FooTable.Row(this.ft,this.ft.columns.array,b)),d instanceof FooTable.Row&&d.add(c)},a.Rows.prototype.update=function(b,c,d){var e=this.ft.rows.all.length,f=b;a.is.number(b)&&b>=0&&e>b&&(f=this.ft.rows.all[b]),f instanceof FooTable.Row&&a.is.hash(c)&&f.val(c,d)},a.Rows.prototype["delete"]=function(b,c){var d=this.ft.rows.all.length,e=b;a.is.number(b)&&b>=0&&d>b&&(e=this.ft.rows.all[b]),e instanceof FooTable.Row&&e["delete"](c)}}(FooTable),function(a,b){var c=0,d=function(a){var b,c,d=2166136261;for(b=0,c=a.length;c>b;b++)d^=a.charCodeAt(b),d+=(d<<1)+(d<<4)+(d<<7)+(d<<8)+(d<<24);return d>>>0}(location.origin+location.pathname);b.State=b.Component.extend({construct:function(a){this._super(a,a.o.state.enabled),this._key="1",this.key=this._key+(b.is.string(a.o.state.key)?a.o.state.key:this._uid()),this.filtering=b.is["boolean"](a.o.state.filtering)?a.o.state.filtering:!0,this.paging=b.is["boolean"](a.o.state.paging)?a.o.state.paging:!0,this.sorting=b.is["boolean"](a.o.state.sorting)?a.o.state.sorting:!0},preinit:function(a){var c=this;this.ft.raise("preinit.ft.state",[a]).then(function(){c.enabled=b.is["boolean"](a.state)?a.state:c.enabled,c.enabled&&(c.key=c._key+(b.is.string(a.stateKey)?a.stateKey:c.key),c.filtering=b.is["boolean"](a.stateFiltering)?a.stateFiltering:c.filtering,c.paging=b.is["boolean"](a.statePaging)?a.statePaging:c.paging,c.sorting=b.is["boolean"](a.stateSorting)?a.stateSorting:c.sorting)},function(){c.enabled=!1})},get:function(a){return JSON.parse(localStorage.getItem(this.key+":"+a))},set:function(a,b){localStorage.setItem(this.key+":"+a,JSON.stringify(b))},remove:function(a){localStorage.removeItem(this.key+":"+a)},read:function(){this.ft.execute(!1,!0,"readState")},write:function(){this.ft.execute(!1,!0,"writeState")},clear:function(){this.ft.execute(!1,!0,"clearState")},_uid:function(){var a=this.ft.$el.attr("id");return d+"_"+(b.is.string(a)?a:++c)}}),b.components.register("state",b.State,700)}(jQuery,FooTable),function(a){a.Component.prototype.readState=function(){},a.Component.prototype.writeState=function(){},a.Component.prototype.clearState=function(){}}(FooTable),function(a){a.Defaults.prototype.state={enabled:!1,filtering:!0,paging:!0,sorting:!0,key:null}}(FooTable),function(a){a.Filtering&&(a.Filtering.prototype.readState=function(){if(this.ft.state.filtering){var b=this.ft.state.get("filtering");a.is.hash(b)&&!a.is.emptyArray(b.filters)&&(this.filters=this.ensure(b.filters))}},a.Filtering.prototype.writeState=function(){if(this.ft.state.filtering){var b=a.arr.map(this.filters,function(b){return{name:b.name,query:b.query instanceof a.Query?b.query.val():b.query,columns:a.arr.map(b.columns,function(a){return a.name}),hidden:b.hidden,space:b.space,connectors:b.connectors,ignoreCase:b.ignoreCase}});this.ft.state.set("filtering",{filters:b})}},a.Filtering.prototype.clearState=function(){this.ft.state.filtering&&this.ft.state.remove("filtering")})}(FooTable),function(a){a.Paging&&(a.Paging.prototype.readState=function(){if(this.ft.state.paging){var b=this.ft.state.get("paging");a.is.hash(b)&&(this.current=b.current,this.size=b.size)}},a.Paging.prototype.writeState=function(){this.ft.state.paging&&this.ft.state.set("paging",{current:this.current,size:this.size})},a.Paging.prototype.clearState=function(){this.ft.state.paging&&this.ft.state.remove("paging")})}(FooTable),function(a){a.Sorting&&(a.Sorting.prototype.readState=function(){if(this.ft.state.sorting){var b=this.ft.state.get("sorting");if(a.is.hash(b)){var c=this.ft.columns.get(b.column);c instanceof a.Column&&(this.column=c,this.column.direction=b.direction)}}},a.Sorting.prototype.writeState=function(){this.ft.state.sorting&&this.column instanceof a.Column&&this.ft.state.set("sorting",{column:this.column.name,direction:this.column.direction})},a.Sorting.prototype.clearState=function(){this.ft.state.sorting&&this.ft.state.remove("sorting")})}(FooTable),function(a){a.Table.extend("_construct",function(a){return this.state=this.use(FooTable.State),this._super(a)}),a.Table.extend("_preinit",function(){var a=this;return a._super().then(function(){a.state.enabled&&a.state.read()})}),a.Table.extend("draw",function(){var a=this;return a._super().then(function(){a.state.enabled&&a.state.write()})})}(FooTable),function(a,b){b.Export=b.Component.extend({construct:function(a){this._super(a,!0),this.snapshot=[]},predraw:function(){this.snapshot=this.ft.rows.array.slice(0)},columns:function(){var a=[];return b.arr.each(this.ft.columns.array,function(b){b.internal||a.push({type:b.type,name:b.name,title:b.title,visible:b.visible,hidden:b.hidden,classes:b.classes,style:b.style})}),a},rows:function(a){a=b.is["boolean"](a)?a:!1;var c=a?this.ft.rows.all:this.snapshot,d=[];return b.arr.each(c,function(a){d.push(a.val())}),d},json:function(a){return JSON.parse(JSON.stringify({columns:this.columns(),rows:this.rows(a)}))},csv:function(a){var c,d,e="",f=this.columns();b.arr.each(f,function(a,b){d='"'+a.title.replace(/"/g,'""')+'"',e+=0===b?d:","+d}),e+="\n";var g=a?this.ft.rows.all:this.snapshot;return b.arr.each(g,function(a){b.arr.each(a.cells,function(a,b){a.column.internal||(c=a.column.stringify.call(a.column,a.value,a.ft.o,a.row.value),d='"'+c.replace(/"/g,'""')+'"',e+=0===b?d:","+d)}),e+="\n"}),e}}),b.components.register("export",b.Export,490)}(jQuery,FooTable),function(a){a.Column.prototype.__export_define__=function(b){this.stringify=a.checkFnValue(this,b.stringify,this.stringify)},a.Column.extend("define",function(a){this._super(a),this.__export_define__(a)}),a.Column.prototype.stringify=function(a,b,c){return a+""},a.is.defined(a.DateColumn)&&(a.DateColumn.prototype.stringify=function(b,c,d){return a.is.object(b)&&a.is["boolean"](b._isAMomentObject)&&b.isValid()?b.format(this.formatString):""}),a.ObjectColumn.prototype.stringify=function(b,c,d){return a.is.object(b)?JSON.stringify(b):""},a.ArrayColumn.prototype.stringify=function(b,c,d){return a.is.array(b)?JSON.stringify(b):""}}(FooTable),function(a){a.Table.prototype.toJSON=function(b){return this.use(a.Export).json(b)},a.Table.prototype.toCSV=function(b){return this.use(a.Export).csv(b)}}(FooTable);
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/build/014-mailcow.js b/mailcow/src/mailcow-dockerized/data/web/js/build/013-mailcow.js
similarity index 63%
rename from mailcow/src/mailcow-dockerized/data/web/js/build/014-mailcow.js
rename to mailcow/src/mailcow-dockerized/data/web/js/build/013-mailcow.js
index 7468310..c734c82 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/build/014-mailcow.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/build/013-mailcow.js
@@ -1,276 +1,353 @@
-$(document).ready(function() {
- // mailcow alert box generator
- window.mailcow_alert_box = function(message, type) {
- msg = $('<span/>').text(message).text();
- if (type == 'danger' || type == 'info') {
- auto_hide = 0;
- $('#' + localStorage.getItem("add_modal")).modal('show');
- localStorage.removeItem("add_modal");
- } else {
- auto_hide = 5000;
- }
- $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}});
- }
-
- $(".generate_password").click(function( event ) {
- event.preventDefault();
- $('[data-hibp]').trigger('input');
- if (typeof($(this).closest("form").data('pwgen-length')) == "number") {
- var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length'))
- }
- else {
- var random_passwd = GPW.pronounceable(8)
- }
- $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text');
- $(this).closest("form").find('[data-pwgen-field]').val(random_passwd);
- });
- function str_rot13(str) {
- return (str + '').replace(/[a-z]/gi, function(s){
- return String.fromCharCode(s.charCodeAt(0) + (s.toLowerCase() < 'n' ? 13 : -13))
- })
- }
- $(".rot-enc").html(function(){
- return str_rot13($(this).html())
- });
- // https://stackoverflow.com/questions/4399005/implementing-jquerys-shake-effect-with-animate
- function shake(div,interval,distance,times) {
- if(typeof interval === 'undefined') {
- interval = 100;
- }
- if(typeof distance === 'undefined') {
- distance = 10;
- }
- if(typeof times === 'undefined') {
- times = 4;
- }
- $(div).css('position','relative');
- for(var iter=0;iter<(times+1);iter++){
- $(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
- }
- $(div).animate({ left: 0},interval);
- }
-
- // form cache
- $('[data-cached-form="true"]').formcache({key: $(this).data('id')});
-
- // tooltips
- $(function () {
- $('[data-toggle="tooltip"]').tooltip()
- });
-
- // remember last navigation pill
- (function () {
- 'use strict';
- if ($('a[data-toggle="tab"]').length) {
- $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
- if ($(this).data('dont-remember') == 1) {
- return true;
- }
- var id = $(this).parents('[role="tablist"]').attr('id');
- var key = 'lastTag';
- if (id) {
- key += ':' + id;
- }
- localStorage.setItem(key, $(e.target).attr('href'));
- });
- $('[role="tablist"]').each(function (idx, elem) {
- var id = $(elem).attr('id');
- var key = 'lastTag';
- if (id) {
- key += ':' + id;
- }
- var lastTab = localStorage.getItem(key);
- if (lastTab) {
- $('[href="' + lastTab + '"]').tab('show');
- }
- });
- }
- })();
-
- // IE fix to hide scrollbars when table body is empty
- $('tbody').filter(function (index) {
- return $(this).children().length < 1;
- }).remove();
-
- // selectpicker
- $('select').selectpicker({
- 'styleBase': 'btn btn-xs-lg',
- 'noneSelectedText': lang_footer.nothing_selected
- });
-
- // haveibeenpwned and passwd policy
- $.ajax({
- url: '/api/v1/get/passwordpolicy/html',
- type: 'GET',
- success: function(res) {
- $(".hibp-out").after(res);
- }
- });
- $('[data-hibp]').after('<p class="small haveibeenpwned"><i class="bi bi-shield-fill-exclamation"></i> ' + lang_footer.hibp_check + '</p><span class="hibp-out"></span>');
- $('[data-hibp]').on('input', function() {
- out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out');
- });
- $('.haveibeenpwned:not(.task-running)').on('click', function() {
- var hibp_field = $(this)
- $(hibp_field).addClass('task-running');
- var hibp_result = $(hibp_field).next('.hibp-out')
- var password_field = $(this).prev('[data-hibp]')
- if ($(password_field).val() == '') {
- shake(password_field);
- }
- else {
- $(hibp_result).attr('class', 'hibp-out label label-info');
- $(hibp_result).text(lang_footer.loading);
- var password_digest = $.sha1($(password_field).val())
- var digest_five = password_digest.substring(0, 5).toUpperCase();
- var queryURL = "https://api.pwnedpasswords.com/range/" + digest_five;
- var compl_digest = password_digest.substring(5, 41).toUpperCase();
- $.ajax({
- url: queryURL,
- type: 'GET',
- success: function(res) {
- if (res.search(compl_digest) > -1){
- $(hibp_result).removeClass('label label-info').addClass('label label-danger');
- $(hibp_result).text(lang_footer.hibp_nok)
- } else {
- $(hibp_result).removeClass('label label-info').addClass('label label-success');
- $(hibp_result).text(lang_footer.hibp_ok)
- }
- $(hibp_field).removeClass('task-running');
- },
- error: function(xhr, status, error) {
- $(hibp_result).removeClass('label label-info').addClass('label label-warning');
- $(hibp_result).text('API error: ' + xhr.responseText)
- $(hibp_field).removeClass('task-running');
- }
- });
- }
- });
-
- // Disable disallowed inputs
- $('[data-acl="0"]').each(function(event){
- if ($(this).is("a")) {
- $(this).removeAttr("data-toggle");
- $(this).removeAttr("data-target");
- $(this).removeAttr("data-action");
- $(this).click(function(event) {
- event.preventDefault();
- });
- }
- if ($(this).is("select")) {
- $(this).selectpicker('destroy');
- $(this).replaceWith(function() {
- return '<label class="control-label"><b>' + this.innerText + '</b></label>';
- });
- }
- if ($(this).hasClass('btn-group')) {
- $(this).find('a').each(function(){
- $(this).removeClass('dropdown-toggle')
- .removeAttr('data-toggle')
- .removeAttr('data-target')
- .removeAttr('data-action')
- .removeAttr('id')
- .attr("disabled", true);
- $(this).click(function(event) {
- event.preventDefault();
- return;
- });
- });
- $(this).find('button').each(function() {
- $(this).attr("disabled", true);
- });
- } else if ($(this).hasClass('input-group')) {
- $(this).find('input').each(function() {
- $(this).removeClass('dropdown-toggle')
- .removeAttr('data-toggle')
- .attr("disabled", true);
- $(this).click(function(event) {
- event.preventDefault();
- });
- });
- $(this).find('button').each(function() {
- $(this).attr("disabled", true);
- });
- } else if ($(this).hasClass('form-group')) {
- $(this).find('input').each(function() {
- $(this).attr("disabled", true);
- });
- } else if ($(this).hasClass('btn')) {
- $(this).attr("disabled", true);
- } else if ($(this).attr('data-provide') == 'slider') {
- $(this).attr('disabled', true);
- } else if ($(this).is(':checkbox')) {
- $(this).attr("disabled", true);
- }
- $(this).data("toggle", "tooltip");
- $(this).attr("title", lang_acl.prohibited);
- $(this).tooltip();
- });
-
- // disable submit after submitting form (not API driven buttons)
- $('form').submit(function() {
- if ($('form button[type="submit"]').data('submitted') == '1') {
- return false;
- } else {
- $(this).find('button[type="submit"]').first().text(lang_footer.loading);
- $('form button[type="submit"]').attr('data-submitted', '1');
- function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); };
- $(document).on("keydown", disableF5);
- }
- });
- // Textarea line numbers
- $(".textarea-code").numberedtextarea({allowTabChar: true});
- // trigger container restart
- $('#RestartContainer').on('show.bs.modal', function(e) {
- var container = $(e.relatedTarget).data('container');
- $('#containerName').text(container);
- $('#triggerRestartContainer').click(function(){
- $(this).prop("disabled",true);
- $(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> ');
- $('#statusTriggerRestartContainer').html(lang_footer.restarting_container);
- $.ajax({
- method: 'get',
- url: '/inc/ajax/container_ctrl.php',
- timeout: docker_timeout,
- data: {
- 'service': container,
- 'action': 'restart'
- }
- })
- .always( function (data, status) {
- $('#statusTriggerRestartContainer').append(data);
- var htmlResponse = $.parseHTML(data)
- if ($(htmlResponse).find('span').hasClass('text-success')) {
- $('#triggerRestartContainer').html('<i class="bi bi-check-lg"></i> ');
- setTimeout(function(){
- $('#RestartContainer').modal('toggle');
- window.location = window.location.href.split("#")[0];
- }, 1200);
- } else {
- $('#triggerRestartContainer').html('<i class="bi bi-slash-lg"></i> ');
- }
- })
- });
- })
-
- // responsive tabs
- $('.responsive-tabs').tabCollapse({
- tabsClass: 'hidden-xs',
- accordionClass: 'js-tabcollapse-panel-group visible-xs'
- });
- $(document).on("shown.bs.collapse shown.bs.tab", function (e) {
- var target = $(e.target);
- if($(window).width() <= 767) {
- var offset = target.offset().top - 112;
- $("html, body").stop().animate({
- scrollTop: offset
- }, 100);
- }
- if(target.hasClass('panel-collapse')){
- var id = e.target.id.replace(/-collapse$/g, '');
- if(id){
- localStorage.setItem('lastTag', '#'+id);
- }
- }
- });
-});
+$(document).ready(function() {
+ // mailcow alert box generator
+ window.mailcow_alert_box = function(message, type) {
+ msg = $('<span/>').text(message).text();
+ if (type == 'danger' || type == 'info') {
+ auto_hide = 0;
+ $('#' + localStorage.getItem("add_modal")).modal('show');
+ localStorage.removeItem("add_modal");
+ } else {
+ auto_hide = 5000;
+ }
+ $.notify({message: msg},{z_index: 20000, delay: auto_hide, type: type,placement: {from: "bottom",align: "right"},animate: {enter: 'animated fadeInUp',exit: 'animated fadeOutDown'}});
+ }
+
+ $(".generate_password").click(function( event ) {
+ event.preventDefault();
+ $('[data-hibp]').trigger('input');
+ if (typeof($(this).closest("form").data('pwgen-length')) == "number") {
+ var random_passwd = GPW.pronounceable($(this).closest("form").data('pwgen-length'))
+ }
+ else {
+ var random_passwd = GPW.pronounceable(8)
+ }
+ $(this).closest("form").find('[data-pwgen-field]').attr('type', 'text');
+ $(this).closest("form").find('[data-pwgen-field]').val(random_passwd);
+ });
+ function str_rot13(str) {
+ return (str + '').replace(/[a-z]/gi, function(s){
+ return String.fromCharCode(s.charCodeAt(0) + (s.toLowerCase() < 'n' ? 13 : -13))
+ })
+ }
+ $(".rot-enc").html(function(){
+ return str_rot13($(this).html())
+ });
+ // https://stackoverflow.com/questions/4399005/implementing-jquerys-shake-effect-with-animate
+ function shake(div,interval,distance,times) {
+ if(typeof interval === 'undefined') {
+ interval = 100;
+ }
+ if(typeof distance === 'undefined') {
+ distance = 10;
+ }
+ if(typeof times === 'undefined') {
+ times = 4;
+ }
+ $(div).css('position','relative');
+ for(var iter=0;iter<(times+1);iter++){
+ $(div).animate({ left: ((iter%2==0 ? distance : distance*-1))}, interval);
+ }
+ $(div).animate({ left: 0},interval);
+ }
+
+ // form cache
+ $('[data-cached-form="true"]').formcache({key: $(this).data('id')});
+
+ // tooltips
+ $(function () {
+ $('[data-bs-toggle="tooltip"]').tooltip()
+ });
+
+ // remember last navigation pill
+ (function () {
+ 'use strict';
+ // remember desktop tabs
+ $('button[data-bs-toggle="tab"]').on('click', function (e) {
+ if ($(this).data('dont-remember') == 1) {
+ return true;
+ }
+ var id = $(this).parents('[role="tablist"]').attr('id');
+ var key = 'lastTag';
+ if (id) {
+ key += ':' + id;
+ }
+
+ var tab_id = $(e.target).attr('data-bs-target').substring(1);
+ localStorage.setItem(key, tab_id);
+ });
+ // remember mobile tabs
+ $('button[data-bs-target^="#collapse-tab-"]').on('click', function (e) {
+ // only remember tab if its being opened
+ if ($(this).hasClass('collapsed')) return false;
+ var tab_id = $(this).closest('div[role="tabpanel"]').attr('id');
+
+ if ($(this).data('dont-remember') == 1) {
+ return true;
+ }
+ var id = $(this).parents('[role="tablist"]').attr('id');;
+ var key = 'lastTag';
+ if (id) {
+ key += ':' + id;
+ }
+
+ localStorage.setItem(key, tab_id);
+ });
+ // open last tab
+ $('[role="tablist"]').each(function (idx, elem) {
+ var id = $(elem).attr('id');
+ var key = 'lastTag';
+ if (id) {
+ key += ':' + id;
+ }
+ var lastTab = localStorage.getItem(key);
+ if (lastTab) {
+ $('[data-bs-target="#' + lastTab + '"]').click();
+ var tab = $('[id^="' + lastTab + '"]');
+ $(tab).find('.card-body.collapse').collapse('show');
+ }
+ });
+ })();
+
+ // IE fix to hide scrollbars when table body is empty
+ $('tbody').filter(function (index) {
+ return $(this).children().length < 1;
+ }).remove();
+
+ // selectpicker
+ $('select').selectpicker({
+ 'styleBase': 'btn btn-xs-lg',
+ 'noneSelectedText': lang_footer.nothing_selected
+ });
+
+ // haveibeenpwned and passwd policy
+ $.ajax({
+ url: '/api/v1/get/passwordpolicy/html',
+ type: 'GET',
+ success: function(res) {
+ $(".hibp-out").after(res);
+ }
+ });
+ $('[data-hibp]').after('<p class="small haveibeenpwned"><i class="bi bi-shield-fill-exclamation"></i> ' + lang_footer.hibp_check + '</p><span class="hibp-out"></span>');
+ $('[data-hibp]').on('input', function() {
+ out_field = $(this).next('.haveibeenpwned').next('.hibp-out').text('').attr('class', 'hibp-out');
+ });
+ $('.haveibeenpwned:not(.task-running)').on('click', function() {
+ var hibp_field = $(this)
+ $(hibp_field).addClass('task-running');
+ var hibp_result = $(hibp_field).next('.hibp-out')
+ var password_field = $(this).prev('[data-hibp]')
+ if ($(password_field).val() == '') {
+ shake(password_field);
+ }
+ else {
+ $(hibp_result).attr('class', 'hibp-out badge fs-5 bg-info');
+ $(hibp_result).text(lang_footer.loading);
+ var password_digest = $.sha1($(password_field).val())
+ var digest_five = password_digest.substring(0, 5).toUpperCase();
+ var queryURL = "https://api.pwnedpasswords.com/range/" + digest_five;
+ var compl_digest = password_digest.substring(5, 41).toUpperCase();
+ $.ajax({
+ url: queryURL,
+ type: 'GET',
+ success: function(res) {
+ if (res.search(compl_digest) > -1){
+ $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-danger');
+ $(hibp_result).text(lang_footer.hibp_nok)
+ } else {
+ $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-success');
+ $(hibp_result).text(lang_footer.hibp_ok)
+ }
+ $(hibp_field).removeClass('task-running');
+ },
+ error: function(xhr, status, error) {
+ $(hibp_result).removeClass('badge fs-5 bg-info').addClass('badge fs-5 bg-warning');
+ $(hibp_result).text('API error: ' + xhr.responseText)
+ $(hibp_field).removeClass('task-running');
+ }
+ });
+ }
+ });
+
+ // Disable disallowed inputs
+ $('[data-acl="0"]').each(function(event){
+ if ($(this).is("a")) {
+ $(this).removeAttr("data-bs-toggle");
+ $(this).removeAttr("data-bs-target");
+ $(this).removeAttr("data-action");
+ $(this).click(function(event) {
+ event.preventDefault();
+ });
+ }
+ if ($(this).is("select")) {
+ $(this).selectpicker('destroy');
+ $(this).replaceWith(function() {
+ return '<label class="control-label"><b>' + this.innerText + '</b></label>';
+ });
+ }
+ if ($(this).hasClass('btn-group')) {
+ $(this).find('a').each(function(){
+ $(this).removeClass('dropdown-toggle')
+ .removeAttr('data-bs-toggle')
+ .removeAttr('data-bs-target')
+ .removeAttr('data-action')
+ .removeAttr('id')
+ .attr("disabled", true);
+ $(this).click(function(event) {
+ event.preventDefault();
+ return;
+ });
+ });
+ $(this).find('button').each(function() {
+ $(this).attr("disabled", true);
+ });
+ } else if ($(this).hasClass('input-group')) {
+ $(this).find('input').each(function() {
+ $(this).removeClass('dropdown-toggle')
+ .removeAttr('data-bs-toggle')
+ .attr("disabled", true);
+ $(this).click(function(event) {
+ event.preventDefault();
+ });
+ });
+ $(this).find('button').each(function() {
+ $(this).attr("disabled", true);
+ });
+ } else if ($(this).hasClass('form-group')) {
+ $(this).find('input').each(function() {
+ $(this).attr("disabled", true);
+ });
+ } else if ($(this).hasClass('btn')) {
+ $(this).attr("disabled", true);
+ } else if ($(this).attr('data-provide') == 'slider') {
+ $(this).attr('disabled', true);
+ } else if ($(this).is(':checkbox')) {
+ $(this).attr("disabled", true);
+ }
+ $(this).data("toggle", "tooltip");
+ $(this).attr("title", lang_acl.prohibited);
+ $(this).tooltip();
+ });
+
+ // disable submit after submitting form (not API driven buttons)
+ $('form').submit(function() {
+ if ($('form button[type="submit"]').data('submitted') == '1') {
+ return false;
+ } else {
+ $(this).find('button[type="submit"]').first().text(lang_footer.loading);
+ $('form button[type="submit"]').attr('data-submitted', '1');
+ function disableF5(e) { if ((e.which || e.keyCode) == 116 || (e.which || e.keyCode) == 82) e.preventDefault(); };
+ $(document).on("keydown", disableF5);
+ }
+ });
+ // Textarea line numbers
+ $(".textarea-code").numberedtextarea({allowTabChar: true});
+ // trigger container restart
+ $('#RestartContainer').on('show.bs.modal', function(e) {
+ var container = $(e.relatedTarget).data('container');
+ $('#containerName').text(container);
+ $('#triggerRestartContainer').click(function(){
+ $(this).prop("disabled",true);
+ $(this).html('<div class="spinner-border text-white" role="status"><span class="visually-hidden">Loading...</span></div>');
+ $('#statusTriggerRestartContainer').html(lang_footer.restarting_container);
+ $.ajax({
+ method: 'get',
+ url: '/inc/ajax/container_ctrl.php',
+ timeout: docker_timeout,
+ data: {
+ 'service': container,
+ 'action': 'restart'
+ }
+ })
+ .always( function (data, status) {
+ $('#statusTriggerRestartContainer').append(data);
+ var htmlResponse = $.parseHTML(data)
+ if ($(htmlResponse).find('span').hasClass('text-success')) {
+ $('#triggerRestartContainer').html('<i class="bi bi-check-lg"></i> ');
+ setTimeout(function(){
+ $('#RestartContainer').modal('toggle');
+ window.location = window.location.href.split("#")[0];
+ }, 1200);
+ } else {
+ $('#triggerRestartContainer').html('<i class="bi bi-slash-lg"></i> ');
+ }
+ })
+ });
+ })
+
+ // Jquery Datatables, enable responsive plugin
+ $.extend($.fn.dataTable.defaults, {
+ responsive: true
+ });
+
+ // tag boxes
+ $('.tag-box .tag-add').click(function(){
+ addTag(this);
+ });
+ $(".tag-box .tag-input").keydown(function (e) {
+ if (e.which == 13){
+ e.preventDefault();
+ addTag(this);
+ }
+ });
+
+ // Dark Mode Loader
+ $('#dark-mode-toggle').click(toggleDarkMode);
+ if ($('#dark-mode-theme').length) {
+ $('#dark-mode-toggle').prop('checked', true);
+ if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
+ if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
+ }
+ function toggleDarkMode(){
+ if($('#dark-mode-theme').length){
+ $('#dark-mode-theme').remove();
+ $('#dark-mode-toggle').prop('checked', false);
+ if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_dark.png');
+ if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_dark.png');
+ localStorage.setItem('theme', 'light');
+ }else{
+ $('head').append('<link id="dark-mode-theme" rel="stylesheet" type="text/css" href="/css/themes/mailcow-darkmode.css">');
+ $('#dark-mode-toggle').prop('checked', true);
+ if ($('#rspamd_logo').length) $('#rspamd_logo').attr('src', '/img/rspamd_logo_light.png');
+ if ($('#rspamd_logo_sm').length) $('#rspamd_logo_sm').attr('src', '/img/rspamd_logo_light.png');
+ localStorage.setItem('theme', 'dark');
+ }
+ }
+});
+
+
+// https://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
+function escapeHtml(n){var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="}; return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
+function unescapeHtml(t){var n={"&":"&","<":"<",">":">",""":'"',"'":"'","/":"/","`":"`","=":"="};return String(t).replace(/&|<|>|"|'|/|`|=/g,function(t){return n[t]})}
+
+function addTag(tagAddElem, tag = null){
+ var tagboxElem = $(tagAddElem).parent();
+ var tagInputElem = $(tagboxElem).find(".tag-input")[0];
+ var tagValuesElem = $(tagboxElem).find(".tag-values")[0];
+
+ if (!tag)
+ tag = $(tagInputElem).val();
+ if (!tag) return;
+ var value_tags = [];
+ try {
+ value_tags = JSON.parse($(tagValuesElem).val());
+ } catch {}
+ if (!Array.isArray(value_tags)) value_tags = [];
+ if (value_tags.includes(tag)) return;
+
+ $('<span class="badge bg-primary tag-badge btn-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(tag) + '</span>').insertBefore('.tag-input').click(function(){
+ var del_tag = unescapeHtml($(this).text());
+ var del_tags = [];
+ try {
+ del_tags = JSON.parse($(tagValuesElem).val());
+ } catch {}
+ if (Array.isArray(del_tags)){
+ del_tags.splice(del_tags.indexOf(del_tag), 1);
+ $(tagValuesElem).val(JSON.stringify(del_tags));
+ }
+ $(this).remove();
+ });
+
+ value_tags.push(tag);
+ $(tagValuesElem).val(JSON.stringify(value_tags));
+ $(tagInputElem).val('');
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/admin.js b/mailcow/src/mailcow-dockerized/data/web/js/site/admin.js
index eac7b21..d47a222 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/admin.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/admin.js
@@ -53,237 +53,426 @@
$("#show_rspamd_global_filters").click(function() {
$.get("inc/ajax/show_rspamd_global_filters.php");
$("#confirm_show_rspamd_global_filters").hide();
- $("#rspamd_global_filters").removeClass("hidden");
+ $("#rspamd_global_filters").removeClass("d-none");
});
$("#super_delete").click(function() { return confirm(lang.queue_ays); });
+
$(".refresh_table").on('click', function(e) {
e.preventDefault();
var table_name = $(this).data('table');
- $('#' + table_name).find("tr.footable-empty").remove();
- draw_table = $(this).data('draw');
- eval(draw_table + '()');
+ $('#' + table_name).DataTable().ajax.reload();
});
- function table_admin_ready(ft, name) {
- heading = ft.$el.parents('.panel').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- $(heading).children('.table-lines').text(function(){
- return ft_paging.totalRows;
- })
- }
function draw_domain_admins() {
- ft_domainadmins = FooTable.init('#domainadminstable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"username","title":lang.username,"style":{"width":"250px"}},
- {"name":"selected_domains","title":lang.admin_domains,"breakpoints":"xs sm"},
- {"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/domain-admin/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw domain admin table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#domainadminstable') ) {
+ $('#domainadminstable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#domainadminstable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/domain-admin/all",
+ dataSrc: function(data){
return process_table_data(data, 'domainadminstable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "state": {"enabled": true},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle"
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: lang.admin_domains,
+ data: 'selected_domains',
+ defaultContent: '',
+ },
+ {
+ title: "TFA",
+ data: 'tfa_active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ],
+ initComplete: function(settings, json){
+ }
});
}
function draw_oauth2_clients() {
- ft_oauth2clientstable = FooTable.init('#oauth2clientstable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
- {"name":"client_id","type":"text","title":lang.oauth2_client_id,"style":{"width":"200px"}},
- {"name":"client_secret","title":lang.oauth2_client_secret,"breakpoints":"xs sm md","style":{"width":"200px"}},
- {"name":"redirect_uri","title":lang.oauth2_redirect_uri, "type": "text"},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/oauth2-client/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw oauth2 clients table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#oauth2clientstable') ) {
+ $('#oauth2clientstable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#oauth2clientstable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/oauth2-client/all",
+ dataSrc: function(data){
return process_table_data(data, 'oauth2clientstable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle"
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.oauth2_client_id,
+ data: 'client_id',
+ defaultContent: ''
+ },
+ {
+ title: lang.oauth2_client_secret,
+ data: 'client_secret',
+ defaultContent: ''
+ },
+ {
+ title: lang.oauth2_redirect_uri,
+ data: 'redirect_uri',
+ defaultContent: ''
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
});
}
function draw_admins() {
- ft_admins = FooTable.init('#adminstable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"usr","title":lang.username,"style":{"width":"250px"}},
- {"name":"tfa_active","title":"TFA", "filterable": false,"style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/admin/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw admin table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#adminstable') ) {
+ $('#adminstable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#adminstable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/admin/all",
+ dataSrc: function(data){
return process_table_data(data, 'adminstable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": false},
- "state": {"enabled": true},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle"
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: "TFA",
+ data: 'tfa_active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ defaultContent: '',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right'
+ },
+ ]
});
}
function draw_fwd_hosts() {
- ft_forwardinghoststable = FooTable.init('#forwardinghoststable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"host","type":"text","title":lang.host,"style":{"width":"250px"}},
- {"name":"source","title":lang.source,"breakpoints":"xs sm"},
- {"name":"keep_spam","title":lang.spamfilter, "type": "text","style":{"maxWidth":"80px","width":"80px"},"formatter": function(value){return 'yes'==value?'<i class="bi bi-x-lg"></i>':'no'==value&&'<i class="bi bi-check-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/fwdhost/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw forwarding hosts table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#forwardinghoststable') ) {
+ $('#forwardinghoststable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#forwardinghoststable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/fwdhost/all",
+ dataSrc: function(data){
return process_table_data(data, 'forwardinghoststable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle"
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: lang.host,
+ data: 'host',
+ defaultContent: ''
+ },
+ {
+ title: lang.source,
+ data: 'source',
+ defaultContent: ''
+ },
+ {
+ title: lang.spamfilter,
+ data: 'keep_spam',
+ defaultContent: ''
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
});
}
function draw_relayhosts() {
- ft_relayhoststable = FooTable.init('#relayhoststable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
- {"name":"hostname","type":"text","title":lang.host,"style":{"width":"250px"}},
- {"name":"username","title":lang.username,"breakpoints":"xs sm"},
- {"name":"in_use_by","title":lang.in_use_by,"style":{"min-width":"200px","width":"200px"}, "type": "text","breakpoints":"xs sm"},
- {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/relayhost/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw forwarding hosts table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#relayhoststable') ) {
+ $('#relayhoststable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#relayhoststable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/relayhost/all",
+ dataSrc: function(data){
return process_table_data(data, 'relayhoststable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle"
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.host,
+ data: 'hostname',
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: lang.in_use_by,
+ data: 'in_use_by',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
});
}
function draw_transport_maps() {
- ft_transportstable = FooTable.init('#transportstable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","type":"text","title":"ID","style":{"width":"50px"}},
- {"name":"destination","type":"text","title":lang.destination,"style":{"min-width":"300px","width":"300px"}},
- {"name":"nexthop","type":"text","title":lang.nexthop,"style":{"min-width":"200px","width":"200px"}},
- {"name":"username","title":lang.username,"breakpoints":"xs sm"},
- {"name":"active","filterable": false,"style":{"maxWidth":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/transport/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw transports table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#transportstable') ) {
+ $('#transportstable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#transportstable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/transport/all",
+ dataSrc: function(data){
return process_table_data(data, 'transportstable');
}
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle",
- "on": {
- "ready.ft.table": function(e, ft){
- $('.mx-info').tooltip();
- }
- }
- });
- }
- function draw_queue() {
- ft_queuetable = FooTable.init('#queuetable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"queue_id","type":"text","title":"QID","style":{"width":"50px"}},
- {"name":"queue_name","type":"text","title":"Queue","style":{"width":"120px"}},
- {"name":"arrival_time","sorted": true,"direction": "DESC","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.arrival_time,"style":{"width":"170px"}},
- {"name":"message_size","style":{"whiteSpace":"nowrap"},"title":lang.message_size,"formatter": function(value){
- return humanFileSize(value);
- }},
- {"name":"sender","title":lang.sender, "type": "text","breakpoints":"xs sm"},
- {"name":"recipients","title":lang.recipients, "type": "text","style":{"word-break":"break-all","min-width":"300px"},"breakpoints":"xs sm md"},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","maxWidth":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/mailq/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw forwarding hosts table');
- },
- success: function (data) {
- return process_table_data(data, 'queuetable');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "sorting": {"enabled": true},
- "toggleSelector": "table tbody span.footable-toggle",
- "on": {
- "ready.ft.table": function(e, ft){
- table_admin_ready(ft, 'queuetable');
- }
- }
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.destination,
+ data: 'destination',
+ defaultContent: ''
+ },
+ {
+ title: lang.nexthop,
+ data: 'nexthop',
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ if(data == 1) return '<i class="bi bi-check-lg"></i>';
+ else return '<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
});
}
function process_table_data(data, table) {
if (table == 'relayhoststable') {
$.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
- '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="sender-dependent" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
+ '<a href="/edit/relayhost/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-rlyhost" data-api-url="delete/relayhost" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
if (item.used_by_mailboxes == '') { item.in_use_by = item.used_by_domains; }
@@ -294,14 +483,14 @@
} else if (table == 'transportstable') {
$.each(data, function (i, item) {
if (item.is_mx_based) {
- item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>';
+ item.destination = '<i class="bi bi-info-circle-fill text-info mx-info" data-bs-toggle="tooltip" title="' + lang.is_mx_based + '"></i> <code>' + item.destination + '</code>';
}
if (item.username) {
item.username = '<i style="color:#' + intToRGB(hashCode(item.nexthop)) + ';" class="bi bi-square-fill"></i> ' + item.username;
}
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="#" data-toggle="modal" data-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-caret-right-fill"></i> Test</a>' +
- '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="#" data-bs-toggle="modal" data-bs-target="#testTransportModal" data-transport-id="' + encodeURI(item.id) + '" data-transport-type="transport-map" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-caret-right-fill"></i> Test</a>' +
+ '<a href="/edit/transport/' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-transport" data-api-url="delete/transport" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="transports" name="multi_select" value="' + item.id + '" />';
@@ -313,21 +502,21 @@
return escapeHtml(i);
});
item.recipients = rcpts.join('<hr style="margin:1px!important">');
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="#" data-toggle="modal" data-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-default">' + lang.queue_show_message + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.queue_show_message + '</a>' +
'</div>';
});
} else if (table == 'forwardinghoststable') {
$.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
+ item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-fwdhost" data-api-url="delete/fwdhost" data-item="' + encodeURI(item.host) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="fwdhosts" name="multi_select" value="' + item.host + '" />';
});
} else if (table == 'oauth2clientstable') {
$.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit.php?oauth2client=' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-oauth2-client" data-api-url="delete/oauth2-client" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.scope = "profile";
@@ -339,8 +528,8 @@
item.selected_domains = escapeHtml(item.selected_domains);
item.selected_domains = item.selected_domains.toString().replace(/,/g, "<br>");
item.chkbox = '<input type="checkbox" data-id="domain_admins" name="multi_select" value="' + item.username + '" />';
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/domainadmin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-domain-admin" data-api-url="delete/domain-admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-third btn-success"><i class="bi bi-person-fill"></i> Login</a>' +
'</div>';
@@ -353,22 +542,38 @@
item.usr = item.username;
}
item.chkbox = '<input type="checkbox" data-id="admins" name="multi_select" value="' + item.username + '" />';
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/admin/' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-admin" data-api-url="delete/admin" data-item="' + encodeURI(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
});
}
return data
};
- // Initial table drawings
- draw_domain_admins();
- draw_admins();
- draw_fwd_hosts();
- draw_relayhosts();
- draw_oauth2_clients();
- draw_transport_maps();
- draw_queue();
+
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
+
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+ // Draw Table if tab is active
+ onVisible("[id^=adminstable]", () => draw_admins());
+ onVisible("[id^=domainadminstable]", () => draw_domain_admins());
+ onVisible("[id^=oauth2clientstable]", () => draw_oauth2_clients());
+ onVisible("[id^=forwardinghoststable]", () => draw_fwd_hosts());
+ onVisible("[id^=relayhoststable]", () => draw_relayhosts());
+ onVisible("[id^=transportstable]", () => draw_transport_maps());
+
$('body').on('click', 'span.footable-toggle', function () {
event.stopPropagation();
@@ -427,27 +632,11 @@
$('#transport_type').val(button.data('transport-type'));
}
})
- // Queue item
- $('#showQueuedMsg').on('show.bs.modal', function (e) {
- $('#queue_msg_content').text(lang.loading);
- button = $(e.relatedTarget)
- if (button != null) {
- $('#queue_id').text(button.data('queue-id'));
- }
- $.ajax({
- type: 'GET',
- url: '/api/v1/get/postcat/' + button.data('queue-id'),
- dataType: 'text',
- complete: function (data) {
- $('#queue_msg_content').text(data.responseText);
- }
- });
- })
$('#test_transport').on('click', function (e) {
e.preventDefault();
prev = $('#test_transport').text();
$(this).prop("disabled",true);
- $(this).html('<i class="bi bi-arrow-repeat icon-spin"></i> ');
+ $(this).html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div> ');
$.ajax({
type: 'GET',
url: 'inc/ajax/transport_check.php',
@@ -481,13 +670,13 @@
function add_table_row(table_id, type) {
var row = $('<tr />');
if (type == "app_link") {
- cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
- cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
- cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
+ cols = '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="app" required></td>';
+ cols += '<td><input class="input-sm input-xs-lg form-control" data-id="app_links" type="text" name="href" required></td>';
+ cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
} else if (type == "f2b_regex") {
- cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
- cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
- cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-default" type="button">' + lang.remove_row + '</a></td>';
+ cols = '<td><input style="text-align:center" class="input-sm input-xs-lg form-control" data-id="f2b_regex" type="text" value="+" disabled></td>';
+ cols += '<td><input class="input-sm input-xs-lg form-control regex-input" data-id="f2b_regex" type="text" name="regex" required></td>';
+ cols += '<td><a href="#" role="button" class="btn btn-sm btn-xs-lg btn-secondary h-100 w-100" type="button">' + lang.remove_row + '</a></td>';
}
row.append(cols);
table_id.append(row);
@@ -507,4 +696,3 @@
add_table_row($('#f2b_regex_table'), "f2b_regex");
});
});
-
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/debug.js b/mailcow/src/mailcow-dockerized/data/web/js/site/debug.js
index 8f2aa66..85e6b78 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/debug.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/debug.js
@@ -1,805 +1,1536 @@
-$(document).ready(function() {
- // Parse seconds ago to date
- // Get "now" timestamp
- var ts_now = Math.round((new Date()).getTime() / 1000);
- $('.parse_s_ago').each(function(i, parse_s_ago) {
- var started_s_ago = parseInt($(this).text(), 10);
- if (typeof started_s_ago != 'NaN') {
- var started_date = new Date((ts_now - started_s_ago) * 1000);
- if (started_date instanceof Date && !isNaN(started_date)) {
- var started_local_date = started_date.toLocaleDateString(undefined, {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- second: "2-digit"
- });
- $(this).text(started_local_date);
- } else {
- $(this).text('-');
- }
- }
- });
- // Parse general dates
- $('.parse_date').each(function(i, parse_date) {
- var started_date = new Date(Date.parse($(this).text()));
- if (typeof started_date != 'NaN') {
- var started_local_date = started_date.toLocaleDateString(undefined, {
- year: "numeric",
- month: "2-digit",
- day: "2-digit",
- hour: "2-digit",
- minute: "2-digit",
- second: "2-digit"
- });
- $(this).text(started_local_date);
- }
- });
-});
-jQuery(function($){
- if (localStorage.getItem("current_page") === null) {
- var current_page = {};
- } else {
- var current_page = JSON.parse(localStorage.getItem('current_page'));
- }
- // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
- var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
- function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
- function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
- function hashCode(t){for(var n=0,r=0;r<t.length;r++)n=t.charCodeAt(r)+((n<<5)-n);return n}
- function intToRGB(t){var n=(16777215&t).toString(16).toUpperCase();return"00000".substring(0,6-n.length)+n}
- $(".refresh_table").on('click', function(e) {
- e.preventDefault();
- var table_name = $(this).data('table');
- $('#' + table_name).find("tr.footable-empty").remove();
- draw_table = $(this).data('draw');
- eval(draw_table + '()');
- });
- function table_log_ready(ft, name) {
- heading = ft.$el.parents('.panel').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- $('.refresh_table').prop("disabled", false);
- $(heading).children('.table-lines').text(function(){
- return ft_paging.totalRows;
- })
- if (current_page[name]) {
- ft_paging.goto(parseInt(current_page[name]))
- }
- }
- function table_log_paging(ft, name) {
- var ft_paging = ft.use(FooTable.Paging)
- current_page[name] = ft_paging.current;
- localStorage.setItem('current_page', JSON.stringify(current_page));
- }
- function draw_autodiscover_logs() {
- ft_autodiscover_logs = FooTable.init('#autodiscover_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"ua","title":"User-Agent","style":{"min-width":"200px"}},
- {"name":"user","title":"Username","style":{"min-width":"200px"}},
- {"name":"ip","title":"IP","style":{"min-width":"200px"}},
- {"name":"service","title":"Service"},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/autodiscover/100',
- jsonp: false,
- error: function () {
- console.log('Cannot draw autodiscover log table');
- },
- success: function (data) {
- return process_table_data(data, 'autodiscover_log');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'autodiscover_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'autodiscover_logs');
- }
- }
- });
- }
- function draw_postfix_logs() {
- ft_postfix_logs = FooTable.init('#postfix_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/postfix',
- jsonp: false,
- error: function () {
- console.log('Cannot draw postfix log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'postfix_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'postfix_logs');
- }
- }
- });
- }
- function draw_watchdog_logs() {
- ft_watchdog_logs = FooTable.init('#watchdog_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"service","title":"Service"},
- {"name":"trend","title":"Trend"},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/watchdog',
- jsonp: false,
- error: function () {
- console.log('Cannot draw watchdog log table');
- },
- success: function (data) {
- return process_table_data(data, 'watchdog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'postfix_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'postfix_logs');
- }
- }
- });
- }
- function draw_api_logs() {
- ft_api_logs = FooTable.init('#api_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"uri","title":"URI","style":{"width":"310px"}},
- {"name":"method","title":"Method","style":{"width":"80px"}},
- {"name":"remote","title":"IP","style":{"width":"80px"}},
- {"name":"data","title":"Data","breakpoints": "all","style":{"word-break":"break-all"}},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/api',
- jsonp: false,
- error: function () {
- console.log('Cannot draw api log table');
- },
- success: function (data) {
- return process_table_data(data, 'apilog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'api_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'api_logs');
- }
- }
- });
- }
- function draw_rl_logs() {
- ft_rl_logs = FooTable.init('#rl_log', {
- "columns": [
- {"name":"indicator","title":" ","style":{"width":"50px"}},
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.last_applied,"style":{"width":"170px"}},
- {"name":"rl_name","title":lang.rate_name},
- {"name":"from","title":lang.sender},
- {"name":"rcpt","title":lang.recipients},
- {"name":"user","title":lang.authed_user},
- {"name":"message_id","title":"Msg ID","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"header_from","title":"Header From","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"header_subject","title":"Subject","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"rl_hash","title":"Hash","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"qid","title":"Rspamd QID","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"ip","title":"IP","breakpoints": "all","style":{"word-break":"break-all"}},
- {"name":"action","title":lang.action,"breakpoints": "all","style":{"word-break":"break-all"}},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/ratelimited',
- jsonp: false,
- error: function () {
- console.log('Cannot draw rl log table');
- },
- success: function (data) {
- return process_table_data(data, 'rllog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'rl_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'rl_logs');
- }
- }
- });
- }
- function draw_ui_logs() {
- ft_api_logs = FooTable.init('#ui_logs', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"type","title":"Type"},
- {"name":"task","title":"Task"},
- {"name":"user","title":"User"},
- {"name":"role","title":"Role"},
- {"name":"remote","title":"IP"},
- {"name":"msg","title":lang.message,"style":{"word-break":"break-all"}},
- {"name":"call","title":"Call","breakpoints": "all"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/ui',
- jsonp: false,
- error: function () {
- console.log('Cannot draw ui log table');
- },
- success: function (data) {
- return process_table_data(data, 'mailcow_ui');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'ui_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'ui_logs');
- }
- }
- });
- }
- function draw_sasl_logs() {
- ft_api_logs = FooTable.init('#sasl_logs', {
- "columns": [
- {"name":"username","title":lang.username},
- {"name":"service","title":lang.service},
- {"name":"real_rip","title":"IP"},
- {"sorted": true,"sortValue": function(value){res = new Date(value);return res.getTime();},"direction":"DESC","name":"datetime","formatter":function date_format(datetime) { var date = new Date(datetime.replace(/-/g, "/")); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.login_time,"style":{"width":"170px"}},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/sasl',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sasl log table');
- },
- success: function (data) {
- return process_table_data(data, 'sasl_log_table');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'sasl_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'sasl_logs');
- }
- }
- });
- }
- function draw_acme_logs() {
- ft_acme_logs = FooTable.init('#acme_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"message","title":lang.message,"style":{"word-break":"break-all"}},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/acme',
- jsonp: false,
- error: function () {
- console.log('Cannot draw acme log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'acme_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'acme_logs');
- }
- }
- });
- }
- function draw_netfilter_logs() {
- ft_netfilter_logs = FooTable.init('#netfilter_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/netfilter',
- jsonp: false,
- error: function () {
- console.log('Cannot draw netfilter log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'netfilter_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'netfilter_logs');
- }
- }
- });
- }
- function draw_sogo_logs() {
- ft_sogo_logs = FooTable.init('#sogo_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/sogo',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sogo log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'sogo_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'sogo_logs');
- }
- }
- });
- }
- function draw_dovecot_logs() {
- ft_dovecot_logs = FooTable.init('#dovecot_log', {
- "columns": [
- {"name":"time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name":"priority","title":lang.priority,"style":{"width":"80px"}},
- {"name":"message","title":lang.message},
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/dovecot',
- jsonp: false,
- error: function () {
- console.log('Cannot draw dovecot log table');
- },
- success: function (data) {
- return process_table_data(data, 'general_syslog');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'dovecot_logs');
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'dovecot_logs');
- }
- }
- });
- }
- function rspamd_pie_graph() {
- $.ajax({
- url: '/api/v1/get/rspamd/actions',
- async: true,
- success: function(data){
-
- var total = 0;
- $(data).map(function(){total += this[1];});
- var labels = $.makeArray($(data).map(function(){return this[0] + ' ' + Math.round(this[1]/total * 100) + '%';}));
- var values = $.makeArray($(data).map(function(){return this[1];}));
-
- var graphdata = {
- labels: labels,
- datasets: [{
- data: values,
- backgroundColor: ['#DC3023', '#59ABE3', '#FFA400', '#FFA400', '#26A65B']
- }]
- };
-
- var options = {
- responsive: true,
- maintainAspectRatio: false,
- plugins: {
- datalabels: {
- color: '#FFF',
- font: {
- weight: 'bold'
- },
- display: function(context) {
- return context.dataset.data[context.dataIndex] !== 0;
- },
- formatter: function(value, context) {
- return Math.round(value/total*100) + '%';
- }
- }
- }
- };
- var chartcanvas = document.getElementById('rspamd_donut');
- Chart.plugins.register('ChartDataLabels');
- if(typeof chart == 'undefined') {
- chart = new Chart(chartcanvas.getContext("2d"), {
- plugins: [ChartDataLabels],
- type: 'doughnut',
- data: graphdata,
- options: options
- });
- }
- else {
- chart.destroy();
- chart = new Chart(chartcanvas.getContext("2d"), {
- plugins: [ChartDataLabels],
- type: 'doughnut',
- data: graphdata,
- options: options
- });
- }
- }
- });
- }
- function draw_rspamd_history() {
- ft_rspamd_history = FooTable.init('#rspamd_history', {
- "columns": [
- {"name":"unix_time","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.time,"style":{"width":"170px"}},
- {"name": "ip","title": "IP address","breakpoints": "all","style": {"minWidth": 88}},
- {"name": "sender_mime","title": "From","breakpoints": "xs sm md","style": {"minWidth": 100}},
- {"name": "rcpt","title": "To","breakpoints": "xs sm md","style": {"minWidth": 100}},
- {"name": "subject","title": "Subject","breakpoints": "all","style": {"word-break": "break-all","minWidth": 150}},
- {"name": "action","title": "Action","style": {"minwidth": 82}},
- {"name": "score","title": "Score","style": {"maxWidth": 110},},
- {"name": "symbols","title": "Symbols","breakpoints": "all",},
- {"name": "size","title": "Msg size","breakpoints": "all","style": {"minwidth": 50},"formatter": function(value){return humanFileSize(value);}},
- {"name": "scan_time","title": "Scan time","breakpoints": "all","style": {"maxWidth": 72},},
- {"name": "message-id","title": "ID","breakpoints": "all","style": {"minWidth": 130,"overflow": "hidden","textOverflow": "ellipsis","wordBreak": "break-all","whiteSpace": "normal"}},
- {"name": "user","title": "Authenticated user","breakpoints": "xs sm md","style": {"minWidth": 100}}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/logs/rspamd-history',
- jsonp: false,
- error: function () {
- console.log('Cannot draw rspamd history table');
- },
- success: function (data) {
- return process_table_data(data, 'rspamd_history');
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": log_pagination_size},
- "filtering": {"enabled": true,"delay": 1200,"position": "left","connectors": false,"placeholder": lang.filter_table,"connectors": false},
- "sorting": {"enabled": true},
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_log_ready(ft, 'rspamd_history');
- heading = ft.$el.parents('.panel').find('.panel-heading')
- $(heading).children('.table-lines').text(function(){
- var ft_paging = ft.use(FooTable.Paging)
- return ft_paging.totalRows;
- })
- rspamd_pie_graph();
- },
- "after.ft.paging": function(e, ft){
- table_log_paging(ft, 'rspamd_history');
- }
- }
- });
- }
- function process_table_data(data, table) {
- if (table == 'rspamd_history') {
- $.each(data, function (i, item) {
- if (item.rcpt_mime != "") {
- item.rcpt = escapeHtml(item.rcpt_mime.join(", "));
- }
- else {
- item.rcpt = escapeHtml(item.rcpt_smtp.join(", "));
- }
- item.symbols = Object.keys(item.symbols).sort(function (a, b) {
- if (item.symbols[a].score === 0) return 1
- if (item.symbols[b].score === 0) return -1
- if (item.symbols[b].score < 0 && item.symbols[a].score < 0) {
- return item.symbols[a].score - item.symbols[b].score
- }
- if (item.symbols[b].score > 0 && item.symbols[a].score > 0) {
- return item.symbols[b].score - item.symbols[a].score
- }
- return item.symbols[b].score - item.symbols[a].score
- }).map(function(key) {
- var sym = item.symbols[key];
- if (sym.score < 0) {
- sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
- }
- else if (sym.score === 0) {
- sym.score_formatted = '(<span><b>' + sym.score + '</b></span>)'
- }
- else {
- sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
- }
- var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
- if (sym.options) {
- str += ' [' + escapeHtml(sym.options.join(", ")) + "]";
- }
- return str
- }).join('<br>\n');
- item.subject = escapeHtml(item.subject);
- var scan_time = item.time_real.toFixed(3);
- if (item.time_virtual) {
- scan_time += ' / ' + item.time_virtual.toFixed(3);
- }
- item.scan_time = {
- "options": {
- "sortValue": item.time_real
- },
- "value": scan_time
- };
- if (item.action === 'clean' || item.action === 'no action') {
- item.action = "<div class='label label-success'>" + item.action + "</div>";
- } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
- item.action = "<div class='label label-warning'>" + item.action + "</div>";
- } else if (item.action === 'spam' || item.action === 'reject') {
- item.action = "<div class='label label-danger'>" + item.action + "</div>";
- } else {
- item.action = "<div class='label label-info'>" + item.action + "</div>";
- }
- var score_content;
- if (item.score < item.required_score) {
- score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
- } else {
- score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
- }
- item.score = {
- "options": {
- "sortValue": item.score
- },
- "value": score_content
- };
- if (item.user == null) {
- item.user = "none";
- }
- });
- } else if (table == 'autodiscover_log') {
- $.each(data, function (i, item) {
- if (item.ua == null) {
- item.ua = 'unknown';
- } else {
- item.ua = escapeHtml(item.ua);
- }
- item.ua = '<span style="font-size:small">' + item.ua + '</span>';
- if (item.service == "activesync") {
- item.service = '<span class="label label-info">ActiveSync</span>';
- }
- else if (item.service == "imap") {
- item.service = '<span class="label label-success">IMAP, SMTP, Cal-/CardDAV</span>';
- }
- else {
- item.service = '<span class="label label-danger">' + escapeHtml(item.service) + '</span>';
- }
- });
- } else if (table == 'watchdog') {
- $.each(data, function (i, item) {
- if (item.message == null) {
- item.message = 'Health level: ' + item.lvl + '% (' + item.hpnow + '/' + item.hptotal + ')';
- if (item.hpdiff < 0) {
- item.trend = '<span class="label label-danger"><i class="bi bi-caret-down-fill"></i> ' + item.hpdiff + '</span>';
- }
- else if (item.hpdiff == 0) {
- item.trend = '<span class="label label-info"><i class="bi bi-caret-right-fill"></i> ' + item.hpdiff + '</span>';
- }
- else {
- item.trend = '<span class="label label-success"><i class="bi bi-caret-up-fill"></i> ' + item.hpdiff + '</span>';
- }
- }
- else {
- item.trend = '';
- item.service = '';
- }
- });
- } else if (table == 'mailcow_ui') {
- $.each(data, function (i, item) {
- if (item === null) { return true; }
- item.user = escapeHtml(item.user);
- item.call = escapeHtml(item.call);
- item.task = '<code>' + item.task + '</code>';
- item.type = '<span class="label label-' + item.type + '">' + item.type + '</span>';
- });
- } else if (table == 'sasl_log_table') {
- $.each(data, function (i, item) {
- if (item === null) { return true; }
- item.username = escapeHtml(item.username);
- item.service = '<div class="label label-default">' + item.service.toUpperCase() + '</div>';
- });
- } else if (table == 'general_syslog') {
- $.each(data, function (i, item) {
- if (item === null) { return true; }
- if (item.message.match("^base64,")) {
- try {
- item.message = atob(item.message.slice(7)).replace(/\\n/g, "<br />");
- } catch(e) {
- item.message = item.message.slice(7);
- }
- } else {
- item.message = escapeHtml(item.message);
- }
- item.call = escapeHtml(item.call);
- var danger_class = ["emerg", "alert", "crit", "err"];
- var warning_class = ["warning", "warn"];
- var info_class = ["notice", "info", "debug"];
- if (jQuery.inArray(item.priority, danger_class) !== -1) {
- item.priority = '<span class="label label-danger">' + item.priority + '</span>';
- } else if (jQuery.inArray(item.priority, warning_class) !== -1) {
- item.priority = '<span class="label label-warning">' + item.priority + '</span>';
- } else if (jQuery.inArray(item.priority, info_class) !== -1) {
- item.priority = '<span class="label label-info">' + item.priority + '</span>';
- }
- });
- } else if (table == 'apilog') {
- $.each(data, function (i, item) {
- if (item === null) { return true; }
- if (item.method == 'GET') {
- item.method = '<span class="label label-success">' + item.method + '</span>';
- } else if (item.method == 'POST') {
- item.method = '<span class="label label-warning">' + item.method + '</span>';
- }
- item.data = escapeHtml(item.data);
- });
- } else if (table == 'rllog') {
- $.each(data, function (i, item) {
- if (item.user == null) {
- item.user = "none";
- }
- if (item.rl_hash == null) {
- item.rl_hash = "err";
- }
- item.indicator = '<span style="border-right:6px solid #' + intToRGB(hashCode(item.rl_hash)) + ';padding-left:5px;"> </span>';
- if (item.rl_hash != 'err') {
- item.action = '<a href="#" data-action="delete_selected" data-id="single-hash" data-api-url="delete/rlhash" data-item="' + encodeURI(item.rl_hash) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.reset_limit + '</a>';
- }
- });
- }
- return data
- };
- $('.add_log_lines').on('click', function (e) {
- e.preventDefault();
- var log_table= $(this).data("table")
- var new_nrows = $(this).data("nrows")
- var post_process = $(this).data("post-process")
- var log_url = $(this).data("log-url")
- if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) {
- console.log("no data-table or data-nrows or log_url or data-post-process attr found");
- return;
- }
- if (ft = FooTable.get($('#' + log_table))) {
- var heading = ft.$el.parents('.panel').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- var load_rows = (ft_paging.totalRows + 1) + '-' + (ft_paging.totalRows + new_nrows)
- $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){
- if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; }
- var rows = process_table_data(data, post_process);
- var rows_now = (ft_paging.totalRows + data.length);
- $(heading).children('.table-lines').text(rows_now)
- mailcow_alert_box(data.length + lang.additional_rows, "success");
- ft.rows.load(rows, true);
- });
- }
- })
- // Initial table drawings
- draw_postfix_logs();
- draw_autodiscover_logs();
- draw_dovecot_logs();
- draw_sogo_logs();
- draw_watchdog_logs();
- draw_acme_logs();
- draw_api_logs();
- draw_rl_logs();
- draw_ui_logs();
- draw_sasl_logs();
- draw_netfilter_logs();
- draw_rspamd_history();
- $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
- var target = $(e.target).attr("href");
- if (target == '#tab-rspamd-history') {
- rspamd_pie_graph();
- }
- });
-});
+const LOCALE = undefined;
+const DATETIME_FORMAT = {
+ year: "numeric",
+ month: "2-digit",
+ day: "2-digit",
+ hour: "2-digit",
+ minute: "2-digit",
+ second: "2-digit"
+};
+
+$(document).ready(function() {
+ // Parse seconds ago to date
+ // Get "now" timestamp
+ var ts_now = Math.round((new Date()).getTime() / 1000);
+ $('.parse_s_ago').each(function(i, parse_s_ago) {
+ var started_s_ago = parseInt($(this).text(), 10);
+ if (typeof started_s_ago != 'NaN') {
+ var started_date = new Date((ts_now - started_s_ago) * 1000);
+ if (started_date instanceof Date && !isNaN(started_date)) {
+ var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
+ $(this).text(started_local_date);
+ } else {
+ $(this).text('-');
+ }
+ }
+ });
+ // Parse general dates
+ $('.parse_date').each(function(i, parse_date) {
+ var started_date = new Date(Date.parse($(this).text()));
+ if (typeof started_date != 'NaN') {
+ var started_local_date = started_date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
+ $(this).text(started_local_date);
+ }
+ });
+
+ // set update loop container list
+ containersToUpdate = {}
+ // set default ChartJs Font Color
+ Chart.defaults.color = '#999';
+ // create host cpu and mem charts
+ createHostCpuAndMemChart();
+ // check for new version
+ if (mailcow_info.branch === "master"){
+ check_update(mailcow_info.version_tag, mailcow_info.project_url);
+ }
+ $("#maiclow_version").click(function(){
+ if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin" ||
+ mailcow_info.branch !== "master")
+ return;
+
+ showVersionModal("Version " + mailcow_info.version_tag, mailcow_info.version_tag);
+ })
+ // get public ips
+ get_public_ips();
+ update_container_stats();
+});
+jQuery(function($){
+ if (localStorage.getItem("current_page") === null) {
+ var current_page = {};
+ } else {
+ var current_page = JSON.parse(localStorage.getItem('current_page'));
+ }
+ // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
+ var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
+ function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
+ function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
+ function hashCode(t){for(var n=0,r=0;r<t.length;r++)n=t.charCodeAt(r)+((n<<5)-n);return n}
+ function intToRGB(t){var n=(16777215&t).toString(16).toUpperCase();return"00000".substring(0,6-n.length)+n}
+ $(".refresh_table").on('click', function(e) {
+ e.preventDefault();
+ var table_name = $(this).data('table');
+ $('#' + table_name).DataTable().ajax.reload();
+ });
+ function createSortableDate(td, cellData) {
+ $(td).attr({
+ "data-order": cellData,
+ "data-sort": cellData
+ });
+ $(td).html(convertTimestampToLocalFormat(cellData));
+ }
+ function draw_autodiscover_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#autodiscover_log') ) {
+ $('#autodiscover_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#autodiscover_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/autodiscover/100",
+ dataSrc: function(data){
+ return process_table_data(data, 'autodiscover_log');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ responsivePriority: 1,
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: 'User-Agent',
+ data: 'ua',
+ defaultContent: '',
+ className: 'dtr-col-md',
+ responsivePriority: 5
+ },
+ {
+ title: 'Username',
+ data: 'user',
+ defaultContent: '',
+ responsivePriority: 4
+ },
+ {
+ title: 'IP',
+ data: 'ip',
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'Service',
+ data: 'service',
+ defaultContent: '',
+ responsivePriority: 3
+ }
+ ]
+ });
+ }
+ function draw_postfix_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#postfix_log') ) {
+ $('#postfix_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#postfix_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/postfix",
+ dataSrc: function(data){
+ return process_table_data(data, 'general_syslog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.priority,
+ data: 'priority',
+ defaultContent: ''
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: '',
+ className: 'dtr-col-md text-break'
+ }
+ ]
+ });
+ }
+ function draw_watchdog_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#watchdog_log') ) {
+ $('#watchdog_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#watchdog_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/watchdog",
+ dataSrc: function(data){
+ return process_table_data(data, 'watchdog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: 'Service',
+ data: 'service',
+ defaultContent: ''
+ },
+ {
+ title: 'Trend',
+ data: 'trend',
+ defaultContent: ''
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: ''
+ }
+ ]
+ });
+ }
+ function draw_api_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#api_log') ) {
+ $('#api_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#api_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/api",
+ dataSrc: function(data){
+ return process_table_data(data, 'apilog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: 'URI',
+ data: 'uri',
+ defaultContent: '',
+ className: 'dtr-col-md dtr-break-all'
+ },
+ {
+ title: 'Method',
+ data: 'method',
+ defaultContent: ''
+ },
+ {
+ title: 'IP',
+ data: 'remote',
+ defaultContent: ''
+ },
+ {
+ title: 'Data',
+ data: 'data',
+ defaultContent: '',
+ className: 'dtr-col-md dtr-break-all'
+ }
+ ]
+ });
+ }
+ function draw_rl_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#rl_log') ) {
+ $('#rl_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#rl_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/ratelimited",
+ dataSrc: function(data){
+ return process_table_data(data, 'rllog');
+ }
+ },
+ columns: [
+ {
+ title: ' ',
+ data: 'indicator',
+ defaultContent: ''
+ },
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.rate_name,
+ data: 'rl_name',
+ defaultContent: ''
+ },
+ {
+ title: lang.sender,
+ data: 'from',
+ defaultContent: ''
+ },
+ {
+ title: lang.recipients,
+ data: 'rcpt',
+ defaultContent: ''
+ },
+ {
+ title: lang.authed_user,
+ data: 'user',
+ defaultContent: ''
+ },
+ {
+ title: 'Msg ID',
+ data: 'message_id',
+ defaultContent: ''
+ },
+ {
+ title: 'Header From',
+ data: 'header_from',
+ defaultContent: ''
+ },
+ {
+ title: 'Subject',
+ data: 'header_subject',
+ defaultContent: ''
+ },
+ {
+ title: 'Hash',
+ data: 'rl_hash',
+ defaultContent: ''
+ },
+ {
+ title: 'Rspamd QID',
+ data: 'qid',
+ defaultContent: ''
+ },
+ {
+ title: 'IP',
+ data: 'ip',
+ defaultContent: ''
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ defaultContent: ''
+ }
+ ]
+ });
+ }
+ function draw_ui_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#ui_logs') ) {
+ $('#ui_logs').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#ui_logs').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/ui",
+ dataSrc: function(data){
+ return process_table_data(data, 'mailcow_ui');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: 'Type',
+ data: 'type',
+ defaultContent: ''
+ },
+ {
+ title: 'Task',
+ data: 'task',
+ defaultContent: ''
+ },
+ {
+ title: 'User',
+ data: 'user',
+ defaultContent: '',
+ className: 'dtr-col-sm'
+ },
+ {
+ title: 'Role',
+ data: 'role',
+ defaultContent: '',
+ className: 'dtr-col-sm'
+ },
+ {
+ title: 'IP',
+ data: 'remote',
+ defaultContent: '',
+ className: 'dtr-col-md dtr-break-all'
+ },
+ {
+ title: lang.message,
+ data: 'msg',
+ defaultContent: '',
+ className: 'dtr-col-md dtr-break-all'
+ },
+ {
+ title: 'Call',
+ data: 'call',
+ defaultContent: '',
+ className: 'none dtr-col-md dtr-break-all'
+ }
+ ]
+ });
+ }
+ function draw_sasl_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#sasl_logs') ) {
+ $('#sasl_logs').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#sasl_logs').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/sasl",
+ dataSrc: function(data){
+ return process_table_data(data, 'sasl_log_table');
+ }
+ },
+ columns: [
+ {
+ title: lang.username,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: lang.service,
+ data: 'service',
+ defaultContent: ''
+ },
+ {
+ title: 'IP',
+ data: 'real_rip',
+ defaultContent: '',
+ className: 'dtr-col-md text-break'
+ },
+ {
+ title: lang.login_time,
+ data: 'datetime',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ cellData = Math.floor((new Date(data.replace(/-/g, "/"))).getTime() / 1000);
+ createSortableDate(td, cellData)
+ }
+ }
+ ]
+ });
+ }
+ function draw_acme_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#acme_log') ) {
+ $('#acme_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#acme_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/acme",
+ dataSrc: function(data){
+ return process_table_data(data, 'general_syslog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: '',
+ className: 'dtr-col-md dtr-break-all'
+ }
+ ]
+ });
+ }
+ function draw_netfilter_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#netfilter_log') ) {
+ $('#netfilter_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#netfilter_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/netfilter",
+ dataSrc: function(data){
+ return process_table_data(data, 'general_syslog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.priority,
+ data: 'priority',
+ defaultContent: ''
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: '',
+ className: 'dtr-col-md text-break'
+ }
+ ]
+ });
+ }
+ function draw_sogo_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#sogo_log') ) {
+ $('#sogo_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#sogo_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/sogo",
+ dataSrc: function(data){
+ return process_table_data(data, 'general_syslog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.priority,
+ data: 'priority',
+ defaultContent: ''
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: '',
+ className: 'dtr-col-md text-break'
+ }
+ ]
+ });
+ }
+ function draw_dovecot_logs() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#dovecot_log') ) {
+ $('#dovecot_log').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#dovecot_log').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/dovecot",
+ dataSrc: function(data){
+ return process_table_data(data, 'general_syslog');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: lang.priority,
+ data: 'priority',
+ defaultContent: ''
+ },
+ {
+ title: lang.message,
+ data: 'message',
+ defaultContent: '',
+ className: 'dtr-col-md text-break'
+ }
+ ]
+ });
+ }
+ function rspamd_pie_graph() {
+ $.ajax({
+ url: '/api/v1/get/rspamd/actions',
+ async: true,
+ success: function(data){
+ console.log(data);
+
+ var total = 0;
+ $(data).map(function(){total += this[1];});
+ var labels = $.makeArray($(data).map(function(){return this[0] + ' ' + Math.round(this[1]/total * 100) + '%';}));
+ var values = $.makeArray($(data).map(function(){return this[1];}));
+ console.log(values);
+
+ var graphdata = {
+ labels: labels,
+ datasets: [{
+ data: values,
+ backgroundColor: ['#DC3023', '#59ABE3', '#FFA400', '#FFA400', '#26A65B']
+ }]
+ };
+
+ var options = {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ datalabels: {
+ color: '#FFF',
+ font: {
+ weight: 'bold'
+ },
+ display: function(context) {
+ return context.dataset.data[context.dataIndex] !== 0;
+ },
+ formatter: function(value, context) {
+ return Math.round(value/total*100) + '%';
+ }
+ }
+ }
+ };
+ var chartcanvas = document.getElementById('rspamd_donut');
+ Chart.register('ChartDataLabels');
+ if(typeof chart == 'undefined') {
+ chart = new Chart(chartcanvas.getContext("2d"), {
+ plugins: [ChartDataLabels],
+ type: 'doughnut',
+ data: graphdata,
+ options: options
+ });
+ }
+ else {
+ chart.destroy();
+ chart = new Chart(chartcanvas.getContext("2d"), {
+ plugins: [ChartDataLabels],
+ type: 'doughnut',
+ data: graphdata,
+ options: options
+ });
+ }
+ }
+ });
+ }
+ function draw_rspamd_history() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#rspamd_history') ) {
+ $('#rspamd_history').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#rspamd_history').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ order: [[0, 'desc']],
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/logs/rspamd-history",
+ dataSrc: function(data){
+ return process_table_data(data, 'rspamd_history');
+ }
+ },
+ columns: [
+ {
+ title: lang.time,
+ data: 'unix_time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ createSortableDate(td, cellData)
+ }
+ },
+ {
+ title: 'IP address',
+ data: 'ip',
+ defaultContent: ''
+ },
+ {
+ title: 'From',
+ data: 'sender_mime',
+ defaultContent: ''
+ },
+ {
+ title: 'To',
+ data: 'rcpt',
+ defaultContent: ''
+ },
+ {
+ title: 'Subject',
+ data: 'subject',
+ defaultContent: ''
+ },
+ {
+ title: 'Action',
+ data: 'action',
+ defaultContent: ''
+ },
+ {
+ title: 'Score',
+ data: 'score',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ $(td).attr({
+ "data-order": cellData.sortBy,
+ "data-sort": cellData.sortBy
+ });
+ $(td).html(cellData.value);
+ }
+ },
+ {
+ title: 'Symbols',
+ data: 'symbols',
+ defaultContent: '',
+ className: 'none dtr-col-md'
+ },
+ {
+ title: 'Msg size',
+ data: 'size',
+ defaultContent: ''
+ },
+ {
+ title: 'Scan Time',
+ data: 'scan_time',
+ defaultContent: '',
+ createdCell: function(td, cellData) {
+ $(td).attr({
+ "data-order": cellData.sortBy,
+ "data-sort": cellData.sortBy
+ });
+ $(td).html(cellData.value);
+ }
+ },
+ {
+ title: 'ID',
+ data: 'message-id',
+ defaultContent: ''
+ },
+ {
+ title: 'Authenticated user',
+ data: 'user',
+ defaultContent: ''
+ }
+ ]
+ });
+ }
+ function process_table_data(data, table) {
+ if (table == 'rspamd_history') {
+ $.each(data, function (i, item) {
+ if (item.rcpt_mime != "") {
+ item.rcpt = escapeHtml(item.rcpt_mime.join(", "));
+ }
+ else {
+ item.rcpt = escapeHtml(item.rcpt_smtp.join(", "));
+ }
+ item.symbols = Object.keys(item.symbols).sort(function (a, b) {
+ if (item.symbols[a].score === 0) return 1
+ if (item.symbols[b].score === 0) return -1
+ if (item.symbols[b].score < 0 && item.symbols[a].score < 0) {
+ return item.symbols[a].score - item.symbols[b].score
+ }
+ if (item.symbols[b].score > 0 && item.symbols[a].score > 0) {
+ return item.symbols[b].score - item.symbols[a].score
+ }
+ return item.symbols[b].score - item.symbols[a].score
+ }).map(function(key) {
+ var sym = item.symbols[key];
+ if (sym.score < 0) {
+ sym.score_formatted = '(<span class="text-success"><b>' + sym.score + '</b></span>)'
+ }
+ else if (sym.score === 0) {
+ sym.score_formatted = '(<span><b>' + sym.score + '</b></span>)'
+ }
+ else {
+ sym.score_formatted = '(<span class="text-danger"><b>' + sym.score + '</b></span>)'
+ }
+ var str = '<strong>' + key + '</strong> ' + sym.score_formatted;
+ if (sym.options) {
+ str += ' [' + escapeHtml(sym.options.join(", ")) + "]";
+ }
+ return str
+ }).join('<br>\n');
+ item.subject = escapeHtml(item.subject);
+ var scan_time = item.time_real.toFixed(3);
+ if (item.time_virtual) {
+ scan_time += ' / ' + item.time_virtual.toFixed(3);
+ }
+ item.scan_time = {
+ "sortBy": item.time_real,
+ "value": scan_time
+ };
+ if (item.action === 'clean' || item.action === 'no action') {
+ item.action = "<div class='badge fs-6 bg-success'>" + item.action + "</div>";
+ } else if (item.action === 'rewrite subject' || item.action === 'add header' || item.action === 'probable spam') {
+ item.action = "<div class='badge fs-6 bg-warning'>" + item.action + "</div>";
+ } else if (item.action === 'spam' || item.action === 'reject') {
+ item.action = "<div class='badge fs-6 bg-danger'>" + item.action + "</div>";
+ } else {
+ item.action = "<div class='badge fs-6 bg-info'>" + item.action + "</div>";
+ }
+ var score_content;
+ if (item.score < item.required_score) {
+ score_content = "[ <span class='text-success'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+ } else {
+ score_content = "[ <span class='text-danger'>" + item.score.toFixed(2) + " / " + item.required_score + "</span> ]";
+ }
+ item.score = {
+ "sortBy": item.score,
+ "value": score_content
+ };
+ if (item.user == null) {
+ item.user = "none";
+ }
+ });
+ } else if (table == 'autodiscover_log') {
+ $.each(data, function (i, item) {
+ if (item.ua == null) {
+ item.ua = 'unknown';
+ } else {
+ item.ua = escapeHtml(item.ua);
+ }
+ item.ua = '<span style="font-size:small">' + item.ua + '</span>';
+ if (item.service == "activesync") {
+ item.service = '<span class="badge fs-6 bg-info">ActiveSync</span>';
+ }
+ else if (item.service == "imap") {
+ item.service = '<span class="badge fs-6 bg-success">IMAP, SMTP, Cal-/CardDAV</span>';
+ }
+ else {
+ item.service = '<span class="badge fs-6 bg-danger">' + escapeHtml(item.service) + '</span>';
+ }
+ });
+ } else if (table == 'watchdog') {
+ $.each(data, function (i, item) {
+ if (item.message == null) {
+ item.message = 'Health level: ' + item.lvl + '% (' + item.hpnow + '/' + item.hptotal + ')';
+ if (item.hpdiff < 0) {
+ item.trend = '<span class="badge fs-6 bg-danger"><i class="bi bi-caret-down-fill"></i> ' + item.hpdiff + '</span>';
+ }
+ else if (item.hpdiff == 0) {
+ item.trend = '<span class="badge fs-6 bg-info"><i class="bi bi-caret-right-fill"></i> ' + item.hpdiff + '</span>';
+ }
+ else {
+ item.trend = '<span class="badge fs-6 bg-success"><i class="bi bi-caret-up-fill"></i> ' + item.hpdiff + '</span>';
+ }
+ }
+ else {
+ item.trend = '';
+ item.service = '';
+ }
+ });
+ } else if (table == 'mailcow_ui') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ item.user = escapeHtml(item.user);
+ item.call = escapeHtml(item.call);
+ item.task = '<code>' + item.task + '</code>';
+ item.type = '<span class="badge fs-6 bg-' + item.type + '">' + item.type + '</span>';
+ });
+ } else if (table == 'sasl_log_table') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ item.username = escapeHtml(item.username);
+ item.service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>';
+ });
+ } else if (table == 'general_syslog') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ if (item.message.match("^base64,")) {
+ try {
+ item.message = atob(item.message.slice(7)).replace(/\\n/g, "<br />");
+ } catch(e) {
+ item.message = item.message.slice(7);
+ }
+ } else {
+ item.message = escapeHtml(item.message);
+ }
+ item.call = escapeHtml(item.call);
+ var danger_class = ["emerg", "alert", "crit", "err"];
+ var warning_class = ["warning", "warn"];
+ var info_class = ["notice", "info", "debug"];
+ if (jQuery.inArray(item.priority, danger_class) !== -1) {
+ item.priority = '<span class="badge fs-6 bg-danger">' + item.priority + '</span>';
+ } else if (jQuery.inArray(item.priority, warning_class) !== -1) {
+ item.priority = '<span class="badge fs-6 bg-warning">' + item.priority + '</span>';
+ } else if (jQuery.inArray(item.priority, info_class) !== -1) {
+ item.priority = '<span class="badge fs-6 bg-info">' + item.priority + '</span>';
+ }
+ });
+ } else if (table == 'apilog') {
+ $.each(data, function (i, item) {
+ if (item === null) { return true; }
+ if (item.method == 'GET') {
+ item.method = '<span class="badge fs-6 bg-success">' + item.method + '</span>';
+ } else if (item.method == 'POST') {
+ item.method = '<span class="badge fs-6 bg-warning">' + item.method + '</span>';
+ }
+ item.data = escapeHtml(item.data);
+ });
+ } else if (table == 'rllog') {
+ $.each(data, function (i, item) {
+ if (item.user == null) {
+ item.user = "none";
+ }
+ if (item.rl_hash == null) {
+ item.rl_hash = "err";
+ }
+ item.indicator = '<span style="border-right:6px solid #' + intToRGB(hashCode(item.rl_hash)) + ';padding-left:5px;"> </span>';
+ if (item.rl_hash != 'err') {
+ item.action = '<a href="#" data-action="delete_selected" data-id="single-hash" data-api-url="delete/rlhash" data-item="' + encodeURI(item.rl_hash) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.reset_limit + '</a>';
+ }
+ });
+ }
+ return data
+ };
+ $('.add_log_lines').on('click', function (e) {
+ e.preventDefault();
+ var log_table= $(this).data("table")
+ var new_nrows = $(this).data("nrows")
+ var post_process = $(this).data("post-process")
+ var log_url = $(this).data("log-url")
+ if (log_table === undefined || new_nrows === undefined || post_process === undefined || log_url === undefined) {
+ console.log("no data-table or data-nrows or log_url or data-post-process attr found");
+ return;
+ }
+
+ if (table = $('#' + log_table).DataTable()) {
+ var heading = $('#' + log_table).closest('.card').find('.card-header');
+ var load_rows = (table.page.len() + 1) + '-' + (table.page.len() + new_nrows)
+
+ $.get('/api/v1/get/logs/' + log_url + '/' + load_rows).then(function(data){
+ if (data.length === undefined) { mailcow_alert_box(lang.no_new_rows, "info"); return; }
+ var rows = process_table_data(data, post_process);
+ var rows_now = (table.page.len() + data.length);
+ $(heading).children('.table-lines').text(rows_now)
+ mailcow_alert_box(data.length + lang.additional_rows, "success");
+ table.rows.add(rows).draw();
+ });
+ }
+ })
+
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
+
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+ // Draw Table if tab is active
+ onVisible("[id^=postfix_log]", () => draw_postfix_logs());
+ onVisible("[id^=dovecot_log]", () => draw_dovecot_logs());
+ onVisible("[id^=sogo_log]", () => draw_sogo_logs());
+ onVisible("[id^=watchdog_log]", () => draw_watchdog_logs());
+ onVisible("[id^=autodiscover_log]", () => draw_autodiscover_logs());
+ onVisible("[id^=acme_log]", () => draw_acme_logs());
+ onVisible("[id^=api_log]", () => draw_api_logs());
+ onVisible("[id^=rl_log]", () => draw_rl_logs());
+ onVisible("[id^=ui_logs]", () => draw_ui_logs());
+ onVisible("[id^=sasl_logs]", () => draw_sasl_logs());
+ onVisible("[id^=netfilter_log]", () => draw_netfilter_logs());
+ onVisible("[id^=rspamd_history]", () => draw_rspamd_history());
+ onVisible("[id^=rspamd_donut]", () => rspamd_pie_graph());
+
+
+
+ // start polling host stats if tab is active
+ onVisible("[id^=tab-containers]", () => update_stats());
+ // start polling container stats if collapse is active
+ var containerElements = document.querySelectorAll(".container-details-collapse");
+ for (let i = 0; i < containerElements.length; i++){
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+
+ if (!containerElements[i].classList.contains("show")){
+ var container = containerElements[i].id.replace("Collapse", "");
+ var container_id = containerElements[i].getAttribute("data-id");
+
+ // check if chart exists or needs to be created
+ if (!Chart.getChart(container + "_DiskIOChart"))
+ createReadWriteChart(container + "_DiskIOChart", "Read", "Write");
+ if (!Chart.getChart(container + "_NetIOChart"))
+ createReadWriteChart(container + "_NetIOChart", "Recv", "Sent");
+
+ // add container to polling list
+ containersToUpdate[container] = {
+ id: container_id,
+ state: "idle"
+ }
+
+ // stop polling if collapse is closed
+ containerElements[i].addEventListener('hidden.bs.collapse', function () {
+ var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
+ var netIOCtx = Chart.getChart(container + "_NetIOChart");
+
+ diskIOCtx.data.datasets[0].data = [];
+ diskIOCtx.data.datasets[1].data = [];
+ diskIOCtx.data.labels = [];
+ netIOCtx.data.datasets[0].data = [];
+ netIOCtx.data.datasets[1].data = [];
+ netIOCtx.data.labels = [];
+
+ diskIOCtx.update();
+ netIOCtx.update();
+
+ delete containersToUpdate[container];
+ });
+ }
+
+ }
+ });
+ }).observe(containerElements[i]);
+ }
+});
+
+
+// update system stats - every 5 seconds if system & container tab is active
+function update_stats(timeout=5){
+ if (!$('#tab-containers').hasClass('active')) {
+ // tab not active - dont fetch stats - run again in n seconds
+ return;
+ }
+
+ window.fetch("/api/v1/get/status/host", {method:'GET',cache:'no-cache'}).then(function(response) {
+ return response.json();
+ }).then(function(data) {
+ console.log(data);
+
+ if (data){
+ // display table data
+ $("#host_date").text(data.system_time);
+ $("#host_uptime").text(formatUptime(data.uptime));
+ $("#host_cpu_cores").text(data.cpu.cores);
+ $("#host_cpu_usage").text(parseInt(data.cpu.usage).toString() + "%");
+ $("#host_memory_total").text((data.memory.total / (1024 ** 3)).toFixed(2).toString() + "GB");
+ $("#host_memory_usage").text(parseInt(data.memory.usage).toString() + "%");
+
+ // update cpu and mem chart
+ var cpu_chart = Chart.getChart("host_cpu_chart");
+ var mem_chart = Chart.getChart("host_mem_chart");
+
+ cpu_chart.data.labels.push(data.system_time.split(" ")[1]);
+ if (cpu_chart.data.labels.length > 30) cpu_chart.data.labels.shift();
+ mem_chart.data.labels.push(data.system_time.split(" ")[1]);
+ if (mem_chart.data.labels.length > 30) mem_chart.data.labels.shift();
+
+ cpu_chart.data.datasets[0].data.push(data.cpu.usage);
+ if (cpu_chart.data.datasets[0].data.length > 30) cpu_chart.data.datasets[0].data.shift();
+ mem_chart.data.datasets[0].data.push(data.memory.usage);
+ if (mem_chart.data.datasets[0].data.length > 30) mem_chart.data.datasets[0].data.shift();
+
+ cpu_chart.update();
+ mem_chart.update();
+ }
+
+ // run again in n seconds
+ setTimeout(update_stats, timeout * 1000);
+ });
+}
+// update specific container stats - every n (default 5s) seconds
+function update_container_stats(timeout=5){
+
+ if ($('#tab-containers').hasClass('active')) {
+ for (let container in containersToUpdate){
+ container_id = containersToUpdate[container].id;
+ // check if container update stats is already running
+ if (containersToUpdate[container].state == "running")
+ continue;
+ containersToUpdate[container].state = "running";
+
+
+ window.fetch("/api/v1/get/status/container/" + container_id, {method:'GET',cache:'no-cache'}).then(function(response) {
+ return response.json();
+ }).then(function(data) {
+ var diskIOCtx = Chart.getChart(container + "_DiskIOChart");
+ var netIOCtx = Chart.getChart(container + "_NetIOChart");
+
+ console.log(container);
+ console.log(data);
+ prev_stats = null;
+ if (data.length >= 2){
+ prev_stats = data[data.length -2];
+
+ // hide spinners if we collected enough data
+ $('#' + container + "_DiskIOChart").removeClass('d-none');
+ $('#' + container + "_DiskIOChart").prev().addClass('d-none');
+ $('#' + container + "_NetIOChart").removeClass('d-none');
+ $('#' + container + "_NetIOChart").prev().addClass('d-none');
+ }
+
+ data = data[data.length -1];
+
+ if (prev_stats != null){
+ // calc time diff
+ var time_diff = (new Date(data.read) - new Date(prev_stats.read)) / 1000;
+
+ // calc disk io b/s
+ if ('io_service_bytes_recursive' in prev_stats.blkio_stats && prev_stats.blkio_stats.io_service_bytes_recursive !== null){
+ var prev_read_bytes = 0;
+ var prev_write_bytes = 0;
+ for (var i = 0; i < prev_stats.blkio_stats.io_service_bytes_recursive.length; i++){
+ if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "read")
+ prev_read_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
+ else if (prev_stats.blkio_stats.io_service_bytes_recursive[i].op == "write")
+ prev_write_bytes = prev_stats.blkio_stats.io_service_bytes_recursive[i].value;
+ }
+ var read_bytes = 0;
+ var write_bytes = 0;
+ for (var i = 0; i < data.blkio_stats.io_service_bytes_recursive.length; i++){
+ if (data.blkio_stats.io_service_bytes_recursive[i].op == "read")
+ read_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
+ else if (data.blkio_stats.io_service_bytes_recursive[i].op == "write")
+ write_bytes = data.blkio_stats.io_service_bytes_recursive[i].value;
+ }
+ var diff_bytes_read = (read_bytes - prev_read_bytes) / time_diff;
+ var diff_bytes_write = (write_bytes - prev_write_bytes) / time_diff;
+ }
+
+ // calc net io b/s
+ if ('networks' in prev_stats){
+ var prev_recv_bytes = 0;
+ var prev_sent_bytes = 0;
+ for (var key in prev_stats.networks){
+ prev_recv_bytes += prev_stats.networks[key].rx_bytes;
+ prev_sent_bytes += prev_stats.networks[key].tx_bytes;
+ }
+ var recv_bytes = 0;
+ var sent_bytes = 0;
+ for (var key in data.networks){
+ recv_bytes += data.networks[key].rx_bytes;
+ sent_bytes += data.networks[key].tx_bytes;
+ }
+ var diff_bytes_recv = (recv_bytes - prev_recv_bytes) / time_diff;
+ var diff_bytes_sent = (sent_bytes - prev_sent_bytes) / time_diff;
+ }
+
+ addReadWriteChart(diskIOCtx, diff_bytes_read, diff_bytes_write, "");
+ addReadWriteChart(netIOCtx, diff_bytes_recv, diff_bytes_sent, "");
+ }
+
+ // run again in n seconds
+ containersToUpdate[container].state = "idle";
+ }).catch(err => {
+ console.log(err);
+ });
+ }
+ }
+
+ // run again in n seconds
+ setTimeout(update_container_stats, timeout * 1000);
+}
+// get public ips
+function get_public_ips(){
+ window.fetch("/api/v1/get/status/host/ip", {method:'GET',cache:'no-cache'}).then(function(response) {
+ return response.json();
+ }).then(function(data) {
+ console.log(data);
+
+ // display host ips
+ if (data.ipv4)
+ $("#host_ipv4").text(data.ipv4);
+ if (data.ipv6)
+ $("#host_ipv6").text(data.ipv6);
+ });
+}
+// format hosts uptime seconds to readable string
+function formatUptime(seconds){
+ seconds = Number(seconds);
+ var d = Math.floor(seconds / (3600*24));
+ var h = Math.floor(seconds % (3600*24) / 3600);
+ var m = Math.floor(seconds % 3600 / 60);
+ var s = Math.floor(seconds % 60);
+
+ var dFormat = d > 0 ? d + "D " : "";
+ var hFormat = h > 0 ? h + "H " : "";
+ var mFormat = m > 0 ? m + "M " : "";
+ var sFormat = s > 0 ? s + "S" : "";
+ return dFormat + hFormat + mFormat + sFormat;
+}
+// format bytes to readable string
+function formatBytes(bytes){
+ // b
+ if (bytes < 1000) return bytes.toFixed(2).toString()+' B/s';
+ // b to kb
+ bytes = bytes / 1024;
+ if (bytes < 1000) return bytes.toFixed(2).toString()+' KB/s';
+ // kb to mb
+ bytes = bytes / 1024;
+ if (bytes < 1000) return bytes.toFixed(2).toString()+' MB/s';
+ // final mb to gb
+ return (bytes / 1024).toFixed(2).toString()+' GB/s';
+}
+// create read write line chart
+function createReadWriteChart(chart_id, read_lable, write_lable){
+ var ctx = document.getElementById(chart_id);
+
+ var dataNet = {
+ labels: [],
+ datasets: [{
+ label: read_lable,
+ backgroundColor: "rgba(41, 187, 239, 0.3)",
+ borderColor: "rgba(41, 187, 239, 0.6)",
+ pointRadius: 1,
+ pointHitRadius: 6,
+ borderWidth: 2,
+ fill: true,
+ tension: 0.2,
+ data: []
+ }, {
+ label: write_lable,
+ backgroundColor: "rgba(239, 60, 41, 0.3)",
+ borderColor: "rgba(239, 60, 41, 0.6)",
+ pointRadius: 1,
+ pointHitRadius: 6,
+ borderWidth: 2,
+ fill: true,
+ tension: 0.2,
+ data: []
+ }]
+ };
+ var optionsNet = {
+ interaction: {
+ mode: 'index'
+ },
+ scales: {
+ yAxis: {
+ min: 0,
+ grid: {
+ display: false
+ },
+ ticks: {
+ callback: function(i, index, ticks) {
+ return formatBytes(i);
+ }
+ }
+ },
+ xAxis: {
+ grid: {
+ display: false
+ }
+ }
+ }
+ };
+
+ return new Chart(ctx, {
+ type: 'line',
+ data: dataNet,
+ options: optionsNet
+ });
+}
+// add to read write line chart
+function addReadWriteChart(chart_context, read_point, write_point, time, limit = 30){
+ // push time label for x-axis
+ chart_context.data.labels.push(time);
+ if (chart_context.data.labels.length > limit) chart_context.data.labels.shift();
+
+ // push datapoints
+ chart_context.data.datasets[0].data.push(read_point);
+ chart_context.data.datasets[1].data.push(write_point);
+ // shift data if more than 20 entires exists
+ if (chart_context.data.datasets[0].data.length > limit) chart_context.data.datasets[0].data.shift();
+ if (chart_context.data.datasets[1].data.length > limit) chart_context.data.datasets[1].data.shift();
+
+ chart_context.update();
+}
+// create host cpu and mem chart
+function createHostCpuAndMemChart(){
+ var cpu_ctx = document.getElementById("host_cpu_chart");
+ var mem_ctx = document.getElementById("host_mem_chart");
+
+ var dataCpu = {
+ labels: [],
+ datasets: [{
+ label: "CPU %",
+ backgroundColor: "rgba(41, 187, 239, 0.3)",
+ borderColor: "rgba(41, 187, 239, 0.6)",
+ pointRadius: 1,
+ pointHitRadius: 6,
+ borderWidth: 2,
+ fill: true,
+ tension: 0.2,
+ data: []
+ }]
+ };
+ var optionsCpu = {
+ interaction: {
+ mode: 'index'
+ },
+ scales: {
+ yAxis: {
+ min: 0,
+ grid: {
+ display: false
+ },
+ ticks: {
+ callback: function(i, index, ticks) {
+ return i.toFixed(0).toString() + "%";
+ }
+ }
+ },
+ xAxis: {
+ grid: {
+ display: false
+ }
+ }
+ }
+ };
+
+ var dataMem = {
+ labels: [],
+ datasets: [{
+ label: "MEM %",
+ backgroundColor: "rgba(41, 187, 239, 0.3)",
+ borderColor: "rgba(41, 187, 239, 0.6)",
+ pointRadius: 1,
+ pointHitRadius: 6,
+ borderWidth: 2,
+ fill: true,
+ tension: 0.2,
+ data: []
+ }]
+ };
+ var optionsMem = {
+ interaction: {
+ mode: 'index'
+ },
+ scales: {
+ yAxis: {
+ min: 0,
+ grid: {
+ display: false
+ },
+ ticks: {
+ callback: function(i, index, ticks) {
+ return i.toFixed(0).toString() + "%";
+ }
+ }
+ },
+ xAxis: {
+ grid: {
+ display: false
+ }
+ }
+ }
+ };
+
+
+ var net_io_chart = new Chart(cpu_ctx, {
+ type: 'line',
+ data: dataCpu,
+ options: optionsCpu
+ });
+ var disk_io_chart = new Chart(mem_ctx, {
+ type: 'line',
+ data: dataMem,
+ options: optionsMem
+ });
+}
+// check for mailcow updates
+function check_update(current_version, github_repo_url){
+ if (!current_version || !github_repo_url) return false;
+
+ var github_account = github_repo_url.split("/")[3];
+ var github_repo_name = github_repo_url.split("/")[4];
+
+ // get details about latest release
+ window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/latest", {method:'GET',cache:'no-cache'}).then(function(response) {
+ return response.json();
+ }).then(function(latest_data) {
+ // get details about current release
+ window.fetch("https://api.github.com/repos/"+github_account+"/"+github_repo_name+"/releases/tags/"+current_version, {method:'GET',cache:'no-cache'}).then(function(response) {
+ return response.json();
+ }).then(function(current_data) {
+ // compare releases
+ var date_current = new Date(current_data.created_at);
+ var date_latest = new Date(latest_data.created_at);
+ if (date_latest.getTime() <= date_current.getTime()){
+ // no update available
+ $("#mailcow_update").removeClass("text-warning text-danger").addClass("text-success");
+ $("#mailcow_update").html("<b>" + lang_debug.no_update_available + "</b>");
+ } else {
+ // update available
+ $("#mailcow_update").removeClass("text-danger text-success").addClass("text-warning");
+ $("#mailcow_update").html(lang_debug.update_available + ` <a href="#" id="mailcow_update_changelog">`+latest_data.tag_name+`</a>`);
+ $("#mailcow_update_changelog").click(function(){
+ if (mailcow_cc_role !== "admin" && mailcow_cc_role !== "domainadmin")
+ return;
+
+ showVersionModal("New Release " + latest_data.tag_name, latest_data.tag_name);
+ })
+ }
+ }).catch(err => {
+ // err
+ console.log(err);
+ $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger");
+ $("#mailcow_update").html("<b>"+ lang_debug.update_failed +"</b>");
+ });
+ }).catch(err => {
+ // err
+ console.log(err);
+ $("#mailcow_update").removeClass("text-success text-warning").addClass("text-danger");
+ $("#mailcow_update").html("<b>"+ lang_debug.update_failed +"</b>");
+ });
+}
+// show version changelog modal
+function showVersionModal(title, version){
+ $.ajax({
+ type: 'GET',
+ url: 'https://api.github.com/repos/' + mailcow_info.project_owner + '/' + mailcow_info.project_repo + '/releases/tags/' + version,
+ dataType: 'json',
+ success: function (data) {
+ var md = window.markdownit();
+ var result = md.render(data.body);
+ result = parseGithubMarkdownLinks(result);
+
+ $('#showVersionModal').find(".modal-title").html(title);
+ $('#showVersionModal').find(".modal-body").html(`
+ <h3>` + data.name + `</h3>
+ <span class="mt-4">` + result + `</span>
+ <span><b>Github Link:</b>
+ <a target="_blank" href="https://github.com/` + mailcow_info.project_owner + `/` + mailcow_info.project_repo + `/releases/tag/` + version + `">` + version + `</a>
+ </span>
+ `);
+
+ new bootstrap.Modal(document.getElementById("showVersionModal"), {
+ backdrop: 'static',
+ keyboard: false
+ }).show();
+ }
+ });
+}
+function parseGithubMarkdownLinks(inputText) {
+ var replacedText, replacePattern1;
+
+ replacePattern1 = /(\b(https?):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
+ replacedText = inputText.replace(replacePattern1, (matched, index, original, input_string) => {
+ if (matched.includes('github.com')){
+ // return short link if it's github link
+ last_uri_path = matched.split('/');
+ last_uri_path = last_uri_path[last_uri_path.length - 1];
+
+ // adjust Full Changelog link to match last git version and new git version, if link is a compare link
+ if (matched.includes('/compare/') && mailcow_info.last_version_tag !== ''){
+ matched = matched.replace(last_uri_path, mailcow_info.last_version_tag + '...' + mailcow_info.version_tag);
+ last_uri_path = mailcow_info.last_version_tag + '...' + mailcow_info.version_tag;
+ }
+
+ return '<a href="' + matched + '" target="_blank">' + last_uri_path + '</a><br>';
+ };
+
+ // if it's not a github link, return complete link
+ return '<a href="' + matched + '" target="_blank">' + matched + '</a>';
+ });
+
+ return replacedText;
+}
+
+function convertTimestampToLocalFormat(timestamp) {
+ var date = new Date(timestamp ? timestamp * 1000 : 0);
+ return date.toLocaleDateString(LOCALE, DATETIME_FORMAT);
+}
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/edit.js b/mailcow/src/mailcow-dockerized/data/web/js/site/edit.js
index 786a599..55a8e6b 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/edit.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/edit.js
@@ -57,6 +57,17 @@
$("#multiple_bookings_custom").bind("change keypress keyup blur", function() {
$('input[name=multiple_bookings]').val($("#multiple_bookings_custom").val());
});
+
+ // load tags
+ if ($('#tags').length){
+ var tagsEl = $('#tags').parent().find('.tag-values')[0];
+ console.log($(tagsEl).val())
+ var tags = JSON.parse($(tagsEl).val());
+ $(tagsEl).val("");
+
+ for (var i = 0; i < tags.length; i++)
+ addTag($('#tags'), tags[i]);
+ }
});
jQuery(function($){
@@ -66,22 +77,14 @@
return re.test(email);
}
function draw_wl_policy_domain_table() {
- ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_domain_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang_user.empty,
- "rows": $.ajax({
- dataType: 'json',
+ $('#wl_policy_domain_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_wl_domain/' + table_for_domain,
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy wl table');
- },
- success: function (data) {
+ dataSrc: function(data){
$.each(data, function (i, item) {
if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_domain" name="multi_select" value="' + item.prefid + '" />';
@@ -90,35 +93,53 @@
item.chkbox = '<input type="checkbox" disabled title="' + lang_user.spamfilter_table_domain_policy + '" />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang_user.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title: 'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_bl_policy_domain_table() {
- ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_domain_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang_user.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang_user.empty,
- "rows": $.ajax({
- dataType: 'json',
+ $('#bl_policy_domain_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_bl_domain/' + table_for_domain,
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy bl table');
- },
- success: function (data) {
+ dataSrc: function(data){
$.each(data, function (i, item) {
if (!validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_domain" name="multi_select" value="' + item.prefid + '" />';
@@ -127,18 +148,63 @@
item.chkbox = '<input type="checkbox" disabled tooltip="' + lang_user.spamfilter_table_domain_policy + '" />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang_user.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title: 'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
- draw_wl_policy_domain_table();
- draw_bl_policy_domain_table();
+
+
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
+
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ observer.disconnect();
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+ // Draw Table if tab is active
+ onVisible("[id^=wl_policy_domain_table]", () => draw_wl_policy_domain_table());
+ onVisible("[id^=bl_policy_domain_table]", () => draw_bl_policy_domain_table());
});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/index.js b/mailcow/src/mailcow-dockerized/data/web/js/site/index.js
index 1b3e56a..4c812a3 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/index.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/index.js
@@ -1,3 +1,5 @@
$(document).ready(function() {
+ var theme = localStorage.getItem("theme");
localStorage.clear();
+ localStorage.setItem("theme", theme);
});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/mailbox.js b/mailcow/src/mailcow-dockerized/data/web/js/site/mailbox.js
index 745c4f2..12c4bb4 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/mailbox.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/mailbox.js
@@ -1,75 +1,6 @@
$(document).ready(function() {
acl_data = JSON.parse(acl);
- FooTable.domainFilter = FooTable.Filtering.extend({
- construct: function(instance){
- this._super(instance);
- this.def = lang.all_domains;
- this.$domain = null;
- },
- $create: function(){
- this._super();
- var self = this;
- var domains = [];
-
- $.each(self.ft.rows.all, function(i, row){
- if((row.val().domain != null) && ($.inArray(row.val().domain, domains) === -1)) domains.push(row.val().domain);
- });
-
- $form_grp = $('<div/>', {'class': 'form-group'})
- .append($('<label/>', {'class': 'sr-only', text: 'Domain'}))
- .prependTo(self.$form);
- self.$domain = $('<select/>', { 'class': 'aform-control' })
- .on('change', {self: self}, self._onDomainDropdownChanged)
- .append($('<option/>', {text: self.def}))
- .appendTo($form_grp);
-
- $.each(domains, function(i, domain){
- domainname = $($.parseHTML(domain)).data('domainname')
- if (domainname !== undefined) {
- self.$domain.append($('<option/>').text(domainname));
- } else {
- self.$domain.append($('<option/>').text(domain));
- }
- });
- },
- _onDomainDropdownChanged: function(e){
- var self = e.data.self,
- selected = $(this).val();
- if (selected !== self.def){
- self.addFilter('domain', selected, ['domain']);
- } else {
- self.removeFilter('domain');
- }
- self.filter();
- },
- draw: function(){
- this._super();
- var domain = this.find('domain');
- if (domain instanceof FooTable.Filter){
- this.$domain.val(domain.query.val());
- } else {
- this.$domain.val(this.def);
- }
- $(this.$domain).closest("select").selectpicker();
- }
- });
// Set paging
- $('[data-page-size]').on('click', function(e){
- e.preventDefault();
- var new_size = $(this).data('page-size');
- var parent_ul = $(this).closest('ul');
- var table_id = $(parent_ul).data('table-id');
- FooTable.get('#' + table_id).pageSize(new_size);
- //$(this).parent().addClass('active').siblings().removeClass('active')
- heading = $(this).parents('.panel').find('.panel-heading')
- var n_results = $(heading).children('.table-lines').text().split(' / ')[1];
- $(heading).children('.table-lines').text(function(){
- if (new_size > n_results) {
- new_size = n_results;
- }
- return new_size + ' / ' + n_results;
- })
- });
// Clone mailbox mass actions
$("div").find("[data-actions-header='true'").each(function() {
$(this).html($(this).nextAll('.mass-actions-mailbox:first').html());
@@ -99,37 +30,6 @@
});
auto_fill_quota($('#addSelectDomain').val());
- // Read bcc local dests
- // Using ajax to not be a blocking moo
- $.get("/api/v1/get/bcc-destination-options", function(data){
- // Domains
- var optgroup = "<optgroup label='" + lang.domains + "'>";
- $.each(data.domains, function(index, domain){
- optgroup += "<option value='" + domain + "'>" + domain + "</option>"
- });
- optgroup += "</optgroup>"
- $('#bcc-local-dest').append(optgroup);
- // Alias domains
- var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
- $.each(data.alias_domains, function(index, alias_domain){
- optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
- });
- optgroup += "</optgroup>"
- $('#bcc-local-dest').append(optgroup);
- // Mailboxes and aliases
- $.each(data.mailboxes, function(mailbox, aliases){
- var optgroup = "<optgroup label='" + mailbox + "'>";
- $.each(aliases, function(index, alias){
- optgroup += "<option value='" + alias + "'>" + alias + "</option>"
- });
- optgroup += "</optgroup>"
- $('#bcc-local-dest').append(optgroup);
- });
- // Finish
- $('#bcc-local-dest').find('option:selected').remove();
- $('#bcc-local-dest').selectpicker('refresh');
- });
-
$(".goto_checkbox").click(function( event ) {
$("form[data-id='add_alias'] .goto_checkbox").not(this).prop('checked', false);
if ($("form[data-id='add_alias'] .goto_checkbox:checked").length > 0) {
@@ -165,7 +65,7 @@
// Log modal
$('#dnsInfoModal').on('show.bs.modal', function(e) {
var domain = $(e.relatedTarget).data('domain');
- $('.dns-modal-body').html('<center><i class="bi bi-arrow-repeat icon-spin"></i></center>');
+ $('.dns-modal-body').html('<div class="spinner-border" role="status"><span class="visually-hidden">Loading...</span></div>');
$.ajax({
url: '/inc/ajax/dns_diagnostics.php',
data: { domain: domain },
@@ -177,6 +77,90 @@
$('.dns-modal-body').html(xhr.responseText);
}
});
+ });
+ // @Open Domain add modal
+ $('#addDomainModal').on('show.bs.modal', function(e) {
+ $.ajax({
+ url: '/api/v1/get/domain/template/all',
+ data: {},
+ dataType: 'json',
+ success: async function(data){
+ $('#domain_templates').find('option').remove();
+ $('#domain_templates').selectpicker('destroy');
+ $('#domain_templates').selectpicker();
+ for (var i = 0; i < data.length; i++){
+ if (data[i].template === "Default"){
+ $('#domain_templates').prepend($('<option>', {
+ 'value': data[i].id,
+ 'text': data[i].template,
+ 'data-attributes': JSON.stringify(data[i].attributes),
+ 'selected': true
+ }));
+ setDomainTemplateData(data[i].attributes);
+ } else {
+ $('#domain_templates').append($('<option>', {
+ 'value': data[i].id,
+ 'text': data[i].template,
+ 'data-attributes': JSON.stringify(data[i].attributes),
+ 'selected': false
+ }));
+ }
+ };
+ $('#domain_templates').selectpicker("refresh");
+
+ // @selecting template
+ $('#domain_templates').on('change', function(){
+ var selected = $('#domain_templates option:selected');
+ var attr = selected.data('attributes');
+ setDomainTemplateData(attr);
+ });
+ },
+ error: function(xhr, status, error) {
+ console.log(error);
+ }
+ });
+ });
+ // @Open Mailbox add modal
+ $('#addMailboxModal').on('show.bs.modal', function(e) {
+ $.ajax({
+ url: '/api/v1/get/mailbox/template/all',
+ data: {},
+ dataType: 'json',
+ success: async function(data){
+ $('#mailbox_templates').find('option').remove();
+ $('#mailbox_templates').selectpicker('destroy');
+ $('#mailbox_templates').selectpicker();
+ for (var i = 0; i < data.length; i++){
+ if (data[i].template === "Default"){
+ $('#mailbox_templates').prepend($('<option>', {
+ 'value': data[i].id,
+ 'text': data[i].template,
+ 'data-attributes': JSON.stringify(data[i].attributes),
+ 'selected': true
+ }));
+ setMailboxTemplateData(data[i].attributes);
+ } else {
+ $('#mailbox_templates').append($('<option>', {
+ value: data[i].id,
+ text : data[i].template,
+ 'data-attributes': JSON.stringify(data[i].attributes),
+ 'selected': false
+ }));
+ }
+ };
+ $('#mailbox_templates').selectpicker("refresh");
+
+ // @selecting template
+ $('#mailbox_templates').on('change', function(){
+ var selected = $('#mailbox_templates option:selected');
+ var attr = selected.data('attributes');
+ setMailboxTemplateData(attr);
+ });
+ },
+ error: function(xhr, status, error) {
+ console.log(error);
+ }
+ });
});
// Sieve data modal
$('#sieveDataModal').on('show.bs.modal', function(e) {
@@ -233,204 +217,614 @@
$("#multiple_bookings").val($("#multiple_bookings_custom").val());
});
+ function setDomainTemplateData(template){
+ $("#addDomain_max_aliases").val(template.max_num_aliases_for_domain);
+ $("#addDomain_max_mailboxes").val(template.max_num_mboxes_for_domain);
+ $("#addDomain_mailbox_quota_def").val(template.def_quota_for_mbox / 1048576);
+ $("#addDomain_mailbox_quota_m").val(template.max_quota_for_mbox / 1048576);
+ $("#addDomain_domain_quota_m").val(template.max_quota_for_domain / 1048576);
+ if (template.gal == 1){
+ $('#addDomain_gal').prop('checked', true);
+ } else {
+ $('#addDomain_gal').prop('checked', false);
+ }
+
+ if (template.active == 1){
+ $('#addDomain_active').prop('checked', true);
+ } else {
+ $('#addDomain_active').prop('checked', false);
+ }
+
+ $("#addDomain_rl_value").val(template.rl_value);
+ $('#addDomain_rl_frame').selectpicker('val', template.rl_frame);
+ $("#dkim_selector").val(template.dkim_selector);
+ if (!template.key_size)
+ template.key_size = 2048;
+ $('#key_size').selectpicker('val', template.key_size.toString());
+
+ if (template.backupmx == 1){
+ $('#addDomain_relay_domain').prop('checked', true);
+ } else {
+ $('#addDomain_relay_domain').prop('checked', false);
+ }
+ if (template.relay_all_recipients == 1){
+ $('#addDomain_relay_all').prop('checked', true);
+ } else {
+ $('#addDomain_relay_all').prop('checked', false);
+ }
+ if (template.relay_unknown_only == 1){
+ $('#addDomain_relay_unknown_only').prop('checked', true);
+ } else {
+ $('#addDomain_relay_unknown_only').prop('checked', false);
+ }
+
+
+ // load tags
+ $('#addDomain_tags').val("");
+ $($('#addDomain_tags').parent().find(".tag-values")[0]).val("");
+ $('#addDomain_tags').parent().find(".tag-badge").remove();
+ for (var i = 0; i < template.tags.length; i++)
+ addTag($('#addDomain_tags'), template.tags[i]);
+ }
+ function setMailboxTemplateData(template){
+ $("#addInputQuota").val(template.quota / 1048576);
+
+ if (template.quarantine_notification === "never"){
+ $('#quarantine_notification_never').prop('checked', true);
+ $('#quarantine_notification_hourly').prop('checked', false);
+ $('#quarantine_notification_daily').prop('checked', false);
+ $('#quarantine_notification_weekly').prop('checked', false);
+ } else if(template.quarantine_notification === "hourly"){
+ $('#quarantine_notification_never').prop('checked', false);
+ $('#quarantine_notification_hourly').prop('checked', true);
+ $('#quarantine_notification_daily').prop('checked', false);
+ $('#quarantine_notification_weekly').prop('checked', false);
+ } else if(template.quarantine_notification === "daily"){
+ $('#quarantine_notification_never').prop('checked', false);
+ $('#quarantine_notification_hourly').prop('checked', false);
+ $('#quarantine_notification_daily').prop('checked', true);
+ $('#quarantine_notification_weekly').prop('checked', false);
+ } else if(template.quarantine_notification === "weekly"){
+ $('#quarantine_notification_never').prop('checked', false);
+ $('#quarantine_notification_hourly').prop('checked', false);
+ $('#quarantine_notification_daily').prop('checked', false);
+ $('#quarantine_notification_weekly').prop('checked', true);
+ } else {
+ $('#quarantine_notification_never').prop('checked', false);
+ $('#quarantine_notification_hourly').prop('checked', false);
+ $('#quarantine_notification_daily').prop('checked', false);
+ $('#quarantine_notification_weekly').prop('checked', false);
+ }
+
+ if (template.quarantine_category === "reject"){
+ $('#quarantine_category_reject').prop('checked', true);
+ $('#quarantine_category_add_header').prop('checked', false);
+ $('#quarantine_category_all').prop('checked', false);
+ } else if(template.quarantine_category === "add_header"){
+ $('#quarantine_category_reject').prop('checked', false);
+ $('#quarantine_category_add_header').prop('checked', true);
+ $('#quarantine_category_all').prop('checked', false);
+ } else if(template.quarantine_category === "all"){
+ $('#quarantine_category_reject').prop('checked', false);
+ $('#quarantine_category_add_header').prop('checked', false);
+ $('#quarantine_category_all').prop('checked', true);
+ }
+
+ if (template.tls_enforce_in == 1){
+ $('#tls_enforce_in').prop('checked', true);
+ } else {
+ $('#tls_enforce_in').prop('checked', false);
+ }
+ if (template.tls_enforce_out == 1){
+ $('#tls_enforce_out').prop('checked', true);
+ } else {
+ $('#tls_enforce_out').prop('checked', false);
+ }
+
+ var protocol_access = [];
+ if (template.imap_access == 1){
+ protocol_access.push("imap");
+ }
+ if (template.pop3_access == 1){
+ protocol_access.push("pop3");
+ }
+ if (template.smtp_access == 1){
+ protocol_access.push("smtp");
+ }
+ if (template.sieve_access == 1){
+ protocol_access.push("sieve");
+ }
+ $('#protocol_access').selectpicker('val', protocol_access);
+
+ var acl = [];
+ if (template.acl_spam_alias == 1){
+ acl.push("spam_alias");
+ }
+ if (template.acl_tls_policy == 1){
+ acl.push("tls_policy");
+ }
+ if (template.acl_spam_score == 1){
+ acl.push("spam_score");
+ }
+ if (template.acl_spam_policy == 1){
+ acl.push("spam_policy");
+ }
+ if (template.acl_delimiter_action == 1){
+ acl.push("delimiter_action");
+ }
+ if (template.acl_syncjobs == 1){
+ acl.push("syncjobs");
+ }
+ if (template.acl_eas_reset == 1){
+ acl.push("eas_reset");
+ }
+ if (template.acl_sogo_profile_reset == 1){
+ acl.push("sogo_profile_reset");
+ }
+ if (template.acl_pushover == 1){
+ acl.push("pushover");
+ }
+ if (template.acl_quarantine == 1){
+ acl.push("quarantine");
+ }
+ if (template.acl_quarantine_attachments == 1){
+ acl.push("quarantine_attachments");
+ }
+ if (template.acl_quarantine_notification == 1){
+ acl.push("quarantine_notification");
+ }
+ if (template.acl_quarantine_category == 1){
+ acl.push("quarantine_category");
+ }
+ if (template.acl_app_passwds == 1){
+ acl.push("app_passwds");
+ }
+ $('#user_acl').selectpicker('val', acl);
+
+ $('#rl_value').val(template.rl_value);
+ if (template.rl_frame){
+ $('#rl_frame').selectpicker('val', template.rl_frame);
+ }
+
+ console.log(template.active)
+ if (template.active){
+ $('#mbox_active').selectpicker('val', template.active.toString());
+ } else {
+ $('#mbox_active').selectpicker('val', '');
+ }
+
+ if (template.force_pw_update == 1){
+ $('#force_pw_update').prop('checked', true);
+ } else {
+ $('#force_pw_update').prop('checked', false);
+ }
+ if (template.sogo_access == 1){
+ $('#sogo_access').prop('checked', true);
+ } else {
+ $('#sogo_access').prop('checked', false);
+ }
+
+ // load tags
+ $('#addMailbox_tags').val("");
+ $($('#addMailbox_tags').parent().find(".tag-values")[0]).val("");
+ $('#addMailbox_tags').parent().find(".tag-badge").remove();
+ for (var i = 0; i < template.tags.length; i++)
+ addTag($('#addMailbox_tags'), template.tags[i]);
+ }
});
jQuery(function($){
- // http://stackoverflow.com/questions/24816/escaping-html-strings-with-jquery
- var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
- function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
// http://stackoverflow.com/questions/46155/validate-email-address-in-javascript
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
- function unix_time_format(i){return""==i?'<i class="bi bi-x-lg"></i>':new Date(i?1e3*i:0).toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}
+ function unix_time_format(i){return""==i?'<i class="bi bi-x"></i>':new Date(i?1e3*i:0).toLocaleDateString(void 0,{year:"numeric",month:"2-digit",day:"2-digit",hour:"2-digit",minute:"2-digit",second:"2-digit"})}
+
$(".refresh_table").on('click', function(e) {
e.preventDefault();
var table_name = $(this).data('table');
- $('#' + table_name).find("tr.footable-empty").remove();
- draw_table = $(this).data('draw');
- eval(draw_table + '()');
+
+ if ($.fn.DataTable.isDataTable('#' + table_name))
+ $('#' + table_name).DataTable().ajax.reload();
});
- function table_mailbox_ready(ft, name) {
- if(is_dual) {
- $('.login_as').data("toggle", "tooltip")
- .attr("disabled", true)
- .removeAttr("href")
- .attr("title", "Dual login cannot be used twice")
- .tooltip();
- }
- $('.refresh_table').prop("disabled", false);
- heading = ft.$el.parents('.panel').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- $(heading).children('.table-lines').text(function(){
- var total_rows = ft_paging.totalRows;
- var size = ft_paging.size;
- if (size > total_rows) {
- size = total_rows;
- }
- return size + ' / ' + total_rows;
- })
- }
function draw_domain_table() {
- ft_domain_table = FooTable.init('#domain_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"domain_name","title":lang.domain,"style":{"width":"250px"}},
- {"name":"aliases","title":lang.aliases,"breakpoints":"xs sm"},
- {"name":"mailboxes","title":lang.mailboxes},
- {"name":"quota","style":{"whiteSpace":"nowrap"},"title":lang.domain_quota,"formatter": function(value){
- res = value.split("/");
- return humanFileSize(res[0]) + " / " + humanFileSize(res[1]);
- },
- "sortValue": function(value){
- res = value.split("/");
- return Number(res[0]);
- }},
- {"name":"stats","sortable": false,"style":{"whiteSpace":"nowrap"},"title":lang.stats,"formatter": function(value){
- res = value.split("/");
- return '<i class="bi bi-files"></i> ' + res[0] + ' / ' + humanFileSize(res[1]);
- }},
- {"name":"def_quota_for_mbox","title":lang.mailbox_defquota,"breakpoints":"xs sm md","style":{"width":"125px"}},
- {"name":"max_quota_for_mbox","title":lang.mailbox_quota,"breakpoints":"xs sm","style":{"width":"125px"}},
- {"name":"rl","title":"RL","breakpoints":"xs sm md lg","style":{"min-width":"100px","width":"100px"}},
- {"name":"backupmx","filterable": false,"style":{"min-width":"120px","width":"120px"},"title":lang.backup_mx,"breakpoints":"xs sm md lg","formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"domain_admins","title":lang.domain_admins,"style":{"word-break":"break-all","min-width":"200px"},"breakpoints":"xs sm md lg","filterable":(role == "admin"),"visible":(role == "admin")},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"240px","width":"240px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/domain/all',
- jsonp: false,
- error: function (data) {
- console.log('Cannot draw domain table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#domain_table') ) {
+ $('#domain_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ var table = $('#domain_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/domain/all",
+ dataSrc: function(json){
+ $.each(json, function(i, item) {
+ item.domain_name = escapeHtml(item.domain_name);
+
item.aliases = item.aliases_in_domain + " / " + item.max_num_aliases_for_domain;
item.mailboxes = item.mboxes_in_domain + " / " + item.max_num_mboxes_for_domain;
item.quota = item.quota_used_in_domain + "/" + item.max_quota_for_domain + "/" + item.bytes_total;
item.stats = item.msgs_total + "/" + item.bytes_total;
- if (!item.rl) {
- item.rl = '∞';
- } else {
+
+ if (!item.rl) item.rl = '∞';
+ else {
item.rl = $.map(item.rl, function(e){
return e;
}).join('/1');
}
+
item.def_quota_for_mbox = humanFileSize(item.def_quota_for_mbox);
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.chkbox = '<input type="checkbox" data-id="domain" name="multi_select" value="' + encodeURIComponent(item.domain_name) + '" />';
- item.action = '<div class="btn-group footable-actions">';
+ item.action = '<div class="btn-group">';
if (role == "admin") {
- item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
- '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-third btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-domain" data-api-url="delete/domain" data-item="' + encodeURIComponent(item.domain_name) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '<a href="#dnsInfoModal" class="btn btn-sm btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
}
else {
- item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
+ item.action += '<a href="/edit/domain/' + encodeURIComponent(item.domain_name) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-half btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.domain_name) + '"><i class="bi bi-globe2"></i> DNS</a></div>';
+ }
+
+ if (Array.isArray(item.tags)){
+ var tags = '';
+ for (var i = 0; i < item.tags.length; i++)
+ tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
+ item.tags = tags;
+ } else {
+ item.tags = '';
}
if (item.backupmx == 1) {
if (item.relay_unknown_only == 1) {
- item.domain_name = '<div class="label label-info">Relay Non-Local</div> ' + item.domain_name;
+ item.domain_name = '<div class="badge fs-6 bg-info">Relay Non-Local</div> ' + item.domain_name;
} else if (item.relay_all_recipients == 1) {
- item.domain_name = '<div class="label label-info">Relay All</div> ' + item.domain_name;
+ item.domain_name = '<div class="badge fs-6 bg-info">Relay All</div> ' + item.domain_name;
} else {
- item.domain_name = '<div class="label label-info">Relay</div> ' + item.domain_name;
+ item.domain_name = '<div class="badge fs-6 bg-info">Relay</div> ' + item.domain_name;
}
}
});
- }
- }),
- "empty": lang.empty,
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'domain_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'domain_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: lang.domain,
+ data: 'domain_name',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.aliases,
+ data: 'aliases',
+ defaultContent: ''
+ },
+ {
+ title: lang.mailboxes,
+ data: 'mailboxes',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.domain_quota,
+ data: 'quota',
+ defaultContent: '',
+ render: function (data, type) {
+ data = data.split("/");
+ return humanFileSize(data[0]) + " / " + humanFileSize(data[1]);
+ }
+ },
+ {
+ title: lang.stats,
+ data: 'stats',
+ defaultContent: '',
+ render: function (data, type) {
+ data = data.split("/");
+ return '<i class="bi bi-files"></i> ' + data[0] + ' / ' + humanFileSize(data[1]);
+ }
+ },
+ {
+ title: lang.mailbox_defquota,
+ data: 'def_quota_for_mbox',
+ defaultContent: ''
+ },
+ {
+ title: lang.mailbox_quota,
+ data: 'max_quota_for_mbox',
+ defaultContent: ''
+ },
+ {
+ title: 'RL',
+ data: 'rl',
+ defaultContent: ''
+ },
+ {
+ title: lang.backup_mx,
+ data: 'backupmx',
+ defaultContent: '',
+ redner: function (data, type){
+ return 1==value ? '<i class="bi bi-check-lg"></i>' : 0==value && '<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.domain_admins,
+ data: 'domain_admins',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.created_on,
+ data: 'created',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.last_modified,
+ data: 'modified',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'Tags',
+ data: 'tags',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ responsivePriority: 6,
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
+ });
+ }
+ function draw_templates_domain_table() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#templates_domain_table') ) {
+ $('#templates_domain_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#templates_domain_table').DataTable({
+ responsive : true,
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/domain/template/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.chkbox = '<input type="checkbox" data-id="domain_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
+
+ item.attributes.def_quota_for_mbox = humanFileSize(item.attributes.def_quota_for_mbox);
+ item.attributes.max_quota_for_mbox = humanFileSize(item.attributes.max_quota_for_mbox);
+ item.attributes.max_quota_for_domain = humanFileSize(item.attributes.max_quota_for_domain);
+
+ item.template = escapeHtml(item.template);
+ if (item.attributes.rl_frame === "s"){
+ item.attributes.rl_frame = lang_rl.second;
+ } else if (item.attributes.rl_frame === "m"){
+ item.attributes.rl_frame = lang_rl.minute;
+ } else if (item.attributes.rl_frame === "h"){
+ item.attributes.rl_frame = lang_rl.hour;
+ } else if (item.attributes.rl_frame === "d"){
+ item.attributes.rl_frame = lang_rl.day;
+ }
+ item.attributes.rl_value = escapeHtml(item.attributes.rl_value);
+
+
+ if (item.template.toLowerCase() == "default"){
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '</div>';
+ }
+ else{
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/domain/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '</div>';
+ }
+
+ if (Array.isArray(item.attributes.tags)){
+ var tags = '';
+ for (var i = 0; i < item.attributes.tags.length; i++)
+ tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.attributes.tags[i]) + '</span>';
+ item.attributes.tags = tags;
+ } else {
+ item.attributes.tags = '';
+ }
+ });
+
+ return json;
+ }
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: "ID",
+ data: 'id',
+ responsivePriority: 2,
+ defaultContent: ''
+ },
+ {
+ title: lang.template,
+ data: 'template',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.max_aliases,
+ data: 'attributes.max_num_aliases_for_domain',
+ defaultContent: '',
+ },
+ {
+ title: lang.max_mailboxes,
+ data: 'attributes.max_num_mboxes_for_domain',
+ defaultContent: '',
+ },
+ {
+ title: lang.mailbox_defquota,
+ data: 'attributes.def_quota_for_mbox',
+ defaultContent: '',
+ },
+ {
+ title: lang.max_quota,
+ data: 'attributes.max_quota_for_mbox',
+ defaultContent: '',
+ },
+ {
+ title: lang.domain_quota_total,
+ data: 'attributes.max_quota_for_domain',
+ defaultContent: '',
+ },
+ {
+ title: lang.gal,
+ data: 'attributes.gal',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.backup_mx,
+ data: 'attributes.backupmx',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.relay_all,
+ data: 'attributes.relay_all_recipients',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.relay_unknown,
+ data: 'attributes.relay_unknown_only',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.active,
+ data: 'attributes.active',
+ defaultContent: '',
+ responsivePriority: 4,
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: 'rl_frame',
+ data: 'attributes.rl_frame',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: 'rl_value',
+ data: 'attributes.rl_value',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: lang.dkim_domains_selector,
+ data: 'attributes.dkim_selector',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: lang.dkim_key_length,
+ data: 'attributes.key_size',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: 'Tags',
+ data: 'attributes.tags',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
+ responsivePriority: 6,
+ defaultContent: ''
+ },
+ ]
});
}
function draw_mailbox_table() {
- ft_mailbox_table = FooTable.init('#mailbox_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"username","style":{"word-break":"break-all","min-width":"120px"},"title":lang.username},
- {"name":"name","title":lang.fname,"style":{"word-break":"break-all","min-width":"120px"},"breakpoints":"xs sm md lg"},
- {"name":"domain","title":lang.domain,"breakpoints":"xs sm md lg"},
- {"name":"quota","style":{"whiteSpace":"nowrap"},"title":lang.domain_quota,"formatter": function(value){
- res = value.split("/");
- var of_q = (res[1] == 0 ? "∞" : humanFileSize(res[1]));
- return humanFileSize(res[0]) + " / " + of_q;
- },
- "sortValue": function(value){
- res = value.split("/");
- return Number(res[0]);
- },
- },
- /* {"name":"spam_aliases","filterable": false,"title":lang.spam_aliases,"breakpoints":"all"}, */
- {"name":"tls_enforce_in","filterable": false,"title":lang.tls_enforce_in,"breakpoints":"all"},
- {"name":"tls_enforce_out","filterable": false,"title":lang.tls_enforce_out,"breakpoints":"all"},
- {"name":"smtp_access","filterable": false,"title":"SMTP","breakpoints":"all"},
- {"name":"imap_access","filterable": false,"title":"IMAP","breakpoints":"all"},
- {"name":"pop3_access","filterable": false,"title":"POP3","breakpoints":"all"},
- {"name":"last_mail_login","breakpoints":"xs sm","title":lang.last_mail_login,"style":{"width":"170px"},
- "sortValue": function(value){
- res = value.split("/");
- return Math.max(res[0], res[1]);
- },
- "formatter": function(value){
- res = value.split("/");
- return '<div class="label label-last-login">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' +
- '<div class="label label-last-login">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
- '<div class="label label-last-login">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>';
- }},
- {"name":"last_pw_change","filterable": false,"title":lang.last_pw_change,"breakpoints":"all"},
- {"name":"quarantine_notification","filterable": false,"title":lang.quarantine_notification,"breakpoints":"all"},
- {"name":"quarantine_category","filterable": false,"title":lang.quarantine_category,"breakpoints":"all"},
- {"name":"in_use","filterable": false,"type":"html","title":lang.in_use,"sortValue": function(value){
- return Number($(value).find(".progress-bar-mailbox").attr('aria-valuenow'));
- },
- },
- {"name":"messages","filterable": false,"title":lang.msg_num,"breakpoints":"xs sm md"},
- /* {"name":"rl","title":"RL","breakpoints":"all","style":{"width":"125px"}}, */
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':(0==value?'<i class="bi bi-x-lg"></i>':2==value&&'—');}},
- {"name":"action","filterable": false,"sortable": false,"style":{"min-width":"290px","text-align":"right"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/mailbox/reduced',
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#mailbox_table') ) {
+ $('#mailbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#mailbox_table').DataTable({
+ responsive : true,
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/mailbox/reduced",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
item.quota = item.quota_used + "/" + item.quota;
item.max_quota_for_mbox = humanFileSize(item.max_quota_for_mbox);
item.last_mail_login = item.last_imap_login + '/' + item.last_pop3_login + '/' + item.last_smtp_login;
@@ -458,6 +852,7 @@
item.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
item.imap_access = '<i class="text-' + (item.attributes.imap_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.imap_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
item.smtp_access = '<i class="text-' + (item.attributes.smtp_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.smtp_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ item.sieve_access = '<i class="text-' + (item.attributes.sieve_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sieve_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
if (item.attributes.quarantine_notification === 'never') {
item.quarantine_notification = lang.never;
} else if (item.attributes.quarantine_notification === 'hourly') {
@@ -475,21 +870,19 @@
item.quarantine_category = lang.q_all;
}
if (acl_data.login_as === 1) {
- var btnSize = 'btn-xs-third';
- if (ALLOW_ADMIN_EMAIL_LOGIN) btnSize = 'btn-xs-quart';
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs ' + btnSize + ' btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs ' + btnSize + ' btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
- '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs ' + btnSize + ' btn-success"><i class="bi bi-person-fill"></i> Login</a>';
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '<a href="/index.php?duallogin=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-success"><i class="bi bi-person-fill"></i> Login</a>';
if (ALLOW_ADMIN_EMAIL_LOGIN) {
- item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-xs ' + btnSize + ' btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
+ item.action += '<a href="/sogo-auth.php?login=' + encodeURIComponent(item.username) + '" class="login_as btn btn-sm btn-xs-half btn-primary" target="_blank"><i class="bi bi-envelope-fill"></i> SOGo</a>';
}
item.action += '</div>';
}
else {
item.action = '<div class="btn-group">' +
- '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="/edit/mailbox/' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-mailbox" data-api-url="delete/mailbox" data-item="' + encodeURIComponent(item.username) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
}
@@ -497,348 +890,810 @@
'<div class="progress-bar-mailbox progress-bar progress-bar-' + item.percent_class + '" role="progressbar" aria-valuenow="' + item.percent_in_use + '" aria-valuemin="0" aria-valuemax="100" ' +
'style="min-width:2em;width:' + item.percent_in_use + '%">' + item.percent_in_use + '%' + '</div></div>';
item.username = escapeHtml(item.username);
+
+ if (Array.isArray(item.tags)){
+ var tags = '';
+ for (var i = 0; i < item.tags.length; i++)
+ tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.tags[i]) + '</span>';
+ item.tags = tags;
+ } else {
+ item.tags = '';
+ }
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- //"container": "#tab-mailboxes.panel",
- "placeholder": lang.filter_table
- },
- "components": {
- "filtering": FooTable.domainFilter
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'mailbox_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'mailbox_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: lang.username,
+ data: 'username',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.domain_quota,
+ data: 'quota',
+ responsivePriority: 8,
+ defaultContent: '',
+ render: function (data, type) {
+ data = data.split("/");
+ var of_q = (data[1] == 0 ? "∞" : humanFileSize(data[1]));
+ return humanFileSize(data[0]) + " / " + of_q;
+ }
+ },
+ {
+ title: lang.last_mail_login,
+ data: 'last_mail_login',
+ defaultContent: '',
+ responsivePriority: 7,
+ render: function (data, type) {
+ res = data.split("/");
+ return '<div class="badge bg-info mb-2">IMAP @ ' + unix_time_format(Number(res[0])) + '</div><br>' +
+ '<div class="badge bg-info mb-2">POP3 @ ' + unix_time_format(Number(res[1])) + '</div><br>' +
+ '<div class="badge bg-info">SMTP @ ' + unix_time_format(Number(res[2])) + '</div>';
+ }
+ },
+ {
+ title: lang.last_pw_change,
+ data: 'last_pw_change',
+ defaultContent: ''
+ },
+ {
+ title: lang.in_use,
+ data: 'in_use',
+ defaultContent: '',
+ responsivePriority: 9,
+ className: 'dt-data-w100'
+ },
+ {
+ title: lang.fname,
+ data: 'name',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.domain,
+ data: 'domain',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.tls_enforce_in,
+ data: 'tls_enforce_in',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.tls_enforce_out,
+ data: 'tls_enforce_out',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'SMTP',
+ data: 'smtp_access',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'IMAP',
+ data: 'imap_access',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'POP3',
+ data: 'pop3_access',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'SIEVE',
+ data: 'sieve_access',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.quarantine_notification,
+ data: 'quarantine_notification',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.quarantine_category,
+ data: 'quarantine_category',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.msg_num,
+ data: 'messages',
+ defaultContent: '',
+ responsivePriority: 5
+ },
+ {
+ title: lang.created_on,
+ data: 'created',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.last_modified,
+ data: 'modified',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: 'Tags',
+ data: 'tags',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ responsivePriority: 4,
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
+ responsivePriority: 6,
+ defaultContent: ''
+ },
+ ]
+ });
+ }
+ function draw_templates_mbox_table() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#templates_mbox_table') ) {
+ $('#templates_mbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#templates_mbox_table').DataTable({
+ responsive : true,
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/mailbox/template/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.chkbox = '<input type="checkbox" data-id="mailbox_template" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
+
+ item.template = escapeHtml(item.template);
+ if (item.attributes.rl_frame === "s"){
+ item.attributes.rl_frame = lang_rl.second;
+ } else if (item.attributes.rl_frame === "m"){
+ item.attributes.rl_frame = lang_rl.minute;
+ } else if (item.attributes.rl_frame === "h"){
+ item.attributes.rl_frame = lang_rl.hour;
+ } else if (item.attributes.rl_frame === "d"){
+ item.attributes.rl_frame = lang_rl.day;
+ }
+ item.attributes.rl_value = escapeHtml(item.attributes.rl_value);
+
+ item.attributes.quota = humanFileSize(item.attributes.quota);
+
+ item.attributes.tls_enforce_in = '<i class="text-' + (item.attributes.tls_enforce_in == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
+ item.attributes.tls_enforce_out = '<i class="text-' + (item.attributes.tls_enforce_out == 1 ? 'success bi bi-lock-fill' : 'danger bi bi-unlock-fill') + '"></i>';
+ item.attributes.pop3_access = '<i class="text-' + (item.attributes.pop3_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.pop3_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ item.attributes.imap_access = '<i class="text-' + (item.attributes.imap_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.imap_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ item.attributes.smtp_access = '<i class="text-' + (item.attributes.smtp_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.smtp_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ item.attributes.sieve_access = '<i class="text-' + (item.attributes.sieve_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sieve_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ item.attributes.sogo_access = '<i class="text-' + (item.attributes.sogo_access == 1 ? 'success' : 'danger') + ' bi bi-' + (item.attributes.sogo_access == 1 ? 'check-lg' : 'x-lg') + '"></i>';
+ if (item.attributes.quarantine_notification === 'never') {
+ item.attributes.quarantine_notification = lang.never;
+ } else if (item.attributes.quarantine_notification === 'hourly') {
+ item.attributes.quarantine_notification = lang.hourly;
+ } else if (item.attributes.quarantine_notification === 'daily') {
+ item.attributes.quarantine_notification = lang.daily;
+ } else if (item.attributes.quarantine_notification === 'weekly') {
+ item.attributes.quarantine_notification = lang.weekly;
+ }
+ if (item.attributes.quarantine_category === 'reject') {
+ item.attributes.quarantine_category = '<span class="text-danger">' + lang.q_reject + '</span>';
+ } else if (item.attributes.quarantine_category === 'add_header') {
+ item.attributes.quarantine_category = '<span class="text-warning">' + lang.q_add_header + '</span>';
+ } else if (item.attributes.quarantine_category === 'all') {
+ item.attributes.quarantine_category = lang.q_all;
+ }
+
+
+ if (item.template.toLowerCase() == "default"){
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '</div>';
+ }
+ else {
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/template/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-template" data-api-url="delete/mailbox/template" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '</div>';
+ }
+
+ if (Array.isArray(item.attributes.tags)){
+ var tags = '';
+ for (var i = 0; i < item.attributes.tags.length; i++)
+ tags += '<span class="badge bg-primary tag-badge"><i class="bi bi-tag-fill"></i> ' + escapeHtml(item.attributes.tags[i]) + '</span>';
+ item.attributes.tags = tags;
+ } else {
+ item.attributes.tags = '';
+ }
+ });
+
+ return json;
+ }
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: "ID",
+ data: 'id',
+ responsivePriority: 2,
+ defaultContent: ''
+ },
+ {
+ title: lang.template,
+ data: 'template',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.domain_quota,
+ data: 'attributes.quota',
+ defaultContent: '',
+ },
+ {
+ title: lang.tls_enforce_in,
+ data: 'attributes.tls_enforce_in',
+ defaultContent: ''
+ },
+ {
+ title: lang.tls_enforce_out,
+ data: 'attributes.tls_enforce_out',
+ defaultContent: ''
+ },
+ {
+ title: 'SMTP',
+ data: 'attributes.smtp_access',
+ defaultContent: '',
+ },
+ {
+ title: 'IMAP',
+ data: 'attributes.imap_access',
+ defaultContent: '',
+ },
+ {
+ title: 'POP3',
+ data: 'attributes.pop3_access',
+ defaultContent: '',
+ },
+ {
+ title: 'SIEVE',
+ data: 'attributes.sieve_access',
+ defaultContent: '',
+ },
+ {
+ title: 'SOGO',
+ data: 'attributes.sogo_access',
+ defaultContent: '',
+ },
+ {
+ title: lang.quarantine_notification,
+ data: 'attributes.quarantine_notification',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.quarantine_category,
+ data: 'attributes.quarantine_category',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.force_pw_update,
+ data: 'attributes.force_pw_update',
+ defaultContent: '',
+ class: 'none',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: "rl_frame",
+ data: 'attributes.rl_frame',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: 'rl_value',
+ data: 'attributes.rl_value',
+ defaultContent: '',
+ class: 'none',
+ },
+ {
+ title: 'Tags',
+ data: 'attributes.tags',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.active,
+ data: 'attributes.active',
+ defaultContent: '',
+ responsivePriority: 4,
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md',
+ responsivePriority: 6,
+ defaultContent: ''
+ },
+ ]
});
}
function draw_resource_table() {
- ft_resource_table = FooTable.init('#resource_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"description","title":lang.description,"style":{"width":"250px"}},
- {"name":"name","title":lang.alias},
- {"name":"kind","title":lang.kind},
- {"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
- {"name":"multiple_bookings","filterable": false,"style":{"min-width":"150px","width":"140px"},"title":lang.multiple_bookings,"breakpoints":"xs sm"},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/resource/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw resource table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#resource_table') ) {
+ $('#resource_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#resource_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/resource/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
if (item.multiple_bookings == '0') {
- item.multiple_bookings = '<span id="active-script" class="label label-success">' + lang.booking_0_short + '</span>';
+ item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-success">' + lang.booking_0_short + '</span>';
} else if (item.multiple_bookings == '-1') {
- item.multiple_bookings = '<span id="active-script" class="label label-warning">' + lang.booking_lt0_short + '</span>';
+ item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-warning">' + lang.booking_lt0_short + '</span>';
} else {
- item.multiple_bookings = '<span id="active-script" class="label label-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
+ item.multiple_bookings = '<span id="active-script" class="badge fs-6 bg-danger">' + lang.booking_custom_short + ' (' + item.multiple_bookings + ')</span>';
}
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/resource/' + encodeURIComponent(item.name) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-resource" data-api-url="delete/resource" data-item="' + item.name + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="resource" name="multi_select" value="' + encodeURIComponent(item.name) + '" />';
item.name = escapeHtml(item.name);
+ item.description = escapeHtml(item.description);
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "components": {
- "filtering": FooTable.domainFilter
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'resource_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'resource_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: lang.description,
+ data: 'description',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.alias,
+ data: 'name',
+ defaultContent: ''
+ },
+ {
+ title: lang.kind,
+ data: 'kind',
+ defaultContent: ''
+ },
+ {
+ title: lang.domain,
+ data: 'domain',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.multiple_bookings,
+ data: 'multiple_bookings',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ responsivePriority: 5,
+ defaultContent: '',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right'
+ },
+ ]
});
}
function draw_bcc_table() {
- ft_bcc_table = FooTable.init('#bcc_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"name":"type","title":lang.bcc_type},
- {"name":"local_dest","title":lang.bcc_local_dest},
- {"name":"bcc_dest","title":lang.bcc_destinations},
- {"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/bcc/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw bcc table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/bcc/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ $.get("/api/v1/get/bcc-destination-options", function(data){
+ // Domains
+ var optgroup = "<optgroup label='" + lang.domains + "'>";
+ $.each(data.domains, function(index, domain){
+ optgroup += "<option value='" + domain + "'>" + domain + "</option>"
+ });
+ optgroup += "</optgroup>"
+ $('#bcc-local-dest').append(optgroup);
+ // Alias domains
+ var optgroup = "<optgroup label='" + lang.domain_aliases + "'>";
+ $.each(data.alias_domains, function(index, alias_domain){
+ optgroup += "<option value='" + alias_domain + "'>" + alias_domain + "</option>"
+ });
+ optgroup += "</optgroup>"
+ $('#bcc-local-dest').append(optgroup);
+ // Mailboxes and aliases
+ $.each(data.mailboxes, function(mailbox, aliases){
+ var optgroup = "<optgroup label='" + mailbox + "'>";
+ $.each(aliases, function(index, alias){
+ optgroup += "<option value='" + alias + "'>" + alias + "</option>"
+ });
+ optgroup += "</optgroup>"
+ $('#bcc-local-dest').append(optgroup);
+ });
+ // Finish
+ $('#bcc-local-dest').selectpicker('refresh');
+ });
+
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#bcc_table') ) {
+ $('#bcc_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#bcc_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/bcc/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/bcc/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-bcc" data-api-url="delete/bcc" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="bcc" name="multi_select" value="' + item.id + '" />';
item.local_dest = escapeHtml(item.local_dest);
item.bcc_dest = escapeHtml(item.bcc_dest);
if (item.type == 'sender') {
- item.type = '<span id="active-script" class="label label-success">' + lang.bcc_sender_map + '</span>';
+ item.type = '<span id="active-script" class="badge fs-6 bg-success">' + lang.bcc_sender_map + '</span>';
} else {
- item.type = '<span id="inactive-script" class="label label-warning">' + lang.bcc_rcpt_map + '</span>';
+ item.type = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.bcc_rcpt_map + '</span>';
}
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'bcc_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'bcc_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.bcc_type,
+ data: 'type',
+ defaultContent: ''
+ },
+ {
+ title: lang.bcc_local_dest,
+ data: 'local_dest',
+ defaultContent: ''
+ },
+ {
+ title: lang.bcc_destinations,
+ data: 'bcc_dest',
+ defaultContent: ''
+ },
+ {
+ title: lang.domain,
+ data: 'domain',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':(0==data?'<i class="bi bi-x-lg"></i>':2==data&&'—');
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
function draw_recipient_map_table() {
- ft_recipient_map_table = FooTable.init('#recipient_map_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"name":"recipient_map_old","title":lang.recipient_map_old},
- {"name":"recipient_map_new","title":lang.recipient_map_new},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":(role == "admin" ? lang.action : ""),"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/recipient_map/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw recipient map table');
- },
- success: function (data) {
- if (role == "admin") {
- $.each(data, function (i, item) {
- item.recipient_map_old = escapeHtml(item.recipient_map_old);
- item.recipient_map_new = escapeHtml(item.recipient_map_new);
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
- '</div>';
- item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
- });
- }
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'recipient_map_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'recipient_map_table');
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#recipient_map_table') ) {
+ $('#recipient_map_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#recipient_map_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/recipient_map/all",
+ dataSrc: function(json){
+ if (role !== "admin") return null;
+
+ $.each(json, function (i, item) {
+ item.recipient_map_old = escapeHtml(item.recipient_map_old);
+ item.recipient_map_new = escapeHtml(item.recipient_map_new);
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/recipient_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-recipient_map" data-api-url="delete/recipient_map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '</div>';
+ item.chkbox = '<input type="checkbox" data-id="recipient_map" name="multi_select" value="' + item.id + '" />';
+ });
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.recipient_map_old,
+ data: 'recipient_map_old',
+ defaultContent: ''
+ },
+ {
+ title: lang.recipient_map_new,
+ data: 'recipient_map_new',
+ defaultContent: '',
+ responsivePriority: 4
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
function draw_tls_policy_table() {
- ft_tls_policy_table = FooTable.init('#tls_policy_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"name":"dest","title":lang.tls_map_dest},
- {"name":"policy","title":lang.tls_map_policy},
- {"name":"parameters","title":lang.tls_map_parameters},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":(role == "admin" ? lang.action : ""),"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/tls-policy-map/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw tls policy map table');
- },
- success: function (data) {
- if (role == "admin") {
- $.each(data, function (i, item) {
- item.dest = escapeHtml(item.dest);
- item.policy = '<b>' + escapeHtml(item.policy) + '</b>';
- if (item.parameters == '') {
- item.parameters = '<code>-</code>';
- } else {
- item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
- }
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
- '</div>';
- item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
- });
- }
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'tls_policy_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'tls_policy_table');
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#tls_policy_table') ) {
+ $('#tls_policy_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#tls_policy_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/tls-policy-map/all",
+ dataSrc: function(json){
+ if (role !== "admin") return null;
+
+ $.each(json, function (i, item) {
+ item.dest = escapeHtml(item.dest);
+ item.policy = '<b>' + escapeHtml(item.policy) + '</b>';
+ if (item.parameters == '') {
+ item.parameters = '<code>-</code>';
+ } else {
+ item.parameters = '<code>' + escapeHtml(item.parameters) + '</code>';
+ }
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/tls_policy_map/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-tls-policy-map" data-api-url="delete/tls-policy-map" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '</div>';
+ item.chkbox = '<input type="checkbox" data-id="tls-policy-map" name="multi_select" value="' + item.id + '" />';
+ });
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.tls_map_dest,
+ data: 'dest',
+ defaultContent: '',
+ responsivePriority: 4
+ },
+ {
+ title: lang.tls_map_policy,
+ data: 'policy',
+ defaultContent: ''
+ },
+ {
+ title: lang.tls_map_parameters,
+ data: 'parameters',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
function draw_alias_table() {
- ft_alias_table = FooTable.init('#alias_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"sorted": true,"name":"address","title":lang.alias,"style":{"width":"250px"}},
- {"name":"goto","title":lang.target_address},
- {"name":"domain","title":lang.domain,"breakpoints":"xs sm"},
- {"name":"public_comment","title":lang.public_comment,"breakpoints":"all"},
- {"name":"private_comment","title":lang.private_comment,"breakpoints":"all"},
- {"name":"sogo_visible","title":lang.sogo_visible,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';},"breakpoints":"all"},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/alias/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw alias table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#alias_table') ) {
+ $('#alias_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#alias_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/alias/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/alias/' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-alias" data-api-url="delete/alias" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias" name="multi_select" value="' + encodeURIComponent(item.id) + '" />';
item.goto = escapeHtml(item.goto.replace(/,/g, " "));
@@ -855,7 +1710,7 @@
item.private_comment = '-';
}
if (item.is_catch_all == 1) {
- item.address = '<div class="label label-default">' + lang.catch_all + '</div> ' + escapeHtml(item.address);
+ item.address = '<div class="badge fs-6 bg-secondary">' + lang.catch_all + '</div> ' + escapeHtml(item.address);
}
else {
item.address = escapeHtml(item.address);
@@ -864,163 +1719,217 @@
item.goto = '⤷ <i class="bi bi-trash" style="font-size:12px"></i>';
}
else if (item.goto == "spam@localhost") {
- item.goto = '<span class="label label-danger">' + lang.goto_spam + '</span>';
+ item.goto = '<span class="badge fs-6 bg-danger">' + lang.goto_spam + '</span>';
}
else if (item.goto == "ham@localhost") {
- item.goto = '<span class="label label-success">' + lang.goto_ham + '</span>';
+ item.goto = '<span class="badge fs-6 bg-success">' + lang.goto_ham + '</span>';
}
if (item.in_primary_domain !== "") {
- item.domain = '<i data-domainname="' + item.domain + '" class="bi bi-info-circle-fill alias-domain-info text-info" data-toggle="tooltip" title="' + lang.target_domain + ': ' + item.in_primary_domain + '"></i> ' + item.domain;
+ item.domain = '<i data-domainname="' + item.domain + '" class="bi bi-info-circle-fill alias-domain-info text-info" data-bs-toggle="tooltip" title="' + lang.target_domain + ': ' + item.in_primary_domain + '"></i> ' + item.domain;
}
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "components": {
- "filtering": FooTable.domainFilter
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'alias_table');
- $('.alias-domain-info').tooltip();
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'alias_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.alias,
+ data: 'address',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.target_address,
+ data: 'goto',
+ defaultContent: ''
+ },
+ {
+ title: lang.domain,
+ data: 'domain',
+ defaultContent: '',
+ responsivePriority: 5,
+ },
+ {
+ title: lang.bcc_destinations,
+ data: 'bcc_dest',
+ defaultContent: ''
+ },
+ {
+ title: lang.sogo_visible,
+ data: 'sogo_visible',
+ defaultContent: '',
+ render: function(data, type){
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.public_comment,
+ data: 'public_comment',
+ defaultContent: ''
+ },
+ {
+ title: lang.private_comment,
+ data: 'private_comment',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ responsivePriority: 6,
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
-
function draw_aliasdomain_table() {
- ft_aliasdomain_table = FooTable.init('#aliasdomain_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"alias_domain","title":lang.alias,"style":{"width":"250px"}},
- {"name":"target_domain","title":lang.target_domain,"type":"html"},
- {"name":"active","filterable": false,"style":{"min-width":"80px","width":"80px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"250px","width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/alias-domain/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw alias domain table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-xs-third btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-xs btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
- '<a href="#dnsInfoModal" class="btn btn-xs btn-xs-third btn-info" data-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#aliasdomain_table') ) {
+ $('#aliasdomain_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#aliasdomain_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/alias-domain/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.alias_domain = escapeHtml(item.alias_domain);
+
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/aliasdomain/' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-alias-domain" data-api-url="delete/alias-domain" data-item="' + encodeURIComponent(item.alias_domain) + '" class="btn btn-sm btn-xs-third btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ '<a href="#dnsInfoModal" class="btn btn-sm btn-xs-third btn-info" data-bs-toggle="modal" data-domain="' + encodeURIComponent(item.alias_domain) + '"><i class="bi bi-globe2"></i> DNS</a></div>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="alias-domain" name="multi_select" value="' + encodeURIComponent(item.alias_domain) + '" />';
if(item.parent_is_backupmx == '1') {
- item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a> <div class="label label-warning">' + lang.alias_domain_backupmx + '</div></span>';
+ item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a> <div class="badge fs-6 bg-warning">' + lang.alias_domain_backupmx + '</div></span>';
} else {
item.target_domain = '<span><a href="/edit/domain/' + item.target_domain + '">' + item.target_domain + '</a></span>';
}
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'aliasdomain_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'aliasdomain_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: lang.alias,
+ data: 'alias_domain',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.target_domain,
+ data: 'target_domain',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
-
function draw_sync_job_table() {
- ft_syncjob_table = FooTable.init('#sync_job_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"name":"user2","title":lang.owner},
- {"name":"server_w_port","title":"Server","breakpoints":"xs sm md","style":{"word-break":"break-all"}},
- {"name":"exclude","title":lang.excludes,"breakpoints":"all"},
- {"name":"mins_interval","title":lang.mins_interval,"breakpoints":"all"},
- {"name":"last_run","title":lang.last_run,"breakpoints":"xs sm md"},
- {"name":"exit_status","filterable": false,"title":lang.syncjob_last_run_result},
- {"name":"log","title":"Log"},
- {"name":"active","filterable": false,"style":{"min-width":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"is_running","filterable": false,"style":{"min-width":"120px","width":"100px"},"title":lang.status},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/syncjobs/all/no_log',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sync job table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
- item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + encodeURIComponent(item.id) + '">' + lang.open_logs + '</a>'
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#sync_job_table') ) {
+ $('#sync_job_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#sync_job_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/syncjobs/all/no_log",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
+ item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + encodeURIComponent(item.id) + '">' + lang.open_logs + '</a>'
item.user2 = escapeHtml(item.user2);
if (!item.exclude > 0) {
item.exclude = '-';
} else {
- item.exclude = '<code>' + item.exclude + '</code>';
+ item.exclude = '<code>' + escapeHtml(item.exclude) + '</code>';
}
- item.server_w_port = escapeHtml(item.user1) + '@' + item.host1 + ':' + item.port1;
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ item.server_w_port = escapeHtml(item.user1) + '@' + escapeHtml(item.host1) + ':' + escapeHtml(item.port1);
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
if (item.is_running == 1) {
- item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
+ item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
} else {
- item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
+ item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>';
}
if (!item.last_run > 0) {
item.last_run = lang.waiting;
@@ -1038,124 +1947,220 @@
}
item.exit_status = item.success + ' ' + item.exit_status;
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'sync_job_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'sync_job_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: lang.owner,
+ data: 'user2',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: 'Server',
+ data: 'server_w_port',
+ defaultContent: ''
+ },
+ {
+ title: lang.last_run,
+ data: 'last_run',
+ defaultContent: ''
+ },
+ {
+ title: lang.syncjob_last_run_result,
+ data: 'exit_status',
+ defaultContent: ''
+ },
+ {
+ title: 'Log',
+ data: 'log',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>';
+ }
+ },
+ {
+ title: lang.status,
+ data: 'is_running',
+ defaultContent: ''
+ },
+ {
+ title: lang.excludes,
+ data: 'exclude',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.mins_interval,
+ data: 'mins_interval',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
}
-
function draw_filter_table() {
- ft_filter_table = FooTable.init('#filter_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","title":"ID","style":{"min-width":"60px","width":"60px","text-align":"center"}},
- {"name":"active","style":{"min-width":"80px","width":"80px"},"title":lang.active},
- {"name":"filter_type","style":{"min-width":"80px","width":"80px"},"title":"Type"},
- {"sorted": true,"name":"username","title":lang.owner,"style":{"min-width":"550px","width":"350px"}},
- {"name":"script_desc","title":lang.description,"breakpoints":"xs"},
- {"name":"script_data","title":"Script","breakpoints":"all"},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"180px","width":"180px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/filters/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw filter table');
- },
- success: function (data) {
- $.each(data, function (i, item) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#filter_table') ) {
+ $('#filter_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ var table = $('#filter_table').DataTable({
+ autoWidth: false,
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/filters/all",
+ dataSrc: function(json){
+ $.each(json, function (i, item) {
if (item.active == 1) {
- item.active = '<span id="active-script" class="label label-success">' + lang.active + '</span>';
+ item.active = '<span id="active-script" class="badge fs-6 bg-success">' + lang.active + '</span>';
} else {
- item.active = '<span id="inactive-script" class="label label-warning">' + lang.inactive + '</span>';
+ item.active = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.inactive + '</span>';
}
- item.script_data = '<pre style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
- item.filter_type = '<div class="label label-default">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/filter/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
- '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
+ item.script_desc = escapeHtml(item.script_desc);
+ item.script_data = '<pre class="text-break" style="margin:0px">' + escapeHtml(item.script_data) + '</pre>'
+ item.filter_type = '<div class="badge fs-6 bg-secondary">' + item.filter_type.charAt(0).toUpperCase() + item.filter_type.slice(1).toLowerCase() + '</div>'
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/filter/' + item.id + '" class="btn btn-sm btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ '<a href="#" data-action="delete_selected" data-id="single-filter" data-api-url="delete/filter" data-item="' + encodeURIComponent(item.id) + '" class="btn btn-sm btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="filter_item" name="multi_select" value="' + item.id + '" />'
});
- }
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
- },
- "state": {
- "enabled": true
- },
- "filtering": {
- "enabled": true,
- "delay": 1200,
- "position": "left",
- "connectors": false,
- "placeholder": lang.filter_table
- },
- "sorting": {
- "enabled": true
- },
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_mailbox_ready(ft, 'filter_table');
- },
- "after.ft.filtering": function(e, ft){
- table_mailbox_ready(ft, 'filter_table');
+
+ return json;
}
},
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ responsivePriority: 2,
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ responsivePriority: 3,
+ defaultContent: ''
+ },
+ {
+ title: 'Type',
+ data: 'filter_type',
+ responsivePriority: 4,
+ defaultContent: ''
+ },
+ {
+ title: lang.owner,
+ data: 'username',
+ defaultContent: ''
+ },
+ {
+ title: lang.description,
+ data: 'script_desc',
+ defaultContent: ''
+ },
+ {
+ title: 'Script',
+ data: 'script_data',
+ defaultContent: '',
+ className: 'none'
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'dt-sm-head-hidden dt-data-w100 dtr-col-md dt-body-right',
+ responsivePriority: 5,
+ defaultContent: ''
+ },
+ ]
});
};
- $('body').on('click', 'span.footable-toggle', function () {
- event.stopPropagation();
- })
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
- draw_domain_table();
- draw_mailbox_table();
- draw_resource_table();
- draw_alias_table();
- draw_aliasdomain_table();
- draw_sync_job_table();
- draw_filter_table();
- draw_bcc_table();
- draw_recipient_map_table();
- draw_tls_policy_table();
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+ // Load only if the tab is visible
+ onVisible("[id^=domain_table]", () => draw_domain_table());
+ onVisible("[id^=templates_domain_table]", () => draw_templates_domain_table());
+ onVisible("[id^=mailbox_table]", () => draw_mailbox_table());
+ onVisible("[id^=templates_mbox_table]", () => draw_templates_mbox_table());
+ onVisible("[id^=resource_table]", () => draw_resource_table());
+ onVisible("[id^=alias_table]", () => draw_alias_table());
+ onVisible("[id^=aliasdomain_table]", () => draw_aliasdomain_table());
+ onVisible("[id^=sync_job_table]", () => draw_sync_job_table());
+ onVisible("[id^=filter_table]", () => draw_filter_table());
+ onVisible("[id^=bcc_table]", () => draw_bcc_table());
+ onVisible("[id^=recipient_map_table]", () => draw_recipient_map_table());
+ onVisible("[id^=tls_policy_table]", () => draw_tls_policy_table());
});
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/qhandler.js b/mailcow/src/mailcow-dockerized/data/web/js/site/qhandler.js
index 4d32547..4fcc963 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/qhandler.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/qhandler.js
@@ -40,17 +40,17 @@
if (value.score > 0) highlightClass = 'negative'
else if (value.score < 0) highlightClass = 'positive'
else highlightClass = 'neutral'
- $('#qid_detail_symbols').append('<span data-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
+ $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
});
- $('[data-toggle="tooltip"]').tooltip()
+ $('[data-bs-toggle="tooltip"]').tooltip()
}
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
if (data.action === "add header") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
} else if (data.action === "reject") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
} else if (data.action === "rewrite subject") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
}
}
if (typeof data.recipients !== 'undefined') {
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/quarantine.js b/mailcow/src/mailcow-dockerized/data/web/js/site/quarantine.js
index 57bd4cc..34531b0 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/quarantine.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/quarantine.js
@@ -7,67 +7,20 @@
var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};
function escapeHtml(n){return String(n).replace(/[&<>"'`=\/]/g,function(n){return entityMap[n]})}
function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
- // Set paging
- $('[data-page-size]').on('click', function(e){
- e.preventDefault();
- var new_size = $(this).data('page-size');
- var parent_ul = $(this).closest('ul');
- var table_id = $(parent_ul).data('table-id');
- FooTable.get('#' + table_id).pageSize(new_size);
- //$(this).parent().addClass('active').siblings().removeClass('active')
- heading = $(this).parents('.panel').find('.panel-heading')
- var n_results = $(heading).children('.table-lines').text().split(' / ')[1];
- $(heading).children('.table-lines').text(function(){
- if (new_size > n_results) {
- new_size = n_results;
- }
- return new_size + ' / ' + n_results;
- })
- });
$(".refresh_table").on('click', function(e) {
e.preventDefault();
var table_name = $(this).data('table');
- $('#' + table_name).find("tr.footable-empty").remove();
- draw_table = $(this).data('draw');
- eval(draw_table + '()');
+ $('#' + table_name).DataTable().ajax.reload();
});
- function table_quarantine_ready(ft, name) {
- $('.refresh_table').prop("disabled", false);
- heading = ft.$el.parents('.panel').find('.panel-heading')
- var ft_paging = ft.use(FooTable.Paging)
- $(heading).children('.table-lines').text(function(){
- var total_rows = ft_paging.totalRows;
- var size = ft_paging.size;
- if (size > total_rows) {
- size = total_rows;
- }
- return size + ' / ' + total_rows;
- })
- }
function draw_quarantine_table() {
- ft_quarantinetable = FooTable.init('#quarantinetable', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"id","type":"ID","filterable": false,"sorted": true,"direction":"DESC","title":"ID","style":{"width":"50px"}},
- {"name":"qid","breakpoints":"all","type":"text","title":lang.qid,"style":{"width":"125px"}},
- {"name":"sender","title":lang.sender},
- {"name":"subject","title":lang.subj, "type": "text"},
- {"name":"rspamdaction","title":lang.rspamd_result, "type": "html"},
- {"name":"rcpt","title":lang.rcpt, "type": "text"},
- {"name":"virus","title":lang.danger, "type": "text"},
- {"name":"score","title": lang.spam_score, "type": "text"},
- {"name":"notified","title":lang.notified, "type": "text"},
- {"name":"created","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.received,"style":{"width":"170px"}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right"},"style":{"min-width":"250px"},"type":"html","title":lang.action,"breakpoints":"xs sm md"}
- ],
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/quarantine/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw quarantine table');
- },
- success: function (data) {
+ $('#quarantinetable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/quarantine/all",
+ dataSrc: function(data){
$.each(data, function (i, item) {
if (item.subject === null) {
item.subject = '';
@@ -78,16 +31,16 @@
item.score = '-';
}
if (item.virus_flag > 0) {
- item.virus = '<span class="label label-danger">' + lang.high_danger + '</span>';
+ item.virus = '<span class="badge fs-6 bg-danger">' + lang.high_danger + '</span>';
} else {
- item.virus = '<span class="label label-default">' + lang.neutral_danger + '</span>';
+ item.virus = '<span class="badge fs-6 bg-secondary">' + lang.neutral_danger + '</span>';
}
if (item.action === "reject") {
- item.rspamdaction = '<span class="label label-danger">' + lang.rejected + '</span>';
+ item.rspamdaction = '<span class="badge fs-6 bg-danger">' + lang.rejected + '</span>';
} else if (item.action === "add header") {
- item.rspamdaction = '<span class="label label-warning">' + lang.junk_folder + '</span>';
+ item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.junk_folder + '</span>';
} else if (item.action === "rewrite subject") {
- item.rspamdaction = '<span class="label label-warning">' + lang.rewrite_subject + '</span>';
+ item.rspamdaction = '<span class="badge fs-6 bg-warning">' + lang.rewrite_subject + '</span>';
}
if(item.notified > 0) {
item.notified = '✔';
@@ -95,7 +48,7 @@
item.notified = '✖';
}
if (acl_data.login_as === 1) {
- item.action = '<div class="btn-group footable-actions">' +
+ item.action = '<div class="btn-group">' +
'<a href="#" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-info show_qid_info"><i class="bi bi-box-arrow-up-right"></i> ' + lang.show_item + '</a>' +
'<a href="#" data-action="delete_selected" data-id="del-single-qitem" data-api-url="delete/qitem" data-item="' + encodeURI(item.id) + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
@@ -107,25 +60,87 @@
}
item.chkbox = '<input type="checkbox" data-id="qitems" name="multi_select" value="' + item.id + '" />';
});
- }
- }),
- "empty": lang.empty,
- "paging": {"enabled": true,"limit": 5,"size": pagination_size},
- "state": {"enabled": true},
- "sorting": {"enabled": true},
- "filtering": {"enabled": true,"position": "left","connectors": false,"placeholder": lang.filter_table},
- "toggleSelector": "table tbody span.footable-toggle",
- "on": {
- "destroy.ft.table": function(e, ft){
- $('.refresh_table').attr('disabled', 'true');
- },
- "ready.ft.table": function(e, ft){
- table_quarantine_ready(ft, 'quarantinetable');
- },
- "after.ft.filtering": function(e, ft){
- table_quarantine_ready(ft, 'quarantinetable');
+
+ return data;
}
},
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.qid,
+ data: 'qid',
+ defaultContent: ''
+ },
+ {
+ title: lang.sender,
+ data: 'sender',
+ defaultContent: ''
+ },
+ {
+ title: lang.subj,
+ data: 'subject',
+ defaultContent: ''
+ },
+ {
+ title: lang.rspamd_result,
+ data: 'rspamdaction',
+ defaultContent: ''
+ },
+ {
+ title: lang.rcpt,
+ data: 'rcpt',
+ defaultContent: ''
+ },
+ {
+ title: lang.danger,
+ data: 'virus',
+ defaultContent: ''
+ },
+ {
+ title: lang.spam_score,
+ data: 'score',
+ defaultContent: ''
+ },
+ {
+ title: lang.notified,
+ data: 'notified',
+ defaultContent: ''
+ },
+ {
+ title: lang.received,
+ data: 'created',
+ defaultContent: '',
+ render: function (data,type) {
+ var date = new Date(data ? data * 1000 : 0);
+ return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
});
}
@@ -175,9 +190,9 @@
if (value.score > 0) highlightClass = 'negative'
else if (value.score < 0) highlightClass = 'positive'
else highlightClass = 'neutral'
- $('#qid_detail_symbols').append('<span data-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
+ $('#qid_detail_symbols').append('<span data-bs-toggle="tooltip" class="rspamd-symbol ' + highlightClass + '" title="' + (value.options ? value.options.join(', ') : '') + '">' + value.name + ' (<span class="score">' + value.score + '</span>)</span>');
});
- $('[data-toggle="tooltip"]').tooltip()
+ $('[data-bs-toggle="tooltip"]').tooltip()
}
if (typeof data.fuzzy_hashes === 'object' && data.fuzzy_hashes !== null && data.fuzzy_hashes.length !== 0) {
$.each(data.fuzzy_hashes, function (index, value) {
@@ -188,11 +203,11 @@
}
if (typeof data.score !== 'undefined' && typeof data.action !== 'undefined') {
if (data.action == "add header") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.junk_folder + '</span>');
} else if (data.action == "reject") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-danger"><b>' + data.score + '</b> - ' + lang.rejected + '</span>');
} else if (data.action == "rewrite subject") {
- $('#qid_detail_score').append('<span class="label-rspamd-action label label-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
+ $('#qid_detail_score').append('<span class="label-rspamd-action badge fs-6 bg-warning"><b>' + data.score + '</b> - ' + lang.rewrite_subject + '</span>');
}
}
if (typeof data.recipients !== 'undefined') {
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/queue.js b/mailcow/src/mailcow-dockerized/data/web/js/site/queue.js
new file mode 100644
index 0000000..057ad84
--- /dev/null
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/queue.js
@@ -0,0 +1,123 @@
+jQuery(function($){
+
+ $(".refresh_table").on('click', function(e) {
+ e.preventDefault();
+ var table_name = $(this).data('table');
+ $('#' + table_name).DataTable().ajax.reload();
+ });
+
+
+ function humanFileSize(i){if(Math.abs(i)<1024)return i+" B";var B=["KiB","MiB","GiB","TiB","PiB","EiB","ZiB","YiB"],e=-1;do{i/=1024,++e}while(Math.abs(i)>=1024&&e<B.length-1);return i.toFixed(1)+" "+B[e]}
+
+ // Queue item
+ $('#showQueuedMsg').on('show.bs.modal', function (e) {
+ $('#queue_msg_content').text(lang.loading);
+ button = $(e.relatedTarget)
+ if (button != null) {
+ $('#queue_id').text(button.data('queue-id'));
+ }
+ $.ajax({
+ type: 'GET',
+ url: '/api/v1/get/postcat/' + button.data('queue-id'),
+ dataType: 'text',
+ complete: function (data) {
+ console.log(data);
+ $('#queue_msg_content').text(data.responseText);
+ }
+ });
+ })
+
+ function draw_queue() {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#queuetable') ) {
+ $('#queuetable').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#queuetable').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/mailq/all",
+ dataSrc: function(data){
+ $.each(data, function (i, item) {
+ item.chkbox = '<input type="checkbox" data-id="mailqitems" name="multi_select" value="' + item.queue_id + '" />';
+ rcpts = $.map(item.recipients, function(i) {
+ return escapeHtml(i);
+ });
+ item.recipients = rcpts.join('<hr style="margin:1px!important">');
+ item.action = '<div class="btn-group">' +
+ '<a href="#" data-bs-toggle="modal" data-bs-target="#showQueuedMsg" data-queue-id="' + encodeURI(item.queue_id) + '" class="btn btn-xs btn-secondary">' + lang.queue_show_message + '</a>' +
+ '</div>';
+ });
+ return data;
+ }
+ },
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'QID',
+ data: 'queue_id',
+ defaultContent: ''
+ },
+ {
+ title: 'Queue',
+ data: 'queue_name',
+ defaultContent: ''
+ },
+ {
+ title: lang_admin.arrival_time,
+ data: 'arrival_time',
+ defaultContent: '',
+ render: function (data, type){
+ var date = new Date(data ? data * 1000 : 0);
+ return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+ }
+ },
+ {
+ title: lang_admin.message_size,
+ data: 'message_size',
+ defaultContent: '',
+ render: function (data, type){
+ return humanFileSize(data);
+ }
+ },
+ {
+ title: lang_admin.sender,
+ data: 'sender',
+ defaultContent: ''
+ },
+ {
+ title: lang_admin.recipients,
+ data: 'recipients',
+ defaultContent: ''
+ },
+ {
+ title: lang_admin.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ },
+ ]
+ });
+ }
+
+ draw_queue();
+
+})
\ No newline at end of file
diff --git a/mailcow/src/mailcow-dockerized/data/web/js/site/user.js b/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
index 8fd7b47..36bcfa6 100644
--- a/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
+++ b/mailcow/src/mailcow-dockerized/data/web/js/site/user.js
@@ -101,7 +101,7 @@
$.each(data.sasl, function (i, item) {
var datetime = new Date(item.datetime.replace(/-/g, "/"));
var local_datetime = datetime.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
- var service = '<div class="label label-default">' + item.service.toUpperCase() + '</div>';
+ var service = '<div class="badge fs-6 bg-secondary">' + item.service.toUpperCase() + '</div>';
var app_password = item.app_password ? ' <a href="/edit/app-passwd/' + item.app_password + '"><i class="bi bi-app-indicator"></i> ' + escapeHtml(item.app_password_name || "App") + '</a>' : '';
var real_rip = item.real_rip.startsWith("Web") ? item.real_rip : '<a href="https://bgp.he.net/ip/' + item.real_rip + '" target="_blank">' + item.real_rip + "</a>";
var ip_location = item.location ? ' <span class="flag-icon flag-icon-' + item.location.toLowerCase() + '"></span>' : '';
@@ -128,26 +128,24 @@
}
function draw_tla_table() {
- ft_tla_table = FooTable.init('#tla_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"address","title":lang.alias},
- {"name":"validity","formatter":function unix_time_format(tm) { var date = new Date(tm ? tm * 1000 : 0); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.alias_valid_until,"style":{"width":"170px"}},
- {"sorted": true,"sortValue": function(value){res = new Date(value);return res.getTime();},"direction":"DESC","name":"created","formatter":function date_format(datetime) { var date = new Date(datetime.replace(/-/g, "/")); return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});},"title":lang.created_on,"style":{"width":"170px"}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
- url: '/api/v1/get/time_limited_aliases',
- jsonp: false,
- error: function () {
- console.log('Cannot draw tla table');
- },
- success: function (data) {
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#tla_table') ) {
+ $('#tla_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#tla_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
+ url: "/api/v1/get/time_limited_aliases",
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (acl_data.spam_alias === 1) {
- item.action = '<div class="btn-group footable-actions">' +
+ item.action = '<div class="btn-group">' +
'<a href="#" data-action="delete_selected" data-id="single-tla" data-api-url="delete/time_limited_alias" data-item="' + encodeURIComponent(item.address) + '" class="btn btn-xs btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="tla" name="multi_select" value="' + encodeURIComponent(item.address) + '" />';
@@ -158,49 +156,77 @@
item.action = '<span>-</span>';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "sorting": {
- "enabled": true
- },
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: lang.alias,
+ data: 'address',
+ defaultContent: ''
+ },
+ {
+ title: lang.alias_valid_until,
+ data: 'validity',
+ defaultContent: '',
+ render: function (data, type) {
+ var date = new Date(data ? data * 1000 : 0);
+ return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+ }
+ },
+ {
+ title: lang.created_on,
+ data: 'created',
+ defaultContent: '',
+ render: function (data, type) {
+ var date = new Date(data.replace(/-/g, "/"));
+ return date.toLocaleDateString(undefined, {year: "numeric", month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", second: "2-digit"});
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_sync_job_table() {
- ft_syncjob_table = FooTable.init('#sync_job_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"min-width":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
- {"name":"server_w_port","title":"Server","breakpoints":"xs sm md","style":{"word-break":"break-all"}},
- {"name":"enc1","title":lang.encryption,"breakpoints":"all"},
- {"name":"user1","title":lang.username},
- {"name":"exclude","title":lang.excludes,"breakpoints":"all"},
- {"name":"mins_interval","title":lang.interval + " (min)","breakpoints":"all"},
- {"name":"last_run","title":lang.last_run,"breakpoints":"xs sm md"},
- {"name":"exit_status","filterable": false,"title":lang.syncjob_last_run_result},
- {"name":"log","title":"Log"},
- {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"is_running","filterable": false,"style":{"maxWidth":"120px","width":"100px"},"title":lang.status},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"260px","width":"260px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#sync_job_table') ) {
+ $('#sync_job_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#sync_job_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/syncjobs/' + encodeURIComponent(mailcow_cc_username) + '/no_log',
- jsonp: false,
- error: function () {
- console.log('Cannot draw sync job table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
item.user1 = escapeHtml(item.user1);
- item.log = '<a href="#syncjobLogModal" data-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
+ item.log = '<a href="#syncjobLogModal" data-bs-toggle="modal" data-syncjob-id="' + item.id + '">' + lang.open_logs + '</a>'
if (!item.exclude > 0) {
item.exclude = '-';
} else {
@@ -208,8 +234,8 @@
}
item.server_w_port = escapeHtml(item.user1 + '@' + item.host1 + ':' + item.port1);
if (acl_data.syncjobs === 1) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/syncjob/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-syncjob" data-api-url="delete/syncjob" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="syncjob" name="multi_select" value="' + item.id + '" />';
@@ -219,9 +245,9 @@
item.chkbox = '<input type="checkbox" disabled />';
}
if (item.is_running == 1) {
- item.is_running = '<span id="active-script" class="label label-success">' + lang.running + '</span>';
+ item.is_running = '<span id="active-script" class="badge fs-6 bg-success">' + lang.running + '</span>';
} else {
- item.is_running = '<span id="inactive-script" class="label label-warning">' + lang.waiting + '</span>';
+ item.is_running = '<span id="inactive-script" class="badge fs-6 bg-warning">' + lang.waiting + '</span>';
}
if (!item.last_run > 0) {
item.last_run = lang.waiting;
@@ -239,39 +265,115 @@
}
item.exit_status = item.success + ' ' + item.exit_status;
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "sorting": {
- "enabled": true
- },
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 1
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: '',
+ responsivePriority: 2
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: '',
+ responsivePriority: 3
+ },
+ {
+ title: 'Server',
+ data: 'server_w_port',
+ defaultContent: ''
+ },
+ {
+ title: lang.username,
+ data: 'user1',
+ defaultContent: '',
+ responsivePriority: 3
+ },
+ {
+ title: lang.last_run,
+ data: 'last_run',
+ defaultContent: ''
+ },
+ {
+ title: lang.syncjob_last_run_result,
+ data: 'exit_status',
+ defaultContent: ''
+ },
+ {
+ title: 'Log',
+ data: 'log',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.status,
+ data: 'is_running',
+ defaultContent: '',
+ responsivePriority: 5
+ },
+ {
+ title: lang.encryption,
+ data: 'enc1',
+ defaultContent: ''
+ },
+ {
+ title: lang.excludes,
+ data: 'exclude',
+ defaultContent: ''
+ },
+ {
+ title: lang.interval + " (min)",
+ data: 'mins_interval',
+ defaultContent: ''
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: '',
+ responsivePriority: 5
+ }
+ ]
});
}
function draw_app_passwd_table() {
- ft_apppasswd_table = FooTable.init('#app_passwd_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"60px","width":"60px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"sorted": true,"name":"id","title":"ID","style":{"maxWidth":"60px","width":"60px","text-align":"center"}},
- {"name":"name","title":lang.app_name},
- {"name":"protocols","title":lang.allowed_protocols},
- {"name":"active","filterable": false,"style":{"maxWidth":"70px","width":"70px"},"title":lang.active,"formatter": function(value){return 1==value?'<i class="bi bi-check-lg"></i>':0==value&&'<i class="bi bi-x-lg"></i>';}},
- {"name":"action","filterable": false,"sortable": false,"style":{"text-align":"right","min-width":"220px","width":"220px"},"type":"html","title":lang.action,"breakpoints":"xs sm"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#app_passwd_table') ) {
+ $('#app_passwd_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#app_passwd_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/app-passwd/all',
- jsonp: false,
- error: function () {
- console.log('Cannot draw app passwd table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
item.name = escapeHtml(item.name)
item.protocols = []
@@ -283,8 +385,8 @@
if (item.sieve_access == 1) { item.protocols.push("<code>Sieve</code>"); }
item.protocols = item.protocols.join(" ")
if (acl_data.app_passwds === 1) {
- item.action = '<div class="btn-group footable-actions">' +
- '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-default"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
+ item.action = '<div class="btn-group">' +
+ '<a href="/edit/app-passwd/' + item.id + '" class="btn btn-xs btn-xs-half btn-secondary"><i class="bi bi-pencil-fill"></i> ' + lang.edit + '</a>' +
'<a href="#" data-action="delete_selected" data-id="single-apppasswd" data-api-url="delete/app-passwd" data-item="' + item.id + '" class="btn btn-xs btn-xs-half btn-danger"><i class="bi bi-trash"></i> ' + lang.remove + '</a>' +
'</div>';
item.chkbox = '<input type="checkbox" data-id="apppasswd" name="multi_select" value="' + item.id + '" />';
@@ -294,37 +396,74 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "sorting": {
- "enabled": true
- },
- "toggleSelector": "table tbody span.footable-toggle"
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'id',
+ defaultContent: ''
+ },
+ {
+ title: lang.app_name,
+ data: 'name',
+ defaultContent: ''
+ },
+ {
+ title: lang.allowed_protocols,
+ data: 'protocols',
+ defaultContent: ''
+ },
+ {
+ title: lang.active,
+ data: 'active',
+ defaultContent: '',
+ render: function (data, type) {
+ return 1==data?'<i class="bi bi-check-lg"></i>':0==data&&'<i class="bi bi-x-lg"></i>'
+ }
+ },
+ {
+ title: lang.action,
+ data: 'action',
+ className: 'text-md-end dt-sm-head-hidden dt-body-right',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_wl_policy_mailbox_table() {
- ft_wl_policy_mailbox_table = FooTable.init('#wl_policy_mailbox_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#wl_policy_mailbox_table') ) {
+ $('#wl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#wl_policy_mailbox_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_wl_mailbox',
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy wl table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_wl_mailbox" name="multi_select" value="' + item.prefid + '" />';
@@ -336,36 +475,60 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "state": {"enabled": true},
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title:'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
function draw_bl_policy_mailbox_table() {
- ft_bl_policy_mailbox_table = FooTable.init('#bl_policy_mailbox_table', {
- "columns": [
- {"name":"chkbox","title":"","style":{"maxWidth":"40px","width":"40px","text-align":"center"},"filterable": false,"sortable": false,"type":"html"},
- {"name":"prefid","style":{"maxWidth":"40px","width":"40px"},"title":"ID","filterable": false,"sortable": false},
- {"sorted": true,"name":"value","title":lang.spamfilter_table_rule},
- {"name":"object","title":"Scope"}
- ],
- "empty": lang.empty,
- "rows": $.ajax({
- dataType: 'json',
+ // just recalc width if instance already exists
+ if ($.fn.DataTable.isDataTable('#bl_policy_mailbox_table') ) {
+ $('#bl_policy_mailbox_table').DataTable().columns.adjust().responsive.recalc();
+ return;
+ }
+
+ $('#bl_policy_mailbox_table').DataTable({
+ processing: true,
+ serverSide: false,
+ language: lang_datatables,
+ ajax: {
+ type: "GET",
url: '/api/v1/get/policy_bl_mailbox',
- jsonp: false,
- error: function () {
- console.log('Cannot draw mailbox policy bl table');
- },
- success: function (data) {
+ dataSrc: function(data){
+ console.log(data);
$.each(data, function (i, item) {
if (validateEmail(item.object)) {
item.chkbox = '<input type="checkbox" data-id="policy_bl_mailbox" name="multi_select" value="' + item.prefid + '" />';
@@ -377,31 +540,45 @@
item.chkbox = '<input type="checkbox" disabled />';
}
});
+
+ return data;
}
- }),
- "paging": {
- "enabled": true,
- "limit": 5,
- "size": pagination_size
},
- "state": {"enabled": true},
- "sorting": {
- "enabled": true
- }
+ columns: [
+ {
+ // placeholder, so checkbox will not block child row toggle
+ title: '',
+ data: null,
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: '',
+ data: 'chkbox',
+ searchable: false,
+ orderable: false,
+ defaultContent: ''
+ },
+ {
+ title: 'ID',
+ data: 'prefid',
+ defaultContent: ''
+ },
+ {
+ title: lang.spamfilter_table_rule,
+ data: 'value',
+ defaultContent: ''
+ },
+ {
+ title:'Scope',
+ data: 'object',
+ defaultContent: ''
+ }
+ ]
});
}
- $('body').on('click', 'span.footable-toggle', function () {
- event.stopPropagation();
- })
-
- draw_sync_job_table();
- draw_app_passwd_table();
- draw_tla_table();
- draw_wl_policy_mailbox_table();
- draw_bl_policy_mailbox_table();
- last_logins('get');
-
// FIDO2 friendly name modal
$('#fido2ChangeFn').on('show.bs.modal', function (e) {
rename_link = $(e.relatedTarget)
@@ -433,4 +610,28 @@
$('#userFilterModal').on('hidden.bs.modal', function () {
$('#user_sieve_filter').text(lang.loading);
});
+
+ // detect element visibility changes
+ function onVisible(element, callback) {
+ $(document).ready(function() {
+ element_object = document.querySelector(element);
+ if (element_object === null) return;
+
+ new IntersectionObserver((entries, observer) => {
+ entries.forEach(entry => {
+ if(entry.intersectionRatio > 0) {
+ callback(element_object);
+ }
+ });
+ }).observe(element_object);
+ });
+ }
+
+ // Load only if the tab is visible
+ onVisible("[id^=tla_table]", () => draw_tla_table());
+ onVisible("[id^=bl_policy_mailbox_table]", () => draw_bl_policy_mailbox_table());
+ onVisible("[id^=wl_policy_mailbox_table]", () => draw_wl_policy_mailbox_table());
+ onVisible("[id^=sync_job_table]", () => draw_sync_job_table());
+ onVisible("[id^=app_passwd_table]", () => draw_app_passwd_table());
+ last_logins('get');
});