// source --> https://lipper-quartiere.de/wp-includes/js/jquery/jquery.min.js?ver=3.7.1 
/*! jQuery v3.7.1 | (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(ie,e){"use strict";var oe=[],r=Object.getPrototypeOf,ae=oe.slice,g=oe.flat?function(e){return oe.flat.call(e)}:function(e){return oe.concat.apply([],e)},s=oe.push,se=oe.indexOf,n={},i=n.toString,ue=n.hasOwnProperty,o=ue.toString,a=o.call(Object),le={},v=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},y=function(e){return null!=e&&e===e.window},C=ie.document,u={type:!0,src:!0,nonce:!0,noModule:!0};function m(e,t,n){var r,i,o=(n=n||C).createElement("script");if(o.text=e,t)for(r in u)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function x(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[i.call(e)]||"object":typeof e}var t="3.7.1",l=/HTML$/i,ce=function(e,t){return new ce.fn.init(e,t)};function c(e){var t=!!e&&"length"in e&&e.length,n=x(e);return!v(e)&&!y(e)&&("array"===n||0===t||"number"==typeof t&&0<t&&t-1 in e)}function fe(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}ce.fn=ce.prototype={jquery:t,constructor:ce,length:0,toArray:function(){return ae.call(this)},get:function(e){return null==e?ae.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=ce.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return ce.each(this,e)},map:function(n){return this.pushStack(ce.map(this,function(e,t){return n.call(e,t,e)}))},slice:function(){return this.pushStack(ae.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(ce.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(ce.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:s,sort:oe.sort,splice:oe.splice},ce.extend=ce.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||v(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&&(ce.isPlainObject(r)||(i=Array.isArray(r)))?(n=a[t],o=i&&!Array.isArray(n)?[]:i||ce.isPlainObject(n)?n:{},i=!1,a[t]=ce.extend(l,o,r)):void 0!==r&&(a[t]=r));return a},ce.extend({expando:"jQuery"+(t+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]"!==i.call(e))&&(!(t=r(e))||"function"==typeof(n=ue.call(t,"constructor")&&t.constructor)&&o.call(n)===a)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},globalEval:function(e,t,n){m(e,{nonce:t&&t.nonce},n)},each:function(e,t){var n,r=0;if(c(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},text:function(e){var t,n="",r=0,i=e.nodeType;if(!i)while(t=e[r++])n+=ce.text(t);return 1===i||11===i?e.textContent:9===i?e.documentElement.textContent:3===i||4===i?e.nodeValue:n},makeArray:function(e,t){var n=t||[];return null!=e&&(c(Object(e))?ce.merge(n,"string"==typeof e?[e]:e):s.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:se.call(t,e,n)},isXMLDoc:function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!l.test(t||n&&n.nodeName||"HTML")},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(c(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:le}),"function"==typeof Symbol&&(ce.fn[Symbol.iterator]=oe[Symbol.iterator]),ce.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){n["[object "+t+"]"]=t.toLowerCase()});var pe=oe.pop,de=oe.sort,he=oe.splice,ge="[\\x20\\t\\r\\n\\f]",ve=new RegExp("^"+ge+"+|((?:^|[^\\\\])(?:\\\\.)*)"+ge+"+$","g");ce.contains=function(e,t){var n=t&&t.parentNode;return e===n||!(!n||1!==n.nodeType||!(e.contains?e.contains(n):e.compareDocumentPosition&&16&e.compareDocumentPosition(n)))};var f=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g;function p(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e}ce.escapeSelector=function(e){return(e+"").replace(f,p)};var ye=C,me=s;!function(){var e,b,w,o,a,T,r,C,d,i,k=me,S=ce.expando,E=0,n=0,s=W(),c=W(),u=W(),h=W(),l=function(e,t){return e===t&&(a=!0),0},f="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",t="(?:\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\[^\\r\\n\\f]|[\\w-]|[^\0-\\x7f])+",p="\\["+ge+"*("+t+")(?:"+ge+"*([*^$|!~]?=)"+ge+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+t+"))|)"+ge+"*\\]",g=":("+t+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+p+")*)|.*)\\)|)",v=new RegExp(ge+"+","g"),y=new RegExp("^"+ge+"*,"+ge+"*"),m=new RegExp("^"+ge+"*([>+~]|"+ge+")"+ge+"*"),x=new RegExp(ge+"|>"),j=new RegExp(g),A=new RegExp("^"+t+"$"),D={ID:new RegExp("^#("+t+")"),CLASS:new RegExp("^\\.("+t+")"),TAG:new RegExp("^("+t+"|[*])"),ATTR:new RegExp("^"+p),PSEUDO:new RegExp("^"+g),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ge+"*(even|odd|(([+-]|)(\\d*)n|)"+ge+"*(?:([+-]|)"+ge+"*(\\d+)|))"+ge+"*\\)|)","i"),bool:new RegExp("^(?:"+f+")$","i"),needsContext:new RegExp("^"+ge+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ge+"*((?:-\\d)?\\d*)"+ge+"*\\)|)(?=[^-]|$)","i")},N=/^(?:input|select|textarea|button)$/i,q=/^h\d$/i,L=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,H=/[+~]/,O=new RegExp("\\\\[\\da-fA-F]{1,6}"+ge+"?|\\\\([^\\r\\n\\f])","g"),P=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))},M=function(){V()},R=J(function(e){return!0===e.disabled&&fe(e,"fieldset")},{dir:"parentNode",next:"legend"});try{k.apply(oe=ae.call(ye.childNodes),ye.childNodes),oe[ye.childNodes.length].nodeType}catch(e){k={apply:function(e,t){me.apply(e,ae.call(t))},call:function(e){me.apply(e,ae.call(arguments,1))}}}function I(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&&(V(e),e=e||T,C)){if(11!==p&&(u=L.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return k.call(n,a),n}else if(f&&(a=f.getElementById(i))&&I.contains(e,a)&&a.id===i)return k.call(n,a),n}else{if(u[2])return k.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&e.getElementsByClassName)return k.apply(n,e.getElementsByClassName(i)),n}if(!(h[t+" "]||d&&d.test(t))){if(c=t,f=e,1===p&&(x.test(t)||m.test(t))){(f=H.test(t)&&U(e.parentNode)||e)==e&&le.scope||((s=e.getAttribute("id"))?s=ce.escapeSelector(s):e.setAttribute("id",s=S)),o=(l=Y(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+Q(l[o]);c=l.join(",")}try{return k.apply(n,f.querySelectorAll(c)),n}catch(e){h(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return re(t.replace(ve,"$1"),e,n,r)}function W(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function F(e){return e[S]=!0,e}function $(e){var t=T.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function B(t){return function(e){return fe(e,"input")&&e.type===t}}function _(t){return function(e){return(fe(e,"input")||fe(e,"button"))&&e.type===t}}function z(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&&R(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function X(a){return F(function(o){return o=+o,F(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 U(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function V(e){var t,n=e?e.ownerDocument||e:ye;return n!=T&&9===n.nodeType&&n.documentElement&&(r=(T=n).documentElement,C=!ce.isXMLDoc(T),i=r.matches||r.webkitMatchesSelector||r.msMatchesSelector,r.msMatchesSelector&&ye!=T&&(t=T.defaultView)&&t.top!==t&&t.addEventListener("unload",M),le.getById=$(function(e){return r.appendChild(e).id=ce.expando,!T.getElementsByName||!T.getElementsByName(ce.expando).length}),le.disconnectedMatch=$(function(e){return i.call(e,"*")}),le.scope=$(function(){return T.querySelectorAll(":scope")}),le.cssHas=$(function(){try{return T.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),le.getById?(b.filter.ID=function(e){var t=e.replace(O,P);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&C){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(O,P);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&&C){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=function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},b.find.CLASS=function(e,t){if("undefined"!=typeof t.getElementsByClassName&&C)return t.getElementsByClassName(e)},d=[],$(function(e){var t;r.appendChild(e).innerHTML="<a id='"+S+"' href='' disabled='disabled'></a><select id='"+S+"-\r\\' disabled='disabled'><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+ge+"*(?:value|"+f+")"),e.querySelectorAll("[id~="+S+"-]").length||d.push("~="),e.querySelectorAll("a#"+S+"+*").length||d.push(".#.+[+~]"),e.querySelectorAll(":checked").length||d.push(":checked"),(t=T.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),r.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&d.push(":enabled",":disabled"),(t=T.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||d.push("\\["+ge+"*name"+ge+"*="+ge+"*(?:''|\"\")")}),le.cssHas||d.push(":has"),d=d.length&&new RegExp(d.join("|")),l=function(e,t){if(e===t)return a=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!le.sortDetached&&t.compareDocumentPosition(e)===n?e===T||e.ownerDocument==ye&&I.contains(ye,e)?-1:t===T||t.ownerDocument==ye&&I.contains(ye,t)?1:o?se.call(o,e)-se.call(o,t):0:4&n?-1:1)}),T}for(e in I.matches=function(e,t){return I(e,null,null,t)},I.matchesSelector=function(e,t){if(V(e),C&&!h[t+" "]&&(!d||!d.test(t)))try{var n=i.call(e,t);if(n||le.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){h(t,!0)}return 0<I(t,T,null,[e]).length},I.contains=function(e,t){return(e.ownerDocument||e)!=T&&V(e),ce.contains(e,t)},I.attr=function(e,t){(e.ownerDocument||e)!=T&&V(e);var n=b.attrHandle[t.toLowerCase()],r=n&&ue.call(b.attrHandle,t.toLowerCase())?n(e,t,!C):void 0;return void 0!==r?r:e.getAttribute(t)},I.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},ce.uniqueSort=function(e){var t,n=[],r=0,i=0;if(a=!le.sortStable,o=!le.sortStable&&ae.call(e,0),de.call(e,l),a){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)he.call(e,n[r],1)}return o=null,e},ce.fn.uniqueSort=function(){return this.pushStack(ce.uniqueSort(ae.apply(this)))},(b=ce.expr={cacheLength:50,createPseudo:F,match:D,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(O,P),e[3]=(e[3]||e[4]||e[5]||"").replace(O,P),"~="===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]||I.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]&&I.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return D.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&j.test(n)&&(t=Y(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(O,P).toLowerCase();return"*"===e?function(){return!0}:function(e){return fe(e,t)}},CLASS:function(e){var t=s[e+" "];return t||(t=new RegExp("(^|"+ge+")"+e+"("+ge+"|$)"))&&s(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=I.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(v," ")+" ").indexOf(i):"|="===r&&(t===i||t.slice(0,i.length+1)===i+"-"))}},CHILD:function(d,e,t,h,g){var v="nth"!==d.slice(0,3),y="last"!==d.slice(-4),m="of-type"===e;return 1===h&&0===g?function(e){return!!e.parentNode}:function(e,t,n){var r,i,o,a,s,u=v!==y?"nextSibling":"previousSibling",l=e.parentNode,c=m&&e.nodeName.toLowerCase(),f=!n&&!m,p=!1;if(l){if(v){while(u){o=e;while(o=o[u])if(m?fe(o,c):1===o.nodeType)return!1;s=u="only"===d&&!s&&"nextSibling"}return!0}if(s=[y?l.firstChild:l.lastChild],y&&f){p=(a=(r=(i=l[S]||(l[S]={}))[d]||[])[0]===E&&r[1])&&r[2],o=a&&l.childNodes[a];while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if(1===o.nodeType&&++p&&o===e){i[d]=[E,a,p];break}}else if(f&&(p=a=(r=(i=e[S]||(e[S]={}))[d]||[])[0]===E&&r[1]),!1===p)while(o=++a&&o&&o[u]||(p=a=0)||s.pop())if((m?fe(o,c):1===o.nodeType)&&++p&&(f&&((i=o[S]||(o[S]={}))[d]=[E,p]),o===e))break;return(p-=g)===h||p%h==0&&0<=p/h}}},PSEUDO:function(e,o){var t,a=b.pseudos[e]||b.setFilters[e.toLowerCase()]||I.error("unsupported pseudo: "+e);return a[S]?a(o):1<a.length?(t=[e,e,"",o],b.setFilters.hasOwnProperty(e.toLowerCase())?F(function(e,t){var n,r=a(e,o),i=r.length;while(i--)e[n=se.call(e,r[i])]=!(t[n]=r[i])}):function(e){return a(e,0,t)}):a}},pseudos:{not:F(function(e){var r=[],i=[],s=ne(e.replace(ve,"$1"));return s[S]?F(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:F(function(t){return function(e){return 0<I(t,e).length}}),contains:F(function(t){return t=t.replace(O,P),function(e){return-1<(e.textContent||ce.text(e)).indexOf(t)}}),lang:F(function(n){return A.test(n||"")||I.error("unsupported lang: "+n),n=n.replace(O,P).toLowerCase(),function(e){var t;do{if(t=C?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=ie.location&&ie.location.hash;return t&&t.slice(1)===e.id},root:function(e){return e===r},focus:function(e){return e===function(){try{return T.activeElement}catch(e){}}()&&T.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:z(!1),disabled:z(!0),checked:function(e){return fe(e,"input")&&!!e.checked||fe(e,"option")&&!!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 q.test(e.nodeName)},input:function(e){return N.test(e.nodeName)},button:function(e){return fe(e,"input")&&"button"===e.type||fe(e,"button")},text:function(e){var t;return fe(e,"input")&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:X(function(){return[0]}),last:X(function(e,t){return[t-1]}),eq:X(function(e,t,n){return[n<0?n+t:n]}),even:X(function(e,t){for(var n=0;n<t;n+=2)e.push(n);return e}),odd:X(function(e,t){for(var n=1;n<t;n+=2)e.push(n);return e}),lt:X(function(e,t,n){var r;for(r=n<0?n+t:t<n?t:n;0<=--r;)e.push(r);return e}),gt:X(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]=B(e);for(e in{submit:!0,reset:!0})b.pseudos[e]=_(e);function G(){}function Y(e,t){var n,r,i,o,a,s,u,l=c[e+" "];if(l)return t?0:l.slice(0);a=e,s=[],u=b.preFilter;while(a){for(o in n&&!(r=y.exec(a))||(r&&(a=a.slice(r[0].length)||a),s.push(i=[])),n=!1,(r=m.exec(a))&&(n=r.shift(),i.push({value:n,type:r[0].replace(ve," ")}),a=a.slice(n.length)),b.filter)!(r=D[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?I.error(e):c(e,s).slice(0)}function Q(e){for(var t=0,n=e.length,r="";t<n;t++)r+=e[t].value;return r}function J(a,e,t){var s=e.dir,u=e.next,l=u||s,c=t&&"parentNode"===l,f=n++;return e.first?function(e,t,n){while(e=e[s])if(1===e.nodeType||c)return a(e,t,n);return!1}:function(e,t,n){var r,i,o=[E,f];if(n){while(e=e[s])if((1===e.nodeType||c)&&a(e,t,n))return!0}else while(e=e[s])if(1===e.nodeType||c)if(i=e[S]||(e[S]={}),u&&fe(e,u))e=e[s]||e;else{if((r=i[l])&&r[0]===E&&r[1]===f)return o[2]=r[2];if((i[l]=o)[2]=a(e,t,n))return!0}return!1}}function K(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 Z(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 ee(d,h,g,v,y,e){return v&&!v[S]&&(v=ee(v)),y&&!y[S]&&(y=ee(y,e)),F(function(e,t,n,r){var i,o,a,s,u=[],l=[],c=t.length,f=e||function(e,t,n){for(var r=0,i=t.length;r<i;r++)I(e,t[r],n);return n}(h||"*",n.nodeType?[n]:n,[]),p=!d||!e&&h?f:Z(f,u,d,n,r);if(g?g(p,s=y||(e?d:c||v)?[]:t,n,r):s=p,v){i=Z(s,l),v(i,[],n,r),o=i.length;while(o--)(a=i[o])&&(s[l[o]]=!(p[l[o]]=a))}if(e){if(y||d){if(y){i=[],o=s.length;while(o--)(a=s[o])&&i.push(p[o]=a);y(null,s=[],i,r)}o=s.length;while(o--)(a=s[o])&&-1<(i=y?se.call(e,a):u[o])&&(e[i]=!(t[i]=a))}}else s=Z(s===t?s.splice(c,s.length):s),y?y(null,t,s,r):k.apply(t,s)})}function te(e){for(var i,t,n,r=e.length,o=b.relative[e[0].type],a=o||b.relative[" "],s=o?1:0,u=J(function(e){return e===i},a,!0),l=J(function(e){return-1<se.call(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=[J(K(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 ee(1<s&&K(c),1<s&&Q(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(ve,"$1"),t,s<n&&te(e.slice(s,n)),n<r&&te(e=e.slice(n)),n<r&&Q(e))}c.push(t)}return K(c)}function ne(e,t){var n,v,y,m,x,r,i=[],o=[],a=u[e+" "];if(!a){t||(t=Y(e)),n=t.length;while(n--)(a=te(t[n]))[S]?i.push(a):o.push(a);(a=u(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=E+=null==p?1:Math.random()||.1,g=d.length;for(i&&(w=t==T||t||i);l!==g&&null!=(o=d[l]);l++){if(x&&o){a=0,t||o.ownerDocument==T||(V(o),n=!C);while(s=v[a++])if(s(o,t||T,n)){k.call(r,o);break}i&&(E=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]=pe.call(r));f=Z(f)}k.apply(r,f),i&&!e&&0<f.length&&1<u+y.length&&ce.uniqueSort(r)}return i&&(E=h,w=p),c},m?F(r):r))).selector=e}return a}function re(e,t,n,r){var i,o,a,s,u,l="function"==typeof e&&e,c=!r&&Y(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&&C&&b.relative[o[1].type]){if(!(t=(b.find.ID(a.matches[0].replace(O,P),t)||[])[0]))return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}i=D.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(O,P),H.test(o[0].type)&&U(t.parentNode)||t))){if(o.splice(i,1),!(e=r.length&&Q(o)))return k.apply(n,r),n;break}}}return(l||ne(e,c))(r,t,!C,n,!t||H.test(e)&&U(t.parentNode)||t),n}G.prototype=b.filters=b.pseudos,b.setFilters=new G,le.sortStable=S.split("").sort(l).join("")===S,V(),le.sortDetached=$(function(e){return 1&e.compareDocumentPosition(T.createElement("fieldset"))}),ce.find=I,ce.expr[":"]=ce.expr.pseudos,ce.unique=ce.uniqueSort,I.compile=ne,I.select=re,I.setDocument=V,I.tokenize=Y,I.escape=ce.escapeSelector,I.getText=ce.text,I.isXML=ce.isXMLDoc,I.selectors=ce.expr,I.support=ce.support,I.uniqueSort=ce.uniqueSort}();var d=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&ce(e).is(n))break;r.push(e)}return r},h=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},b=ce.expr.match.needsContext,w=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function T(e,n,r){return v(n)?ce.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?ce.grep(e,function(e){return e===n!==r}):"string"!=typeof n?ce.grep(e,function(e){return-1<se.call(n,e)!==r}):ce.filter(n,e,r)}ce.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?ce.find.matchesSelector(r,e)?[r]:[]:ce.find.matches(e,ce.grep(t,function(e){return 1===e.nodeType}))},ce.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(ce(e).filter(function(){for(t=0;t<r;t++)if(ce.contains(i[t],this))return!0}));for(n=this.pushStack([]),t=0;t<r;t++)ce.find(e,i[t],n);return 1<r?ce.uniqueSort(n):n},filter:function(e){return this.pushStack(T(this,e||[],!1))},not:function(e){return this.pushStack(T(this,e||[],!0))},is:function(e){return!!T(this,"string"==typeof e&&b.test(e)?ce(e):e||[],!1).length}});var k,S=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(ce.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||k,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:S.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 ce?t[0]:t,ce.merge(this,ce.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:C,!0)),w.test(r[1])&&ce.isPlainObject(t))for(r in t)v(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=C.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):v(e)?void 0!==n.ready?n.ready(e):e(ce):ce.makeArray(e,this)}).prototype=ce.fn,k=ce(C);var E=/^(?:parents|prev(?:Until|All))/,j={children:!0,contents:!0,next:!0,prev:!0};function A(e,t){while((e=e[t])&&1!==e.nodeType);return e}ce.fn.extend({has:function(e){var t=ce(e,this),n=t.length;return this.filter(function(){for(var e=0;e<n;e++)if(ce.contains(this,t[e]))return!0})},closest:function(e,t){var n,r=0,i=this.length,o=[],a="string"!=typeof e&&ce(e);if(!b.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&&ce.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(1<o.length?ce.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?se.call(ce(e),this[0]):se.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(ce.uniqueSort(ce.merge(this.get(),ce(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),ce.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return d(e,"parentNode")},parentsUntil:function(e,t,n){return d(e,"parentNode",n)},next:function(e){return A(e,"nextSibling")},prev:function(e){return A(e,"previousSibling")},nextAll:function(e){return d(e,"nextSibling")},prevAll:function(e){return d(e,"previousSibling")},nextUntil:function(e,t,n){return d(e,"nextSibling",n)},prevUntil:function(e,t,n){return d(e,"previousSibling",n)},siblings:function(e){return h((e.parentNode||{}).firstChild,e)},children:function(e){return h(e.firstChild)},contents:function(e){return null!=e.contentDocument&&r(e.contentDocument)?e.contentDocument:(fe(e,"template")&&(e=e.content||e),ce.merge([],e.childNodes))}},function(r,i){ce.fn[r]=function(e,t){var n=ce.map(this,i,e);return"Until"!==r.slice(-5)&&(t=e),t&&"string"==typeof t&&(n=ce.filter(t,n)),1<this.length&&(j[r]||ce.uniqueSort(n),E.test(r)&&n.reverse()),this.pushStack(n)}});var D=/[^\x20\t\r\n\f]+/g;function N(e){return e}function q(e){throw e}function L(e,t,n,r){var i;try{e&&v(i=e.promise)?i.call(e).done(t).fail(n):e&&v(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}ce.Callbacks=function(r){var e,n;r="string"==typeof r?(e=r,n={},ce.each(e.match(D)||[],function(e,t){n[t]=!0}),n):ce.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){ce.each(e,function(e,t){v(t)?r.unique&&f.has(t)||s.push(t):t&&t.length&&"string"!==x(t)&&n(t)})}(arguments),t&&!i&&c()),this},remove:function(){return ce.each(arguments,function(e,t){var n;while(-1<(n=ce.inArray(t,s,n)))s.splice(n,1),n<=l&&l--}),this},has:function(e){return e?-1<ce.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},ce.extend({Deferred:function(e){var o=[["notify","progress",ce.Callbacks("memory"),ce.Callbacks("memory"),2],["resolve","done",ce.Callbacks("once memory"),ce.Callbacks("once memory"),0,"resolved"],["reject","fail",ce.Callbacks("once memory"),ce.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 ce.Deferred(function(r){ce.each(o,function(e,t){var n=v(i[t[4]])&&i[t[4]];s[t[1]](function(){var e=n&&n.apply(this,arguments);e&&v(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,v(t)?s?t.call(e,l(u,o,N,s),l(u,o,q,s)):(u++,t.call(e,l(u,o,N,s),l(u,o,q,s),l(u,o,N,o.notifyWith))):(a!==N&&(n=void 0,r=[e]),(s||o.resolveWith)(n,r))}},t=s?e:function(){try{e()}catch(e){ce.Deferred.exceptionHook&&ce.Deferred.exceptionHook(e,t.error),u<=i+1&&(a!==q&&(n=void 0,r=[e]),o.rejectWith(n,r))}};i?t():(ce.Deferred.getErrorHook?t.error=ce.Deferred.getErrorHook():ce.Deferred.getStackHook&&(t.error=ce.Deferred.getStackHook()),ie.setTimeout(t))}}return ce.Deferred(function(e){o[0][3].add(l(0,e,v(r)?r:N,e.notifyWith)),o[1][3].add(l(0,e,v(t)?t:N)),o[2][3].add(l(0,e,v(n)?n:q))}).promise()},promise:function(e){return null!=e?ce.extend(e,a):a}},s={};return ce.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=ae.call(arguments),o=ce.Deferred(),a=function(t){return function(e){r[t]=this,i[t]=1<arguments.length?ae.call(arguments):e,--n||o.resolveWith(r,i)}};if(n<=1&&(L(e,o.done(a(t)).resolve,o.reject,!n),"pending"===o.state()||v(i[t]&&i[t].then)))return o.then();while(t--)L(i[t],a(t),o.reject);return o.promise()}});var H=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;ce.Deferred.exceptionHook=function(e,t){ie.console&&ie.console.warn&&e&&H.test(e.name)&&ie.console.warn("jQuery.Deferred exception: "+e.message,e.stack,t)},ce.readyException=function(e){ie.setTimeout(function(){throw e})};var O=ce.Deferred();function P(){C.removeEventListener("DOMContentLoaded",P),ie.removeEventListener("load",P),ce.ready()}ce.fn.ready=function(e){return O.then(e)["catch"](function(e){ce.readyException(e)}),this},ce.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--ce.readyWait:ce.isReady)||(ce.isReady=!0)!==e&&0<--ce.readyWait||O.resolveWith(C,[ce])}}),ce.ready.then=O.then,"complete"===C.readyState||"loading"!==C.readyState&&!C.documentElement.doScroll?ie.setTimeout(ce.ready):(C.addEventListener("DOMContentLoaded",P),ie.addEventListener("load",P));var M=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n))for(s in i=!0,n)M(e,t,s,n[s],!0,o,a);else if(void 0!==r&&(i=!0,v(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(ce(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},R=/^-ms-/,I=/-([a-z])/g;function W(e,t){return t.toUpperCase()}function F(e){return e.replace(R,"ms-").replace(I,W)}var $=function(e){return 1===e.nodeType||9===e.nodeType||!+e.nodeType};function B(){this.expando=ce.expando+B.uid++}B.uid=1,B.prototype={cache:function(e){var t=e[this.expando];return t||(t={},$(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[F(t)]=n;else for(r in t)i[F(r)]=t[r];return i},get:function(e,t){return void 0===t?this.cache(e):e[this.expando]&&e[this.expando][F(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(F):(t=F(t))in r?[t]:t.match(D)||[]).length;while(n--)delete r[t[n]]}(void 0===t||ce.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&&!ce.isEmptyObject(t)}};var _=new B,z=new B,X=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,U=/[A-Z]/g;function V(e,t,n){var r,i;if(void 0===n&&1===e.nodeType)if(r="data-"+t.replace(U,"-$&").toLowerCase(),"string"==typeof(n=e.getAttribute(r))){try{n="true"===(i=n)||"false"!==i&&("null"===i?null:i===+i+""?+i:X.test(i)?JSON.parse(i):i)}catch(e){}z.set(e,t,n)}else n=void 0;return n}ce.extend({hasData:function(e){return z.hasData(e)||_.hasData(e)},data:function(e,t,n){return z.access(e,t,n)},removeData:function(e,t){z.remove(e,t)},_data:function(e,t,n){return _.access(e,t,n)},_removeData:function(e,t){_.remove(e,t)}}),ce.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=z.get(o),1===o.nodeType&&!_.get(o,"hasDataAttrs"))){t=a.length;while(t--)a[t]&&0===(r=a[t].name).indexOf("data-")&&(r=F(r.slice(5)),V(o,r,i[r]));_.set(o,"hasDataAttrs",!0)}return i}return"object"==typeof n?this.each(function(){z.set(this,n)}):M(this,function(e){var t;if(o&&void 0===e)return void 0!==(t=z.get(o,n))?t:void 0!==(t=V(o,n))?t:void 0;this.each(function(){z.set(this,n,e)})},null,e,1<arguments.length,null,!0)},removeData:function(e){return this.each(function(){z.remove(this,e)})}}),ce.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=_.get(e,t),n&&(!r||Array.isArray(n)?r=_.access(e,t,ce.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=ce.queue(e,t),r=n.length,i=n.shift(),o=ce._queueHooks(e,t);"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,function(){ce.dequeue(e,t)},o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return _.get(e,n)||_.access(e,n,{empty:ce.Callbacks("once memory").add(function(){_.remove(e,[t+"queue",n])})})}}),ce.fn.extend({queue:function(t,n){var e=2;return"string"!=typeof t&&(n=t,t="fx",e--),arguments.length<e?ce.queue(this[0],t):void 0===n?this:this.each(function(){var e=ce.queue(this,t,n);ce._queueHooks(this,t),"fx"===t&&"inprogress"!==e[0]&&ce.dequeue(this,t)})},dequeue:function(e){return this.each(function(){ce.dequeue(this,e)})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=ce.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=_.get(o[a],e+"queueHooks"))&&n.empty&&(r++,n.empty.add(s));return s(),i.promise(t)}});var G=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,Y=new RegExp("^(?:([+-])=|)("+G+")([a-z%]*)$","i"),Q=["Top","Right","Bottom","Left"],J=C.documentElement,K=function(e){return ce.contains(e.ownerDocument,e)},Z={composed:!0};J.getRootNode&&(K=function(e){return ce.contains(e.ownerDocument,e)||e.getRootNode(Z)===e.ownerDocument});var ee=function(e,t){return"none"===(e=t||e).style.display||""===e.style.display&&K(e)&&"none"===ce.css(e,"display")};function te(e,t,n,r){var i,o,a=20,s=r?function(){return r.cur()}:function(){return ce.css(e,t,"")},u=s(),l=n&&n[3]||(ce.cssNumber[t]?"":"px"),c=e.nodeType&&(ce.cssNumber[t]||"px"!==l&&+u)&&Y.exec(ce.css(e,t));if(c&&c[3]!==l){u/=2,l=l||c[3],c=+u||1;while(a--)ce.style(e,t,c+l),(1-o)*(1-(o=s()/u||.5))<=0&&(a=0),c/=o;c*=2,ce.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 ne={};function re(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]=_.get(r,"display")||null,l[c]||(r.style.display="")),""===r.style.display&&ee(r)&&(l[c]=(u=a=o=void 0,a=(i=r).ownerDocument,s=i.nodeName,(u=ne[s])||(o=a.body.appendChild(a.createElement(s)),u=ce.css(o,"display"),o.parentNode.removeChild(o),"none"===u&&(u="block"),ne[s]=u)))):"none"!==n&&(l[c]="none",_.set(r,"display",n)));for(c=0;c<f;c++)null!=l[c]&&(e[c].style.display=l[c]);return e}ce.fn.extend({show:function(){return re(this,!0)},hide:function(){return re(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){ee(this)?ce(this).show():ce(this).hide()})}});var xe,be,we=/^(?:checkbox|radio)$/i,Te=/<([a-z][^\/\0>\x20\t\r\n\f]*)/i,Ce=/^$|^module$|\/(?:java|ecma)script/i;xe=C.createDocumentFragment().appendChild(C.createElement("div")),(be=C.createElement("input")).setAttribute("type","radio"),be.setAttribute("checked","checked"),be.setAttribute("name","t"),xe.appendChild(be),le.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="<textarea>x</textarea>",le.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="<option></option>",le.option=!!xe.lastChild;var ke={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 Se(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&fe(e,t)?ce.merge([e],n):n}function Ee(e,t){for(var n=0,r=e.length;n<r;n++)_.set(e[n],"globalEval",!t||_.get(t[n],"globalEval"))}ke.tbody=ke.tfoot=ke.colgroup=ke.caption=ke.thead,ke.th=ke.td,le.option||(ke.optgroup=ke.option=[1,"<select multiple='multiple'>","</select>"]);var je=/<|&#?\w+;/;function Ae(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"===x(o))ce.merge(p,o.nodeType?[o]:o);else if(je.test(o)){a=a||f.appendChild(t.createElement("div")),s=(Te.exec(o)||["",""])[1].toLowerCase(),u=ke[s]||ke._default,a.innerHTML=u[1]+ce.htmlPrefilter(o)+u[2],c=u[0];while(c--)a=a.lastChild;ce.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<ce.inArray(o,r))i&&i.push(o);else if(l=K(o),a=Se(f.appendChild(o),"script"),l&&Ee(a),n){c=0;while(o=a[c++])Ce.test(o.type||"")&&n.push(o)}return f}var De=/^([^.]*)(?:\.(.+)|)/;function Ne(){return!0}function qe(){return!1}function Le(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)Le(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=qe;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return ce().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=ce.guid++)),e.each(function(){ce.event.add(this,t,i,r,n)})}function He(e,r,t){t?(_.set(e,r,!1),ce.event.add(e,r,{namespace:!1,handler:function(e){var t,n=_.get(this,r);if(1&e.isTrigger&&this[r]){if(n)(ce.event.special[r]||{}).delegateType&&e.stopPropagation();else if(n=ae.call(arguments),_.set(this,r,n),this[r](),t=_.get(this,r),_.set(this,r,!1),n!==t)return e.stopImmediatePropagation(),e.preventDefault(),t}else n&&(_.set(this,r,ce.event.trigger(n[0],n.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ne)}})):void 0===_.get(e,r)&&ce.event.add(e,r,Ne)}ce.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.get(t);if($(t)){n.handler&&(n=(o=n).handler,i=o.selector),i&&ce.find.matchesSelector(J,i),n.guid||(n.guid=ce.guid++),(u=v.events)||(u=v.events=Object.create(null)),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof ce&&ce.event.triggered!==e.type?ce.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(D)||[""]).length;while(l--)d=g=(s=De.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=ce.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=ce.event.special[d]||{},c=ce.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&ce.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),ce.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=_.hasData(e)&&_.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(D)||[""]).length;while(l--)if(d=g=(s=De.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=ce.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)||ce.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)ce.event.remove(e,d+t[l],n,r,!0);ce.isEmptyObject(u)&&_.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=new Array(arguments.length),u=ce.event.fix(e),l=(_.get(this,"events")||Object.create(null))[u.type]||[],c=ce.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=ce.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=((ce.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<ce(i,this).index(l):ce.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(ce.Event.prototype,t,{enumerable:!0,configurable:!0,get:v(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[ce.expando]?e:new ce.Event(e)},special:{load:{noBubble:!0},click:{setup:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click",!0),!1},trigger:function(e){var t=this||e;return we.test(t.type)&&t.click&&fe(t,"input")&&He(t,"click"),!0},_default:function(e){var t=e.target;return we.test(t.type)&&t.click&&fe(t,"input")&&_.get(t,"click")||fe(t,"a")}},beforeunload:{postDispatch:function(e){void 0!==e.result&&e.originalEvent&&(e.originalEvent.returnValue=e.result)}}}},ce.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n)},ce.Event=function(e,t){if(!(this instanceof ce.Event))return new ce.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||void 0===e.defaultPrevented&&!1===e.returnValue?Ne:qe,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&&ce.extend(this,t),this.timeStamp=e&&e.timeStamp||Date.now(),this[ce.expando]=!0},ce.Event.prototype={constructor:ce.Event,isDefaultPrevented:qe,isPropagationStopped:qe,isImmediatePropagationStopped:qe,isSimulated:!1,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=Ne,e&&!this.isSimulated&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=Ne,e&&!this.isSimulated&&e.stopPropagation()},stopImmediatePropagation:function(){var e=this.originalEvent;this.isImmediatePropagationStopped=Ne,e&&!this.isSimulated&&e.stopImmediatePropagation(),this.stopPropagation()}},ce.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},ce.event.addProp),ce.each({focus:"focusin",blur:"focusout"},function(r,i){function o(e){if(C.documentMode){var t=_.get(this,"handle"),n=ce.event.fix(e);n.type="focusin"===e.type?"focus":"blur",n.isSimulated=!0,t(e),n.target===n.currentTarget&&t(n)}else ce.event.simulate(i,e.target,ce.event.fix(e))}ce.event.special[r]={setup:function(){var e;if(He(this,r,!0),!C.documentMode)return!1;(e=_.get(this,i))||this.addEventListener(i,o),_.set(this,i,(e||0)+1)},trigger:function(){return He(this,r),!0},teardown:function(){var e;if(!C.documentMode)return!1;(e=_.get(this,i)-1)?_.set(this,i,e):(this.removeEventListener(i,o),_.remove(this,i))},_default:function(e){return _.get(e.target,r)},delegateType:i},ce.event.special[i]={setup:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i);n||(C.documentMode?this.addEventListener(i,o):e.addEventListener(r,o,!0)),_.set(t,i,(n||0)+1)},teardown:function(){var e=this.ownerDocument||this.document||this,t=C.documentMode?this:e,n=_.get(t,i)-1;n?_.set(t,i,n):(C.documentMode?this.removeEventListener(i,o):e.removeEventListener(r,o,!0),_.remove(t,i))}}}),ce.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(e,i){ce.event.special[e]={delegateType:i,bindType:i,handle:function(e){var t,n=e.relatedTarget,r=e.handleObj;return n&&(n===this||ce.contains(this,n))||(e.type=r.origType,t=r.handler.apply(this,arguments),e.type=i),t}}}),ce.fn.extend({on:function(e,t,n,r){return Le(this,e,t,n,r)},one:function(e,t,n,r){return Le(this,e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,ce(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=qe),this.each(function(){ce.event.remove(this,e,n,t)})}});var Oe=/<script|<style|<link/i,Pe=/checked\s*(?:[^=]|=\s*.checked.)/i,Me=/^\s*<!\[CDATA\[|\]\]>\s*$/g;function Re(e,t){return fe(e,"table")&&fe(11!==t.nodeType?t:t.firstChild,"tr")&&ce(e).children("tbody")[0]||e}function Ie(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function We(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Fe(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(_.hasData(e)&&(s=_.get(e).events))for(i in _.remove(t,"handle events"),s)for(n=0,r=s[i].length;n<r;n++)ce.event.add(t,i,s[i][n]);z.hasData(e)&&(o=z.access(e),a=ce.extend({},o),z.set(t,a))}}function $e(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=v(d);if(h||1<f&&"string"==typeof d&&!le.checkClone&&Pe.test(d))return n.each(function(e){var t=n.eq(e);h&&(r[0]=d.call(this,e,t.html())),$e(t,r,i,o)});if(f&&(t=(e=Ae(r,n[0].ownerDocument,!1,n,o)).firstChild,1===e.childNodes.length&&(e=t),t||o)){for(s=(a=ce.map(Se(e,"script"),Ie)).length;c<f;c++)u=e,c!==p&&(u=ce.clone(u,!0,!0),s&&ce.merge(a,Se(u,"script"))),i.call(n[c],u,c);if(s)for(l=a[a.length-1].ownerDocument,ce.map(a,We),c=0;c<s;c++)u=a[c],Ce.test(u.type||"")&&!_.access(u,"globalEval")&&ce.contains(l,u)&&(u.src&&"module"!==(u.type||"").toLowerCase()?ce._evalUrl&&!u.noModule&&ce._evalUrl(u.src,{nonce:u.nonce||u.getAttribute("nonce")},l):m(u.textContent.replace(Me,""),u,l))}return n}function Be(e,t,n){for(var r,i=t?ce.filter(t,e):e,o=0;null!=(r=i[o]);o++)n||1!==r.nodeType||ce.cleanData(Se(r)),r.parentNode&&(n&&K(r)&&Ee(Se(r,"script")),r.parentNode.removeChild(r));return e}ce.extend({htmlPrefilter:function(e){return e},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=K(e);if(!(le.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||ce.isXMLDoc(e)))for(a=Se(c),r=0,i=(o=Se(e)).length;r<i;r++)s=o[r],u=a[r],void 0,"input"===(l=u.nodeName.toLowerCase())&&we.test(s.type)?u.checked=s.checked:"input"!==l&&"textarea"!==l||(u.defaultValue=s.defaultValue);if(t)if(n)for(o=o||Se(e),a=a||Se(c),r=0,i=o.length;r<i;r++)Fe(o[r],a[r]);else Fe(e,c);return 0<(a=Se(c,"script")).length&&Ee(a,!f&&Se(e,"script")),c},cleanData:function(e){for(var t,n,r,i=ce.event.special,o=0;void 0!==(n=e[o]);o++)if($(n)){if(t=n[_.expando]){if(t.events)for(r in t.events)i[r]?ce.event.remove(n,r):ce.removeEvent(n,r,t.handle);n[_.expando]=void 0}n[z.expando]&&(n[z.expando]=void 0)}}}),ce.fn.extend({detach:function(e){return Be(this,e,!0)},remove:function(e){return Be(this,e)},text:function(e){return M(this,function(e){return void 0===e?ce.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 $e(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Re(this,e).appendChild(e)})},prepend:function(){return $e(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Re(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return $e(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return $e(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&&(ce.cleanData(Se(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return ce.clone(this,e,t)})},html:function(e){return M(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&&!Oe.test(e)&&!ke[(Te.exec(e)||["",""])[1].toLowerCase()]){e=ce.htmlPrefilter(e);try{for(;n<r;n++)1===(t=this[n]||{}).nodeType&&(ce.cleanData(Se(t,!1)),t.innerHTML=e);t=0}catch(e){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var n=[];return $e(this,arguments,function(e){var t=this.parentNode;ce.inArray(this,n)<0&&(ce.cleanData(Se(this)),t&&t.replaceChild(e,this))},n)}}),ce.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,a){ce.fn[e]=function(e){for(var t,n=[],r=ce(e),i=r.length-1,o=0;o<=i;o++)t=o===i?this:this.clone(!0),ce(r[o])[a](t),s.apply(n,t.get());return this.pushStack(n)}});var _e=new RegExp("^("+G+")(?!px)[a-z%]+$","i"),ze=/^--/,Xe=function(e){var t=e.ownerDocument.defaultView;return t&&t.opener||(t=ie),t.getComputedStyle(e)},Ue=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},Ve=new RegExp(Q.join("|"),"i");function Ge(e,t,n){var r,i,o,a,s=ze.test(t),u=e.style;return(n=n||Xe(e))&&(a=n.getPropertyValue(t)||n[t],s&&a&&(a=a.replace(ve,"$1")||void 0),""!==a||K(e)||(a=ce.style(e,t)),!le.pixelBoxStyles()&&_e.test(a)&&Ve.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=n.width,u.width=r,u.minWidth=i,u.maxWidth=o)),void 0!==a?a+"":a}function Ye(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%",J.appendChild(u).appendChild(l);var e=ie.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),J.removeChild(u),l=null}}function t(e){return Math.round(parseFloat(e))}var n,r,i,o,a,s,u=C.createElement("div"),l=C.createElement("div");l.style&&(l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",le.clearCloneStyle="content-box"===l.style.backgroundClip,ce.extend(le,{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=C.createElement("table"),t=C.createElement("tr"),n=C.createElement("div"),e.style.cssText="position:absolute;left:-11111px;border-collapse:separate",t.style.cssText="box-sizing:content-box;border:1px solid",t.style.height="1px",n.style.height="9px",n.style.display="block",J.appendChild(e).appendChild(t).appendChild(n),r=ie.getComputedStyle(t),a=parseInt(r.height,10)+parseInt(r.borderTopWidth,10)+parseInt(r.borderBottomWidth,10)===t.offsetHeight,J.removeChild(e)),a}}))}();var Qe=["Webkit","Moz","ms"],Je=C.createElement("div").style,Ke={};function Ze(e){var t=ce.cssProps[e]||Ke[e];return t||(e in Je?e:Ke[e]=function(e){var t=e[0].toUpperCase()+e.slice(1),n=Qe.length;while(n--)if((e=Qe[n]+t)in Je)return e}(e)||e)}var et=/^(none|table(?!-c[ea]).+)/,tt={position:"absolute",visibility:"hidden",display:"block"},nt={letterSpacing:"0",fontWeight:"400"};function rt(e,t,n){var r=Y.exec(t);return r?Math.max(0,r[2]-(n||0))+(r[3]||"px"):t}function it(e,t,n,r,i,o){var a="width"===t?1:0,s=0,u=0,l=0;if(n===(r?"border":"content"))return 0;for(;a<4;a+=2)"margin"===n&&(l+=ce.css(e,n+Q[a],!0,i)),r?("content"===n&&(u-=ce.css(e,"padding"+Q[a],!0,i)),"margin"!==n&&(u-=ce.css(e,"border"+Q[a]+"Width",!0,i))):(u+=ce.css(e,"padding"+Q[a],!0,i),"padding"!==n?u+=ce.css(e,"border"+Q[a]+"Width",!0,i):s+=ce.css(e,"border"+Q[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+l}function ot(e,t,n){var r=Xe(e),i=(!le.boxSizingReliable()||n)&&"border-box"===ce.css(e,"boxSizing",!1,r),o=i,a=Ge(e,t,r),s="offset"+t[0].toUpperCase()+t.slice(1);if(_e.test(a)){if(!n)return a;a="auto"}return(!le.boxSizingReliable()&&i||!le.reliableTrDimensions()&&fe(e,"tr")||"auto"===a||!parseFloat(a)&&"inline"===ce.css(e,"display",!1,r))&&e.getClientRects().length&&(i="border-box"===ce.css(e,"boxSizing",!1,r),(o=s in e)&&(a=e[s])),(a=parseFloat(a)||0)+it(e,t,n||(i?"border":"content"),o,r,a)+"px"}function at(e,t,n,r,i){return new at.prototype.init(e,t,n,r,i)}ce.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!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,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=F(t),u=ze.test(t),l=e.style;if(u||(t=Ze(s)),a=ce.cssHooks[t]||ce.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=Y.exec(n))&&i[1]&&(n=te(e,t,i),o="number"),null!=n&&n==n&&("number"!==o||u||(n+=i&&i[3]||(ce.cssNumber[s]?"":"px")),le.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=F(t);return ze.test(t)||(t=Ze(s)),(a=ce.cssHooks[t]||ce.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Ge(e,t,r)),"normal"===i&&t in nt&&(i=nt[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),ce.each(["height","width"],function(e,u){ce.cssHooks[u]={get:function(e,t,n){if(t)return!et.test(ce.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?ot(e,u,n):Ue(e,tt,function(){return ot(e,u,n)})},set:function(e,t,n){var r,i=Xe(e),o=!le.scrollboxSize()&&"absolute"===i.position,a=(o||n)&&"border-box"===ce.css(e,"boxSizing",!1,i),s=n?it(e,u,n,a,i):0;return a&&o&&(s-=Math.ceil(e["offset"+u[0].toUpperCase()+u.slice(1)]-parseFloat(i[u])-it(e,u,"border",!1,i)-.5)),s&&(r=Y.exec(t))&&"px"!==(r[3]||"px")&&(e.style[u]=t,t=ce.css(e,u)),rt(0,t,s)}}}),ce.cssHooks.marginLeft=Ye(le.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,"marginLeft"))||e.getBoundingClientRect().left-Ue(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),ce.each({margin:"",padding:"",border:"Width"},function(i,o){ce.cssHooks[i+o]={expand:function(e){for(var t=0,n={},r="string"==typeof e?e.split(" "):[e];t<4;t++)n[i+Q[t]+o]=r[t]||r[t-2]||r[0];return n}},"margin"!==i&&(ce.cssHooks[i+o].set=rt)}),ce.fn.extend({css:function(e,t){return M(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=Xe(e),i=t.length;a<i;a++)o[t[a]]=ce.css(e,t[a],!1,r);return o}return void 0!==n?ce.style(e,t,n):ce.css(e,t)},e,t,1<arguments.length)}}),((ce.Tween=at).prototype={constructor:at,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||ce.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(ce.cssNumber[n]?"":"px")},cur:function(){var e=at.propHooks[this.prop];return e&&e.get?e.get(this):at.propHooks._default.get(this)},run:function(e){var t,n=at.propHooks[this.prop];return this.options.duration?this.pos=t=ce.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):at.propHooks._default.set(this),this}}).init.prototype=at.prototype,(at.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=ce.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){ce.fx.step[e.prop]?ce.fx.step[e.prop](e):1!==e.elem.nodeType||!ce.cssHooks[e.prop]&&null==e.elem.style[Ze(e.prop)]?e.elem[e.prop]=e.now:ce.style(e.elem,e.prop,e.now+e.unit)}}}).scrollTop=at.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},ce.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},ce.fx=at.prototype.init,ce.fx.step={};var st,ut,lt,ct,ft=/^(?:toggle|show|hide)$/,pt=/queueHooks$/;function dt(){ut&&(!1===C.hidden&&ie.requestAnimationFrame?ie.requestAnimationFrame(dt):ie.setTimeout(dt,ce.fx.interval),ce.fx.tick())}function ht(){return ie.setTimeout(function(){st=void 0}),st=Date.now()}function gt(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=Q[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function vt(e,t,n){for(var r,i=(yt.tweeners[t]||[]).concat(yt.tweeners["*"]),o=0,a=i.length;o<a;o++)if(r=i[o].call(n,t,e))return r}function yt(o,e,t){var n,a,r=0,i=yt.prefilters.length,s=ce.Deferred().always(function(){delete u.elem}),u=function(){if(a)return!1;for(var e=st||ht(),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:ce.extend({},e),opts:ce.extend(!0,{specialEasing:{},easing:ce.easing._default},t),originalProperties:e,originalOptions:t,startTime:st||ht(),duration:t.duration,tweens:[],createTween:function(e,t){var n=ce.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=F(n)],o=e[n],Array.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),(a=ce.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=yt.prefilters[r].call(l,o,c,l.opts))return v(n.stop)&&(ce._queueHooks(l.elem,l.opts.queue).stop=n.stop.bind(n)),n;return ce.map(c,vt,l),v(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),ce.fx.timer(ce.extend(u,{elem:o,anim:l,queue:l.opts.queue})),l}ce.Animation=ce.extend(yt,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return te(n.elem,e,Y.exec(t),n),n}]},tweener:function(e,t){v(e)?(t=e,e=["*"]):e=e.match(D);for(var n,r=0,i=e.length;r<i;r++)n=e[r],yt.tweeners[n]=yt.tweeners[n]||[],yt.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&&ee(e),v=_.get(e,"fxshow");for(r in n.queue||(null==(a=ce._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--,ce.queue(e,"fx").length||a.empty.fire()})})),t)if(i=t[r],ft.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]||ce.style(e,r)}if((u=!ce.isEmptyObject(t))||!ce.isEmptyObject(d))for(r in f&&1===e.nodeType&&(n.overflow=[h.overflow,h.overflowX,h.overflowY],null==(l=v&&v.display)&&(l=_.get(e,"display")),"none"===(c=ce.css(e,"display"))&&(l?c=l:(re([e],!0),l=e.style.display||l,c=ce.css(e,"display"),re([e]))),("inline"===c||"inline-block"===c&&null!=l)&&"none"===ce.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=_.access(e,"fxshow",{display:l}),o&&(v.hidden=!g),g&&re([e],!0),p.done(function(){for(r in g||re([e]),_.remove(e,"fxshow"),d)ce.style(e,r,d[r])})),u=vt(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?yt.prefilters.unshift(e):yt.prefilters.push(e)}}),ce.speed=function(e,t,n){var r=e&&"object"==typeof e?ce.extend({},e):{complete:n||!n&&t||v(e)&&e,duration:e,easing:n&&t||t&&!v(t)&&t};return ce.fx.off?r.duration=0:"number"!=typeof r.duration&&(r.duration in ce.fx.speeds?r.duration=ce.fx.speeds[r.duration]:r.duration=ce.fx.speeds._default),null!=r.queue&&!0!==r.queue||(r.queue="fx"),r.old=r.complete,r.complete=function(){v(r.old)&&r.old.call(this),r.queue&&ce.dequeue(this,r.queue)},r},ce.fn.extend({fadeTo:function(e,t,n,r){return this.filter(ee).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(t,e,n,r){var i=ce.isEmptyObject(t),o=ce.speed(e,n,r),a=function(){var e=yt(this,ce.extend({},t),o);(i||_.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=ce.timers,r=_.get(this);if(t)r[t]&&r[t].stop&&a(r[t]);else for(t in r)r[t]&&r[t].stop&&pt.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||ce.dequeue(this,i)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var e,t=_.get(this),n=t[a+"queue"],r=t[a+"queueHooks"],i=ce.timers,o=n?n.length:0;for(t.finish=!0,ce.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})}}),ce.each(["toggle","show","hide"],function(e,r){var i=ce.fn[r];ce.fn[r]=function(e,t,n){return null==e||"boolean"==typeof e?i.apply(this,arguments):this.animate(gt(r,!0),e,t,n)}}),ce.each({slideDown:gt("show"),slideUp:gt("hide"),slideToggle:gt("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,r){ce.fn[e]=function(e,t,n){return this.animate(r,e,t,n)}}),ce.timers=[],ce.fx.tick=function(){var e,t=0,n=ce.timers;for(st=Date.now();t<n.length;t++)(e=n[t])()||n[t]!==e||n.splice(t--,1);n.length||ce.fx.stop(),st=void 0},ce.fx.timer=function(e){ce.timers.push(e),ce.fx.start()},ce.fx.interval=13,ce.fx.start=function(){ut||(ut=!0,dt())},ce.fx.stop=function(){ut=null},ce.fx.speeds={slow:600,fast:200,_default:400},ce.fn.delay=function(r,e){return r=ce.fx&&ce.fx.speeds[r]||r,e=e||"fx",this.queue(e,function(e,t){var n=ie.setTimeout(e,r);t.stop=function(){ie.clearTimeout(n)}})},lt=C.createElement("input"),ct=C.createElement("select").appendChild(C.createElement("option")),lt.type="checkbox",le.checkOn=""!==lt.value,le.optSelected=ct.selected,(lt=C.createElement("input")).value="t",lt.type="radio",le.radioValue="t"===lt.value;var mt,xt=ce.expr.attrHandle;ce.fn.extend({attr:function(e,t){return M(this,ce.attr,e,t,1<arguments.length)},removeAttr:function(e){return this.each(function(){ce.removeAttr(this,e)})}}),ce.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?ce.prop(e,t,n):(1===o&&ce.isXMLDoc(e)||(i=ce.attrHooks[t.toLowerCase()]||(ce.expr.match.bool.test(t)?mt:void 0)),void 0!==n?null===n?void ce.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=ce.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!le.radioValue&&"radio"===t&&fe(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(D);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),mt={set:function(e,t,n){return!1===t?ce.removeAttr(e,n):e.setAttribute(n,n),n}},ce.each(ce.expr.match.bool.source.match(/\w+/g),function(e,t){var a=xt[t]||ce.find.attr;xt[t]=function(e,t,n){var r,i,o=t.toLowerCase();return n||(i=xt[o],xt[o]=r,r=null!=a(e,t,n)?o:null,xt[o]=i),r}});var bt=/^(?:input|select|textarea|button)$/i,wt=/^(?:a|area)$/i;function Tt(e){return(e.match(D)||[]).join(" ")}function Ct(e){return e.getAttribute&&e.getAttribute("class")||""}function kt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match(D)||[]}ce.fn.extend({prop:function(e,t){return M(this,ce.prop,e,t,1<arguments.length)},removeProp:function(e){return this.each(function(){delete this[ce.propFix[e]||e]})}}),ce.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&ce.isXMLDoc(e)||(t=ce.propFix[t]||t,i=ce.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=ce.find.attr(e,"tabindex");return t?parseInt(t,10):bt.test(e.nodeName)||wt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),le.optSelected||(ce.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)}}),ce.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){ce.propFix[this.toLowerCase()]=this}),ce.fn.extend({addClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).addClass(t.call(this,e,Ct(this)))}):(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++)i=e[o],n.indexOf(" "+i+" ")<0&&(n+=i+" ");a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this},removeClass:function(t){var e,n,r,i,o,a;return v(t)?this.each(function(e){ce(this).removeClass(t.call(this,e,Ct(this)))}):arguments.length?(e=kt(t)).length?this.each(function(){if(r=Ct(this),n=1===this.nodeType&&" "+Tt(r)+" "){for(o=0;o<e.length;o++){i=e[o];while(-1<n.indexOf(" "+i+" "))n=n.replace(" "+i+" "," ")}a=Tt(n),r!==a&&this.setAttribute("class",a)}}):this:this.attr("class","")},toggleClass:function(t,n){var e,r,i,o,a=typeof t,s="string"===a||Array.isArray(t);return v(t)?this.each(function(e){ce(this).toggleClass(t.call(this,e,Ct(this),n),n)}):"boolean"==typeof n&&s?n?this.addClass(t):this.removeClass(t):(e=kt(t),this.each(function(){if(s)for(o=ce(this),i=0;i<e.length;i++)r=e[i],o.hasClass(r)?o.removeClass(r):o.addClass(r);else void 0!==t&&"boolean"!==a||((r=Ct(this))&&_.set(this,"__className__",r),this.setAttribute&&this.setAttribute("class",r||!1===t?"":_.get(this,"__className__")||""))}))},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&-1<(" "+Tt(Ct(n))+" ").indexOf(t))return!0;return!1}});var St=/\r/g;ce.fn.extend({val:function(n){var r,e,i,t=this[0];return arguments.length?(i=v(n),this.each(function(e){var t;1===this.nodeType&&(null==(t=i?n.call(this,e,ce(this).val()):n)?t="":"number"==typeof t?t+="":Array.isArray(t)&&(t=ce.map(t,function(e){return null==e?"":e+""})),(r=ce.valHooks[this.type]||ce.valHooks[this.nodeName.toLowerCase()])&&"set"in r&&void 0!==r.set(this,t,"value")||(this.value=t))})):t?(r=ce.valHooks[t.type]||ce.valHooks[t.nodeName.toLowerCase()])&&"get"in r&&void 0!==(e=r.get(t,"value"))?e:"string"==typeof(e=t.value)?e.replace(St,""):null==e?"":e:void 0}}),ce.extend({valHooks:{option:{get:function(e){var t=ce.find.attr(e,"value");return null!=t?t:Tt(ce.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||!fe(n.parentNode,"optgroup"))){if(t=ce(n).val(),a)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=ce.makeArray(t),a=i.length;while(a--)((r=i[a]).selected=-1<ce.inArray(ce.valHooks.option.get(r),o))&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),ce.each(["radio","checkbox"],function(){ce.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=-1<ce.inArray(ce(e).val(),t)}},le.checkOn||(ce.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Et=ie.location,jt={guid:Date.now()},At=/\?/;ce.parseXML=function(e){var t,n;if(!e||"string"!=typeof e)return null;try{t=(new ie.DOMParser).parseFromString(e,"text/xml")}catch(e){}return n=t&&t.getElementsByTagName("parsererror")[0],t&&!n||ce.error("Invalid XML: "+(n?ce.map(n.childNodes,function(e){return e.textContent}).join("\n"):e)),t};var Dt=/^(?:focusinfocus|focusoutblur)$/,Nt=function(e){e.stopPropagation()};ce.extend(ce.event,{trigger:function(e,t,n,r){var i,o,a,s,u,l,c,f,p=[n||C],d=ue.call(e,"type")?e.type:e,h=ue.call(e,"namespace")?e.namespace.split("."):[];if(o=f=a=n=n||C,3!==n.nodeType&&8!==n.nodeType&&!Dt.test(d+ce.event.triggered)&&(-1<d.indexOf(".")&&(d=(h=d.split(".")).shift(),h.sort()),u=d.indexOf(":")<0&&"on"+d,(e=e[ce.expando]?e:new ce.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]:ce.makeArray(t,[e]),c=ce.event.special[d]||{},r||!c.trigger||!1!==c.trigger.apply(n,t))){if(!r&&!c.noBubble&&!y(n)){for(s=c.delegateType||d,Dt.test(s+d)||(o=o.parentNode);o;o=o.parentNode)p.push(o),a=o;a===(n.ownerDocument||C)&&p.push(a.defaultView||a.parentWindow||ie)}i=0;while((o=p[i++])&&!e.isPropagationStopped())f=o,e.type=1<i?s:c.bindType||d,(l=(_.get(o,"events")||Object.create(null))[e.type]&&_.get(o,"handle"))&&l.apply(o,t),(l=u&&o[u])&&l.apply&&$(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)||!$(n)||u&&v(n[d])&&!y(n)&&((a=n[u])&&(n[u]=null),ce.event.triggered=d,e.isPropagationStopped()&&f.addEventListener(d,Nt),n[d](),e.isPropagationStopped()&&f.removeEventListener(d,Nt),ce.event.triggered=void 0,a&&(n[u]=a)),e.result}},simulate:function(e,t,n){var r=ce.extend(new ce.Event,n,{type:e,isSimulated:!0});ce.event.trigger(r,null,t)}}),ce.fn.extend({trigger:function(e,t){return this.each(function(){ce.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return ce.event.trigger(e,t,n,!0)}});var qt=/\[\]$/,Lt=/\r?\n/g,Ht=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Pt(n,e,r,i){var t;if(Array.isArray(e))ce.each(e,function(e,t){r||qt.test(n)?i(n,t):Pt(n+"["+("object"==typeof t&&null!=t?e:"")+"]",t,r,i)});else if(r||"object"!==x(e))i(n,e);else for(t in e)Pt(n+"["+t+"]",e[t],r,i)}ce.param=function(e,t){var n,r=[],i=function(e,t){var n=v(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!ce.isPlainObject(e))ce.each(e,function(){i(this.name,this.value)});else for(n in e)Pt(n,e[n],t,i);return r.join("&")},ce.fn.extend({serialize:function(){return ce.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=ce.prop(this,"elements");return e?ce.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!ce(this).is(":disabled")&&Ot.test(this.nodeName)&&!Ht.test(e)&&(this.checked||!we.test(e))}).map(function(e,t){var n=ce(this).val();return null==n?null:Array.isArray(n)?ce.map(n,function(e){return{name:t.name,value:e.replace(Lt,"\r\n")}}):{name:t.name,value:n.replace(Lt,"\r\n")}}).get()}});var Mt=/%20/g,Rt=/#.*$/,It=/([?&])_=[^&]*/,Wt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Ft=/^(?:GET|HEAD)$/,$t=/^\/\//,Bt={},_t={},zt="*/".concat("*"),Xt=C.createElement("a");function Ut(o){return function(e,t){"string"!=typeof e&&(t=e,e="*");var n,r=0,i=e.toLowerCase().match(D)||[];if(v(t))while(n=i[r++])"+"===n[0]?(n=n.slice(1)||"*",(o[n]=o[n]||[]).unshift(t)):(o[n]=o[n]||[]).push(t)}}function Vt(t,i,o,a){var s={},u=t===_t;function l(e){var r;return s[e]=!0,ce.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 Gt(e,t){var n,r,i=ce.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&ce.extend(!0,e,r),e}Xt.href=Et.href,ce.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:{"*":zt,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":ce.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Gt(Gt(e,ce.ajaxSettings),t):Gt(ce.ajaxSettings,e)},ajaxPrefilter:Ut(Bt),ajaxTransport:Ut(_t),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=ce.ajaxSetup({},t),y=v.context||v,m=v.context&&(y.nodeType||y.jquery)?ce(y):ce.event,x=ce.Deferred(),b=ce.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=Wt.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($t,Et.protocol+"//"),v.type=t.method||t.type||v.method||v.type,v.dataTypes=(v.dataType||"*").toLowerCase().match(D)||[""],null==v.crossDomain){r=C.createElement("a");try{r.href=v.url,r.href=r.href,v.crossDomain=Xt.protocol+"//"+Xt.host!=r.protocol+"//"+r.host}catch(e){v.crossDomain=!0}}if(v.data&&v.processData&&"string"!=typeof v.data&&(v.data=ce.param(v.data,v.traditional)),Vt(Bt,v,t,T),h)return T;for(i in(g=ce.event&&v.global)&&0==ce.active++&&ce.event.trigger("ajaxStart"),v.type=v.type.toUpperCase(),v.hasContent=!Ft.test(v.type),f=v.url.replace(Rt,""),v.hasContent?v.data&&v.processData&&0===(v.contentType||"").indexOf("application/x-www-form-urlencoded")&&(v.data=v.data.replace(Mt,"+")):(o=v.url.slice(f.length),v.data&&(v.processData||"string"==typeof v.data)&&(f+=(At.test(f)?"&":"?")+v.data,delete v.data),!1===v.cache&&(f=f.replace(It,"$1"),o=(At.test(f)?"&":"?")+"_="+jt.guid+++o),v.url=f+o),v.ifModified&&(ce.lastModified[f]&&T.setRequestHeader("If-Modified-Since",ce.lastModified[f]),ce.etag[f]&&T.setRequestHeader("If-None-Match",ce.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]?", "+zt+"; 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=Vt(_t,v,t,T)){if(T.readyState=1,g&&m.trigger("ajaxSend",[T,v]),h)return T;v.async&&0<v.timeout&&(d=ie.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&&ie.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<ce.inArray("script",v.dataTypes)&&ce.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"))&&(ce.lastModified[f]=u),(u=T.getResponseHeader("etag"))&&(ce.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]),--ce.active||ce.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return ce.get(e,t,n,"json")},getScript:function(e,t){return ce.get(e,void 0,t,"script")}}),ce.each(["get","post"],function(e,i){ce[i]=function(e,t,n,r){return v(t)&&(r=r||n,n=t,t=void 0),ce.ajax(ce.extend({url:e,type:i,dataType:r,data:t,success:n},ce.isPlainObject(e)&&e))}}),ce.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),ce._evalUrl=function(e,t,n){return ce.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){ce.globalEval(e,t,n)}})},ce.fn.extend({wrapAll:function(e){var t;return this[0]&&(v(e)&&(e=e.call(this[0])),t=ce(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 v(n)?this.each(function(e){ce(this).wrapInner(n.call(this,e))}):this.each(function(){var e=ce(this),t=e.contents();t.length?t.wrapAll(n):e.append(n)})},wrap:function(t){var n=v(t);return this.each(function(e){ce(this).wrapAll(n?t.call(this,e):t)})},unwrap:function(e){return this.parent(e).not("body").each(function(){ce(this).replaceWith(this.childNodes)}),this}}),ce.expr.pseudos.hidden=function(e){return!ce.expr.pseudos.visible(e)},ce.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},ce.ajaxSettings.xhr=function(){try{return new ie.XMLHttpRequest}catch(e){}};var Yt={0:200,1223:204},Qt=ce.ajaxSettings.xhr();le.cors=!!Qt&&"withCredentials"in Qt,le.ajax=Qt=!!Qt,ce.ajaxTransport(function(i){var o,a;if(le.cors||Qt&&!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(Yt[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&&ie.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()}}}),ce.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),ce.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 ce.globalEval(e),e}}}),ce.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),ce.ajaxTransport("script",function(n){var r,i;if(n.crossDomain||n.scriptAttrs)return{send:function(e,t){r=ce("<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)}),C.head.appendChild(r[0])},abort:function(){i&&i()}}});var Jt,Kt=[],Zt=/(=)\?(?=&|$)|\?\?/;ce.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Kt.pop()||ce.expando+"_"+jt.guid++;return this[e]=!0,e}}),ce.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Zt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Zt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=v(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Zt,"$1"+r):!1!==e.jsonp&&(e.url+=(At.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||ce.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=ie[r],ie[r]=function(){o=arguments},n.always(function(){void 0===i?ce(ie).removeProp(r):ie[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Kt.push(r)),o&&v(i)&&i(o[0]),o=i=void 0}),"script"}),le.createHTMLDocument=((Jt=C.implementation.createHTMLDocument("").body).innerHTML="<form></form><form></form>",2===Jt.childNodes.length),ce.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(le.createHTMLDocument?((r=(t=C.implementation.createHTMLDocument("")).createElement("base")).href=C.location.href,t.head.appendChild(r)):t=C),o=!n&&[],(i=w.exec(e))?[t.createElement(i[1])]:(i=Ae([e],t,o),o&&o.length&&ce(o).remove(),ce.merge([],i.childNodes)));var r,i,o},ce.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1<s&&(r=Tt(e.slice(s)),e=e.slice(0,s)),v(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),0<a.length&&ce.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?ce("<div>").append(ce.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},ce.expr.pseudos.animated=function(t){return ce.grep(ce.timers,function(e){return t===e.elem}).length},ce.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=ce.css(e,"position"),c=ce(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=ce.css(e,"top"),u=ce.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),v(t)&&(t=t.call(e,n,ce.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)}},ce.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){ce.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"===ce.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"===ce.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=ce(e).offset()).top+=ce.css(e,"borderTopWidth",!0),i.left+=ce.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-ce.css(r,"marginTop",!0),left:t.left-i.left-ce.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===ce.css(e,"position"))e=e.offsetParent;return e||J})}}),ce.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;ce.fn[t]=function(e){return M(this,function(e,t,n){var r;if(y(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)}}),ce.each(["top","left"],function(e,n){ce.cssHooks[n]=Ye(le.pixelPosition,function(e,t){if(t)return t=Ge(e,n),_e.test(t)?ce(e).position()[n]+"px":t})}),ce.each({Height:"height",Width:"width"},function(a,s){ce.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){ce.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return M(this,function(e,t,n){var r;return y(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?ce.css(e,t,i):ce.style(e,t,n,i)},s,n?e:void 0,n)}})}),ce.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){ce.fn[t]=function(e){return this.on(t,e)}}),ce.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.on("mouseenter",e).on("mouseleave",t||e)}}),ce.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){ce.fn[n]=function(e,t){return 0<arguments.length?this.on(n,null,e,t):this.trigger(n)}});var en=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;ce.proxy=function(e,t){var n,r,i;if("string"==typeof t&&(n=e[t],t=e,e=n),v(e))return r=ae.call(arguments,2),(i=function(){return e.apply(t||this,r.concat(ae.call(arguments)))}).guid=e.guid=e.guid||ce.guid++,i},ce.holdReady=function(e){e?ce.readyWait++:ce.ready(!0)},ce.isArray=Array.isArray,ce.parseJSON=JSON.parse,ce.nodeName=fe,ce.isFunction=v,ce.isWindow=y,ce.camelCase=F,ce.type=x,ce.now=Date.now,ce.isNumeric=function(e){var t=ce.type(e);return("number"===t||"string"===t)&&!isNaN(e-parseFloat(e))},ce.trim=function(e){return null==e?"":(e+"").replace(en,"$1")},"function"==typeof define&&define.amd&&define("jquery",[],function(){return ce});var tn=ie.jQuery,nn=ie.$;return ce.noConflict=function(e){return ie.$===ce&&(ie.$=nn),e&&ie.jQuery===ce&&(ie.jQuery=tn),ce},"undefined"==typeof e&&(ie.jQuery=ie.$=ce),ce});
jQuery.noConflict();
// source --> https://lipper-quartiere.de/wp-includes/js/jquery/jquery-migrate.min.js?ver=3.4.1 
/*! jQuery Migrate v3.4.1 | (c) OpenJS Foundation and other contributors | jquery.org/license */
"undefined"==typeof jQuery.migrateMute&&(jQuery.migrateMute=!0),function(t){"use strict";"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)||[],a=1;a<=3;a++){if(+o[a]<+n[a])return 1;if(+n[a]<+o[a])return-1}return 0}(s.fn.jquery,e)}s.migrateVersion="3.4.1";var t=Object.create(null);s.migrateDisablePatches=function(){for(var e=0;e<arguments.length;e++)t[arguments[e]]=!0},s.migrateEnablePatches=function(){for(var e=0;e<arguments.length;e++)delete t[arguments[e]]},s.migrateIsPatchEnabled=function(e){return!t[e]},n.console&&n.console.log&&(s&&e("3.0.0")&&!e("5.0.0")||n.console.log("JQMIGRATE: jQuery 3.x-4.x 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 o={};function u(e,t){var r=n.console;!s.migrateIsPatchEnabled(e)||s.migrateDeduplicateWarnings&&o[t]||(o[t]=!0,s.migrateWarnings.push(t+" ["+e+"]"),r&&r.warn&&!s.migrateMute&&(r.warn("JQMIGRATE: "+t),s.migrateTrace&&r.trace&&r.trace()))}function r(e,t,r,n,o){Object.defineProperty(e,t,{configurable:!0,enumerable:!0,get:function(){return u(n,o),r},set:function(e){u(n,o),r=e}})}function a(e,t,r,n,o){var a=e[t];e[t]=function(){return o&&u(n,o),(s.migrateIsPatchEnabled(n)?r:a||s.noop).apply(this,arguments)}}function c(e,t,r,n,o){if(!o)throw new Error("No warning message provided");return a(e,t,r,n,o),0}function i(e,t,r,n){return a(e,t,r,n),0}s.migrateDeduplicateWarnings=!0,s.migrateWarnings=[],void 0===s.migrateTrace&&(s.migrateTrace=!0),s.migrateReset=function(){o={},s.migrateWarnings.length=0},"BackCompat"===n.document.compatMode&&u("quirks","jQuery is not compatible with Quirks Mode");var d,l,p,f={},m=s.fn.init,y=s.find,h=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,g=/\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,v=/^[\s\uFEFF\xA0]+|([^\s\uFEFF\xA0])[\s\uFEFF\xA0]+$/g;for(d in i(s.fn,"init",function(e){var t=Array.prototype.slice.call(arguments);return s.migrateIsPatchEnabled("selector-empty-id")&&"string"==typeof e&&"#"===e&&(u("selector-empty-id","jQuery( '#' ) is not a valid selector"),t[0]=[]),m.apply(this,t)},"selector-empty-id"),s.fn.init.prototype=s.fn,i(s,"find",function(t){var r=Array.prototype.slice.call(arguments);if("string"==typeof t&&h.test(t))try{n.document.querySelector(t)}catch(e){t=t.replace(g,function(e,t,r,n){return"["+t+r+'"'+n+'"]'});try{n.document.querySelector(t),u("selector-hash","Attribute selector with '#' must be quoted: "+r[0]),r[0]=t}catch(e){u("selector-hash","Attribute selector with '#' was not fixed: "+r[0])}}return y.apply(this,r)},"selector-hash"),y)Object.prototype.hasOwnProperty.call(y,d)&&(s.find[d]=y[d]);c(s.fn,"size",function(){return this.length},"size","jQuery.fn.size() is deprecated and removed; use the .length property"),c(s,"parseJSON",function(){return JSON.parse.apply(null,arguments)},"parseJSON","jQuery.parseJSON is deprecated; use JSON.parse"),c(s,"holdReady",s.holdReady,"holdReady","jQuery.holdReady is deprecated"),c(s,"unique",s.uniqueSort,"unique","jQuery.unique is deprecated; use jQuery.uniqueSort"),r(s.expr,"filters",s.expr.pseudos,"expr-pre-pseudos","jQuery.expr.filters is deprecated; use jQuery.expr.pseudos"),r(s.expr,":",s.expr.pseudos,"expr-pre-pseudos","jQuery.expr[':'] is deprecated; use jQuery.expr.pseudos"),e("3.1.1")&&c(s,"trim",function(e){return null==e?"":(e+"").replace(v,"$1")},"trim","jQuery.trim is deprecated; use String.prototype.trim"),e("3.2.0")&&(c(s,"nodeName",function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},"nodeName","jQuery.nodeName is deprecated"),c(s,"isArray",Array.isArray,"isArray","jQuery.isArray is deprecated; use Array.isArray")),e("3.3.0")&&(c(s,"isNumeric",function(e){var t=typeof e;return("number"==t||"string"==t)&&!isNaN(e-parseFloat(e))},"isNumeric","jQuery.isNumeric() is deprecated"),s.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(e,t){f["[object "+t+"]"]=t.toLowerCase()}),c(s,"type",function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?f[Object.prototype.toString.call(e)]||"object":typeof e},"type","jQuery.type is deprecated"),c(s,"isFunction",function(e){return"function"==typeof e},"isFunction","jQuery.isFunction() is deprecated"),c(s,"isWindow",function(e){return null!=e&&e===e.window},"isWindow","jQuery.isWindow() is deprecated")),s.ajax&&(l=s.ajax,p=/(=)\?(?=&|$)|\?\?/,i(s,"ajax",function(){var e=l.apply(this,arguments);return e.promise&&(c(e,"success",e.done,"jqXHR-methods","jQXHR.success is deprecated and removed"),c(e,"error",e.fail,"jqXHR-methods","jQXHR.error is deprecated and removed"),c(e,"complete",e.always,"jqXHR-methods","jQXHR.complete is deprecated and removed")),e},"jqXHR-methods"),e("4.0.0")||s.ajaxPrefilter("+json",function(e){!1!==e.jsonp&&(p.test(e.url)||"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&p.test(e.data))&&u("jsonp-promotion","JSON-to-JSONP auto-promotion is deprecated")}));var j=s.fn.removeAttr,b=s.fn.toggleClass,w=/\S+/g;function x(e){return e.replace(/-([a-z])/g,function(e,t){return t.toUpperCase()})}i(s.fn,"removeAttr",function(e){var r=this,n=!1;return s.each(e.match(w),function(e,t){s.expr.match.bool.test(t)&&r.each(function(){if(!1!==s(this).prop(t))return!(n=!0)}),n&&(u("removeAttr-bool","jQuery.fn.removeAttr no longer sets boolean properties: "+t),r.prop(t,!1))}),j.apply(this,arguments)},"removeAttr-bool"),i(s.fn,"toggleClass",function(t){return void 0!==t&&"boolean"!=typeof t?b.apply(this,arguments):(u("toggleClass-bool","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__")||"")}))},"toggleClass-bool");var Q,A,R=!1,C=/^[a-z]/,N=/^(?:Border(?:Top|Right|Bottom|Left)?(?:Width|)|(?:Margin|Padding)?(?:Top|Right|Bottom|Left)?|(?:Min|Max)?(?:Width|Height))$/;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 R=!0,e=r.apply(this,arguments),R=!1,e})}),i(s,"swap",function(e,t,r,n){var o,a,i={};for(a in R||u("swap","jQuery.swap() is undocumented and deprecated"),t)i[a]=e.style[a],e.style[a]=t[a];for(a in o=r.apply(e,n||[]),t)e.style[a]=i[a];return o},"swap"),e("3.4.0")&&"undefined"!=typeof Proxy&&(s.cssProps=new Proxy(s.cssProps||{},{set:function(){return u("cssProps","jQuery.cssProps is deprecated"),Reflect.set.apply(this,arguments)}})),e("4.0.0")?(A={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},"undefined"!=typeof Proxy?s.cssNumber=new Proxy(A,{get:function(){return u("css-number","jQuery.cssNumber is deprecated"),Reflect.get.apply(this,arguments)},set:function(){return u("css-number","jQuery.cssNumber is deprecated"),Reflect.set.apply(this,arguments)}}):s.cssNumber=A):A=s.cssNumber,Q=s.fn.css,i(s.fn,"css",function(e,t){var r,n,o=this;return e&&"object"==typeof e&&!Array.isArray(e)?(s.each(e,function(e,t){s.fn.css.call(o,e,t)}),this):("number"==typeof t&&(r=x(e),n=r,C.test(n)&&N.test(n[0].toUpperCase()+n.slice(1))||A[r]||u("css-number",'Number-typed values are deprecated for jQuery.fn.css( "'+e+'", value )')),Q.apply(this,arguments))},"css-number");var S,P,k,H,E=s.data;i(s,"data",function(e,t,r){var n,o,a;if(t&&"object"==typeof t&&2===arguments.length){for(a in n=s.hasData(e)&&E.call(this,e),o={},t)a!==x(a)?(u("data-camelCase","jQuery.data() always sets/gets camelCased names: "+a),n[a]=t[a]):o[a]=t[a];return E.call(this,e,o),t}return t&&"string"==typeof t&&t!==x(t)&&(n=s.hasData(e)&&E.call(this,e))&&t in n?(u("data-camelCase","jQuery.data() always sets/gets camelCased names: "+t),2<arguments.length&&(n[t]=r),n[t]):E.apply(this,arguments)},"data-camelCase"),s.fx&&(k=s.Tween.prototype.run,H=function(e){return e},i(s.Tween.prototype,"run",function(){1<s.easing[this.easing].length&&(u("easing-one-arg","'jQuery.easing."+this.easing.toString()+"' should use only one argument"),s.easing[this.easing]=H),k.apply(this,arguments)},"easing-one-arg"),S=s.fx.interval,P="jQuery.fx.interval is deprecated",n.requestAnimationFrame&&Object.defineProperty(s.fx,"interval",{configurable:!0,enumerable:!0,get:function(){return n.document.hidden||u("fx-interval",P),s.migrateIsPatchEnabled("fx-interval")&&void 0===S?13:S},set:function(e){u("fx-interval",P),S=e}}));var M=s.fn.load,q=s.event.add,O=s.event.fix;s.event.props=[],s.event.fixHooks={},r(s.event.props,"concat",s.event.props.concat,"event-old-patch","jQuery.event.props.concat() is deprecated and removed"),i(s.event,"fix",function(e){var t,r=e.type,n=this.fixHooks[r],o=s.event.props;if(o.length){u("event-old-patch","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("event-old-patch","jQuery.event.fixHooks are deprecated and removed: "+r),(o=n.props)&&o.length))while(o.length)s.event.addProp(o.pop());return t=O.call(this,e),n&&n.filter?n.filter(t,e):t},"event-old-patch"),i(s.event,"add",function(e,t){return e===n&&"load"===t&&"complete"===n.document.readyState&&u("load-after-event","jQuery(window).on('load'...) called after load event occurred"),q.apply(this,arguments)},"load-after-event"),s.each(["load","unload","error"],function(e,t){i(s.fn,t,function(){var e=Array.prototype.slice.call(arguments,0);return"load"===t&&"string"==typeof e[0]?M.apply(this,e):(u("shorthand-removed-v3","jQuery.fn."+t+"() is deprecated"),e.splice(0,0,t),arguments.length?this.on.apply(this,e):(this.triggerHandler.apply(this,e),this))},"shorthand-removed-v3")}),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){c(s.fn,r,function(e,t){return 0<arguments.length?this.on(r,null,e,t):this.trigger(r)},"shorthand-deprecated-v3","jQuery.fn."+r+"() event shorthand is deprecated")}),s(function(){s(n.document).triggerHandler("ready")}),s.event.special.ready={setup:function(){this===n.document&&u("ready-event","'ready' event is deprecated")}},c(s.fn,"bind",function(e,t,r){return this.on(e,null,t,r)},"pre-on-methods","jQuery.fn.bind() is deprecated"),c(s.fn,"unbind",function(e,t){return this.off(e,null,t)},"pre-on-methods","jQuery.fn.unbind() is deprecated"),c(s.fn,"delegate",function(e,t,r,n){return this.on(t,e,r,n)},"pre-on-methods","jQuery.fn.delegate() is deprecated"),c(s.fn,"undelegate",function(e,t,r){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",r)},"pre-on-methods","jQuery.fn.undelegate() is deprecated"),c(s.fn,"hover",function(e,t){return this.on("mouseenter",e).on("mouseleave",t||e)},"pre-on-methods","jQuery.fn.hover() is deprecated");function T(e){var t=n.document.implementation.createHTMLDocument("");return t.body.innerHTML=e,t.body&&t.body.innerHTML}var F=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi;s.UNSAFE_restoreLegacyHtmlPrefilter=function(){s.migrateEnablePatches("self-closed-tags")},i(s,"htmlPrefilter",function(e){var t,r;return(r=(t=e).replace(F,"<$1></$2>"))!==t&&T(t)!==T(r)&&u("self-closed-tags","HTML tags must be properly nested and closed: "+t),e.replace(F,"<$1></$2>")},"self-closed-tags"),s.migrateDisablePatches("self-closed-tags");var D,W,_,I=s.fn.offset;return i(s.fn,"offset",function(){var e=this[0];return!e||e.nodeType&&e.getBoundingClientRect?I.apply(this,arguments):(u("offset-valid-elem","jQuery.fn.offset() requires a valid DOM element"),arguments.length?this:void 0)},"offset-valid-elem"),s.ajax&&(D=s.param,i(s,"param",function(e,t){var r=s.ajaxSettings&&s.ajaxSettings.traditional;return void 0===t&&r&&(u("param-ajax-traditional","jQuery.param() no longer uses jQuery.ajaxSettings.traditional"),t=r),D.call(this,e,t)},"param-ajax-traditional")),c(s.fn,"andSelf",s.fn.addBack,"andSelf","jQuery.fn.andSelf() is deprecated and removed, use jQuery.fn.addBack()"),s.Deferred&&(W=s.Deferred,_=[["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")]],i(s,"Deferred",function(e){var a=W(),i=a.promise();function t(){var o=arguments;return s.Deferred(function(n){s.each(_,function(e,t){var r="function"==typeof o[e]&&o[e];a[t[1]](function(){var e=r&&r.apply(this,arguments);e&&"function"==typeof e.promise?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[t[0]+"With"](this===i?n.promise():this,r?[e]:arguments)})}),o=null}).promise()}return c(a,"pipe",t,"deferred-pipe","deferred.pipe() is deprecated"),c(i,"pipe",t,"deferred-pipe","deferred.pipe() is deprecated"),e&&e.call(a,a),a},"deferred-pipe"),s.Deferred.exceptionHook=W.exceptionHook),s});
// source --> https://lipper-quartiere.de/wp-includes/js/jquery/ui/core.min.js?ver=1.13.3 
/*! jQuery UI - v1.13.3 - 2024-04-26
* https://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */
!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(x){"use strict";var t,e,i,n,W,C,o,s,r,l,a,h,u;function E(t,e,i){return[parseFloat(t[0])*(a.test(t[0])?e/100:1),parseFloat(t[1])*(a.test(t[1])?i/100:1)]}function L(t,e){return parseInt(x.css(t,e),10)||0}function N(t){return null!=t&&t===t.window}x.ui=x.ui||{},x.ui.version="1.13.3",
/*!
 * jQuery UI :data 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.extend(x.expr.pseudos,{data:x.expr.createPseudo?x.expr.createPseudo(function(e){return function(t){return!!x.data(t,e)}}):function(t,e,i){return!!x.data(t,i[3])}}),
/*!
 * jQuery UI Disable Selection 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.fn.extend({disableSelection:(t="onselectstart"in document.createElement("div")?"selectstart":"mousedown",function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}),enableSelection:function(){return this.off(".ui-disableSelection")}}),
/*!
 * jQuery UI Focusable 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.ui.focusable=function(t,e){var i,n,o,s=t.nodeName.toLowerCase();return"area"===s?(o=(i=t.parentNode).name,!(!t.href||!o||"map"!==i.nodeName.toLowerCase())&&0<(i=x("img[usemap='#"+o+"']")).length&&i.is(":visible")):(/^(input|select|textarea|button|object)$/.test(s)?(n=!t.disabled)&&(o=x(t).closest("fieldset")[0])&&(n=!o.disabled):n="a"===s&&t.href||e,n&&x(t).is(":visible")&&function(t){var e=t.css("visibility");for(;"inherit"===e;)t=t.parent(),e=t.css("visibility");return"visible"===e}(x(t)))},x.extend(x.expr.pseudos,{focusable:function(t){return x.ui.focusable(t,null!=x.attr(t,"tabindex"))}}),x.fn._form=function(){return"string"==typeof this[0].form?this.closest("form"):x(this[0].form)},
/*!
 * jQuery UI Form Reset Mixin 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.ui.formResetMixin={_formResetHandler:function(){var e=x(this);setTimeout(function(){var t=e.data("ui-form-reset-instances");x.each(t,function(){this.refresh()})})},_bindFormResetHandler:function(){var t;this.form=this.element._form(),this.form.length&&((t=this.form.data("ui-form-reset-instances")||[]).length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t))},_unbindFormResetHandler:function(){var t;this.form.length&&((t=this.form.data("ui-form-reset-instances")).splice(x.inArray(this,t),1),t.length?this.form.data("ui-form-reset-instances",t):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset"))}},x.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase()),
/*!
 * jQuery UI Support for jQuery core 1.8.x and newer 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 *
 */
x.expr.pseudos||(x.expr.pseudos=x.expr[":"]),x.uniqueSort||(x.uniqueSort=x.unique),x.escapeSelector||(e=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\x80-\uFFFF\w-]/g,i=function(t,e){return e?"\0"===t?"�":t.slice(0,-1)+"\\"+t.charCodeAt(t.length-1).toString(16)+" ":"\\"+t},x.escapeSelector=function(t){return(t+"").replace(e,i)}),x.fn.even&&x.fn.odd||x.fn.extend({even:function(){return this.filter(function(t){return t%2==0})},odd:function(){return this.filter(function(t){return t%2==1})}}),
/*!
 * jQuery UI Keycode 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},
/*!
 * jQuery UI Labels 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.fn.labels=function(){var t,e,i;return this.length?this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(e=this.eq(0).parents("label"),(t=this.attr("id"))&&(i=(i=this.eq(0).parents().last()).add((i.length?i:this).siblings()),t="label[for='"+x.escapeSelector(t)+"']",e=e.add(i.find(t).addBack(t))),this.pushStack(e)):this.pushStack([])},x.ui.plugin={add:function(t,e,i){var n,o=x.ui[t].prototype;for(n in i)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([e,i[n]])},call:function(t,e,i,n){var o,s=t.plugins[e];if(s&&(n||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(o=0;o<s.length;o++)t.options[s[o][0]]&&s[o][1].apply(t.element,i)}},
/*!
 * jQuery UI Position 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 *
 * https://api.jqueryui.com/position/
 */
W=Math.max,C=Math.abs,o=/left|center|right/,s=/top|center|bottom/,r=/[\+\-]\d+(\.[\d]+)?%?/,l=/^\w+/,a=/%$/,h=x.fn.position,x.position={scrollbarWidth:function(){var t,e,i;return void 0!==n?n:(i=(e=x("<div style='display:block;position:absolute;width:200px;height:200px;overflow:hidden;'><div style='height:300px;width:auto;'></div></div>")).children()[0],x("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),n=t-i)},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.width<t.element[0].scrollWidth;return{width:"scroll"===i||"auto"===i&&t.height<t.element[0].scrollHeight?x.position.scrollbarWidth():0,height:e?x.position.scrollbarWidth():0}},getWithinInfo:function(t){var e=x(t||window),i=N(e[0]),n=!!e[0]&&9===e[0].nodeType;return{element:e,isWindow:i,isDocument:n,offset:!i&&!n?x(t).offset():{left:0,top:0},scrollLeft:e.scrollLeft(),scrollTop:e.scrollTop(),width:e.outerWidth(),height:e.outerHeight()}}},x.fn.position=function(f){var c,d,p,g,m,v,y,w,b,_,t,e;return f&&f.of?(v="string"==typeof(f=x.extend({},f)).of?x(document).find(f.of):x(f.of),y=x.position.getWithinInfo(f.within),w=x.position.getScrollInfo(y),b=(f.collision||"flip").split(" "),_={},e=9===(e=(t=v)[0]).nodeType?{width:t.width(),height:t.height(),offset:{top:0,left:0}}:N(e)?{width:t.width(),height:t.height(),offset:{top:t.scrollTop(),left:t.scrollLeft()}}:e.preventDefault?{width:0,height:0,offset:{top:e.pageY,left:e.pageX}}:{width:t.outerWidth(),height:t.outerHeight(),offset:t.offset()},v[0].preventDefault&&(f.at="left top"),d=e.width,p=e.height,m=x.extend({},g=e.offset),x.each(["my","at"],function(){var t,e,i=(f[this]||"").split(" ");(i=1===i.length?o.test(i[0])?i.concat(["center"]):s.test(i[0])?["center"].concat(i):["center","center"]:i)[0]=o.test(i[0])?i[0]:"center",i[1]=s.test(i[1])?i[1]:"center",t=r.exec(i[0]),e=r.exec(i[1]),_[this]=[t?t[0]:0,e?e[0]:0],f[this]=[l.exec(i[0])[0],l.exec(i[1])[0]]}),1===b.length&&(b[1]=b[0]),"right"===f.at[0]?m.left+=d:"center"===f.at[0]&&(m.left+=d/2),"bottom"===f.at[1]?m.top+=p:"center"===f.at[1]&&(m.top+=p/2),c=E(_.at,d,p),m.left+=c[0],m.top+=c[1],this.each(function(){var i,t,r=x(this),l=r.outerWidth(),a=r.outerHeight(),e=L(this,"marginLeft"),n=L(this,"marginTop"),o=l+e+L(this,"marginRight")+w.width,s=a+n+L(this,"marginBottom")+w.height,h=x.extend({},m),u=E(_.my,r.outerWidth(),r.outerHeight());"right"===f.my[0]?h.left-=l:"center"===f.my[0]&&(h.left-=l/2),"bottom"===f.my[1]?h.top-=a:"center"===f.my[1]&&(h.top-=a/2),h.left+=u[0],h.top+=u[1],i={marginLeft:e,marginTop:n},x.each(["left","top"],function(t,e){x.ui.position[b[t]]&&x.ui.position[b[t]][e](h,{targetWidth:d,targetHeight:p,elemWidth:l,elemHeight:a,collisionPosition:i,collisionWidth:o,collisionHeight:s,offset:[c[0]+u[0],c[1]+u[1]],my:f.my,at:f.at,within:y,elem:r})}),f.using&&(t=function(t){var e=g.left-h.left,i=e+d-l,n=g.top-h.top,o=n+p-a,s={target:{element:v,left:g.left,top:g.top,width:d,height:p},element:{element:r,left:h.left,top:h.top,width:l,height:a},horizontal:i<0?"left":0<e?"right":"center",vertical:o<0?"top":0<n?"bottom":"middle"};d<l&&C(e+i)<d&&(s.horizontal="center"),p<a&&C(n+o)<p&&(s.vertical="middle"),W(C(e),C(i))>W(C(n),C(o))?s.important="horizontal":s.important="vertical",f.using.call(this,t,s)}),r.offset(x.extend(h,{using:t}))})):h.apply(this,arguments)},x.ui.position={fit:{left:function(t,e){var i,n=e.within,o=n.isWindow?n.scrollLeft:n.offset.left,n=n.width,s=t.left-e.collisionPosition.marginLeft,r=o-s,l=s+e.collisionWidth-n-o;n<e.collisionWidth?0<r&&l<=0?(i=t.left+r+e.collisionWidth-n-o,t.left+=r-i):t.left=!(0<l&&r<=0)&&l<r?o+n-e.collisionWidth:o:0<r?t.left+=r:0<l?t.left-=l:t.left=W(t.left-s,t.left)},top:function(t,e){var i,n=e.within,n=n.isWindow?n.scrollTop:n.offset.top,o=e.within.height,s=t.top-e.collisionPosition.marginTop,r=n-s,l=s+e.collisionHeight-o-n;o<e.collisionHeight?0<r&&l<=0?(i=t.top+r+e.collisionHeight-o-n,t.top+=r-i):t.top=!(0<l&&r<=0)&&l<r?n+o-e.collisionHeight:n:0<r?t.top+=r:0<l?t.top-=l:t.top=W(t.top-s,t.top)}},flip:{left:function(t,e){var i=e.within,n=i.offset.left+i.scrollLeft,o=i.width,i=i.isWindow?i.scrollLeft:i.offset.left,s=t.left-e.collisionPosition.marginLeft,r=s-i,s=s+e.collisionWidth-o-i,l="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,a="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,h=-2*e.offset[0];r<0?((o=t.left+l+a+h+e.collisionWidth-o-n)<0||o<C(r))&&(t.left+=l+a+h):0<s&&(0<(n=t.left-e.collisionPosition.marginLeft+l+a+h-i)||C(n)<s)&&(t.left+=l+a+h)},top:function(t,e){var i=e.within,n=i.offset.top+i.scrollTop,o=i.height,i=i.isWindow?i.scrollTop:i.offset.top,s=t.top-e.collisionPosition.marginTop,r=s-i,s=s+e.collisionHeight-o-i,l="top"===e.my[1]?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,a="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,h=-2*e.offset[1];r<0?((o=t.top+l+a+h+e.collisionHeight-o-n)<0||o<C(r))&&(t.top+=l+a+h):0<s&&(0<(n=t.top-e.collisionPosition.marginTop+l+a+h-i)||C(n)<s)&&(t.top+=l+a+h)}},flipfit:{left:function(){x.ui.position.flip.left.apply(this,arguments),x.ui.position.fit.left.apply(this,arguments)},top:function(){x.ui.position.flip.top.apply(this,arguments),x.ui.position.fit.top.apply(this,arguments)}}},x.ui.safeActiveElement=function(e){var i;try{i=e.activeElement}catch(t){i=e.body}return i=(i=i||e.body).nodeName?i:e.body},x.ui.safeBlur=function(t){t&&"body"!==t.nodeName.toLowerCase()&&x(t).trigger("blur")},
/*!
 * jQuery UI Scroll Parent 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.fn.scrollParent=function(t){var e=this.css("position"),i="absolute"===e,n=t?/(auto|scroll|hidden)/:/(auto|scroll)/,t=this.parents().filter(function(){var t=x(this);return(!i||"static"!==t.css("position"))&&n.test(t.css("overflow")+t.css("overflow-y")+t.css("overflow-x"))}).eq(0);return"fixed"!==e&&t.length?t:x(this[0].ownerDocument||document)},
/*!
 * jQuery UI Tabbable 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.extend(x.expr.pseudos,{tabbable:function(t){var e=x.attr(t,"tabindex"),i=null!=e;return(!i||0<=e)&&x.ui.focusable(t,i)}}),
/*!
 * jQuery UI Unique ID 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
x.fn.extend({uniqueId:(u=0,function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++u)})}),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&x(this).removeAttr("id")})}});
/*!
 * jQuery UI Widget 1.13.3
 * https://jqueryui.com
 *
 * Copyright OpenJS Foundation and other contributors
 * Released under the MIT license.
 * https://jquery.org/license
 */
var f,c=0,d=Array.prototype.hasOwnProperty,p=Array.prototype.slice;x.cleanData=(f=x.cleanData,function(t){for(var e,i,n=0;null!=(i=t[n]);n++)(e=x._data(i,"events"))&&e.remove&&x(i).triggerHandler("remove");f(t)}),x.widget=function(t,i,e){var n,o,s,r={},l=t.split(".")[0],a=l+"-"+(t=t.split(".")[1]);return e||(e=i,i=x.Widget),Array.isArray(e)&&(e=x.extend.apply(null,[{}].concat(e))),x.expr.pseudos[a.toLowerCase()]=function(t){return!!x.data(t,a)},x[l]=x[l]||{},n=x[l][t],o=x[l][t]=function(t,e){if(!this||!this._createWidget)return new o(t,e);arguments.length&&this._createWidget(t,e)},x.extend(o,n,{version:e.version,_proto:x.extend({},e),_childConstructors:[]}),(s=new i).options=x.widget.extend({},s.options),x.each(e,function(e,n){function o(){return i.prototype[e].apply(this,arguments)}function s(t){return i.prototype[e].apply(this,t)}r[e]="function"!=typeof n?n:function(){var t,e=this._super,i=this._superApply;return this._super=o,this._superApply=s,t=n.apply(this,arguments),this._super=e,this._superApply=i,t}}),o.prototype=x.widget.extend(s,{widgetEventPrefix:n&&s.widgetEventPrefix||t},r,{constructor:o,namespace:l,widgetName:t,widgetFullName:a}),n?(x.each(n._childConstructors,function(t,e){var i=e.prototype;x.widget(i.namespace+"."+i.widgetName,o,e._proto)}),delete n._childConstructors):i._childConstructors.push(o),x.widget.bridge(t,o),o},x.widget.extend=function(t){for(var e,i,n=p.call(arguments,1),o=0,s=n.length;o<s;o++)for(e in n[o])i=n[o][e],d.call(n[o],e)&&void 0!==i&&(x.isPlainObject(i)?t[e]=x.isPlainObject(t[e])?x.widget.extend({},t[e],i):x.widget.extend({},i):t[e]=i);return t},x.widget.bridge=function(s,e){var r=e.prototype.widgetFullName||s;x.fn[s]=function(i){var t="string"==typeof i,n=p.call(arguments,1),o=this;return t?this.length||"instance"!==i?this.each(function(){var t,e=x.data(this,r);return"instance"===i?(o=e,!1):e?"function"!=typeof e[i]||"_"===i.charAt(0)?x.error("no such method '"+i+"' for "+s+" widget instance"):(t=e[i].apply(e,n))!==e&&void 0!==t?(o=t&&t.jquery?o.pushStack(t.get()):t,!1):void 0:x.error("cannot call methods on "+s+" prior to initialization; attempted to call method '"+i+"'")}):o=void 0:(n.length&&(i=x.widget.extend.apply(null,[i].concat(n))),this.each(function(){var t=x.data(this,r);t?(t.option(i||{}),t._init&&t._init()):x.data(this,r,new e(i,this))})),o}},x.Widget=function(){},x.Widget._childConstructors=[],x.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"<div>",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=x(e||this.defaultElement||this)[0],this.element=x(e),this.uuid=c++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=x(),this.hoverable=x(),this.focusable=x(),this.classesElementLookup={},e!==this&&(x.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=x(e.style?e.ownerDocument:e.document||e),this.window=x(this.document[0].defaultView||this.document[0].parentWindow)),this.options=x.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:x.noop,_create:x.noop,_init:x.noop,destroy:function(){var i=this;this._destroy(),x.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:x.noop,widget:function(){return this.element},option:function(t,e){var i,n,o,s=t;if(0===arguments.length)return x.widget.extend({},this.options);if("string"==typeof t)if(s={},t=(i=t.split(".")).shift(),i.length){for(n=s[t]=x.widget.extend({},this.options[t]),o=0;o<i.length-1;o++)n[i[o]]=n[i[o]]||{},n=n[i[o]];if(t=i.pop(),1===arguments.length)return void 0===n[t]?null:n[t];n[t]=e}else{if(1===arguments.length)return void 0===this.options[t]?null:this.options[t];s[t]=e}return this._setOptions(s),this},_setOptions:function(t){for(var e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(t){var e,i,n;for(e in t)n=this.classesElementLookup[e],t[e]!==this.options.classes[e]&&n&&n.length&&(i=x(n.get()),this._removeClass(n,e),i.addClass(this._classes({element:i,keys:e,classes:t,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(o){var s=[],r=this;function t(t,e){for(var i,n=0;n<t.length;n++)i=r.classesElementLookup[t[n]]||x(),i=o.add?(function(){var i=[];o.element.each(function(t,e){x.map(r.classesElementLookup,function(t){return t}).some(function(t){return t.is(e)})||i.push(e)}),r._on(x(i),{remove:"_untrackClassesElement"})}(),x(x.uniqueSort(i.get().concat(o.element.get())))):x(i.not(o.element).get()),r.classesElementLookup[t[n]]=i,s.push(t[n]),e&&o.classes[t[n]]&&s.push(o.classes[t[n]])}return(o=x.extend({element:this.element,classes:this.options.classes||{}},o)).keys&&t(o.keys.match(/\S+/g)||[],!0),o.extra&&t(o.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(i){var n=this;x.each(n.classesElementLookup,function(t,e){-1!==x.inArray(i.target,e)&&(n.classesElementLookup[t]=x(e.not(i.target).get()))}),this._off(x(i.target))},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,n){var o="string"==typeof t||null===t,e={extra:o?e:i,keys:o?t:e,element:o?this.element:t,add:n="boolean"==typeof n?n:i};return e.element.toggleClass(this._classes(e),n),this},_on:function(o,s,t){var r,l=this;"boolean"!=typeof o&&(t=s,s=o,o=!1),t?(s=r=x(s),this.bindings=this.bindings.add(s)):(t=s,s=this.element,r=this.widget()),x.each(t,function(t,e){function i(){if(o||!0!==l.options.disabled&&!x(this).hasClass("ui-state-disabled"))return("string"==typeof e?l[e]:e).apply(l,arguments)}"string"!=typeof e&&(i.guid=e.guid=e.guid||i.guid||x.guid++);var t=t.match(/^([\w:-]*)\s*(.*)$/),n=t[1]+l.eventNamespace,t=t[2];t?r.on(n,t,i):s.on(n,i)})},_off:function(t,e){e=(e||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,t.off(e),this.bindings=x(this.bindings.not(t).get()),this.focusable=x(this.focusable.not(t).get()),this.hoverable=x(this.hoverable.not(t).get())},_delay:function(t,e){var i=this;return setTimeout(function(){return("string"==typeof t?i[t]:t).apply(i,arguments)},e||0)},_hoverable:function(t){this.hoverable=this.hoverable.add(t),this._on(t,{mouseenter:function(t){this._addClass(x(t.currentTarget),null,"ui-state-hover")},mouseleave:function(t){this._removeClass(x(t.currentTarget),null,"ui-state-hover")}})},_focusable:function(t){this.focusable=this.focusable.add(t),this._on(t,{focusin:function(t){this._addClass(x(t.currentTarget),null,"ui-state-focus")},focusout:function(t){this._removeClass(x(t.currentTarget),null,"ui-state-focus")}})},_trigger:function(t,e,i){var n,o,s=this.options[t];if(i=i||{},(e=x.Event(e)).type=(t===this.widgetEventPrefix?t:this.widgetEventPrefix+t).toLowerCase(),e.target=this.element[0],o=e.originalEvent)for(n in o)n in e||(e[n]=o[n]);return this.element.trigger(e,i),!("function"==typeof s&&!1===s.apply(this.element[0],[e].concat(i))||e.isDefaultPrevented())}},x.each({show:"fadeIn",hide:"fadeOut"},function(s,r){x.Widget.prototype["_"+s]=function(e,t,i){var n,o=(t="string"==typeof t?{effect:t}:t)?!0!==t&&"number"!=typeof t&&t.effect||r:s;"number"==typeof(t=t||{})?t={duration:t}:!0===t&&(t={}),n=!x.isEmptyObject(t),t.complete=i,t.delay&&e.delay(t.delay),n&&x.effects&&x.effects.effect[o]?e[s](t):o!==s&&e[o]?e[o](t.duration,t.easing,i):e.queue(function(t){x(this)[s](),i&&i.call(e[0]),t()})}})});
// source --> https://lipper-quartiere.de/wp-content/plugins/vikbooking/site/resources/datesrangepicker.js 
/**
 * VikBooking - DatesRangePicker v1.2.3.
 * Copyright (C) 2025 E4J s.r.l. All Rights Reserved.
 * http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * https://vikwp.com | https://e4j.com | https://e4jconnect.com
 * 
 * Forked from MultiDatesPicker v1.6.6
 * https://dubrox.github.io/Multiple-Dates-Picker-for-jQuery-UI
 */
(function(factory) {
	if (typeof define === 'function' && define.amd) {
		define(['jquery', 'jquery-ui-dist'], factory);
	} else {
		factory(jQuery);
	}
}(function($) {
	$.extend($.ui, { vboMultiDatesPicker: { version: '1.6.6' } });

	$.fn.vboMultiDatesPicker = function(method) {
		var mdp_arguments = arguments;
		var ret = this;
		var today_date = new Date;
		var day_zero = new Date(0);
		var mdp_events = {};

		function removeDate(date, type) {
			if (!type) {
				type = 'picked';
			}
			date = dateConvert.call(this, date);
			for (var i = 0; i < this.vboMultiDatesPicker.dates[type].length; i++)
				if (!methods.compareDates(this.vboMultiDatesPicker.dates[type][i], date)) {
					return this.vboMultiDatesPicker.dates[type].splice(i, 1).pop();
				}
		}
		function removeIndex(index, type) {
			if (!type) {
				type = 'picked';
			}
			return this.vboMultiDatesPicker.dates[type].splice(index, 1).pop();
		}
		function addDate(date, type, no_sort) {
			if (!type) {
				type = 'picked';
			}
			date = dateConvert.call(this, date);

			date.setHours(0);
			date.setMinutes(0);
			date.setSeconds(0);
			date.setMilliseconds(0);
			
			if (methods.gotDate.call(this, date, type) === false) {
				this.vboMultiDatesPicker.dates[type].push(date);
				if (!no_sort) {
					this.vboMultiDatesPicker.dates[type].sort(methods.compareDates);
				}
			}
		}
		function sortDates(type) {
			if (!type) {
				type = 'picked';
			}
			this.vboMultiDatesPicker.dates[type].sort(methods.compareDates);
		}
		function dateConvert(date, desired_type, date_format) {
			if (!desired_type) {
				desired_type = 'object';
			}
			return methods.dateConvert.call(this, date, desired_type, date_format);
		}
		
		var methods = {
			init: function(options) {
				var $this = $(this);
				this.vboMultiDatesPicker.changed = false;
				
				var mdp_events = {
					beforeShow: function(input, inst) {
						this.vboMultiDatesPicker.changed = false;
						if (this.vboMultiDatesPicker.originalBeforeShow) {
							this.vboMultiDatesPicker.originalBeforeShow.call(this, input, inst);
						}
					},
					onSelect: function(dateText, inst) {
						var $this = $(this);
						this.vboMultiDatesPicker.changed = true;
						
						if (dateText) {
							$this.vboMultiDatesPicker('toggleDate', dateText);
							this.vboMultiDatesPicker.changed = true;
						}
						
						if (this.vboMultiDatesPicker.mode == 'normal' && this.vboMultiDatesPicker.pickableRange) {
							if (this.vboMultiDatesPicker.dates.picked.length > 0) {
								var min_date = this.vboMultiDatesPicker.dates.picked[0],
									max_date = new Date(min_date.getTime());

								methods.sumDays(max_date, this.vboMultiDatesPicker.pickableRange-1);

								// counts the number of disabled dates in the range
								if (this.vboMultiDatesPicker.adjustRangeToDisabled) {
									var c_disabled, 
										disabled = this.vboMultiDatesPicker.dates.disabled.slice(0);
									do {
										c_disabled = 0;
										for (var i = 0; i < disabled.length; i++) {
											if (disabled[i].getTime() <= max_date.getTime()) {
												if ((min_date.getTime() <= disabled[i].getTime()) && (disabled[i].getTime() <= max_date.getTime()) ) {
													c_disabled++;
												}
												disabled.splice(i, 1);
												i--;
											}
										}
										max_date.setDate(max_date.getDate() + c_disabled);
									} while(c_disabled != 0);
								}
								
								if (this.vboMultiDatesPicker.maxDate && (max_date > this.vboMultiDatesPicker.maxDate)) {
									max_date = this.vboMultiDatesPicker.maxDate;
								}

								$this.datepicker('option', 'minDate', min_date).datepicker('option', 'maxDate', max_date);
							} else {
								$this.datepicker('option', 'minDate', this.vboMultiDatesPicker.minDate).datepicker('option', 'maxDate', this.vboMultiDatesPicker.maxDate);
							}
						}

						if (this.vboMultiDatesPicker.originalOnSelect && dateText) {
							this.vboMultiDatesPicker.originalOnSelect.call(this, dateText, inst);
						}
					},
					beforeShowDay: function(date) {
						var $this = $(this),
							gotThisDate = $this.vboMultiDatesPicker('gotDate', date) !== false,
							isDisabledCalendar = $this.datepicker('option', 'disabled'),
							isDisabledDate = $this.vboMultiDatesPicker('gotDate', date, 'disabled') !== false,
							areAllSelected = this.vboMultiDatesPicker.maxPicks <= this.vboMultiDatesPicker.dates.picked.length;

						var bsdReturn = [true, '', null];
						if (this.vboMultiDatesPicker.originalBeforeShowDay) {
							bsdReturn = this.vboMultiDatesPicker.originalBeforeShowDay.call(this, date);
						}

						bsdReturn[1] = gotThisDate ? 'ui-state-highlight ' + bsdReturn[1] : bsdReturn[1];
						bsdReturn[0] = bsdReturn[0] && !(isDisabledCalendar || isDisabledDate || (areAllSelected && !bsdReturn[1]));
						return bsdReturn;
					}
				};

				// value needs to be extracted before datepicker is initiated
				if ($this.val()) {
					var inputDates = $this.val();
				}

				if (options) {
					// value needs to be extracted before datepicker is initiated
					if (options.separator) {
						this.vboMultiDatesPicker.separator = options.separator;
					}
					if (!this.vboMultiDatesPicker.separator) {
						this.vboMultiDatesPicker.separator = ', ';
					}

					this.vboMultiDatesPicker.originalBeforeShow = options.beforeShow;
					this.vboMultiDatesPicker.originalOnSelect = options.onSelect;
					this.vboMultiDatesPicker.originalBeforeShowDay = options.beforeShowDay;
					this.vboMultiDatesPicker.originalOnClose = options.onClose;

					// datepicker init
					$this.datepicker(options);

					this.vboMultiDatesPicker.minDate = $.datepicker._determineDate(this, options.minDate, null);
					this.vboMultiDatesPicker.maxDate = $.datepicker._determineDate(this, options.maxDate, null);
					if (options.addDates) {
						methods.addDates.call(this, options.addDates);
					}

					if (options.addDisabledDates) {
						methods.addDates.call(this, options.addDisabledDates, 'disabled');
					}

					methods.setMode.call(this, options);
				} else {
					$this.datepicker();
				}
				$this.datepicker('option', mdp_events);

				// adds any dates found in the input or alt field
				if (inputDates) $this.vboMultiDatesPicker('value', inputDates);

				// generates the new string of added dates
				var inputs_values = $this.vboMultiDatesPicker('value');

				// fills the input field back with all the dates in the calendar
				$this.val(inputs_values);

				// Fixes the altField filled with defaultDate by default
				var altFieldOption = $this.datepicker('option', 'altField');
				if (altFieldOption) $(altFieldOption).val(inputs_values);

				// Updates the calendar view
				$this.datepicker('refresh');
			},
			compareDates: function(date1, date2) {
				date1 = dateConvert.call(this, date1);
				date2 = dateConvert.call(this, date2);
				// return > 0 means date1 is later than date2
				// return == 0 means date1 is the same day as date2
				// return < 0 means date1 is earlier than date2
				var diff = date1.getFullYear() - date2.getFullYear();
				if (!diff) {
					diff = date1.getMonth() - date2.getMonth();
					if (!diff) {
						diff = date1.getDate() - date2.getDate();
					}
				}
				return diff;
			},
			sumDays: function(date, n_days) {
				var origDateType = typeof date;
				obj_date = dateConvert.call(this, date);
				obj_date.setDate(obj_date.getDate() + n_days);
				return dateConvert.call(this, obj_date, origDateType);
			},
			dateConvert: function(date, desired_format, dateFormat) {
				var from_format = typeof date;
				var $this = $(this);

				if (from_format == desired_format) {
					if (from_format == 'object') {
						try {
							date.getTime();
						} catch (e) {
							$.error('Received date is in a non supported format!');
							return false;
						}
					}
					return date;
				}

				if (typeof date == 'undefined') {
					date = new Date(0);
				}

				if (desired_format != 'string' && desired_format != 'object' && desired_format != 'number')
					$.error('Date format "'+ desired_format +'" not supported!');
				
				if (!dateFormat) {
					var dp_dateFormat = $this.datepicker('option', 'dateFormat');
					if (dp_dateFormat) {
						dateFormat = dp_dateFormat;
					} else {
						dateFormat = $.datepicker._defaults.dateFormat;
					}
				}
				
				// converts to object as a neutral format
				switch (from_format) {
					case 'object': break;
					case 'string': date = $.datepicker.parseDate(dateFormat, date); break;
					case 'number': date = new Date(date); break;
					default: $.error('Conversion from "'+ from_format +'" format not allowed on jQuery.vboMultiDatesPicker');
				}
				// then converts to the desired format
				switch (desired_format) {
					case 'object': return date;
					case 'string': return $.datepicker.formatDate(dateFormat, date);
					case 'number': return date.getTime();
					default: $.error('Conversion to "'+ desired_format +'" format not allowed on jQuery.vboMultiDatesPicker');
				}
				return false;
			},
			gotDate: function(date, type) {
				if (!type) {
					type = 'picked';
				}
				for (var i = 0; i < this.vboMultiDatesPicker.dates[type].length; i++) {
					if (methods.compareDates.call(this, this.vboMultiDatesPicker.dates[type][i], date) === 0) {
						return i;
					}
				}
				return false;
			},
			value: function(value) {
				if (value && typeof value == 'string') {
					methods.addDates.call(this, value.split(this.vboMultiDatesPicker.separator));
				} else {
					var dates = methods.getDates.call(this, 'string');
					return dates.length
						? dates.join(this.vboMultiDatesPicker.separator)
						: '';
				}
			},
			getDates: function(format, type) {
				if (!format) {
					format = 'string';
				}
				if (!type) {
					type = 'picked';
				}
				switch (format) {
					case 'object':
						return this.vboMultiDatesPicker.dates[type];
					case 'string':
					case 'number':
						var o_dates = [];
						for (var i = 0; i < this.vboMultiDatesPicker.dates[type].length; i++)
							o_dates.push(
								dateConvert.call(
									this, 
									this.vboMultiDatesPicker.dates[type][i], 
									format
								)
							);
						return o_dates;
					
					default: $.error('Format "'+format+'" not supported!');
				}
			},
			addDates: function(dates, type) {
				if (dates.length > 0) {
					if (!type) {
						type = 'picked';
					}
					switch (typeof dates) {
						case 'object':
						case 'array':
							if (dates.length) {
								for (var i = 0; i < dates.length; i++)
									addDate.call(this, dates[i], type, true);
								sortDates.call(this, type);
								break;
							} // else does the same as 'string'
						case 'string':
						case 'number':
							addDate.call(this, dates, type);
							break;
						default: 
							$.error('Date format "'+ typeof dates +'" not allowed on jQuery.vboMultiDatesPicker');
					}
				} else {
					$.error('Empty array of dates received.');
				}
			},
			removeDates: function(dates, type) {
				if (!type) {
					type = 'picked';
				}
				var removed = [];
				if (Object.prototype.toString.call(dates) === '[object Array]') {
					dates.sort(function(a,b) {return b-a});
					for (var i = 0; i < dates.length; i++) {
						removed.push(removeDate.call(this, dates[i], type));
					}
				} else {
					removed.push(removeDate.call(this, dates, type));
				}
				return removed;
			},
			removeIndexes: function(indexes, type) {
				if (!type) {
					type = 'picked';
				}
				var removed = [];
				if (Object.prototype.toString.call(indexes) === '[object Array]') {
					indexes.sort(function(a,b) {return b-a});
					for (var i = 0; i < indexes.length; i++) {
						removed.push(removeIndex.call(this, indexes[i], type));
					}
				} else {
					removed.push(removeIndex.call(this, indexes, type));
				}
				return removed;
			},
			resetDates: function (type) {
				if (!type) {
					type = 'picked';
				}
				this.vboMultiDatesPicker.dates[type] = [];
			},
			toggleDate: function(date, type) {
				if (!type) {
					type = 'picked';
				}
				switch (this.vboMultiDatesPicker.mode) {
					case 'daysRange':
						this.vboMultiDatesPicker.dates[type] = []; // deletes all picked/disabled dates
						var end = this.vboMultiDatesPicker.autoselectRange[1];
						var begin = this.vboMultiDatesPicker.autoselectRange[0];
						if (end < begin) {
							end = this.vboMultiDatesPicker.autoselectRange[0];
							begin = this.vboMultiDatesPicker.autoselectRange[1];
						}
						for (var i = begin; i < end; i++) {
							methods.addDates.call(this, methods.sumDays.call(this,date, i), type);
						}
						break;
					default:
						if (methods.gotDate.call(this, date) === false) {
							methods.addDates.call(this, date, type);
						} else {
							methods.removeDates.call(this, date, type);
						}
						break;
				}
			},
			setMode: function(options) {
				var $this = $(this);
				if (options.mode) {
					this.vboMultiDatesPicker.mode = options.mode;
				}

				switch (this.vboMultiDatesPicker.mode) {
					case 'normal':
						for (var option in options) {
							switch (option) {
								case 'maxPicks':
								case 'minPicks':
								case 'pickableRange':
								case 'adjustRangeToDisabled':
									this.vboMultiDatesPicker[option] = options[option];
									break;
								// default: $.error('Option ' + option + ' ignored for mode "'.options.mode.'".');
							}
						}
					break;
					case 'daysRange':
					case 'weeksRange':
						var mandatory = 1;
						for (option in options) {
							switch (option) {
								case 'autoselectRange':
									mandatory--;
								case 'pickableRange':
								case 'adjustRangeToDisabled':
									this.vboMultiDatesPicker[option] = options[option];
									break;
								// default: $.error('Option ' + option + ' does not exist for setMode on jQuery.vboMultiDatesPicker');
							}
						}
						if (mandatory > 0) {
							$.error('Some mandatory options not specified!');
						}
					break;
				}

				if (mdp_events.onSelect) {
					mdp_events.onSelect();
				}
			},
			destroy: function() {
				this.vboMultiDatesPicker = null;
				$(this).datepicker('destroy');
			}
		};

		this.each(function() {
			var $this = $(this);
			if (!this.vboMultiDatesPicker) {
				this.vboMultiDatesPicker = {
					dates: {
						picked: [],
						disabled: []
					},
					mode: 'normal',
					adjustRangeToDisabled: true
				};
			}

			if (methods[method]) {
				var exec_result = methods[method].apply(this, Array.prototype.slice.call(mdp_arguments, 1));
				switch (method) {
					case 'removeDates':
					case 'removeIndexes':
					case 'resetDates':
					case 'toggleDate':
					case 'addDates':
						var altField = $this.datepicker('option', 'altField');
						var dates_string = methods.value.call(this);
						if (altField !== undefined && altField != '') {
							$(altField).val(dates_string);
						}
						$this.val(dates_string);

						$.datepicker._refreshDatepicker(this);
				}
				switch (method) {
					case 'removeDates':
					case 'getDates':
					case 'gotDate':
					case 'sumDays':
					case 'compareDates':
					case 'dateConvert':
					case 'value':
						ret = exec_result;
				}
				return exec_result;
			} else if (typeof method === 'object' || !method) {
				return methods.init.apply(this, mdp_arguments);
			} else {
				$.error('Method ' +  method + ' does not exist on jQuery.vboMultiDatesPicker');
			}
			return false;
		}); 

		return ret;
	};

	$.vboMultiDatesPicker = {version: false};
	$.vboMultiDatesPicker.initialized = false;
	$.vboMultiDatesPicker.uuid = new Date().getTime();
	$.vboMultiDatesPicker.version = $.ui.vboMultiDatesPicker.version;
	
	/**
	 * Allows MDP not to hide everytime a date is picked.
	 */
	$(function() {
		/**
		 * Use a constant instead of a property object to break the loop caused
		 * my modal (AJAX) duplicate rendering.
		 */
		// $.vboMultiDatesPicker._hideDatepicker = $.datepicker._hideDatepicker;
		const vboMultiDatesPicker_hideDatepicker = $.datepicker._hideDatepicker;
		$.datepicker._hideDatepicker = function() {
			/**
			 * Prevent errors with inline datepickers when _curInst is null.
			 * 
			 * @see 	modified from original source code
			 */
			if (!this._curInst) {
				return;
			}

			var target = this._curInst.input[0];
			var mdp = target.vboMultiDatesPicker;
			if (!mdp || (this._curInst.inline === false && !mdp.changed)) {
				return vboMultiDatesPicker_hideDatepicker.apply(this, arguments);
			} else {
				mdp.changed = false;
				$.datepicker._refreshDatepicker(target);
				return;
			}
		};
	});

	/**
	 * VikBooking - DatesRangePicker declaration.
	 * 
	 * @param 	string|object 	checkin 	Check-in input field selector or element.
	 * @param 	string|object 	checkout 	Check-out input field selector or element.
	 * @param 	object			options 	Datepicker options.
	 */
	$.vboDatesRangePicker = function(checkin, checkout, options) {
		if (typeof checkin === 'string') {
			checkin = $(checkin);
		}
		if (typeof checkout === 'string') {
			checkout = $(checkout);
		}

		if (!checkin || !checkout || !checkin.length || !checkout.length) {
			throw new Error('Invalid vboDatesRangePicker check-in/check-out selectors.');
		}

		// ensure the current jQuery version is supported (v1.x is NOT supported)
		let jq_version = $.fn.jquery || '3';
		if (typeof jq_version === 'string' && jq_version.substring(0, 1) === '1') {
			// fallback to regular datepicker
			$(checkin).datepicker(options);
			$(checkout).datepicker(options);
			// abort
			throw new Error('Unsupported jQuery version');
		}

		if (typeof options !== 'object') {
			options = {};
		}

		// get the input fields for check-in and check-out
		const inputCheckin = options?.altFields?.checkin ? $(options.altFields.checkin) : checkin;
		const inputCheckout = options?.altFields?.checkout ? $(options.altFields.checkout) : checkout;

		// get currently populated dates, if any
		let prevCheckinDate = inputCheckin.val();
		let prevCheckoutDate = inputCheckout.val();
		const dates = [prevCheckinDate, prevCheckoutDate].filter(d => d);

		// date range picker configuration
		// 3 picks needed to rectify the completed selection
		options.maxPicks = 3;
		options.addDates = dates.length ? dates : null;

		if (typeof options.altFormat !== 'undefined') {
			// option not supported
			delete options.altFormat;
		}

		// default configuration arguments
		if (typeof options.numberOfMonths === 'undefined') {
			options.numberOfMonths = 2;
		}

		if (typeof options.minDate === 'undefined') {
			options.minDate = new Date;
		} else {
			// ensure minDate is an object
			options.minDate = $(this).vboDatesRangePicker('convertPeriod', options.minDate);
		}

		const _onSelect = options.onSelect ?? null;
		options.onSelect = function(date, instance) {
			let pickedDates = $(this).vboMultiDatesPicker('getDates');

			setTimeout(() => {
				// clear the active status to prevent conflicts in case of deselection
				let dateObj = $.datepicker.parseDate($(this).datepicker('option', 'dateFormat'), date);
				const dayCell = $('.ui-datepicker').find('td.date-' + dateObj.getFullYear() + '-' + dateObj.getMonth() + '-' + dateObj.getDate());
				dayCell.find('.ui-state-active').removeClass('ui-state-active');
				dayCell.removeClass('ui-datepicker-current-day');
				// resolve possible conflicts with tooltip
				dayCell.trigger('mouseenter');
			}, 10);

			if (pickedDates.length > 2) {
				// remove all the dates from the selection, except for the last picked one
				$(this).vboMultiDatesPicker('removeDates', pickedDates.filter(d => d != date));

				// adjust the picked dates
				pickedDates = [date];
			}

			// populate checkin and checkout fields
			if (pickedDates.length == 1) {
				inputCheckin.val(pickedDates[0]);
				inputCheckout.val('');
			} else if (pickedDates.length == 2) {
				inputCheckin.val(pickedDates[0]);
				inputCheckout.val(pickedDates[1]);
			} else {
				inputCheckin.val('');
				inputCheckout.val('');
			}

			/**
			 * @see 	Natively inline datepickers not rendered on input fields cannot be hid!
			 */

			// prevent the datepicker auto-hiding after selecting a date
			instance.inline = true;

			setTimeout(() => {
				// remove the inline state after completing the selection process,
				// this aims to re-allow the datepicker closure when clicking outside
				instance.inline = false;
			});

			if (_onSelect) {
				// propagate selection behavior
				_onSelect(date, instance);
			}

			if (pickedDates.length == 2) {
				setTimeout(() => {
					// prepare the very next click outside to hide the datepicker rather than 2 next clicks
					checkin.datepicker('hide');
				});

				if (options?.environment?.autoHide) {
					// do not allow to rectify the selection, but rather hide the DRP on selection completed
					setTimeout(() => {
						checkin.datepicker('hide');
						checkin.trigger('blur');
					}, (options?.environment?.autoHideDelay || 100));
				}
			}
		};

		const _beforeShowDay = options.beforeShowDay ?? null;
		options.beforeShowDay = function(date) {
			// get the DRP configuration
			let config = $(this).vboDatesRangePicker('drpoption');

			// current dates
			const pickedDates = $(this).vboMultiDatesPicker('getDates');
			const isPicked = pickedDates.some(dt => dt == date);

			// in case the date has been selected, use it as min date
			// in case the date has been deselected, use the first date in the array (config min date if empty selection)
			let minDate = isPicked ? date : (pickedDates[0] || config.minDate);
			// in case we have 0 or 2 selected dates, ignore the minimum date
			// in case we have 1 or 3 selected dates, use the new date
			minDate = pickedDates.length % 2 ? minDate : config.minDate;

			// class identifier to easily select the table cell from a date object
			const dateIdClass = 'date-' + date.getFullYear() + '-' + date.getMonth() + '-' + date.getDate();

			// in case of past date, disable cell
			if ($(this).vboDatesRangePicker('compareDates', date, minDate) < 0) {
				return [false, 'date-past ' + dateIdClass, null];
			}

			// build date return values
			let returnVal = [true, '', null];

			// whether the date is known
			let knownDate = false;

			if (pickedDates.length > 0) {
				// date format
				let dateFormat = $(this).datepicker('option', 'dateFormat');

				// get check-in date
				let checkinDate = $.datepicker.parseDate(dateFormat, pickedDates[0]);

				if ($(this).vboDatesRangePicker('compareDates', checkinDate, date) == 0) {
					// parsing the check-in date
					let checkinDayTitle = config?.labels?.checkin || null;
					if (pickedDates.length == 1 && parseInt((config?.checkoutConstraints?.minStayNights || 0)) > 1) {
						if (typeof config?.labels?.minStayNights === 'function') {
							checkinDayTitle = config.labels.minStayNights.call(null, config.checkoutConstraints.minStayNights);
						} else if (typeof config?.labels?.minStayNights === 'string') {
							checkinDayTitle = config.labels.minStayNights;
						}
					}
					returnVal = [true, 'checkin-date' + (pickedDates.length == 1 ? ' without-checkout-date' : ''), checkinDayTitle];
					knownDate = true;
				} else if (pickedDates.length == 2) {
					// get check-out date
					let checkoutDate = $.datepicker.parseDate(dateFormat, pickedDates[1]);
			  
					if ($(this).vboDatesRangePicker('compareDates', checkoutDate, date) == 0) {
						// parsing the check-out date
						let checkoutDayTitle = config?.labels?.checkout || null;
						returnVal = [true, 'checkout-date', checkoutDayTitle];
						knownDate = true;
					} else if (checkinDate < date && date < checkoutDate) {
						// parsing a date between the check-in and the check-out
						returnVal = [true, 'checkin-checkout-inner', null];
						knownDate = true;
					}
				}
			}

			if (_beforeShowDay && !knownDate) {
				// call the registered methods for validating the current date
				returnVal = _beforeShowDay(date);
			}

			if (returnVal[2]) {
				// in case of tooltip title text, append a specific class
				returnVal[1] += ' date-tooltip';
				if (returnVal[2].length > 20) {
					// this is a large tooltip text
					returnVal[1] += ' date-tooltip-large';
				}
				// determine the tooltip position
				let firstwday = $(this).vboDatesRangePicker('option', 'firstDay');
				if (date.getDay() == firstwday) {
					// first day of week
					returnVal[1] += ' date-tooltip-firstwday';
				} else {
					// calculate last week-day index
					let lastwday = firstwday - 1;
					lastwday = lastwday < 0 ? 6 : lastwday;
					if (date.getDay() == lastwday) {
						// last day of week
						returnVal[1] += ' date-tooltip-lastwday';
					}
				}
			}

			// append the class for this exact day and trim
			returnVal[1] += ' ' + dateIdClass;
			returnVal[1] = returnVal[1].trim();

			return returnVal;
		}

		/**
		 * The beforeShow function will NOT be called for inline datepickers.
		 */
		const _beforeShow = options.beforeShow ?? null;
		const _mouseEnter = (inlineElement) => {
			// determine the proper datepicker container
			let dpContainer = typeof inlineElement === 'undefined' ? $('.ui-datepicker').not('.ui-datepicker-inline') : $(inlineElement).find('.ui-datepicker');

			dpContainer.on('mouseenter', 'td', function() {
				let pickedDates = [];

				try {
					pickedDates = $(checkin).vboMultiDatesPicker('getDates');
				} catch (e) {
					// silently abort in case of elements not being controlled through DRP
					return;
				}

				if ($(this).hasClass('date-tooltip')) {
					let title = $(this).attr('title');
					if (title) {
						// replace native title attribute with data attribute for tooltip
						$(this).attr('title', '');
						$(this).attr('data-title', title);
					}
				}

				if (pickedDates.length == 1) {
					// get the proper date format in case it differs from regional values
					let dateFormat = $(checkin).datepicker('option', 'dateFormat') || options.dateFormat;
					const checkinDate = $.datepicker.parseDate(dateFormat, pickedDates[0]);

					const checkoutDate = new Date;
					// ensure to set the date to 1 first, in case the month to set does not have this day (i.e Jan 30, Feb 30 not existing)
					// without doing so, the Date object constructed would get an extra month, and so the date would not be the desired one
					checkoutDate.setDate(1);
					checkoutDate.setFullYear($(this).data('year'));
					checkoutDate.setMonth($(this).data('month'));
					checkoutDate.setDate($(this).text());

					$('.checkout-date').removeClass('checkout-date date-will');
					$('.checkin-checkout-inner').removeClass('checkin-checkout-inner');

					if ($(checkin).vboDatesRangePicker('compareDates', checkoutDate, checkinDate) == 0) {
						return;
					}

					$('.date-' + checkoutDate.getFullYear() + '-' + checkoutDate.getMonth() + '-' + checkoutDate.getDate()).addClass('checkout-date date-will');
					checkoutDate.setDate(checkoutDate.getDate() - 1);

					while ($(checkin).vboDatesRangePicker('compareDates', checkoutDate, checkinDate) > 0) {
						$('.date-' + checkoutDate.getFullYear() + '-' + checkoutDate.getMonth() + '-' + checkoutDate.getDate()).addClass('checkin-checkout-inner');
						checkoutDate.setDate(checkoutDate.getDate() - 1);
					}
				}
			});
		}
		options.beforeShow = function(input, instance) {
			// register mouseenter event on date cells
			_mouseEnter();

			if (_beforeShow) {
				// propagate show behavior
				_beforeShow(input, instance);
			}
		};

		/**
		 * The onUpdateDatepicker function will NOT be called for inline datepickers.
		 */
		const _onUpdateDatepicker = options.onUpdateDatepicker ?? null;
		options.onUpdateDatepicker = function(instance) {
			// get the DRP configuration
			let config = $(this).vboDatesRangePicker('drpoption');

			if (typeof config?.bottomCommands === 'object') {
				if ($('.vbo-drp-commands-bottom').length) {
					return;
				}

				// build bottom commands
				let btmCommands = $('<div></div>').addClass('vbo-drp-commands-bottom');

				// clear dates
				let clearCommand = $('<div></div>')
					.addClass('vbo-drp-command vbo-drp-command-clear')
					.append(
						$('<a></a>')
							.attr('href', 'JavaScript: void(0);')
							.text((config.bottomCommands?.clear || 'Clear dates'))
							.on('click', () => {
								$(this).vboDatesRangePicker('setDates', []);
								$('#ui-datepicker-div').find('.ui-state-active').removeClass('ui-state-active');
								$('#ui-datepicker-div').find('.ui-datepicker-current-day').removeClass('ui-datepicker-current-day');
								if (typeof config.bottomCommands?.onClear === 'function') {
									// invoke the provided method in case something needs to be cleared from the UI
									config.bottomCommands.onClear.call(this);
								}
							})
					);
				btmCommands.append(clearCommand);

				// close DRP
				let closeCommand = $('<div></div>')
					.addClass('vbo-drp-command vbo-drp-command-close')
					.append(
						$('<button></button>')
							.addClass('btn btn-small ' + (config?.environment?.section === 'admin' ? 'vbo-dark-btn' : 'vbo-pref-color-btn'))
							.attr('type', 'button')
							.text((config.bottomCommands?.close || 'Close'))
							.on('click', () => {
								$(this).datepicker('hide');
							})
					);
				btmCommands.append(closeCommand);

				// append bottom commands to DRP
				$('#ui-datepicker-div').append(btmCommands);
			}

			if (_onUpdateDatepicker) {
				// propagate onUpdateDatepicker behavior
				_onUpdateDatepicker(instance);
			}
		};

		/**
		 * Define the onClose behavior.
		 */
		const _onClose = options.onClose ?? null;
		options.onClose = function(dateText, instance) {
			// unregister mouseenter event from every non-inline datepicker
			$('.ui-datepicker').not('.ui-datepicker-inline').off('mouseenter', 'td');

			if (_onClose) {
				// propagate close behavior
				_onClose(dateText, instance);
			}
		};

		// check for regional default settings
		if (options?.environment?.section === 'admin') {
			let regionalDefaults = $.datepicker.regional['vikbooking'];
			if (typeof regionalDefaults === 'object') {
				// merge regional settings with DRP options
				options = Object.assign(regionalDefaults, options);
			}
		}

		// determine whether the datepicker is inline
		let isInline = !$(checkin).is('input[type="text"]');

		// instantiate multi-dates picker for a single range of dates
		$(checkin).vboMultiDatesPicker(options);

		// trigger datepicker opening when focusing the check-out field too
		$(checkout).on('focus', () => {
			$(checkin).datepicker('show');
		});

		// restore the initial check-in value
		inputCheckin.val(prevCheckinDate);

		if (isInline) {
			// manually register the mouseenter event since the beforeShow won't run
			setTimeout(() => {
				_mouseEnter(checkin);
			}, 100);
		} else {
			// add class to the check-out field to identify the trigger
			$(checkout).addClass('vbo-drp-inp-trigger');
		}
	}

	/**
	 * VikBooking - DatesRangePicker jQuery plugin.
	 * 
	 * @param 	any 	method 		Either string for getter/setter, or object to start the DRP.
	 * @param 	any 	options 	Initialization object options, or mixed value for setter.
	 * @param 	any 	setvalue 	The value to set within the datepicker in case of "option" setter.
	 */
	$.fn.vboDatesRangePicker = function(method, options, setvalue) {
		if (!method) {
			// initialize the DRP
			method = {};
		}

		// immediately exit in case of no elements found
		if ($(this).length == 0) {
			return this;
		}

		/**
		 * Initializes the DRP calendar.
		 */
		const init = (options) => {
			if (!options.dateFormat) {
				options.dateFormat = 'yy-mm-dd';
			}

			// set DRP cloned configuration data
			drpConfig(Object.assign({}, options));

			// element selector
			let that = $(this);

			// handle native datepicker method beforeShowDay
			if (options.beforeShowDay) {
				// get registered callbacks
				let beforeShowDayCheckin = options.beforeShowDay.checkin;
				let beforeShowDayCheckout = options.beforeShowDay.checkout;

				// delete native property
				delete options.beforeShowDay;

				// register native property
				options.beforeShowDay = (date) => {
					// get currently selected dates
					let pickedDates = that.vboMultiDatesPicker('getDates');

					// default date selectable state
					let isSelectable = true;
					let className = '';
					let tooltipText = null;

					// invoke callbacks by injecting the proper arguments
					if ((!pickedDates.length || pickedDates.length == 2) && typeof beforeShowDayCheckin === 'function') {
						// validate cell for check-in selection
						let validation = beforeShowDayCheckin.call(that, date);
						// update cell states
						isSelectable = validation[0];
						className    = validation[1] || className;
						tooltipText  = validation[2] || tooltipText;
					} else if (pickedDates.length == 1 && typeof beforeShowDayCheckout === 'function') {
						// validate cell for check-out selection
						let validation = beforeShowDayCheckout.call(that, date);
						// update cell states
						isSelectable = validation[0];
						className    = validation[1] || className;
						tooltipText  = validation[2] || tooltipText;
					}

					if (!pickedDates.length) {
						// unset any previously set checkout constraints when no dates selected
						unsetCheckoutConstraints(date);
					} else if (pickedDates.length == 1) {
						// before showing the check-out day, validate the constraints, if any
						let constrainData = validateCheckoutConstraints(date, [isSelectable, className, tooltipText], pickedDates[0]);
						// update cell states
						isSelectable = constrainData[0];
						className    = constrainData[1];
						tooltipText  = constrainData[2];
					}

					return [
						// whether it's selectable
						(isSelectable ? true : false),
						// CSS class name to add
						className,
						// tooltip text
						tooltipText,
					];
				};
			}

			// handle native datepicker method onSelect
			if (options.onSelect) {
				// get registered callbacks
				let onSelectCheckin = options.onSelect.checkin;
				let onSelectCheckout = options.onSelect.checkout;

				// delete native property
				delete options.onSelect;

				// register native property
				options.onSelect = (selectedDate) => {
					// get currently selected dates
					let pickedDates = that.vboMultiDatesPicker('getDates');

					// invoke callbacks by injecting the proper arguments
					if (pickedDates.length == 1 && typeof onSelectCheckin === 'function') {
						// call the registered check-in function
						onSelectCheckin.call(that, selectedDate);
					} else if (pickedDates.length == 2 && typeof onSelectCheckout === 'function') {
						// call the registered check-out function
						onSelectCheckout.call(that, selectedDate);
					}
				};
			}

			// handle datepicker alternate field
			if (options?.altFields?.checkin) {
				// set native alternate field
				options.altField = options.altFields.checkin;
			}

			// render DRP
			$.vboDatesRangePicker(that, $(options.checkout), options);

			// threshold for responsiveness
			let thresholdWidth = options?.responsiveNumMonths?.threshold || 860;

			// handle responsive number of months
			if (options?.responsiveNumMonths && (options?.numberOfMonths || 1) > 1) {
				// configure responsive number of months
				options._onResizeWindow = () => {
					let windowWidth = window.innerWidth;
					if (windowWidth && windowWidth <= thresholdWidth) {
						// just one month
						that.datepicker('option', 'numberOfMonths', 1);
					} else {
						// use the number of months configured
						that.datepicker('option', 'numberOfMonths', options.numberOfMonths);
					}
				};

				// remove duplicate event listeners
				window.removeEventListener('resize', options._onResizeWindow);

				// register event listener
				window.addEventListener('resize', options._onResizeWindow);

				// call method on init
				options._onResizeWindow();
			}

			// handle input fields focus/blur on mobile devices
			if (options?.environment?.section === 'admin' && that.is('input[type="text"]')) {
				// disable input fields focus on small screen resolutions
				let windowWidth = window.innerWidth;
				if (windowWidth && windowWidth <= thresholdWidth) {
					// disable focus on check-in input field
					that.on('focus', function() {
						$(this).blur();
					});

					if ($(options.checkout).is('input[type="text"]')) {
						// disable focus on check-out input field
						$(options.checkout).on('focus', function() {
							$(this).blur();
						});
					}
				}
			}

			return this;
		}

		/**
		 * Setter or getter for the DRP calendar.
		 */
		const drpConfig = (options) => {
			if (typeof options === 'undefined') {
				// GETTER: return DRP configuration.
				// Clone the object in order to prevent manual edits to
				// the configuration properties.
				return Object.assign({}, $(this).data('vboDrpConfig'));
			}

			// SETTER: update DRP configuration
			return $(this).data('vboDrpConfig', options);
		}

		/**
		 * Converts a period string like "+1d" into a Date object.
		 * 
		 * @param 	string 	period 		The date period string.
		 * @param 	Date 	fromDate 	Optional Date object from.
		 * 
		 * @return 	Date
		 */
		const convertPeriod = (period, fromDate) => {
			if (!fromDate || !(fromDate instanceof Date)) {
				fromDate = new Date;
			}

			if (typeof period !== 'string') {
				// period must be a string
				return fromDate;
			}

			let instructions = period.match(/^[\+\-]?([0-9]+)(d|w|m|y)$/i);

			if (!instructions || instructions.length != 3) {
				// period not matched
				return fromDate;
			}

			// period number of days/weeks/months/year
			let num = parseInt(instructions[1]);

			if (num === 0) {
				// same day period ("0d")
				return fromDate;
			}

			// period modifier
			if (period.substring(0, 1) == '-') {
				// turn number into negative
				num = num - (num * 2);
			}

			switch ((instructions[2] + '').toLowerCase()) {
				case 'd':
					fromDate.setDate(fromDate.getDate() + num);
					break;
				case 'w':
					fromDate.setDate(fromDate.getDate() + (7 * num));
					break;
				case 'm':
					fromDate.setMonth(fromDate.getMonth() + num);
					break;
				case 'y':
					fromDate.setFullYear(fromDate.getFullYear() + num);
					break;
			}

			return fromDate;
		}

		/**
		 * Compares two date objects against each other with year, month, day.
		 * 
		 * @param 	string|Date 	date1 	The first date.
		 * @param 	string|Date 	date2 	The second date.
		 * 
		 * @return 	int 			Greater than 0 means date1 is after date2.
		 * 							Equal to 0 means date1 is the same as date2.
		 * 							Less than 0 means date1 is before date2.
		 */
		const compareDates = (date1, date2) => {
			if (!date1) {
				// no empty dates allowed, default to today
				date1 = new Date;
			}

			if (!date2) {
				// no empty dates allowed, default to today
				date2 = new Date;
			}

			// get the DRP configuration
			let config = drpConfig();

			if (typeof date1 === 'string') {
				try {
					// convert date string to date object
					date1 = $.datepicker.parseDate(config.dateFormat, date1);
				} catch (e) {
					// attempt to convert a period string into a date object
					date1 = convertPeriod(date1);
				}
			}

			if (typeof date2 === 'string') {
				try {
					// convert date string to date object
					date2 = $.datepicker.parseDate(config.dateFormat, date2);
				} catch (e) {
					// attempt to convert a period string into a date object
					date2 = convertPeriod(date2);
				}
			}

			// year check
			let diff = date1.getFullYear() - date2.getFullYear();

			if (!diff) {
				// month check
				diff = date1.getMonth() - date2.getMonth();

				if (!diff) {
					// day check
					diff = date1.getDate() - date2.getDate();
				}
			}

			return diff;
		}

		/**
		 * Sets new dates in the DRP calendar.
		 * 
		 * @param 	array 	dates 	List of dates to set.
		 * 
		 * @return 	self
		 */
		const setDates = (dates) => {
			if (!Array.isArray(dates)) {
				throw new Error('Invalid dates argument');
			}

			// filter out empty dates
			dates = dates.filter(d => d);

			// get the DRP configuration
			let config = drpConfig();

			// map first the given dates to date strings in the desired format
			dates = dates.map((dt) => {
				if (typeof dt === 'object') {
					// convert date object into date string
					dt = $.datepicker.formatDate(config.dateFormat, dt);
				}

				return dt;
			});

			// remove all dates from the current selection
			let pickedDates = $(this).vboMultiDatesPicker('getDates');
			$(this).vboMultiDatesPicker('removeDates', pickedDates);

			if (dates.length) {
				// set new date(s)
				$(this).vboMultiDatesPicker('addDates', dates);
			} else {
				// remove any active cell state
				$('.ui-state-active').removeClass('ui-state-active');
				$('.ui-datepicker-current-day').removeClass('ui-datepicker-current-day');
			}

			// get the input fields for check-in and check-out
			let inputCheckin = config?.altFields?.checkin ? $(config.altFields.checkin) : $(this);
			let inputCheckout = config?.altFields?.checkout ? $(config.altFields.checkout) : $(config.checkout);

			// populate checkin and checkout fields
			if (dates.length == 1) {
				inputCheckin.val(dates[0]);
				inputCheckout.val('');
			} else if (dates.length == 2) {
				inputCheckin.val(dates[0]);
				inputCheckout.val(dates[1]);
			} else {
				inputCheckin.val('');
				inputCheckout.val('');
			}

			return this;
		}

		/**
		 * Handles the registration of the check-out update upon choosing the check-in.
		 * Expected actions to perform are: minDate, maxDate, setCheckoutDate.
		 * 
		 * @param 	string 	action 	The action to perform.
		 * @param 	any 	value 	The value for the action to perform.
		 * 
		 * @return 	self
		 */
		const handleCheckoutConstraints = (action, value) => {
			if (typeof action !== 'string') {
				throw new Error('Invalid arguments for handleCheckoutConstraints');
			}

			// access DRP configuration
			let config = drpConfig();

			if (action.match(/^setcheckoutdate$/i)) {
				// do NOT update the check-out date unless running in legacy mode
				// with two native datepicker calendars, of if unsetting the date.
				if (config?.legacy || !value) {
					return $(this).vboDatesRangePicker('setCheckoutDate', value);
				}

				// abort
				return this;
			}

			if (config?.legacy) {
				// apply the requested option to the check-out field
				return $(config.checkout).datepicker('option', action, value);
			}

			// build new settings
			let newConfig = Object.assign({}, config);

			// inject action value
			newConfig.checkoutConstraints = newConfig.checkoutConstraints || {};
			newConfig.checkoutConstraints[action] = value;

			// update DRP configuration
			drpConfig(newConfig)

			return this;
		}

		/**
		 * Validates the current check-out constraints against the given date.
		 * 
		 * @param 	Date 			date 		The date object to validate.
		 * @param 	Array 			validation 	The default date validation array of values for "beforeShowDay".
		 * @param 	string|Date 	checkin 	Optional check-in date.
		 * 
		 * @return 	Array 			The new validation array of values (selectable, class-name, tooltip-text).
		 */
		const validateCheckoutConstraints = (date, validation, checkin) => {
			// access DRP configuration
			let config = drpConfig();

			if (!Array.isArray(validation) || !validation.length) {
				// set default date validation array
				validation = [true, '', null];
			}

			if (config?.legacy || !(date instanceof Date)) {
				return validation;
			}

			if (typeof config?.checkoutConstraints !== 'object') {
				return validation;
			}

			if ((validation[1] + '').match(/checkin\-checkout\-inner/i)) {
				// no need to validate a date between the selected range of dates
				return validation;
			}

			// check if the current date is actually the check-in date
			let isCheckin = false;
			if (checkin) {
				isCheckin = !compareDates(date, checkin);
			}

			// get a list of both action and value constraints
			let actions = Object.keys(config.checkoutConstraints);
			let values  = Object.values(config.checkoutConstraints);

			// scan all actions and values
			actions.forEach((action, index) => {
				if (typeof action !== 'string') {
					return;
				}

				// validate minDate
				if (action.match(/^mindate$/i) && (values[index] instanceof Date)) {
					let isPast = compareDates(date, values[index]) < 0;
					if (isPast && !isCheckin) {
						// date should not be selectable
						validation[0] = false;
					}
				}

				// validate maxDate
				if (action.match(/^maxdate$/i) && (values[index] instanceof Date)) {
					let isBeyond = compareDates(date, values[index]) > 0;
					if (isBeyond && !isCheckin) {
						// date should not be selectable
						validation[0] = false;
					}
				}
			});

			return validation;
		}

		/**
		 * Unsets any previously set check-out constraint.
		 * 
		 * @param 	Date 	date 	The date object being validated.
		 * 
		 * @return 	void
		 */
		const unsetCheckoutConstraints = (date) => {
			// access DRP configuration
			let config = drpConfig();

			if (config.hasOwnProperty('checkoutConstraints')) {
				// delete configuration object property
				delete config.checkoutConstraints;

				// update DRP configuration
				drpConfig(config);
			}
		}

		/**
		 * Initializes the DRP calendar.
		 */
		if (typeof method === 'object') {
			return init(method);
		}

		/**
		 * Compares two dates.
		 */
		if (typeof method === 'string' && method.match(/^comparedates$/i)) {
			return compareDates(options, setvalue);
		}

		/**
		 * Converts a period string into a date object.
		 */
		if (typeof method === 'string' && method.match(/^convertperiod$/i)) {
			return convertPeriod(options, setvalue);
		}

		/**
		 * Aliasing dates retrieval.
		 */
		if (typeof method === 'string' && method.match(/^getdates$/i)) {
			return $(this).vboMultiDatesPicker('getDates');
		}

		/**
		 * Aliasing check-in date retrieval.
		 */
		if (typeof method === 'string' && method.match(/^getcheckindate$/i)) {
			let pickedDates = $(this).vboMultiDatesPicker('getDates', 'object');
			return pickedDates[0] || null;
		}

		/**
		 * Aliasing check-out date retrieval.
		 */
		if (typeof method === 'string' && method.match(/^getcheckoutdate$/i)) {
			let pickedDates = $(this).vboMultiDatesPicker('getDates', 'object');
			return pickedDates[1] || null;
		}

		/**
		 * Sets new dates in the DRP.
		 */
		if (typeof method === 'string' && method.match(/^setdates$/i)) {
			return setDates(options);
		}

		/**
		 * Sets the check-in date in the DRP.
		 */
		if (typeof method === 'string' && method.match(/^setcheckindate$/i)) {
			// get current dates
			let pickedDates = $(this).vboMultiDatesPicker('getDates');

			// build new dates
			let newDates = Array.isArray(options) ? options : [options];

			if (!newDates[0]) {
				// we are actually unsetting the check-in date
				newDates = [];
				pickedDates = [];
			}

			if (pickedDates[1]) {
				// push existing check-out date
				newDates.push(pickedDates[1]);
			}

			return setDates(newDates);
		}

		/**
		 * Sets the check-out date in the DRP.
		 */
		if (typeof method === 'string' && method.match(/^setcheckoutdate$/i)) {
			// get current dates
			let pickedDates = $(this).vboMultiDatesPicker('getDates');
			if (!pickedDates.length) {
				// abort if no dates currently selected, or if multiple dates given
				return this;
			}

			// build new dates
			let newDates = [pickedDates[0], Array.isArray(options) ? options[0] : options];

			return setDates(newDates);
		}

		/**
		 * Hides the DRP calendar, as long as it is not rendered inline.
		 */
		if (typeof method === 'string' && method.match(/^hide$/i)) {
			return $(this).datepicker('hide');
		}

		/**
		 * Setter or getter for the native datepicker calendar.
		 */
		if (method === 'option') {
			// native datepicker option getter or setter
			if (typeof setvalue === 'undefined') {
				// native datepicker option getter
				return $(this).datepicker('option', options);
			}

			// native datepicker option setter
			return $(this).datepicker('option', options, setvalue);
		}

		/**
		 * Gets one or all DRP options, or invokes a DRP function.
		 */
		if (method === 'drpoption') {
			// access DRP configuration
			let config = drpConfig();

			if (!options) {
				// return the whole DRP configuration object
				return config;
			}

			if (typeof options === 'string' && options.match(/^.+\..+$/i)) {
				// check for nested configuration object properties (i.e. "beforeShowDay.checkin")
				let macroOption = options;
				macroOption.split('.').forEach((prop) => {
					if (typeof config === 'object' && config.hasOwnProperty(prop) && typeof config[prop] === 'object') {
						config = config[prop];
					} else {
						options = prop;
					}
				});
			}

			if (typeof setvalue === 'undefined') {
				// DRP option getter
				return config[options] || null;
			}

			if (typeof config[options] !== 'function') {
				throw new Error('Invalid DRP function invoked (' + options + ')');
			}

			// call the requested method
			return Array.isArray(setvalue) ? config[options].apply(this, setvalue) : config[options].call(this, setvalue);
		}

		/**
		 * Handles check-out update operations upon selecting check-in.
		 */
		if (method === 'checkout') {
			return handleCheckoutConstraints(options, setvalue);
		}
	}
}));
// source --> https://lipper-quartiere.de/wp-content/plugins/vikbooking/site/resources/jquery.fancybox.js 
/*!
 * fancyBox - jQuery Plugin
 * version: 2.1.5 (Fri, 14 Jun 2013)
 * @requires jQuery v1.6 or later
 *
 * Examples at http://fancyapps.com/fancybox/
 * License: www.fancyapps.com/fancybox/#license
 *
 * Copyright 2012 Janis Skarnelis - janis@fancyapps.com
 *
 */

(function (window, document, $, undefined) {
	"use strict";

	var H = $("html"),
		W = $(window),
		D = $(document),
		F = $.fancybox = function () {
			F.open.apply( this, arguments );
		},
		IE =  navigator.userAgent.match(/msie/i),
		didUpdate	= null,
		isTouch		= document.createTouch !== undefined,

		isQuery	= function(obj) {
			return obj && obj.hasOwnProperty && obj instanceof $;
		},
		isString = function(str) {
			return str && $.type(str) === "string";
		},
		isPercentage = function(str) {
			return isString(str) && str.indexOf('%') > 0;
		},
		isScrollable = function(el) {
			return (el && !(el.style.overflow && el.style.overflow === 'hidden') && ((el.clientWidth && el.scrollWidth > el.clientWidth) || (el.clientHeight && el.scrollHeight > el.clientHeight)));
		},
		getScalar = function(orig, dim) {
			var value = parseInt(orig, 10) || 0;

			if (dim && isPercentage(orig)) {
				value = F.getViewport()[ dim ] / 100 * value;
			}

			return Math.ceil(value);
		},
		getValue = function(value, dim) {
			return getScalar(value, dim) + 'px';
		};

	$.extend(F, {
		// The current version of fancyBox
		version: '2.1.5',

		defaults: {
			padding : 15,
			margin  : 20,

			width     : 800,
			height    : 600,
			minWidth  : 100,
			minHeight : 100,
			maxWidth  : 9999,
			maxHeight : 9999,
			pixelRatio: 1, // Set to 2 for retina display support

			autoSize   : true,
			autoHeight : false,
			autoWidth  : false,

			autoResize  : true,
			autoCenter  : !isTouch,
			fitToView   : true,
			aspectRatio : false,
			topRatio    : 0.5,
			leftRatio   : 0.5,

			scrolling : 'auto', // 'auto', 'yes' or 'no'
			wrapCSS   : '',

			arrows     : true,
			closeBtn   : true,
			closeClick : false,
			nextClick  : false,
			mouseWheel : true,
			autoPlay   : false,
			playSpeed  : 3000,
			preload    : 3,
			modal      : false,
			loop       : true,

			ajax  : {
				dataType : 'html',
				headers  : { 'X-fancyBox': true }
			},
			iframe : {
				scrolling : 'auto',
				preload   : true
			},
			swf : {
				wmode: 'transparent',
				allowfullscreen   : 'true',
				allowscriptaccess : 'always'
			},

			keys  : {
				next : {
					13 : 'left', // enter
					34 : 'up',   // page down
					39 : 'left', // right arrow
					40 : 'up'    // down arrow
				},
				prev : {
					8  : 'right',  // backspace
					33 : 'down',   // page up
					37 : 'right',  // left arrow
					38 : 'down'    // up arrow
				},
				close  : [27], // escape key
				play   : [32], // space - start/stop slideshow
				toggle : [70]  // letter "f" - toggle fullscreen
			},

			direction : {
				next : 'left',
				prev : 'right'
			},

			scrollOutside  : true,

			// Override some properties
			index   : 0,
			type    : null,
			href    : null,
			content : null,
			title   : null,

			// HTML templates
			tpl: {
				wrap     : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
				image    : '<img class="fancybox-image" src="{href}" alt="" />',
				iframe   : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>',
				error    : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
				closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',
				next     : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
				prev     : '<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'
			},

			// Properties for each animation type
			// Opening fancyBox
			openEffect  : 'fade', // 'elastic', 'fade' or 'none'
			openSpeed   : 250,
			openEasing  : 'swing',
			openOpacity : true,
			openMethod  : 'zoomIn',

			// Closing fancyBox
			closeEffect  : 'fade', // 'elastic', 'fade' or 'none'
			closeSpeed   : 250,
			closeEasing  : 'swing',
			closeOpacity : true,
			closeMethod  : 'zoomOut',

			// Changing next gallery item
			nextEffect : 'elastic', // 'elastic', 'fade' or 'none'
			nextSpeed  : 250,
			nextEasing : 'swing',
			nextMethod : 'changeIn',

			// Changing previous gallery item
			prevEffect : 'elastic', // 'elastic', 'fade' or 'none'
			prevSpeed  : 250,
			prevEasing : 'swing',
			prevMethod : 'changeOut',

			// Enable default helpers
			helpers : {
				overlay : true,
				title   : true
			},

			// Callbacks
			onCancel     : $.noop, // If canceling
			beforeLoad   : $.noop, // Before loading
			afterLoad    : $.noop, // After loading
			beforeShow   : $.noop, // Before changing in current item
			afterShow    : $.noop, // After opening
			beforeChange : $.noop, // Before changing gallery item
			beforeClose  : $.noop, // Before closing
			afterClose   : $.noop  // After closing
		},

		//Current state
		group    : {}, // Selected group
		opts     : {}, // Group options
		previous : null,  // Previous element
		coming   : null,  // Element being loaded
		current  : null,  // Currently loaded element
		isActive : false, // Is activated
		isOpen   : false, // Is currently open
		isOpened : false, // Have been fully opened at least once

		wrap  : null,
		skin  : null,
		outer : null,
		inner : null,

		player : {
			timer    : null,
			isActive : false
		},

		// Loaders
		ajaxLoad   : null,
		imgPreload : null,

		// Some collections
		transitions : {},
		helpers     : {},

		/*
		 *	Static methods
		 */

		open: function (group, opts) {
			if (!group) {
				return;
			}

			if (!$.isPlainObject(opts)) {
				opts = {};
			}

			// Close if already active
			if (false === F.close(true)) {
				return;
			}

			// Normalize group
			if (!$.isArray(group)) {
				group = isQuery(group) ? $(group).get() : [group];
			}

			// Recheck if the type of each element is `object` and set content type (image, ajax, etc)
			$.each(group, function(i, element) {
				var obj = {},
					href,
					title,
					content,
					type,
					rez,
					hrefParts,
					selector;

				if ($.type(element) === "object") {
					// Check if is DOM element
					if (element.nodeType) {
						element = $(element);
					}

					if (isQuery(element)) {
						obj = {
							href    : element.data('fancybox-href') || element.attr('href'),
							title   : element.data('fancybox-title') || element.attr('title'),
							isDom   : true,
							element : element
						};

						if ($.metadata) {
							$.extend(true, obj, element.metadata());
						}

					} else {
						obj = element;
					}
				}

				href  = opts.href  || obj.href || (isString(element) ? element : null);
				title = opts.title !== undefined ? opts.title : obj.title || '';

				content = opts.content || obj.content;
				type    = content ? 'html' : (opts.type  || obj.type);

				if (!type && obj.isDom) {
					type = element.data('fancybox-type');

					if (!type) {
						rez  = element.prop('class').match(/fancybox\.(\w+)/);
						type = rez ? rez[1] : null;
					}
				}

				if (isString(href)) {
					// Try to guess the content type
					if (!type) {
						if (F.isImage(href)) {
							type = 'image';

						} else if (F.isSWF(href)) {
							type = 'swf';

						} else if (href.charAt(0) === '#') {
							type = 'inline';

						} else if (isString(element)) {
							type    = 'html';
							content = element;
						}
					}

					// Split url into two pieces with source url and content selector, e.g,
					// "/mypage.html #my_id" will load "/mypage.html" and display element having id "my_id"
					if (type === 'ajax') {
						hrefParts = href.split(/\s+/, 2);
						href      = hrefParts.shift();
						selector  = hrefParts.shift();
					}
				}

				if (!content) {
					if (type === 'inline') {
						if (href) {
							content = $( isString(href) ? href.replace(/.*(?=#[^\s]+$)/, '') : href ); //strip for ie7

						} else if (obj.isDom) {
							content = element;
						}

					} else if (type === 'html') {
						content = href;

					} else if (!type && !href && obj.isDom) {
						type    = 'inline';
						content = element;
					}
				}

				$.extend(obj, {
					href     : href,
					type     : type,
					content  : content,
					title    : title,
					selector : selector
				});

				group[ i ] = obj;
			});

			// Extend the defaults
			F.opts = $.extend(true, {}, F.defaults, opts);

			// All options are merged recursive except keys
			if (opts.keys !== undefined) {
				F.opts.keys = opts.keys ? $.extend({}, F.defaults.keys, opts.keys) : false;
			}

			F.group = group;

			return F._start(F.opts.index);
		},

		// Cancel image loading or abort ajax request
		cancel: function () {
			var coming = F.coming;

			if (!coming || false === F.trigger('onCancel')) {
				return;
			}

			F.hideLoading();

			if (F.ajaxLoad) {
				F.ajaxLoad.abort();
			}

			F.ajaxLoad = null;

			if (F.imgPreload) {
				F.imgPreload.onload = F.imgPreload.onerror = null;
			}

			if (coming.wrap) {
				coming.wrap.stop(true, true).trigger('onReset').remove();
			}

			F.coming = null;

			// If the first item has been canceled, then clear everything
			if (!F.current) {
				F._afterZoomOut( coming );
			}
		},

		// Start closing animation if is open; remove immediately if opening/closing
		close: function (event) {
			F.cancel();

			if (false === F.trigger('beforeClose')) {
				return;
			}

			F.unbindEvents();

			if (!F.isActive) {
				return;
			}

			if (!F.isOpen || event === true) {
				$('.fancybox-wrap').stop(true).trigger('onReset').remove();

				F._afterZoomOut();

			} else {
				F.isOpen = F.isOpened = false;
				F.isClosing = true;

				$('.fancybox-item, .fancybox-nav').remove();

				F.wrap.stop(true, true).removeClass('fancybox-opened');

				F.transitions[ F.current.closeMethod ]();
			}
		},

		// Manage slideshow:
		//   $.fancybox.play(); - toggle slideshow
		//   $.fancybox.play( true ); - start
		//   $.fancybox.play( false ); - stop
		play: function ( action ) {
			var clear = function () {
					clearTimeout(F.player.timer);
				},
				set = function () {
					clear();

					if (F.current && F.player.isActive) {
						F.player.timer = setTimeout(F.next, F.current.playSpeed);
					}
				},
				stop = function () {
					clear();

					D.unbind('.player');

					F.player.isActive = false;

					F.trigger('onPlayEnd');
				},
				start = function () {
					if (F.current && (F.current.loop || F.current.index < F.group.length - 1)) {
						F.player.isActive = true;

						D.bind({
							'onCancel.player beforeClose.player' : stop,
							'onUpdate.player'   : set,
							'beforeLoad.player' : clear
						});

						set();

						F.trigger('onPlayStart');
					}
				};

			if (action === true || (!F.player.isActive && action !== false)) {
				start();
			} else {
				stop();
			}
		},

		// Navigate to next gallery item
		next: function ( direction ) {
			var current = F.current;

			if (current) {
				if (!isString(direction)) {
					direction = current.direction.next;
				}

				F.jumpto(current.index + 1, direction, 'next');
			}
		},

		// Navigate to previous gallery item
		prev: function ( direction ) {
			var current = F.current;

			if (current) {
				if (!isString(direction)) {
					direction = current.direction.prev;
				}

				F.jumpto(current.index - 1, direction, 'prev');
			}
		},

		// Navigate to gallery item by index
		jumpto: function ( index, direction, router ) {
			var current = F.current;

			if (!current) {
				return;
			}

			index = getScalar(index);

			F.direction = direction || current.direction[ (index >= current.index ? 'next' : 'prev') ];
			F.router    = router || 'jumpto';

			if (current.loop) {
				if (index < 0) {
					index = current.group.length + (index % current.group.length);
				}

				index = index % current.group.length;
			}

			if (current.group[ index ] !== undefined) {
				F.cancel();

				F._start(index);
			}
		},

		// Center inside viewport and toggle position type to fixed or absolute if needed
		reposition: function (e, onlyAbsolute) {
			var current = F.current,
				wrap    = current ? current.wrap : null,
				pos;

			if (wrap) {
				pos = F._getPosition(onlyAbsolute);

				if (e && e.type === 'scroll') {
					delete pos.position;

					wrap.stop(true, true).animate(pos, 200);

				} else {
					wrap.css(pos);

					current.pos = $.extend({}, current.dim, pos);
				}
			}
		},

		update: function (e) {
			var type = (e && e.type),
				anyway = !type || type === 'orientationchange';

			if (anyway) {
				clearTimeout(didUpdate);

				didUpdate = null;
			}

			if (!F.isOpen || didUpdate) {
				return;
			}

			didUpdate = setTimeout(function() {
				var current = F.current;

				if (!current || F.isClosing) {
					return;
				}

				F.wrap.removeClass('fancybox-tmp');

				if (anyway || type === 'load' || (type === 'resize' && current.autoResize)) {
					F._setDimension();
				}

				if (!(type === 'scroll' && current.canShrink)) {
					F.reposition(e);
				}

				F.trigger('onUpdate');

				didUpdate = null;

			}, (anyway && !isTouch ? 0 : 300));
		},

		// Shrink content to fit inside viewport or restore if resized
		toggle: function ( action ) {
			if (F.isOpen) {
				F.current.fitToView = $.type(action) === "boolean" ? action : !F.current.fitToView;

				// Help browser to restore document dimensions
				if (isTouch) {
					F.wrap.removeAttr('style').addClass('fancybox-tmp');

					F.trigger('onUpdate');
				}

				F.update();
			}
		},

		hideLoading: function () {
			D.unbind('.loading');

			$('#fancybox-loading').remove();
		},

		showLoading: function () {
			var el, viewport;

			F.hideLoading();

			el = $('<div id="fancybox-loading"><div></div></div>').click(F.cancel).appendTo('body');

			// If user will press the escape-button, the request will be canceled
			D.bind('keydown.loading', function(e) {
				if ((e.which || e.keyCode) === 27) {
					e.preventDefault();

					F.cancel();
				}
			});

			if (!F.defaults.fixed) {
				viewport = F.getViewport();

				el.css({
					position : 'absolute',
					top  : (viewport.h * 0.5) + viewport.y,
					left : (viewport.w * 0.5) + viewport.x
				});
			}
		},

		getViewport: function () {
			var locked = (F.current && F.current.locked) || false,
				rez    = {
					x: W.scrollLeft(),
					y: W.scrollTop()
				};

			if (locked) {
				rez.w = locked[0].clientWidth;
				rez.h = locked[0].clientHeight;

			} else {
				// See http://bugs.jquery.com/ticket/6724
				rez.w = isTouch && window.innerWidth  ? window.innerWidth  : W.width();
				rez.h = isTouch && window.innerHeight ? window.innerHeight : W.height();
			}

			return rez;
		},

		// Unbind the keyboard / clicking actions
		unbindEvents: function () {
			if (F.wrap && isQuery(F.wrap)) {
				F.wrap.unbind('.fb');
			}

			D.unbind('.fb');
			W.unbind('.fb');
		},

		bindEvents: function () {
			var current = F.current,
				keys;

			if (!current) {
				return;
			}

			// Changing document height on iOS devices triggers a 'resize' event,
			// that can change document height... repeating infinitely
			W.bind('orientationchange.fb' + (isTouch ? '' : ' resize.fb') + (current.autoCenter && !current.locked ? ' scroll.fb' : ''), F.update);

			keys = current.keys;

			if (keys) {
				D.bind('keydown.fb', function (e) {
					var code   = e.which || e.keyCode,
						target = e.target || e.srcElement;

					// Skip esc key if loading, because showLoading will cancel preloading
					if (code === 27 && F.coming) {
						return false;
					}

					// Ignore key combinations and key events within form elements
					if (!e.ctrlKey && !e.altKey && !e.shiftKey && !e.metaKey && !(target && (target.type || $(target).is('[contenteditable]')))) {
						$.each(keys, function(i, val) {
							if (current.group.length > 1 && val[ code ] !== undefined) {
								F[ i ]( val[ code ] );

								e.preventDefault();
								return false;
							}

							if ($.inArray(code, val) > -1) {
								F[ i ] ();

								e.preventDefault();
								return false;
							}
						});
					}
				});
			}

			if ($.fn.mousewheel && current.mouseWheel) {
				F.wrap.bind('mousewheel.fb', function (e, delta, deltaX, deltaY) {
					var target = e.target || null,
						parent = $(target),
						canScroll = false;

					while (parent.length) {
						if (canScroll || parent.is('.fancybox-skin') || parent.is('.fancybox-wrap')) {
							break;
						}

						canScroll = isScrollable( parent[0] );
						parent    = $(parent).parent();
					}

					if (delta !== 0 && !canScroll) {
						if (F.group.length > 1 && !current.canShrink) {
							if (deltaY > 0 || deltaX > 0) {
								F.prev( deltaY > 0 ? 'down' : 'left' );

							} else if (deltaY < 0 || deltaX < 0) {
								F.next( deltaY < 0 ? 'up' : 'right' );
							}

							e.preventDefault();
						}
					}
				});
			}
		},

		trigger: function (event, o) {
			var ret, obj = o || F.coming || F.current;

			if (!obj) {
				return;
			}

			if ($.isFunction( obj[event] )) {
				ret = obj[event].apply(obj, Array.prototype.slice.call(arguments, 1));
			}

			if (ret === false) {
				return false;
			}

			if (obj.helpers) {
				$.each(obj.helpers, function (helper, opts) {
					if (opts && F.helpers[helper] && $.isFunction(F.helpers[helper][event])) {
						F.helpers[helper][event]($.extend(true, {}, F.helpers[helper].defaults, opts), obj);
					}
				});
			}

			D.trigger(event);
		},

		isImage: function (str) {
			return isString(str) && str.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\?|#).*)?$)/i);
		},

		isSWF: function (str) {
			return isString(str) && str.match(/\.(swf)((\?|#).*)?$/i);
		},

		_start: function (index) {
			var coming = {},
				obj,
				href,
				type,
				margin,
				padding;

			index = getScalar( index );
			obj   = F.group[ index ] || null;

			if (!obj) {
				return false;
			}

			coming = $.extend(true, {}, F.opts, obj);

			// Convert margin and padding properties to array - top, right, bottom, left
			margin  = coming.margin;
			padding = coming.padding;

			if ($.type(margin) === 'number') {
				coming.margin = [margin, margin, margin, margin];
			}

			if ($.type(padding) === 'number') {
				coming.padding = [padding, padding, padding, padding];
			}

			// 'modal' propery is just a shortcut
			if (coming.modal) {
				$.extend(true, coming, {
					closeBtn   : false,
					closeClick : false,
					nextClick  : false,
					arrows     : false,
					mouseWheel : false,
					keys       : null,
					helpers: {
						overlay : {
							closeClick : false
						}
					}
				});
			}

			// 'autoSize' property is a shortcut, too
			if (coming.autoSize) {
				coming.autoWidth = coming.autoHeight = true;
			}

			if (coming.width === 'auto') {
				coming.autoWidth = true;
			}

			if (coming.height === 'auto') {
				coming.autoHeight = true;
			}

			/*
			 * Add reference to the group, so it`s possible to access from callbacks, example:
			 * afterLoad : function() {
			 *     this.title = 'Image ' + (this.index + 1) + ' of ' + this.group.length + (this.title ? ' - ' + this.title : '');
			 * }
			 */

			coming.group  = F.group;
			coming.index  = index;

			// Give a chance for callback or helpers to update coming item (type, title, etc)
			F.coming = coming;

			if (false === F.trigger('beforeLoad')) {
				F.coming = null;

				return;
			}

			type = coming.type;
			href = coming.href;

			if (!type) {
				F.coming = null;

				//If we can not determine content type then drop silently or display next/prev item if looping through gallery
				if (F.current && F.router && F.router !== 'jumpto') {
					F.current.index = index;

					return F[ F.router ]( F.direction );
				}

				return false;
			}

			F.isActive = true;

			if (type === 'image' || type === 'swf') {
				coming.autoHeight = coming.autoWidth = false;
				coming.scrolling  = 'visible';
			}

			if (type === 'image') {
				coming.aspectRatio = true;
			}

			if (type === 'iframe' && isTouch) {
				coming.scrolling = 'scroll';
			}

			// Build the neccessary markup
			coming.wrap = $(coming.tpl.wrap).addClass('fancybox-' + (isTouch ? 'mobile' : 'desktop') + ' fancybox-type-' + type + ' fancybox-tmp ' + coming.wrapCSS).appendTo( coming.parent || 'body' );

			$.extend(coming, {
				skin  : $('.fancybox-skin',  coming.wrap),
				outer : $('.fancybox-outer', coming.wrap),
				inner : $('.fancybox-inner', coming.wrap)
			});

			$.each(["Top", "Right", "Bottom", "Left"], function(i, v) {
				coming.skin.css('padding' + v, getValue(coming.padding[ i ]));
			});

			F.trigger('onReady');

			// Check before try to load; 'inline' and 'html' types need content, others - href
			if (type === 'inline' || type === 'html') {
				if (!coming.content || !coming.content.length) {
					return F._error( 'content' );
				}

			} else if (!href) {
				return F._error( 'href' );
			}

			if (type === 'image') {
				F._loadImage();

			} else if (type === 'ajax') {
				F._loadAjax();

			} else if (type === 'iframe') {
				F._loadIframe();

			} else {
				F._afterLoad();
			}
		},

		_error: function ( type ) {
			$.extend(F.coming, {
				type       : 'html',
				autoWidth  : true,
				autoHeight : true,
				minWidth   : 0,
				minHeight  : 0,
				scrolling  : 'no',
				hasError   : type,
				content    : F.coming.tpl.error
			});

			F._afterLoad();
		},

		_loadImage: function () {
			// Reset preload image so it is later possible to check "complete" property
			var img = F.imgPreload = new Image();

			img.onload = function () {
				this.onload = this.onerror = null;

				F.coming.width  = this.width / F.opts.pixelRatio;
				F.coming.height = this.height / F.opts.pixelRatio;

				F._afterLoad();
			};

			img.onerror = function () {
				this.onload = this.onerror = null;

				F._error( 'image' );
			};

			img.src = F.coming.href;

			if (img.complete !== true) {
				F.showLoading();
			}
		},

		_loadAjax: function () {
			var coming = F.coming;

			F.showLoading();

			F.ajaxLoad = $.ajax($.extend({}, coming.ajax, {
				url: coming.href,
				error: function (jqXHR, textStatus) {
					if (F.coming && textStatus !== 'abort') {
						F._error( 'ajax', jqXHR );

					} else {
						F.hideLoading();
					}
				},
				success: function (data, textStatus) {
					if (textStatus === 'success') {
						coming.content = data;

						F._afterLoad();
					}
				}
			}));
		},

		_loadIframe: function() {
			var coming = F.coming,
				iframe = $(coming.tpl.iframe.replace(/\{rnd\}/g, new Date().getTime()))
					.attr('scrolling', isTouch ? 'auto' : coming.iframe.scrolling)
					.attr('src', coming.href);

			// This helps IE
			$(coming.wrap).bind('onReset', function () {
				try {
					$(this).find('iframe').hide().attr('src', '//about:blank').end().empty();
				} catch (e) {}
			});

			if (coming.iframe.preload) {
				F.showLoading();

				iframe.one('load', function() {
					$(this).data('ready', 1);

					// iOS will lose scrolling if we resize
					if (!isTouch) {
						$(this).bind('load.fb', F.update);
					}

					// Without this trick:
					//   - iframe won't scroll on iOS devices
					//   - IE7 sometimes displays empty iframe
					$(this).parents('.fancybox-wrap').width('100%').removeClass('fancybox-tmp').show();

					F._afterLoad();
				});
			}

			coming.content = iframe.appendTo( coming.inner );

			if (!coming.iframe.preload) {
				F._afterLoad();
			}
		},

		_preloadImages: function() {
			var group   = F.group,
				current = F.current,
				len     = group.length,
				cnt     = current.preload ? Math.min(current.preload, len - 1) : 0,
				item,
				i;

			for (i = 1; i <= cnt; i += 1) {
				item = group[ (current.index + i ) % len ];

				if (item.type === 'image' && item.href) {
					new Image().src = item.href;
				}
			}
		},

		_afterLoad: function () {
			var coming   = F.coming,
				previous = F.current,
				placeholder = 'fancybox-placeholder',
				current,
				content,
				type,
				scrolling,
				href,
				embed;

			F.hideLoading();

			if (!coming || F.isActive === false) {
				return;
			}

			if (false === F.trigger('afterLoad', coming, previous)) {
				coming.wrap.stop(true).trigger('onReset').remove();

				F.coming = null;

				return;
			}

			if (previous) {
				F.trigger('beforeChange', previous);

				previous.wrap.stop(true).removeClass('fancybox-opened')
					.find('.fancybox-item, .fancybox-nav')
					.remove();
			}

			F.unbindEvents();

			current   = coming;
			content   = coming.content;
			type      = coming.type;
			scrolling = coming.scrolling;

			$.extend(F, {
				wrap  : current.wrap,
				skin  : current.skin,
				outer : current.outer,
				inner : current.inner,
				current  : current,
				previous : previous
			});

			href = current.href;

			switch (type) {
				case 'inline':
				case 'ajax':
				case 'html':
					if (current.selector) {
						content = $('<div>').html(content).find(current.selector);

					} else if (isQuery(content)) {
						if (!content.data(placeholder)) {
							content.data(placeholder, $('<div class="' + placeholder + '"></div>').insertAfter( content ).hide() );
						}

						content = content.show().detach();

						current.wrap.bind('onReset', function () {
							if ($(this).find(content).length) {
								content.hide().replaceAll( content.data(placeholder) ).data(placeholder, false);
							}
						});
					}
				break;

				case 'image':
					content = current.tpl.image.replace('{href}', href);
				break;

				case 'swf':
					content = '<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="' + href + '"></param>';
					embed   = '';

					$.each(current.swf, function(name, val) {
						content += '<param name="' + name + '" value="' + val + '"></param>';
						embed   += ' ' + name + '="' + val + '"';
					});

					content += '<embed src="' + href + '" type="application/x-shockwave-flash" width="100%" height="100%"' + embed + '></embed></object>';
				break;
			}

			if (!(isQuery(content) && content.parent().is(current.inner))) {
				current.inner.append( content );
			}

			// Give a chance for helpers or callbacks to update elements
			F.trigger('beforeShow');

			// Set scrolling before calculating dimensions
			current.inner.css('overflow', scrolling === 'yes' ? 'scroll' : (scrolling === 'no' ? 'hidden' : scrolling));

			// Set initial dimensions and start position
			F._setDimension();

			F.reposition();

			F.isOpen = false;
			F.coming = null;

			F.bindEvents();

			if (!F.isOpened) {
				$('.fancybox-wrap').not( current.wrap ).stop(true).trigger('onReset').remove();

			} else if (previous.prevMethod) {
				F.transitions[ previous.prevMethod ]();
			}

			F.transitions[ F.isOpened ? current.nextMethod : current.openMethod ]();

			F._preloadImages();
		},

		_setDimension: function () {
			var viewport   = F.getViewport(),
				steps      = 0,
				canShrink  = false,
				canExpand  = false,
				wrap       = F.wrap,
				skin       = F.skin,
				inner      = F.inner,
				current    = F.current,
				width      = current.width,
				height     = current.height,
				minWidth   = current.minWidth,
				minHeight  = current.minHeight,
				maxWidth   = current.maxWidth,
				maxHeight  = current.maxHeight,
				scrolling  = current.scrolling,
				scrollOut  = current.scrollOutside ? current.scrollbarWidth : 0,
				margin     = current.margin,
				wMargin    = getScalar(margin[1] + margin[3]),
				hMargin    = getScalar(margin[0] + margin[2]),
				wPadding,
				hPadding,
				wSpace,
				hSpace,
				origWidth,
				origHeight,
				origMaxWidth,
				origMaxHeight,
				ratio,
				width_,
				height_,
				maxWidth_,
				maxHeight_,
				iframe,
				body;

			// Reset dimensions so we could re-check actual size
			wrap.add(skin).add(inner).width('auto').height('auto').removeClass('fancybox-tmp');

			wPadding = getScalar(skin.outerWidth(true)  - skin.width());
			hPadding = getScalar(skin.outerHeight(true) - skin.height());

			// Any space between content and viewport (margin, padding, border, title)
			wSpace = wMargin + wPadding;
			hSpace = hMargin + hPadding;

			origWidth  = isPercentage(width)  ? (viewport.w - wSpace) * getScalar(width)  / 100 : width;
			origHeight = isPercentage(height) ? (viewport.h - hSpace) * getScalar(height) / 100 : height;

			if (current.type === 'iframe') {
				iframe = current.content;

				if (current.autoHeight && iframe.data('ready') === 1) {
					try {
						if (iframe[0].contentWindow.document.location) {
							inner.width( origWidth ).height(9999);

							body = iframe.contents().find('body');

							if (scrollOut) {
								body.css('overflow-x', 'hidden');
							}

							origHeight = body.outerHeight(true);
						}

					} catch (e) {}
				}

			} else if (current.autoWidth || current.autoHeight) {
				inner.addClass( 'fancybox-tmp' );

				// Set width or height in case we need to calculate only one dimension
				if (!current.autoWidth) {
					inner.width( origWidth );
				}

				if (!current.autoHeight) {
					inner.height( origHeight );
				}

				if (current.autoWidth) {
					origWidth = inner.width();
				}

				if (current.autoHeight) {
					origHeight = inner.height();
				}

				inner.removeClass( 'fancybox-tmp' );
			}

			width  = getScalar( origWidth );
			height = getScalar( origHeight );

			ratio  = origWidth / origHeight;

			// Calculations for the content
			minWidth  = getScalar(isPercentage(minWidth) ? getScalar(minWidth, 'w') - wSpace : minWidth);
			maxWidth  = getScalar(isPercentage(maxWidth) ? getScalar(maxWidth, 'w') - wSpace : maxWidth);

			minHeight = getScalar(isPercentage(minHeight) ? getScalar(minHeight, 'h') - hSpace : minHeight);
			maxHeight = getScalar(isPercentage(maxHeight) ? getScalar(maxHeight, 'h') - hSpace : maxHeight);

			// These will be used to determine if wrap can fit in the viewport
			origMaxWidth  = maxWidth;
			origMaxHeight = maxHeight;

			if (current.fitToView) {
				maxWidth  = Math.min(viewport.w - wSpace, maxWidth);
				maxHeight = Math.min(viewport.h - hSpace, maxHeight);
			}

			maxWidth_  = viewport.w - wMargin;
			maxHeight_ = viewport.h - hMargin;

			if (current.aspectRatio) {
				if (width > maxWidth) {
					width  = maxWidth;
					height = getScalar(width / ratio);
				}

				if (height > maxHeight) {
					height = maxHeight;
					width  = getScalar(height * ratio);
				}

				if (width < minWidth) {
					width  = minWidth;
					height = getScalar(width / ratio);
				}

				if (height < minHeight) {
					height = minHeight;
					width  = getScalar(height * ratio);
				}

			} else {
				width = Math.max(minWidth, Math.min(width, maxWidth));

				if (current.autoHeight && current.type !== 'iframe') {
					inner.width( width );

					height = inner.height();
				}

				height = Math.max(minHeight, Math.min(height, maxHeight));
			}

			// Try to fit inside viewport (including the title)
			if (current.fitToView) {
				inner.width( width ).height( height );

				wrap.width( width + wPadding );

				// Real wrap dimensions
				width_  = wrap.width();
				height_ = wrap.height();

				if (current.aspectRatio) {
					while ((width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight) {
						if (steps++ > 19) {
							break;
						}

						height = Math.max(minHeight, Math.min(maxHeight, height - 10));
						width  = getScalar(height * ratio);

						if (width < minWidth) {
							width  = minWidth;
							height = getScalar(width / ratio);
						}

						if (width > maxWidth) {
							width  = maxWidth;
							height = getScalar(width / ratio);
						}

						inner.width( width ).height( height );

						wrap.width( width + wPadding );

						width_  = wrap.width();
						height_ = wrap.height();
					}

				} else {
					width  = Math.max(minWidth,  Math.min(width,  width  - (width_  - maxWidth_)));
					height = Math.max(minHeight, Math.min(height, height - (height_ - maxHeight_)));
				}
			}

			if (scrollOut && scrolling === 'auto' && height < origHeight && (width + wPadding + scrollOut) < maxWidth_) {
				width += scrollOut;
			}

			inner.width( width ).height( height );

			wrap.width( width + wPadding );

			width_  = wrap.width();
			height_ = wrap.height();

			canShrink = (width_ > maxWidth_ || height_ > maxHeight_) && width > minWidth && height > minHeight;
			canExpand = current.aspectRatio ? (width < origMaxWidth && height < origMaxHeight && width < origWidth && height < origHeight) : ((width < origMaxWidth || height < origMaxHeight) && (width < origWidth || height < origHeight));

			$.extend(current, {
				dim : {
					width	: getValue( width_ ),
					height	: getValue( height_ )
				},
				origWidth  : origWidth,
				origHeight : origHeight,
				canShrink  : canShrink,
				canExpand  : canExpand,
				wPadding   : wPadding,
				hPadding   : hPadding,
				wrapSpace  : height_ - skin.outerHeight(true),
				skinSpace  : skin.height() - height
			});

			if (!iframe && current.autoHeight && height > minHeight && height < maxHeight && !canExpand) {
				inner.height('auto');
			}
		},

		_getPosition: function (onlyAbsolute) {
			var current  = F.current,
				viewport = F.getViewport(),
				margin   = current.margin,
				width    = F.wrap.width()  + margin[1] + margin[3],
				height   = F.wrap.height() + margin[0] + margin[2],
				rez      = {
					position: 'absolute',
					top  : margin[0],
					left : margin[3]
				};

			if (current.autoCenter && current.fixed && !onlyAbsolute && height <= viewport.h && width <= viewport.w) {
				rez.position = 'fixed';

			} else if (!current.locked) {
				rez.top  += viewport.y;
				rez.left += viewport.x;
			}

			rez.top  = getValue(Math.max(rez.top,  rez.top  + ((viewport.h - height) * current.topRatio)));
			rez.left = getValue(Math.max(rez.left, rez.left + ((viewport.w - width)  * current.leftRatio)));

			return rez;
		},

		_afterZoomIn: function () {
			var current = F.current;

			if (!current) {
				return;
			}

			F.isOpen = F.isOpened = true;

			F.wrap.css('overflow', 'visible').addClass('fancybox-opened');

			F.update();

			// Assign a click event
			if ( current.closeClick || (current.nextClick && F.group.length > 1) ) {
				F.inner.css('cursor', 'pointer').bind('click.fb', function(e) {
					if (!$(e.target).is('a') && !$(e.target).parent().is('a')) {
						e.preventDefault();

						F[ current.closeClick ? 'close' : 'next' ]();
					}
				});
			}

			// Create a close button
			if (current.closeBtn) {
				$(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
					e.preventDefault();

					F.close();
				});
			}

			// Create navigation arrows
			if (current.arrows && F.group.length > 1) {
				if (current.loop || current.index > 0) {
					$(current.tpl.prev).appendTo(F.outer).bind('click.fb', F.prev);
				}

				if (current.loop || current.index < F.group.length - 1) {
					$(current.tpl.next).appendTo(F.outer).bind('click.fb', F.next);
				}
			}

			F.trigger('afterShow');

			// Stop the slideshow if this is the last item
			if (!current.loop && current.index === current.group.length - 1) {
				F.play( false );

			} else if (F.opts.autoPlay && !F.player.isActive) {
				F.opts.autoPlay = false;

				F.play();
			}
		},

		_afterZoomOut: function ( obj ) {
			obj = obj || F.current;

			$('.fancybox-wrap').trigger('onReset').remove();

			$.extend(F, {
				group  : {},
				opts   : {},
				router : false,
				current   : null,
				isActive  : false,
				isOpened  : false,
				isOpen    : false,
				isClosing : false,
				wrap   : null,
				skin   : null,
				outer  : null,
				inner  : null
			});

			F.trigger('afterClose', obj);
		}
	});

	/*
	 *	Default transitions
	 */

	F.transitions = {
		getOrigPosition: function () {
			var current  = F.current,
				element  = current.element,
				orig     = current.orig,
				pos      = {},
				width    = 50,
				height   = 50,
				hPadding = current.hPadding,
				wPadding = current.wPadding,
				viewport = F.getViewport();

			if (!orig && current.isDom && element.is(':visible')) {
				orig = element.find('img:first');

				if (!orig.length) {
					orig = element;
				}
			}

			if (isQuery(orig)) {
				pos = orig.offset();

				if (orig.is('img')) {
					width  = orig.outerWidth();
					height = orig.outerHeight();
				}

			} else {
				pos.top  = viewport.y + (viewport.h - height) * current.topRatio;
				pos.left = viewport.x + (viewport.w - width)  * current.leftRatio;
			}

			if (F.wrap.css('position') === 'fixed' || current.locked) {
				pos.top  -= viewport.y;
				pos.left -= viewport.x;
			}

			pos = {
				top     : getValue(pos.top  - hPadding * current.topRatio),
				left    : getValue(pos.left - wPadding * current.leftRatio),
				width   : getValue(width  + wPadding),
				height  : getValue(height + hPadding)
			};

			return pos;
		},

		step: function (now, fx) {
			var ratio,
				padding,
				value,
				prop       = fx.prop,
				current    = F.current,
				wrapSpace  = current.wrapSpace,
				skinSpace  = current.skinSpace;

			if (prop === 'width' || prop === 'height') {
				ratio = fx.end === fx.start ? 1 : (now - fx.start) / (fx.end - fx.start);

				if (F.isClosing) {
					ratio = 1 - ratio;
				}

				padding = prop === 'width' ? current.wPadding : current.hPadding;
				value   = now - padding;

				F.skin[ prop ](  getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) ) );
				F.inner[ prop ]( getScalar( prop === 'width' ?  value : value - (wrapSpace * ratio) - (skinSpace * ratio) ) );
			}
		},

		zoomIn: function () {
			var current  = F.current,
				startPos = current.pos,
				effect   = current.openEffect,
				elastic  = effect === 'elastic',
				endPos   = $.extend({opacity : 1}, startPos);

			// Remove "position" property that breaks older IE
			delete endPos.position;

			if (elastic) {
				startPos = this.getOrigPosition();

				if (current.openOpacity) {
					startPos.opacity = 0.1;
				}

			} else if (effect === 'fade') {
				startPos.opacity = 0.1;
			}

			F.wrap.css(startPos).animate(endPos, {
				duration : effect === 'none' ? 0 : current.openSpeed,
				easing   : current.openEasing,
				step     : elastic ? this.step : null,
				complete : F._afterZoomIn
			});
		},

		zoomOut: function () {
			var current  = F.current,
				effect   = current.closeEffect,
				elastic  = effect === 'elastic',
				endPos   = {opacity : 0.1};

			if (elastic) {
				endPos = this.getOrigPosition();

				if (current.closeOpacity) {
					endPos.opacity = 0.1;
				}
			}

			F.wrap.animate(endPos, {
				duration : effect === 'none' ? 0 : current.closeSpeed,
				easing   : current.closeEasing,
				step     : elastic ? this.step : null,
				complete : F._afterZoomOut
			});
		},

		changeIn: function () {
			var current   = F.current,
				effect    = current.nextEffect,
				startPos  = current.pos,
				endPos    = { opacity : 1 },
				direction = F.direction,
				distance  = 200,
				field;

			startPos.opacity = 0.1;

			if (effect === 'elastic') {
				field = direction === 'down' || direction === 'up' ? 'top' : 'left';

				if (direction === 'down' || direction === 'right') {
					startPos[ field ] = getValue(getScalar(startPos[ field ]) - distance);
					endPos[ field ]   = '+=' + distance + 'px';

				} else {
					startPos[ field ] = getValue(getScalar(startPos[ field ]) + distance);
					endPos[ field ]   = '-=' + distance + 'px';
				}
			}

			// Workaround for http://bugs.jquery.com/ticket/12273
			if (effect === 'none') {
				F._afterZoomIn();

			} else {
				F.wrap.css(startPos).animate(endPos, {
					duration : current.nextSpeed,
					easing   : current.nextEasing,
					complete : F._afterZoomIn
				});
			}
		},

		changeOut: function () {
			var previous  = F.previous,
				effect    = previous.prevEffect,
				endPos    = { opacity : 0.1 },
				direction = F.direction,
				distance  = 200;

			if (effect === 'elastic') {
				endPos[ direction === 'down' || direction === 'up' ? 'top' : 'left' ] = ( direction === 'up' || direction === 'left' ? '-' : '+' ) + '=' + distance + 'px';
			}

			previous.wrap.animate(endPos, {
				duration : effect === 'none' ? 0 : previous.prevSpeed,
				easing   : previous.prevEasing,
				complete : function () {
					$(this).trigger('onReset').remove();
				}
			});
		}
	};

	/*
	 *	Overlay helper
	 */

	F.helpers.overlay = {
		defaults : {
			closeClick : true,      // if true, fancyBox will be closed when user clicks on the overlay
			speedOut   : 200,       // duration of fadeOut animation
			showEarly  : true,      // indicates if should be opened immediately or wait until the content is ready
			css        : {},        // custom CSS properties
			locked     : !isTouch,  // if true, the content will be locked into overlay
			fixed      : true       // if false, the overlay CSS position property will not be set to "fixed"
		},

		overlay : null,      // current handle
		fixed   : false,     // indicates if the overlay has position "fixed"
		el      : $('html'), // element that contains "the lock"

		// Public methods
		create : function(opts) {
			opts = $.extend({}, this.defaults, opts);

			if (this.overlay) {
				this.close();
			}

			this.overlay = $('<div class="fancybox-overlay"></div>').appendTo( F.coming ? F.coming.parent : opts.parent );
			this.fixed   = false;

			if (opts.fixed && F.defaults.fixed) {
				this.overlay.addClass('fancybox-overlay-fixed');

				this.fixed = true;
			}
		},

		open : function(opts) {
			var that = this;

			opts = $.extend({}, this.defaults, opts);

			if (this.overlay) {
				this.overlay.unbind('.overlay').width('auto').height('auto');

			} else {
				this.create(opts);
			}

			if (!this.fixed) {
				W.bind('resize.overlay', $.proxy( this.update, this) );

				this.update();
			}

			if (opts.closeClick) {
				this.overlay.bind('click.overlay', function(e) {
					if ($(e.target).hasClass('fancybox-overlay')) {
						if (F.isActive) {
							F.close();
						} else {
							that.close();
						}

						return false;
					}
				});
			}

			this.overlay.css( opts.css ).show();
		},

		close : function() {
			var scrollV, scrollH;

			W.unbind('resize.overlay');

			if (this.el.hasClass('fancybox-lock')) {
				$('.fancybox-margin').removeClass('fancybox-margin');

				scrollV = W.scrollTop();
				scrollH = W.scrollLeft();

				this.el.removeClass('fancybox-lock');

				W.scrollTop( scrollV ).scrollLeft( scrollH );
			}

			$('.fancybox-overlay').remove().hide();

			$.extend(this, {
				overlay : null,
				fixed   : false
			});
		},

		// Private, callbacks

		update : function () {
			var width = '100%', offsetWidth;

			// Reset width/height so it will not mess
			this.overlay.width(width).height('100%');

			// jQuery does not return reliable result for IE
			if (IE) {
				offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);

				if (D.width() > offsetWidth) {
					width = D.width();
				}

			} else if (D.width() > W.width()) {
				width = D.width();
			}

			this.overlay.width(width).height(D.height());
		},

		// This is where we can manipulate DOM, because later it would cause iframes to reload
		onReady : function (opts, obj) {
			var overlay = this.overlay;

			$('.fancybox-overlay').stop(true, true);

			if (!overlay) {
				this.create(opts);
			}

			if (opts.locked && this.fixed && obj.fixed) {
				if (!overlay) {
					this.margin = D.height() > W.height() ? $('html').css('margin-right').replace("px", "") : false;
				}

				obj.locked = this.overlay.append( obj.wrap );
				obj.fixed  = false;
			}

			if (opts.showEarly === true) {
				this.beforeShow.apply(this, arguments);
			}
		},

		beforeShow : function(opts, obj) {
			var scrollV, scrollH;

			if (obj.locked) {
				if (this.margin !== false) {
					$('*').filter(function(){
						return ($(this).css('position') === 'fixed' && !$(this).hasClass("fancybox-overlay") && !$(this).hasClass("fancybox-wrap") );
					}).addClass('fancybox-margin');

					this.el.addClass('fancybox-margin');
				}

				scrollV = W.scrollTop();
				scrollH = W.scrollLeft();

				this.el.addClass('fancybox-lock');

				W.scrollTop( scrollV ).scrollLeft( scrollH );
			}

			this.open(opts);
		},

		onUpdate : function() {
			if (!this.fixed) {
				this.update();
			}
		},

		afterClose: function (opts) {
			// Remove overlay if exists and fancyBox is not opening
			// (e.g., it is not being open using afterClose callback)
			//if (this.overlay && !F.isActive) {
			if (this.overlay && !F.coming) {
				this.overlay.fadeOut(opts.speedOut, $.proxy( this.close, this ));
			}
		}
	};

	/*
	 *	Title helper
	 */

	F.helpers.title = {
		defaults : {
			type     : 'float', // 'float', 'inside', 'outside' or 'over',
			position : 'bottom' // 'top' or 'bottom'
		},

		beforeShow: function (opts) {
			var current = F.current,
				text    = current.title,
				type    = opts.type,
				title,
				target;

			if ($.isFunction(text)) {
				text = text.call(current.element, current);
			}

			if (!isString(text) || $.trim(text) === '') {
				return;
			}

			title = $('<div class="fancybox-title fancybox-title-' + type + '-wrap">' + text + '</div>');

			switch (type) {
				case 'inside':
					target = F.skin;
				break;

				case 'outside':
					target = F.wrap;
				break;

				case 'over':
					target = F.inner;
				break;

				default: // 'float'
					target = F.skin;

					title.appendTo('body');

					if (IE) {
						title.width( title.width() );
					}

					title.wrapInner('<span class="child"></span>');

					//Increase bottom margin so this title will also fit into viewport
					F.current.margin[2] += Math.abs( getScalar(title.css('margin-bottom')) );
				break;
			}

			title[ (opts.position === 'top' ? 'prependTo'  : 'appendTo') ](target);
		}
	};

	// jQuery plugin initialization
	$.fn.fancybox = function (options) {
		var index,
			that     = $(this),
			selector = this.selector || '',
			run      = function(e) {
				var what = $(this).blur(), idx = index, relType, relVal;

				if (!(e.ctrlKey || e.altKey || e.shiftKey || e.metaKey) && !what.is('.fancybox-wrap')) {
					relType = options.groupAttr || 'data-fancybox-group';
					relVal  = what.attr(relType);

					if (!relVal) {
						relType = 'rel';
						relVal  = what.get(0)[ relType ];
					}

					if (relVal && relVal !== '' && relVal !== 'nofollow') {
						what = selector.length ? $(selector) : that;
						what = what.filter('[' + relType + '="' + relVal + '"]');
						idx  = what.index(this);
					}

					options.index = idx;

					// Stop an event from bubbling if everything is fine
					if (F.open(what, options) !== false) {
						e.preventDefault();
					}
				}
			};

		options = options || {};
		index   = options.index || 0;

		if (!selector || options.live === false) {
			that.unbind('click.fb-start').bind('click.fb-start', run);

		} else {
			D.undelegate(selector, 'click.fb-start').delegate(selector + ":not('.fancybox-item, .fancybox-nav')", 'click.fb-start', run);
		}

		this.filter('[data-fancybox-start=1]').trigger('click');

		return this;
	};

	// Tests that need a body at doc ready
	D.ready(function() {
		var w1, w2;

		if ( $.scrollbarWidth === undefined ) {
			// http://benalman.com/projects/jquery-misc-plugins/#scrollbarwidth
			$.scrollbarWidth = function() {
				var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body'),
					child  = parent.children(),
					width  = child.innerWidth() - child.height( 99 ).innerWidth();

				parent.remove();

				return width;
			};
		}

		if ( $.support.fixedPosition === undefined ) {
			$.support.fixedPosition = (function() {
				var elem  = $('<div style="position:fixed;top:20px;"></div>').appendTo('body'),
					fixed = ( elem[0].offsetTop === 20 || elem[0].offsetTop === 15 );

				elem.remove();

				return fixed;
			}());
		}

		$.extend(F.defaults, {
			scrollbarWidth : $.scrollbarWidth(),
			fixed  : $.support.fixedPosition,
			parent : $('body')
		});

		//Get real width of page scroll-bar
		w1 = $(window).width();

		H.addClass('fancybox-lock-test');

		w2 = $(window).width();

		H.removeClass('fancybox-lock-test');

		$("<style type='text/css'>.fancybox-margin{margin-right:" + (w2 - w1) + "px;}</style>").appendTo("head");
	});

}(window, document, jQuery));
// source --> https://lipper-quartiere.de/wp-content/plugins/vikbooking/site/resources/vikfxgallery.js 
/**
 * VikFXGallery jQuery plugin. Forked from
 * the original project simplelightbox.
 * v. 0.12
 */
;(function($, window, document, undefined)
{
	'use strict';
	$.fn.vikFxGallery = function(options)
	{
		var options = $.extend({
			sourceAttr: 'href',
			overlay: true,
			spinner: true,
			nav: true,
			navText: ['&lsaquo;', '&rsaquo;'],
			captions: true,
			captionDelay: 0,
			captionSelector: 'img',
			captionType: 'attr',
			captionsData: 'title',
			captionPosition: 'bottom',
			captionClass: '',
			close: true,
			closeText: '&times;',
			swipeClose: true,
			showCounter: false,
			fileExt: 'png|jpg|jpeg|gif|webp',
			animationSlide: true,
			animationSpeed: 250,
			preloading: true,
			enableKeyboard: true,
			loop: true,
			rel: false,
			docClose: true,
			swipeTolerance: 50,
			widthRatio: 0.8,
			heightRatio: 0.9,
			scaleImageToRatio: false,
			disableRightClick: false,
			disableScroll: true,
			alertError: false,
			alertErrorMessage: 'Image not found',
			additionalHtml: false,
			history: true,
			throttleInterval: 0,
			doubleTapZoom: 2,
			maxZoom: 10,
			htmlClass: 'vikfxg-img-active'
		}, options);

		// global variables
		var touchDevice	= ('ontouchstart' in window),
			pointerEnabled = window.navigator.pointerEnabled || window.navigator.msPointerEnabled,
			touched = function(event) {
				if (touchDevice) return true;
				if (!pointerEnabled || typeof event === 'undefined' || typeof event.pointerType === 'undefined') return false;
				if (typeof event.MSPOINTER_TYPE_MOUSE !== 'undefined') {
					if (event.MSPOINTER_TYPE_MOUSE != event.pointerType) return true;
				}
				else {
					if (event.pointerType != 'mouse') return true;
				}
				return false;
			},
			swipeDiff = 0,
			swipeYDiff = 0,
			curImg = $(),
			transPrefix = function() {
				var s = document.body || document.documentElement;
				s = s.style;
				if (s.WebkitTransition === '') return '-webkit-';
				if (s.MozTransition === '') return '-moz-';
				if (s.OTransition === '') return '-o-';
				if (s.transition === '') return '';
				return false;
			},
			opened = false,
			loaded = [],
			getRelated = function(rel, jqObj) {
				var $related = jqObj.filter(function () {
					return ($(this).attr('rel') === rel);
				});
				return $related;
			},
			objects = (options.rel && options.rel !== false) ? getRelated(options.rel, $(this)) : this,
			tagname = (objects.get()[0] ? objects.get()[0].tagName : null),
			transPrefix = transPrefix(),
			globalScrollbarwidth = 0,
			canTransisions = (transPrefix !== false) ? true : false,
			supportsPushState = ('pushState' in history),
			historyhasChanged = false,
			historyUpdateTimeout,
			winLoc = window.location,
			getHash = function() {
				return winLoc.hash.substring(1);
			},
			initialHash = getHash(),
			updateHash = function() {
				var hash = getHash(),
				newHash = 'pid='+(index+1);
				var newURL = winLoc.href.split('#')[0] + '#' + newHash;

				if (supportsPushState) {
					history[historyhasChanged ? 'replaceState' : 'pushState']('', document.title, newURL);
				}else {
					if (historyhasChanged) {
						winLoc.replace(newURL);
					} else {
						winLoc.hash = newHash;
					}
				}
				historyhasChanged = true;
			},
			resetHash = function() {
				if (supportsPushState) {
					history.pushState('', document.title, winLoc.pathname + winLoc.search);
				} else {
					winLoc.hash = '';
				}
				clearTimeout(historyUpdateTimeout);

			},
			updateURL = function() {
				if (!historyhasChanged) {
					updateHash(); // first time
				} else {
					historyUpdateTimeout = setTimeout(updateHash, 800);
				}
			},
			throttle = function(func, limit) {
				var inThrottle;
				return function() {
					var args = arguments;
					var context = this;
					if (!inThrottle) {
						func.apply(context, args);
						inThrottle = true;
						setTimeout(function() {
							return inThrottle = false;
						}, limit);
					}
				};
			},
			prefix = 'vikfxgl',
			overlay = $('<div>').addClass('vikfxg-overlay'),
			closeBtn = $('<button>').addClass('vikfxg-close').html(options.closeText),
			spinner = $('<div>').addClass('vikfxg-spinner').html('<div></div>'),
			nav = $('<div>').addClass('vikfxg-navigation').html('<button class="vikfxg-prev">'+options.navText[0]+'</button><button class="vikfxg-next">'+options.navText[1]+'</button>'),
			counter = $('<div>').addClass('vikfxg-counter').html('<span class="vikfxg-current"></span>/<span class="vikfxg-total"></span>'),
			animating = false,
			index = 0,
			startIndex = 0,
			caption = $('<div>').addClass('vikfxg-caption '+options.captionClass+' pos-'+options.captionPosition),
			image = $('<div>').addClass('vikfxg-image'),
			wrapper = $('<div>').addClass('vikfxg-wrapper').addClass('vikfx-gallery'),
			isValidLink = function(element) {
				if (!options.fileExt) return true;
				var filEext = /\.([0-9a-z]+)(?=[?#])|(\.)(?:[\w]+)$/gmi;
				var testExt = $(element).attr(options.sourceAttr).match(filEext);
				return testExt && $(element).prop('tagName').toUpperCase() == tagname && (new RegExp('\.(' + options.fileExt + ')$', 'i')).test(testExt);
			},
			setup = function() {
				if (options.close) closeBtn.appendTo(wrapper);
				if (options.showCounter) {
					if (objects.length > 1) {
						counter.appendTo(wrapper);
						counter.find('.vikfxg-total').text(objects.length);
					}
				}
				if (options.nav) nav.appendTo(wrapper);
				if (options.spinner) spinner.appendTo(wrapper);
			},
			openImage = function(elem) {
				elem.trigger($.Event('show.vikfxgallery'));
				if (options.disableScroll) globalScrollbarwidth = handleScrollbar('hide');
				if (options.htmlClass && options.htmlClass != '') $('html').addClass(options.htmlClass);
				wrapper.appendTo('body');
				image.appendTo(wrapper);
				if (options.overlay) overlay.appendTo($('body'));
				animating = true;
				index = objects.index(elem);
				curImg = $('<img/>')
					.hide()
					.attr('src', elem.attr(options.sourceAttr))
					.attr('data-scale', 1)
					.attr('data-translate-x', 0)
					.attr('data-translate-y', 0);
				if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) {
					loaded.push(elem.attr(options.sourceAttr));
				}
				image.html('').attr('style','');
				curImg.appendTo(image);
				addEvents();
				overlay.fadeIn('fast');
				$('.vikfxg-close').fadeIn('fast');
				spinner.show();
				nav.fadeIn('fast');
				$('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1);
				counter.fadeIn('fast');
				adjustImage();
				if (options.preloading) preload();
				setTimeout(function() {
					elem.trigger($.Event('shown.vikfxgallery'));
				}, options.animationSpeed);
			},
			adjustImage = function(dir) {
				if (!curImg.length) return;
				var tmpImage = new Image(),
				windowWidth	 = window.innerWidth * options.widthRatio,
				windowHeight = window.innerHeight * options.heightRatio;
				tmpImage.src = curImg.attr('src');
				curImg.data('scale',1);
				curImg.data('translate-x',0);
				curImg.data('translate-y',0);
				zoomPanElement(0,0,1);
				$(tmpImage).on('error',function(ev) {
					// image not found
					objects.eq(index).trigger($.Event('error.vikfxgallery'));
					animating = false;
					opened = true;
					spinner.hide();
					var dirDefinined = (dir == 1 || dir == -1);
					if (startIndex === index && dirDefinined) {
						close();
						return;
					}
					if (options.alertError) {
						alert(options.alertErrorMessage);
					} else {
						console.error(options.alertErrorMessage);
					}
					if (dirDefinined) {
						loadImage(dir);
					} else {
						loadImage(1);
					}
					return;
				});

				tmpImage.onload = function() {
					if (typeof dir !== 'undefined') {
						objects.eq(index)
							.trigger($.Event('changed.vikfxgallery'))
							.trigger($.Event((dir ===1 ? 'nextDone' : 'prevDone') + '.vikfxgallery'));
					}

					// history
					if (options.history) {
						updateURL();
					}

					if (loaded.indexOf(curImg.attr('src')) == -1) {
						loaded.push(curImg.attr('src'));
					}
					var imageWidth	 = tmpImage.width,
						imageHeight	 = tmpImage.height;

					if (options.scaleImageToRatio || imageWidth > windowWidth || imageHeight > windowHeight) {
						var ratio	 = imageWidth / imageHeight > windowWidth / windowHeight ? imageWidth / windowWidth : imageHeight / windowHeight;
						imageWidth	/= ratio;
						imageHeight	/= ratio;
					}

					$('.vikfxg-image').css({
						'top':    (window.innerHeight - imageHeight) / 2 + 'px',
						'left':   (window.innerWidth - imageWidth - globalScrollbarwidth)/ 2 + 'px',
						'width':  imageWidth + 'px',
						'height': imageHeight + 'px'
					});
					spinner.hide();
					curImg
					.fadeIn('fast');
					opened = true;
					var cSel = (options.captionSelector == 'self') ? objects.eq(index) : objects.eq(index).find(options.captionSelector);
					var captionText;
					if (options.captionType == 'data') {
						captionText = cSel.data(options.captionsData);
					} else if (options.captionType == 'text') {
						captionText = cSel.html();
					} else {
						captionText = cSel.prop(options.captionsData);
					}

					if (!options.loop) {
						if (index === 0) { $('.vikfxg-prev').hide();}
						if (index >= objects.length -1) {$('.vikfxg-next').hide();}
						if (index > 0) { $('.vikfxg-prev').show(); }
						if (index < objects.length -1) { $('.vikfxg-next').show(); }
					}

					if (objects.length == 1) $('.vikfxg-prev, .vikfxg-next').hide();

					if (dir == 1 || dir == -1) {
						var css = { 'opacity': 1.0 };
						if (options.animationSlide) {
							if (canTransisions) {
								slide(0, 100 * dir + 'px');
								setTimeout(function() {
									slide(options.animationSpeed / 1000, 0 + 'px');
								}, 50);
							}
							else {
								css.left = parseInt($('.vikfxg-image').css('left')) + 100 * dir + 'px';
							}
						}

						$('.vikfxg-image').animate(css, options.animationSpeed, function() {
							animating = false;
							setCaption(captionText, imageWidth);
						});
					} else {
						animating = false;
						setCaption(captionText, imageWidth);
					}
					if (options.additionalHtml && $('.vikfxg-additional-html').length === 0) {
						$('<div>').html(options.additionalHtml).addClass('vikfxg-additional-html').appendTo($('.vikfxg-image'));
					}
				};
			},
			setCaption = function(captiontext, imageWidth) {
				if (captiontext !== '' && typeof captiontext !== "undefined" && options.captions) {
					caption.html(captiontext).css({'width': imageWidth + 'px'}).hide().appendTo($('.vikfxg-image')).delay(options.captionDelay).fadeIn('fast');
				}
			},
			slide = function(speed, pos) {
				var styles = {};
					styles[transPrefix + 'transform'] = 'translateX(' + pos + ')';
					styles[transPrefix + 'transition'] = transPrefix + 'transform ' + speed + 's linear';
					$('.vikfxg-image').css(styles);
			},
			zoomPanElement = function(targetOffsetX, targetOffsetY, targetScale) {
				var styles = {};
				styles[transPrefix + 'transform'] = 'translate(' + targetOffsetX + ',' + targetOffsetY+ ') scale('+targetScale+')';
				curImg.css(styles);
			},
			minMax = function(value, min, max) {
				return (value < min) ? min : (value > max) ? max : value;
			},
			setZoomData = function(initialScale,targetOffsetX,targetOffsetY) {
				curImg.data('scale',initialScale);
				curImg.data('translate-x',targetOffsetX);
				curImg.data('translate-y',targetOffsetY);
			},
			addEvents = function() {
				// resize/responsive
				$(window).on('resize.'+prefix, adjustImage);

				// close lightbox on close btn
				$(document).on('click.'+prefix+ ' touchstart.'+prefix, '.vikfxg-close', function(e) {
					e.preventDefault();
					if (opened) { close();}
				});

				if (options.history) {
					setTimeout(function() {
						$(window).on('hashchange.'+prefix,function() {
							if (opened) {
								if (getHash() === initialHash) {
									close();
									return;
								}
							}
						});
					}, 40);
				}

				// nav-buttons
				nav.on('click.'+prefix, 'button', throttle(function(e) {
					e.preventDefault();
					swipeDiff = 0;
					loadImage($(this).hasClass('vikfxg-next') ? 1 : -1);
				}, options.throttleInterval));

				// touch helpers
				var swipeStart	 = 0,
					swipeEnd	 = 0,
					swipeYStart = 0,
					swipeYEnd = 0,
					zoomed = false,
					mousedown = false,
					imageLeft = 0,
					containerHeight,
					containerWidth,
					containerOffsetX,
					containerOffsetY,
					imgHeight,
					imgWidth,
					capture = false,
					initialOffsetX,
					initialOffsetY,
					initialPointerOffsetX,
					initialPointerOffsetY,
					initialPointerOffsetX2,
					initialPointerOffsetY2,
					initialScale = minMax(1, 1, options.maxZoom),
					initialPinchDistance,
					pointerOffsetX,
					pointerOffsetY,
					pointerOffsetX2,
					pointerOffsetY2,
					targetOffsetX,
					targetOffsetY,
					targetScale,
					pinchOffsetX,
					pinchOffsetY,
					limitOffsetX,
					limitOffsetY,
					scaleDifference,
					targetPinchDistance,
					touchCount,
					doubleTapped = false,
					touchmoveCount = 0;

				image
				.on('touchstart.'+prefix+' mousedown.'+prefix, function(e)
				{
					if (e.target.tagName === 'A' && e.type == 'touchstart') {
						return true;
					}
					e = e.originalEvent;
					if (e.type == 'mousedown') {
						initialPointerOffsetX = e.clientX;
						initialPointerOffsetY = e.clientY;
						containerHeight = image.height();
						containerWidth = image.width();
						imgHeight = curImg.height();
						imgWidth = curImg.width();
						containerOffsetX = image.position().left;
						containerOffsetY = image.position().top;

						initialOffsetX = parseFloat(curImg.data('translate-x'));
						initialOffsetY = parseFloat(curImg.data('translate-y'));

						capture = true;
					} else {
						touchCount = e.touches.length;
						initialPointerOffsetX = e.touches[0].clientX;
						initialPointerOffsetY = e.touches[0].clientY;
						containerHeight = image.height();
						containerWidth = image.width();
						imgHeight = curImg.height();
						imgWidth = curImg.width();
						containerOffsetX = image.position().left;
						containerOffsetY = image.position().top;

						if (touchCount === 1) /* Single touch */ {
							if (!doubleTapped) {
								doubleTapped = true;
								setTimeout(function() {
									doubleTapped = false;
								}, 300);
							} else {
								curImg.addClass('vikfxg-transition');
								if (!zoomed) {
									initialScale = options.doubleTapZoom;
									setZoomData(0,0, initialScale);
									zoomPanElement(0 + "px", 0 + "px", initialScale);
									$('.vikfxg-caption').fadeOut(200);
									zoomed = true;
								} else {
									initialScale = 1;
									setZoomData(0,0,initialScale);
									zoomPanElement(0 + "px", 0 + "px", initialScale);
									zoomed = false;
								}

								setTimeout(function() {
									curImg.removeClass('vikfxg-transition');
								}, 200);
								return false;
							}

							initialOffsetX = parseFloat(curImg.data('translate-x'));
							initialOffsetY = parseFloat(curImg.data('translate-y'));
						}
						else if (touchCount === 2) /* Pinch */ {
							initialPointerOffsetX2 = e.touches[1].clientX;
							initialPointerOffsetY2 = e.touches[1].clientY;
							initialOffsetX = parseFloat(curImg.data('translate-x'));
							initialOffsetY = parseFloat(curImg.data('translate-y'));
							pinchOffsetX = (initialPointerOffsetX + initialPointerOffsetX2) / 2;
							pinchOffsetY = (initialPointerOffsetY + initialPointerOffsetY2) / 2;
							initialPinchDistance = Math.sqrt(((initialPointerOffsetX - initialPointerOffsetX2) * (initialPointerOffsetX - initialPointerOffsetX2)) + ((initialPointerOffsetY - initialPointerOffsetY2) * (initialPointerOffsetY - initialPointerOffsetY2)));
						}
						capture = true;
					}

					if (mousedown) return true;
					if (canTransisions) imageLeft = parseInt(image.css('left'));
					mousedown = true;
					swipeDiff = 0;
					swipeYDiff = 0;
					swipeStart = e.pageX || e.touches[ 0 ].pageX;
					swipeYStart = e.pageY || e.touches[ 0 ].pageY;
					return false;
				})
				.on('touchmove.'+prefix+' mousemove.'+prefix+' MSPointerMove', function(e)
				{
					if (!mousedown) return true;
					e.preventDefault();
					e = e.originalEvent;
					/* Initialize helpers */
					if (e.type == 'touchmove') {
						if (capture === false) return false;
						pointerOffsetX = e.touches[0].clientX;
						pointerOffsetY = e.touches[0].clientY;
						touchCount = e.touches.length;
						touchmoveCount++;

						if (touchCount > 1) /* Pinch */ {
							pointerOffsetX2 = e.touches[1].clientX;
							pointerOffsetY2 = e.touches[1].clientY;
							targetPinchDistance = Math.sqrt(((pointerOffsetX - pointerOffsetX2) * (pointerOffsetX - pointerOffsetX2)) + ((pointerOffsetY - pointerOffsetY2) * (pointerOffsetY - pointerOffsetY2)));
							if (initialPinchDistance === null) {
								initialPinchDistance = targetPinchDistance;
							}

							if (Math.abs(initialPinchDistance - targetPinchDistance) >= 1) {
								/* Initialize helpers */
								targetScale = minMax(targetPinchDistance / initialPinchDistance * initialScale, 1, options.maxZoom);
								limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
								limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
								scaleDifference = targetScale - initialScale;
								targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0: minMax(initialOffsetX - ((((((pinchOffsetX - containerOffsetX) - (containerWidth / 2)) - initialOffsetX) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetX * (-1), limitOffsetX);
								targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(initialOffsetY - ((((((pinchOffsetY - containerOffsetY) - (containerHeight / 2)) - initialOffsetY) / (targetScale - scaleDifference))) * scaleDifference), limitOffsetY * (-1), limitOffsetY);

								zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);

								if (targetScale > 1) {
									zoomed = true;
									$('.vikfxg-caption').fadeOut(200);
								}

								initialPinchDistance = targetPinchDistance;
								initialScale = targetScale;
								initialOffsetX = targetOffsetX;
								initialOffsetY = targetOffsetY;
							}
						} else {
							targetScale = initialScale;
							limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
							limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
							targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX);
							targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY);

							if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) {
								initialOffsetX = targetOffsetX;
								initialPointerOffsetX = pointerOffsetX;
							}

							if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) {
								initialOffsetY = targetOffsetY;
								initialPointerOffsetY = pointerOffsetY;
							}

							setZoomData(initialScale,targetOffsetX,targetOffsetY);
							zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);
						}
					}
					/* Mouse Move implementation */
					if (e.type == 'mousemove' && mousedown) {
						if (e.type == 'touchmove') return true;
						if (capture === false) return false;
						pointerOffsetX = e.clientX;
						pointerOffsetY = e.clientY;
						targetScale = initialScale;
						limitOffsetX = ((imgWidth * targetScale) - containerWidth) / 2;
						limitOffsetY = ((imgHeight * targetScale) - containerHeight) / 2;
						targetOffsetX = (imgWidth * targetScale) <= containerWidth ? 0 : minMax(pointerOffsetX - (initialPointerOffsetX - initialOffsetX), limitOffsetX * (-1), limitOffsetX);
						targetOffsetY = (imgHeight * targetScale) <= containerHeight ? 0 : minMax(pointerOffsetY - (initialPointerOffsetY - initialOffsetY), limitOffsetY * (-1), limitOffsetY);

						if (Math.abs(targetOffsetX) === Math.abs(limitOffsetX)) {
							initialOffsetX = targetOffsetX;
							initialPointerOffsetX = pointerOffsetX;
						}

						if (Math.abs(targetOffsetY) === Math.abs(limitOffsetY)) {
							initialOffsetY = targetOffsetY;
							initialPointerOffsetY = pointerOffsetY;
						}

						setZoomData(initialScale,targetOffsetX,targetOffsetY);
						zoomPanElement(targetOffsetX + "px", targetOffsetY + "px", targetScale);
					}
					if (!zoomed) {
						swipeEnd = e.pageX || e.touches[ 0 ].pageX;
						swipeYEnd = e.pageY || e.touches[ 0 ].pageY;
						swipeDiff = swipeStart - swipeEnd;
						swipeYDiff = swipeYStart - swipeYEnd;
						if (options.animationSlide) {
							if (canTransisions) slide(0, -swipeDiff + 'px');
							else image.css('left', imageLeft - swipeDiff + 'px');
						}
					}
				})
				.on('touchend.'+prefix+' mouseup.'+prefix+' touchcancel.'+prefix+' mouseleave.'+prefix+' pointerup pointercancel MSPointerUp MSPointerCancel',function(e)
				{
					e = e.originalEvent;
					if (touchDevice && e.type =='touchend') {
						touchCount = e.touches.length;
						if (touchCount === 0) /* No touch */ {
							/* Set attributes */
							setZoomData(initialScale,targetOffsetX,targetOffsetY);
							if (initialScale == 1) {
								zoomed = false;
								$('.vikfxg-caption').fadeIn(200);
							}
							initialPinchDistance = null;
							capture = false;
						} else if (touchCount === 1) /* Single touch */ {
							initialPointerOffsetX = e.touches[0].clientX;
							initialPointerOffsetY = e.touches[0].clientY;
						} else if (touchCount > 1) /* Pinch */ {
							initialPinchDistance = null;
						}
					}

					if (mousedown) {
						mousedown = false;
						var possibleDir = true;
						if (!options.loop) {
							if (index === 0 && swipeDiff < 0) { possibleDir = false; }
							if (index >= objects.length -1 && swipeDiff > 0) { possibleDir = false; }
						}
						if (Math.abs(swipeDiff) > options.swipeTolerance && possibleDir) {
							loadImage(swipeDiff > 0 ? 1 : -1);
						}
						else if (options.animationSlide)
						{
							if (canTransisions) slide(options.animationSpeed / 1000, 0 + 'px');
							else image.animate({ 'left': imageLeft + 'px' }, options.animationSpeed / 2);
						}

						if (options.swipeClose && Math.abs(swipeYDiff) > 50 && Math.abs(swipeDiff) < options.swipeTolerance) {
							close();
						}
					}
				})
				/** Detect Double click on image*/
				.on('dblclick', function(e)
				{
					initialPointerOffsetX = e.clientX;
					initialPointerOffsetY = e.clientY;
					containerHeight = image.height();
					containerWidth = image.width();
					imgHeight = curImg.height();
					imgWidth = curImg.width();
					containerOffsetX = image.position().left;
					containerOffsetY = image.position().top;

					curImg.addClass('vikfxg-transition');
					if (!zoomed) {
						initialScale = options.doubleTapZoom;
						setZoomData(0,0, initialScale);
						zoomPanElement(0 + "px", 0 + "px", initialScale);
						$('.vikfxg-caption').fadeOut(200);
						zoomed = true;
					} else {
						initialScale = 1;
						setZoomData(0,0,initialScale);
						zoomPanElement(0 + "px", 0 + "px", initialScale);
						zoomed = false;
					}

					setTimeout(function() {
						curImg.removeClass('vikfxg-transition');
					}, 200);
					capture = true;
					return false;
				});
			},
			removeEvents = function() {
				nav.off('click', 'button');
				$(document).off('click.'+prefix, '.vikfxg-close');
				$(window).off('resize.'+prefix);
				$(window).off('hashchange.'+prefix);
			},
			preload = function() {
				var next = (index+1 < 0) ? objects.length -1: (index+1 >= objects.length -1) ? 0 : index+1,
					prev = (index-1 < 0) ? objects.length -1: (index-1 >= objects.length -1) ? 0 : index-1;
				$('<img />').attr('src', objects.eq(next).attr(options.sourceAttr)).on('load', function() {
					if (loaded.indexOf($(this).attr('src')) == -1) {
						loaded.push($(this).attr('src'));
					}
					objects.eq(index).trigger($.Event('nextImageLoaded.vikfxgallery'));
				});
				$('<img />').attr('src', objects.eq(prev).attr(options.sourceAttr)).on('load', function() {
					if (loaded.indexOf($(this).attr('src')) == -1) {
						loaded.push($(this).attr('src'));
					}
					objects.eq(index).trigger($.Event('prevImageLoaded.vikfxgallery'));
				});

			},
			loadImage = function(dir) {
				objects.eq(index)
				.trigger($.Event('change.vikfxgallery'))
				.trigger($.Event((dir === 1 ? 'next' : 'prev') + '.vikfxgallery'));

			var newIndex = index + dir;
				if (animating || (newIndex < 0 || newIndex >= objects.length) && options.loop === false) return;
				index = (newIndex < 0) ? objects.length -1: (newIndex > objects.length -1) ? 0 : newIndex;
				$('.vikfxg-wrapper .vikfxg-counter .vikfxg-current').text(index +1);
					var css = { 'opacity': 0 };
				if (options.animationSlide) {
					if (canTransisions) slide(options.animationSpeed / 1000, (-100 * dir) - swipeDiff + 'px');
					else css.left = parseInt($('.vikfxg-image').css('left')) + -100 * dir + 'px';
				}

				$('.vikfxg-image').animate(css, options.animationSpeed, function() {
					setTimeout(function() {
						// fadeout old image
						var elem = objects.eq(index);
						curImg
						.attr('src', elem.attr(options.sourceAttr));

						if (loaded.indexOf(elem.attr(options.sourceAttr)) == -1) {
							spinner.show();
						}
						$('.vikfxg-caption').remove();
						adjustImage(dir);
						if (options.preloading) preload();
					}, 100);
				});
			},
			close = function() {
				if (animating) return;
				var elem = objects.eq(index),
				triggered = false;

				elem.trigger($.Event('close.vikfxgallery'));
				if (options.history) {
					resetHash();
				}
				$('.vikfxg-image img, .vikfxg-overlay, .vikfxg-close, .vikfxg-navigation, .vikfxg-image .vikfxg-caption, .vikfxg-counter').fadeOut('fast', function() {
					if (options.disableScroll) handleScrollbar('show');
					if (options.htmlClass && options.htmlClass != '') $('html').removeClass(options.htmlClass);
					$('.vikfxg-wrapper, .vikfxg-overlay').remove();
					removeEvents();
					if (!triggered) elem.trigger($.Event('closed.vikfxgallery'));
					triggered = true;
				});
				curImg = $();
				opened = false;
				animating = false;
			},
			handleScrollbar = function(type) {
				var scrollbarWidth = 0;
				if (type == 'hide') {
					var fullWindowWidth = window.innerWidth;
					if (!fullWindowWidth) {
						var documentElementRect = document.documentElement.getBoundingClientRect();
						fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left);
					}
					if (document.body.clientWidth < fullWindowWidth) {
						var scrollDiv = document.createElement('div'),
						padding = parseInt($('body').css('padding-right'),10);
						scrollDiv.className = 'vikfxg-scrollbar-measure';
						$('body').append(scrollDiv);
						scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
						$(document.body)[0].removeChild(scrollDiv);
						$('body').data('padding',padding);
						if (scrollbarWidth > 0) {
							$('body').addClass('hidden-scroll').css({'padding-right':padding+scrollbarWidth});
						}
					}
				} else {
					$('body').removeClass('hidden-scroll').css({'padding-right':$('body').data('padding')});
				}
				return scrollbarWidth;
			};

		// events
		setup();

		// open lightbox
		objects.on('click.'+prefix, function(e) {
			if (isValidLink(this)) {
				e.preventDefault();
				if (animating) return false;
				var elem = $(this);
				startIndex = objects.index(elem);
				openImage(elem);
			}
		});

		// close on click on doc
		$(document).on('click.'+prefix+ ' touchstart.'+prefix, function(e) {
			if (opened) {
				if ((options.docClose && $(e.target).closest('.vikfxg-image').length === 0 && $(e.target).closest('.vikfxg-navigation').length === 0)) {
					close();
				}
			}
		});

		// disable rightclick
		if (options.disableRightClick) {
			$(document).on('contextmenu', '.vikfxg-image img', function(e) {
				return false;
			});
		}

		// keyboard-control
		if (options.enableKeyboard) {
			$(document).on('keyup.'+prefix, throttle(function(e) {
				swipeDiff = 0;
				// keyboard control only if lightbox is open
				var key = e.keyCode;
				if (animating && key == 27) {
					curImg.attr('src', '');
					animating = false;
					close();
				}

				if (opened) {
					e.preventDefault();
					if (key == 27) {
						close();
					}
					if (key == 37 || e.keyCode == 39) {
						loadImage(e.keyCode == 39 ? 1 : -1);
					}
				}
			}, options.throttleInterval));
		}

		// Public methods
		this.open = function(elem) {
			elem = elem || $(this[0]);
			startIndex = objects.index(elem);
			openImage(elem);
		};

		this.close = function() {
			close();
		};

		this.next = function() {
			loadImage(1);
		};

		this.prev = function() {
			loadImage(-1);
		};

		this.destroy = function() {
			$(document).off('click.'+prefix).off('keyup.'+prefix);
			close();
			$('.vikfxg-overlay, .vikfxg-wrapper').remove();
			this.off('click');
		};

		this.refresh = function() {
			this.destroy();
			$(this).vikFxGallery(options);
		};

		return this;

	};
})(jQuery, window, document);
// source --> https://lipper-quartiere.de/wp-content/plugins/vikbooking/admin/resources/vbocore.js 
/**
 * VikBooking Core v1.8.7
 * Copyright (C) 2026 E4J s.r.l. All Rights Reserved.
 * http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * https://vikwp.com | https://e4j.com | https://e4jconnect.com
 */
(function($, w) {
	'use strict';

	/**
	 * AJAX loading of Views may reload the already existing options, so we cache them when available.
	 */
	var CORE_OPTIONS = typeof VBOCore !== 'undefined' ? VBOCore?.options : null;

	/**
	 * VBOCore class implementation.
	 */
	w['VBOCore'] = class VBOCore {

		/**
		 * Proxy to support static injection of params.
		 */
		constructor(params) {
			VBOCore.setOptions(params);
		}

		/**
		 * Inject options by overriding default properties.
		 * 
		 * @param 	object 	params
		 * 
		 * @return 	self
		 */
		static setOptions(params) {
			if (params != null && typeof params === 'object') {
				VBOCore.options = Object.assign(VBOCore.options, params);
			}

			return VBOCore;
		}

		/**
		 * Fires a given function when the DOM content has loaded.
		 * 
		 * @param 	function 	fireFn 	The function to fire when the document is ready.
		 * 
		 * @return 	undefined
		 */
		static DOMLoaded(fireFn) {
			if (typeof fireFn !== 'function') {
				throw new Error('Invalid argument provided');
			}

			if (document.readyState === 'loading') {
				// register event because DOMContentLoaded hasn't finished yet
				document.addEventListener('DOMContentLoaded', fireFn);
			} else {
				// DOMContentLoaded event has fired already
				fireFn();
			}
		}

		/**
		 * Returns a promise that resolves when the specified instance gets defined.
		 * 
		 * @param 	function  check      The callback to invoke to check whether the instance is ready.
		 * @param   mixed     threshold  An optional threshold to estabilish the max number of attempts.
		 * 
		 * @return 	Promise
		 */
		static onInstanceReady(check, threshold) {
			return new Promise((resolve, reject) => {
				// prepare safe counter
				let count = 0;

				const callback = function() {
					// increase counter
					count++;

					let instance;

					try {
						// check whether the instance is ready
						instance = check();
					} catch (err) {
						// an error has occurred, manually abort
						reject();
						return;
					}

					if (instance) {
						// object is now ready
						resolve(instance);
					} else {
						if (!threshold || count < Math.abs(threshold)) {
							// check again
							setTimeout(callback, 32 + Math.floor(Math.random() * 128));
						} else {
							// instance not ready
							reject();
						}
					}
				};

				// check
				callback();
			});
		}

		/**
		 * Getter for admin_widgets private options property.
		 * 
		 * @return 	array
		 */
		static get admin_widgets() {
			return VBOCore.options.admin_widgets;
		}

		/**
		 * Getter for multitask open event private property.
		 * 
		 * @return 	string
		 */
		static get multitask_open_event() {
			return VBOCore.options.multitask_open_event;
		}

		/**
		 * Getter for multitask close event private property.
		 * 
		 * @return 	string
		 */
		static get multitask_close_event() {
			return VBOCore.options.multitask_close_event;
		}

		/**
		 * Getter for multitask shortcut event private property.
		 * 
		 * @return 	string
		 */
		static get multitask_shortcut_event() {
			return VBOCore.options.multitask_shortcut_ev;
		}

		/**
		 * Getter for multitask seach focus shortcut event private property.
		 * 
		 * @return 	string
		 */
		static get multitask_searchfs_event() {
			return VBOCore.options.multitask_searchfs_ev;
		}

		/**
		 * Getter for multitask event widget modal rendered.
		 * 
		 * @return 	string
		 */
		static get widget_modal_rendered() {
			return VBOCore.options.widget_modal_rendered;
		}

		/**
		 * Getter for widget modal dismiss event.
		 * 
		 * @return 	string
		 */
		static get widget_modal_dismissed() {
			return VBOCore.options.widget_modal_dismissed;
		}

		/**
		 * Getter for the service worker file path.
		 * 
		 * @return 	string
		 */
		static get service_worker_path() {
			return VBOCore.options.service_worker_path;
		}

		/**
		 * Getter for the service worker scope.
		 * 
		 * @return 	string
		 */
		static get service_worker_scope() {
			return VBOCore.options.service_worker_scope;
		}

		/**
		 * Getter for the push application key.
		 * 
		 * @return 	string
		 */
		static get push_application_key() {
			return VBOCore.options.push.application_key;
		}

		/**
		 * Getter for the push storage endpoint identifier.
		 * 
		 * @return 	string
		 */
		static get push_storage_endpoint_id() {
			return VBOCore.options.push_options.storage_endp_id;
		}

		/**
		 * Parses an AJAX response error object.
		 * 
		 * @param 	object  err
		 * 
		 * @return  bool
		 */
		static isConnectionLostError(err) {
			if (!err || !err.hasOwnProperty('status')) {
				return false;
			}

			return (
				err.statusText == 'error'
				&& err.status == 0
				&& (err.readyState == 0 || err.readyState == 4)
				&& (!err.hasOwnProperty('responseText') || err.responseText == '')
			);
		}

		/**
		 * Ensures AJAX requests that fail due to connection errors are retried automatically.
		 * 
		 * @param 	string  	url
		 * @param 	object 		data
		 * @param 	function 	success
		 * @param 	function 	failure
		 * @param 	number 		attempt
		 */
		static doAjax(url, data, success, failure, attempt) {
			const AJAX_MAX_ATTEMPTS = 3;

			if (attempt === undefined) {
				attempt = 1;
			}

			let requestOptions = {
				type: 'POST',
				url: url,
				data: data,
			};

			if (data instanceof FormData) {
				// ensure the FormData object is not manipulated
				requestOptions.processData = false;
				requestOptions.contentType = false;
			}

			return $.ajax(
				requestOptions
			).done(function(resp) {
				if (success !== undefined) {
					// launch success callback function
					success(resp);
				}
			}).fail(function(err) {
				/**
				 * If the error is caused by a site connection lost, and if the number
				 * of retries is lower than max attempts, retry the same AJAX request.
				 */
				if (attempt < AJAX_MAX_ATTEMPTS && VBOCore.isConnectionLostError(err)) {
					// delay the retry by half second
					setTimeout(function() {
						// re-launch same request and increase number of attempts
						console.log('Retrying previous AJAX request');
						VBOCore.doAjax(url, data, success, failure, (attempt + 1));
					}, 500);
				} else {
					// launch the failure callback otherwise
					if (failure !== undefined) {
						if (err.responseText === 'false') {
							// make the property empty to rely on others
							err.responseText = '';
						}
						failure(err);
					}
				}

				if (!err.status || err.status == 500) {
					// log the error in console
					console.error('AJAX request failed' + (err.status == 500 ? ' (' + err.responseText + ')' : ''), err);
				}
			});
		}

		/**
		 * Matches a keyword against a text.
		 * 
		 * @param 	string 	search 	the keyword to search.
		 * @param 	string 	text 	the text to compare.
		 * 
		 * @return 	bool
		 */
		static matchString(search, text) {
			return ((text + '').indexOf(search) >= 0);
		}

		/**
		 * Converts a base64 URL for a server key into an array of 8-bit unsigned integers.
		 * 
		 * @param 	string 	key 	the base64 encoded URL key.
		 * 
		 * @return 	Uint8Array
		 */
		static base64ToUint8Array(key) {
			const padding = ('=').repeat((4 - (key.length % 4)) % 4);
			const base64  = (key + padding).replace(/\-/g, '+').replace(/_/g, '/');

			const rawData   = window.atob(base64);
			const uint8_arr = new Uint8Array(rawData.length);

			for (let i = 0; i < rawData.length; ++i) {
				uint8_arr[i] = rawData.charCodeAt(i);
			}

			return uint8_arr;
		}

		/**
		 * Builds an object containing the Push subscription details and data.
		 * 
		 * @param 	PushSubscription 	pushSubscription 	the registration data.
		 * @param 	object 				data 				the extra data to merge.
		 * 
		 * @return 	object
		 */
		static buildPushSubscriptionData(pushSubscription, data) {
			if (!(pushSubscription instanceof PushSubscription)) {
				return data;
			}

			let key			  	= pushSubscription.getKey('p256dh');
			let token 		  	= pushSubscription.getKey('auth');
			let contentEncoding = (PushManager.supportedContentEncodings || ['aesgcm'])[0];

			let details = {
				endpoint:  pushSubscription.endpoint,
				publicKey: key ? btoa(String.fromCharCode.apply(null, new Uint8Array(key))) : null,
				authToken: token ? btoa(String.fromCharCode.apply(null, new Uint8Array(token))) : null,
				encoding:  contentEncoding,
			};

			return Object.assign(details, data);
		}

		/**
		 * Attempts to install (and eventually update) the VikBooking's Service Worker.
		 * 
		 * @param 	bool 	update 	if defined, it will update the Service Worker Registration.
		 * 
		 * @return 	Promise
		 */
		static installServiceWorker(update) {
			// check if support for Web App badge is available
			if (typeof navigator.setAppBadge !== 'undefined') {
				// always clear the app badge
				navigator.clearAppBadge();
			}

			return new Promise((resolve, reject) => {
				if (!('serviceWorker' in navigator)) {
					reject('Service workers are not supported by this browser');
					return;
				}

				if (!('PushManager' in window)) {
					reject('Push notifications are not supported by this browser');
					return;
				}

				if (!VBOCore.service_worker_path) {
					reject('Service Worker path not configured');
					return;
				}

				if (!VBOCore.notificationsEnabled()) {
					reject('Notifications are disabled, and so the service worker will not be installed');
					return;
				}

				navigator.serviceWorker.register(VBOCore.service_worker_path, {scope: VBOCore.service_worker_scope}).then(
					(registration) => {
						if (typeof update !== 'undefined') {
							// attempt to update the registration for un-caching purposes
							registration.update().then((updated) => {
								// all good
							}).catch((e) => {
								// updating should never fail after registering with success
								console.error(`Service worker registration update failed: ${e}`);
							});
						}

						// listen to the ServiceWorker messages for the client
						VBOCore.listenServiceWorkerMessages();

						// resolve the Promise
						resolve(registration);
					},
					(e) => {
						console.error(`Service worker registration failed: ${e}`);
						reject('Service worker registration failed');
					}
				);
			});
		}

		/**
		 * Handles the Push subscription state. To be called after the
		 * Service Worker installation (registration) is ready.
		 * 
		 * @param 	ServiceWorkerRegistration 	registration 	sw registration object.
		 * 
		 * @return 	Promise
		 */
		static handlePushSubscription(registration) {
			return new Promise((resolve, reject) => {
				if (!(registration instanceof ServiceWorkerRegistration)) {
					reject('Missing service worker registration');
					return;
				}

				if (!VBOCore.push_application_key) {
					reject('Missing application key for Push because not supported');
					return;
				}

				// check if a push subscription is available
				registration.pushManager.getSubscription().then((pushSubscription) => {
					if (pushSubscription) {
						// we are subscribed to Push
						let previous_endpoint = VBOCore.storageGetItem(VBOCore.push_storage_endpoint_id);
						if (previous_endpoint && pushSubscription.endpoint != previous_endpoint) {
							// update subscription data
							VBOCore.doAjax(
								VBOCore.options.push.ajax_url,
								VBOCore.buildPushSubscriptionData(pushSubscription, {
									agent: window.navigator.userAgent,
									type: 'update',
								})
							);
						}

						// resolve the promise with the Push subscription data
						resolve(pushSubscription);
						return;
					}

					// push subscription options
					const pushOptions = {
						userVisibleOnly: true,
						applicationServerKey: VBOCore.base64ToUint8Array(VBOCore.push_application_key),
					};

					// subscribe to Push
					registration.pushManager.subscribe(pushOptions).then(
						(pushSubscription) => {
							// store subscription data
							VBOCore.storageSetItem(VBOCore.push_storage_endpoint_id, pushSubscription.endpoint);
							VBOCore.doAjax(
								VBOCore.options.push.ajax_url,
								VBOCore.buildPushSubscriptionData(pushSubscription, {
									agent: window.navigator.userAgent,
									type: 'new',
								})
							);

							// resolve the promise with the Push subscription data
							resolve(pushSubscription);
						},
						(e) => {
							console.error(`Error handling the Push subscription state: ${e}`);
							reject('Error handling the Push subscription state');
						}
					);
				})
				.catch((e) => {
					console.error(`Error getting the Push subscription state: ${e}`);
					reject('Error getting the Push subscription state');
				});
			});
		}

		/**
		 * Starts listening to the "message" events posted by the ServiceWorker.
		 * 
		 * @return 	void
		 */
		static listenServiceWorkerMessages() {
			if (!('serviceWorker' in navigator)) {
				return;
			}

			try {
				// add listener to the message event for the data posted by the ServiceWorker to the client
				navigator.serviceWorker.addEventListener('message', (event) => {
					VBOCore.handleServiceWorkerMessage(event.data);
				});
			} catch(e) {
				// do nothing
			}
		}

		/**
		 * Handles a message data posted by the ServiceWorker upon clicking a Push notification.
		 * 
		 * @param 	object 	data 	the event.notification.data object posted by the ServiceWorker.
		 * 
		 * @return 	void
		 */
		static handleServiceWorkerMessage(data) {
			let notif_type = data.type || '';

			if (!notif_type || !VBOCore.options.push_options.allowed_notif_types.includes(notif_type)) {
				console.error(data);
				throw new Error('Unsupported message type');
			}

			// determine the proper widget for dispatching the message data
			let widget_id = 'booking_details';
			if (notif_type == 'Chat') {
				widget_id = 'guest_messages';
			}

			// the raw notification content
			let raw_content = data.content || {};

			// multitask data options
			let options = Object.assign({
				_push: 	 1,
				title: 	 data.title || '',
				message: data.message || '',
			}, raw_content);

			// dispatch (Push) message data on widget
			VBOCore.handleDisplayWidgetNotification({widget_id: widget_id}, options, true);

			// update pushed data map for the next watching event in the current browsing context
			VBOCore.widgets_pushed_data.push(raw_content);

			// post message onto broadcast channel for any other browsing context
			if (VBOCore.broadcast_push_data) {
				// the next watch-data interval will receive the pushed data information
				VBOCore.broadcast_push_data.postMessage(raw_content);
			}

			// let the window reload the badge counter in case it must be updated
			VBOCore.emitEvent('vbo-badge-count-reload');
		}

		/**
		 * Ensures VBO is ready to support VCM.
		 * 
		 * @param 	any 	env 	optional data to evaluate.
		 * 
		 * @return 	bool
		 */
		static vcmMultitasking(env) {
			// tell VCM that VBOCore supports it
			return true;
		}

		/**
		 * Registers an event identifier as delegated.
		 * Useful to flag an event as registered.
		 * 
		 * @param 	string 	ev 	The event name.
		 * 
		 * @return 	Array
		 */
		static setEventDelegated(ev) {
			VBOCore.options.events_delegated.push(ev);
			return VBOCore.options.events_delegated;
		}

		/**
		 * Un-registers an event identifier as delegated.
		 * 
		 * @param 	string 	ev 	The event name.
		 * 
		 * @return 	Array
		 */
		static unsetEventDelegated(ev) {
			let index = VBOCore.options.events_delegated.indexOf(ev);
			if (index >= 0) {
				VBOCore.options.events_delegated.splice(index, 1);
			}
			return VBOCore.options.events_delegated;
		}

		/**
		 * Tells if an event identifier was delegated.
		 * 
		 * @param 	string 	ev 	The event name.
		 * 
		 * @return 	bool
		 */
		static wasEventDelegated(ev) {
			return VBOCore.options.events_delegated.includes(ev);
		}

		/**
		 * Initializes the multitasking panel for the admin widgets.
		 * 
		 * @param 	object 	params 	the panel object params.
		 * 
		 * @return 	bool
		 */
		static prepareMultitasking(params) {
			var panel_opts = {
				selector: 		 "",
				sclass_l_small:  "vbo-sidepanel-right",
				sclass_l_large:  "vbo-sidepanel-large",
				btn_trigger: 	 "",
				search_selector: "#vbo-sidepanel-search-input",
				search_nores: 	 ".vbo-sidepanel-add-widgets-nores",
				close_selector:  ".vbo-sidepanel-dismiss-btn",
				t_layout_small:	 ".vbo-sidepanel-layout-small",
				t_layout_large:  ".vbo-sidepanel-layout-large",
				wclass_base_sel: ".vbo-admin-widgets-widget-output",
				wclass_l_small:  "vbo-admin-widgets-container-small",
				wclass_l_large:  "vbo-admin-widgets-container-large",
				addws_selector:	 ".vbo-sidepanel-add-widgets",
				addw_selector:	 ".vbo-sidepanel-add-widget",
				addw_modal_cls:  "vbo-widget-render-modal",
				addw_def_cls:    "vbo-widget-render-regular",
				addwfs_selector: ".vbo-sidepanel-add-widget-focussed",
				wtags_selector:	 ".vbo-sidepanel-widget-tags",
				wname_selector:	 ".vbo-sidepanel-widget-name",
				addw_data_attr:  "data-vbowidgetid",
				actws_selector:  ".vbo-sidepanel-active-widgets",
				editw_selector:  ".vbo-sidepanel-edit-widgets-trig",
				shortc_selector: ".vbo-sidepanel-shortcut",
				rmwidget_class:  "vbo-admin-widgets-widget-remove",
				rmwidget_icn: 	 "",
				dtcwidget_class: "vbo-admin-widgets-widget-detach",
				dtctarget_class: "vbo-admin-widget-head",
				dtcwidget_icn: 	 "",
				notif_selector:  ".vbo-sidepanel-notifications-btn",
				notif_on_class:  "vbo-sidepanel-notifications-on",
				notif_off_class: "vbo-sidepanel-notifications-off",
				open_class: 	 "vbo-sidepanel-open",
				close_class: 	 "vbo-sidepanel-close",
				cur_widget_cls:  "vbo-admin-widgets-container-small",
				sortable:        true,
				sort_save_ev:    "vbo-admin-widgets-updateposmp",
				sorting:         null,
			};

			if (typeof params === 'object') {
				panel_opts = Object.assign(panel_opts, params);
			}

			if (!panel_opts.btn_trigger || !panel_opts.selector) {
				console.error('Got no trigger or selector');
				return false;
			}

			// push panel options
			VBOCore.setOptions({
				panel_opts: panel_opts,
			});

			if (VBOCore.options.is_vbo) {
				// setup browser notifications
				VBOCore.setupNotifications();
			}

			// count active widgets on current page
			var tot_active_widgets = VBOCore.options.admin_widgets.length;
			if (tot_active_widgets > 0) {
				// hide add-widgets container
				$(panel_opts.addws_selector).hide();

				// register listener for input search blur
				VBOCore.registerSearchWidgetsBlur();
			}

			// register click event on trigger button
			$(VBOCore.options.panel_opts.btn_trigger).on('click', function() {
				var side_panel = $(VBOCore.options.panel_opts.selector);
				if (side_panel.hasClass(VBOCore.options.panel_opts.open_class)) {
					// hide panel
					VBOCore.side_panel_on = false;
					VBOCore.emitMultitaskEvent(VBOCore.multitask_close_event);
					side_panel.addClass(VBOCore.options.panel_opts.close_class).removeClass(VBOCore.options.panel_opts.open_class);
					// always hide add-widgets container
					$(VBOCore.options.panel_opts.addws_selector).hide();
					// check if we are currently editing
					var is_editing = ($('.' + VBOCore.options.panel_opts.editmode_class).length > 0);
					if (is_editing) {
						// deactivate editing mode
						VBOCore.toggleWidgetsPanelEditing(null);
					}
				} else {
					// show panel
					VBOCore.side_panel_on = true;
					VBOCore.emitMultitaskEvent(VBOCore.multitask_open_event);
					side_panel.addClass(VBOCore.options.panel_opts.open_class).removeClass(VBOCore.options.panel_opts.close_class);
					if (!VBOCore.options.admin_widgets.length) {
						// set focus on search widgets input with delay for the opening animation
						setTimeout(function() {
							$(VBOCore.options.panel_opts.search_selector).focus();
						}, 300);
					}
				}
			});

			// register close/dismiss button
			$(VBOCore.options.panel_opts.close_selector).on('click', function() {
				$(VBOCore.options.panel_opts.btn_trigger).trigger('click');
			});

			if (VBOCore.options.is_vbo) {
				// register toggle layout buttons
				$(VBOCore.options.panel_opts.t_layout_large).on('click', function() {
					// large layout
					$(VBOCore.options.panel_opts.selector).addClass(VBOCore.options.panel_opts.sclass_l_large).removeClass(VBOCore.options.panel_opts.sclass_l_small);
					$(VBOCore.options.panel_opts.wclass_base_sel).addClass(VBOCore.options.panel_opts.wclass_l_large).removeClass(VBOCore.options.panel_opts.wclass_l_small);
					VBOCore.options.panel_opts.cur_widget_cls = VBOCore.options.panel_opts.sclass_l_large;
				});
				$(VBOCore.options.panel_opts.t_layout_small).on('click', function() {
					// small layout
					$(VBOCore.options.panel_opts.selector).addClass(VBOCore.options.panel_opts.sclass_l_small).removeClass(VBOCore.options.panel_opts.sclass_l_large);
					$(VBOCore.options.panel_opts.wclass_base_sel).addClass(VBOCore.options.panel_opts.wclass_l_small).removeClass(VBOCore.options.panel_opts.wclass_l_large);
					VBOCore.options.panel_opts.cur_widget_cls = VBOCore.options.panel_opts.sclass_l_small;
				});
			}

			// register listener for esc key pressed
			$(document).keyup(function(e) {
				if (!VBOCore.side_panel_on) {
					return;
				}
				if ((e.key && e.key === "Escape") || (e.keyCode && e.keyCode == 27)) {
					$(VBOCore.options.panel_opts.btn_trigger).trigger('click');
				}
			});

			// register listener for input search focus
			$(VBOCore.options.panel_opts.search_selector).on('focus', function() {
				// always show add-widgets container
				var widget_focus_class = VBOCore.options.panel_opts.addwfs_selector.replace('.', '');
				$(VBOCore.options.panel_opts.addw_selector).removeClass(widget_focus_class);
				$(VBOCore.options.panel_opts.addws_selector).show();
			});

			// register listener on input search widget
			$(VBOCore.options.panel_opts.search_selector).keyup(function(e) {
				// get the keyword to look for
				var keyword = $(this).val();
				// counting matching widgets
				var matching = 0;
				var first_matched = null;
				var widget_focus_class = VBOCore.options.panel_opts.addwfs_selector.replace('.', '');

				// adjust widgets to be displayed
				if (!keyword.length) {
					// show all widgets for selection
					$(VBOCore.options.panel_opts.addw_selector).show();
					// hide "no results"
					$(VBOCore.options.panel_opts.search_nores).hide();
					// all widgets are matching
					matching = $(VBOCore.options.panel_opts.addw_selector).length;
				} else {
					// make the keyword lowercase
					keyword = (keyword + '').toLowerCase();
					// parse all widget's description tags
					$(VBOCore.options.panel_opts.addw_selector).each(function() {
						var elem  = $(this);
						var descr = elem.find(VBOCore.options.panel_opts.wtags_selector).text();
						if (VBOCore.matchString(keyword, descr)) {
							elem.show();
							matching++;
							if (!first_matched) {
								// store the first widget that matched
								first_matched = elem.attr(VBOCore.options.panel_opts.addw_data_attr);
							}
						} else {
							elem.hide();
						}
					});
					// check how many widget matched
					if (matching > 0) {
						// hide "no results"
						$(VBOCore.options.panel_opts.search_nores).hide();
					} else {
						// show "no results"
						$(VBOCore.options.panel_opts.search_nores).show();
					}
				}

				// check for shortcuts
				if (!e.key) {
					return;
				}

				// handle Enter key press to add a widget
				if (e.key === "Enter") {
					// on Enter key pressed, open/add the first matching widget or the focussed one
					var load_wid_id  = null;
					var focussed_wid = $(VBOCore.options.panel_opts.addwfs_selector + ':visible').first();

					if (focussed_wid.length) {
						load_wid_id = focussed_wid.attr(VBOCore.options.panel_opts.addw_data_attr);
					} else if (first_matched) {
						load_wid_id = first_matched;
					}

					if (!load_wid_id) {
						// no widget to render found
						return;
					}

					if (e.shiftKey === true && !VBOCore.options.is_vcm) {
						// widget multitask panel rendering
						VBOCore.addWidgetToPanel(load_wid_id);
						$(VBOCore.options.panel_opts.search_selector).trigger('blur');

						return;
					}

					// widget modal rendering is the default method
					if (VBOCore.options.is_vcm) {
						// register loading effect with automatic cancellation
						let orig_name = (focussed_wid.length ? focussed_wid : first_matched).find(VBOCore.options.panel_opts.wname_selector).text();
						(focussed_wid.length ? focussed_wid : first_matched).find(VBOCore.options.panel_opts.wname_selector).html(orig_name + ' ' + VBOCore.options.default_loading_body);
						setTimeout(() => {
							(focussed_wid.length ? focussed_wid : first_matched).find(VBOCore.options.panel_opts.wname_selector).text(orig_name);
						}, 1000);

						// assets will be loaded within VCM before rendering the modal widget
						VBOCore.handleDisplayWidgetNotification({widget_id: load_wid_id});
					} else {
						VBOCore.renderModalWidget(load_wid_id);
					}

					return;
				}

				// handle arrow keys selection
				if (matching > 0 && (e.key === 'ArrowDown' || e.key === 'ArrowUp')) {
					// on arrow key pressed, select the next or prev widget
					var addws_element  = $(VBOCore.options.panel_opts.addws_selector);
					var addws_cont_pos = addws_element.offset().top;
					var addws_otheight = addws_element.outerHeight();
					var addws_scrolltp = addws_element.scrollTop();

					if (e.key === 'ArrowDown') {
						var default_widg = $(VBOCore.options.panel_opts.addw_selector + ':visible').first();
					} else {
						var default_widg = $(VBOCore.options.panel_opts.addw_selector + ':visible').last();
					}
					var focussed_wid = $(VBOCore.options.panel_opts.addwfs_selector + ':visible').first();
					var addw_height  = default_widg.outerHeight();
					var focussed_pos = default_widg.offset().top + addw_height;

					if (focussed_wid.length) {
						focussed_wid.removeClass(widget_focus_class);
						if (e.key === 'ArrowDown') {
							var goto_wid = focussed_wid.nextAll(VBOCore.options.panel_opts.addw_selector + ':visible').first();
						} else {
							var goto_wid = focussed_wid.prevAll(VBOCore.options.panel_opts.addw_selector + ':visible').first();
						}
						if (goto_wid.length) {
							goto_wid.addClass(widget_focus_class);
							focussed_pos = goto_wid.offset().top + addw_height;
						} else {
							default_widg.addClass(widget_focus_class);
						}
					} else {
						default_widg.addClass(widget_focus_class);
					}

					if (focussed_pos > (addws_cont_pos + addws_otheight)) {
						addws_element.scrollTop(focussed_pos - addws_cont_pos - addw_height + addws_scrolltp);
					} else if (focussed_pos < 0) {
						addws_element.scrollTop(0);
					}
				}
			});

			// register listener for adding widgets
			$(VBOCore.options.panel_opts.addw_selector).on('click', function(e) {
				var widget_id = $(this).attr(VBOCore.options.panel_opts.addw_data_attr);
				if (!widget_id || !widget_id.length) {
					return false;
				}

				if (VBOCore.options.panel_opts.sorting) {
					// prevent dropped widgets after sorting to be added to the panel
					return false;
				}

				// determine widget rendering method
				if (e && e.target) {
					let cktarget = $(e.target);
					let is_main_elem_clicked = cktarget.length && (cktarget.hasClass('vbo-sidepanel-widget-info-det') || cktarget.hasClass('vbo-sidepanel-widget-name'));
					if (e.shiftKey === true || VBOCore.options.is_vcm || is_main_elem_clicked || (cktarget.hasClass(VBOCore.options.panel_opts.addw_modal_cls) || cktarget.parent().hasClass(VBOCore.options.panel_opts.addw_modal_cls))) {
						// widget modal rendering
						if (VBOCore.options.is_vcm) {
							// register loading effect with automatic cancellation
							let orig_name = $(this).find(VBOCore.options.panel_opts.wname_selector).text();
							$(this).find(VBOCore.options.panel_opts.wname_selector).html(orig_name + ' ' + VBOCore.options.default_loading_body);
							setTimeout(() => {
								$(this).find(VBOCore.options.panel_opts.wname_selector).text(orig_name);
							}, 1000);

							// assets will be loaded within VCM before rendering the modal widget
							VBOCore.handleDisplayWidgetNotification({widget_id: widget_id});
						} else {
							VBOCore.renderModalWidget(widget_id);
						}

						return;
					}
				}

				// widget multitask panel rendering
				VBOCore.addWidgetToPanel(widget_id);
			});

			if (VBOCore.options.is_vbo) {
				// register listener for updating multitask sidepanel with debounce
				document.addEventListener(VBOCore.options.multitask_save_event, VBOCore.debounceEvent(VBOCore.saveMultitasking, 1000));
			}

			// subscribe to event for multitask shortcut
			document.addEventListener(VBOCore.multitask_shortcut_event, function() {
				// toggle multitask panel
				$(VBOCore.options.panel_opts.btn_trigger).trigger('click');
			});

			// subscribe to event for multitask search focus shortcut
			document.addEventListener(VBOCore.multitask_searchfs_event, function() {
				// focus search multitask widgets
				$(VBOCore.options.panel_opts.search_selector).trigger('focus');
			});

			if (VBOCore.options.is_vbo) {
				// register click event on edit widgets button
				$(VBOCore.options.panel_opts.editw_selector).on('click', function() {
					VBOCore.toggleWidgetsPanelEditing(null);
				});

				// register detach widget buttons
				$('.' + VBOCore.options.panel_opts.dtcwidget_class).each(function() {
					let widget_wrapper 	 = $(this).parent(VBOCore.options.panel_opts.wclass_base_sel);
					let detach_widget_id = widget_wrapper.attr(VBOCore.options.panel_opts.addw_data_attr);
					let detach_to_target = widget_wrapper.find('.' + VBOCore.options.panel_opts.dtctarget_class);
					if (!detach_to_target.length) {
						detach_to_target = widget_wrapper;
					}
					// move detach wrapper onto the target (widget head)
					$(this).prependTo(detach_to_target);

					if (!detach_widget_id) {
						return;
					}

					// register detach action
					$(this).on('click', function() {
						// detach widget, meaning do a modal rendering
						VBOCore.renderModalWidget(detach_widget_id);
					});
				});
			}

			if (VBOCore.options.panel_opts.sortable && typeof $.fn.sortable !== 'undefined') {
				// make the admin widgets sortable
				let sortable_env = VBOCore.options.is_vcm ? 'vcm-sidepanel-add-widgets' : 'vbo-sidepanel-add-widgets';
				let handle_env   = VBOCore.options.is_vcm ? 'vcm-sidepanel-widget-info-det' : 'vbo-sidepanel-widget-info-det';
				let item_env     = VBOCore.options.is_vcm ? 'vcm-sidepanel-add-widget' : 'vbo-sidepanel-add-widget';

				// default sorting flag
				VBOCore.options.panel_opts.sorting = null;

				// register listener for updating the widget sorting values on the multitask sidepanel with debounce
				document.addEventListener(VBOCore.options.panel_opts.sort_save_ev, VBOCore.debounceEvent(VBOCore.saveMultitaskingSorting, 500));

				// apply sorting capabilities
				$('.' + sortable_env).sortable({
					axix: 'x',
					cursor: 'move',
					handle: '.' + handle_env,
					items: '.' + item_env,
					containment: 'parent',
					revert: false,
					start: function(event, ui) {
						// update flag
						VBOCore.options.panel_opts.sorting = $(ui.item).attr('data-vbowidgetid');
						// set is-sorting class
						$(ui.item).addClass('is-sorting');
					},
					stop: function(event, ui) {
						// make sure no elements are being sorted
						$('.' + item_env).removeClass('is-sorting');
						// register delayed update flag to allow understanding a sorting was just completed
						setTimeout(() => {
							// restore default sorting flag
							VBOCore.options.panel_opts.sorting = null;
						}, 500);
					},
					update: function(event, ui) {
						// build the current widgets position list
						let pos_list = {};
						document.querySelectorAll('.' + item_env).forEach((elem, index) => {
							let curr_wid = elem.getAttribute('data-vbowidgetid');
							pos_list[curr_wid] = index;
						});
						// trigger the event to update the widget positions
						VBOCore.emitEvent(VBOCore.options.panel_opts.sort_save_ev, {
							pos_list: pos_list,
						});
					}
				});
			}
		}

		/**
		 * Registers the callback for saving the new widget sorting value in the Multitask panel.
		 */
		static saveMultitaskingSorting(e) {
			if (!e || !e.detail || !e.detail.pos_list) {
				return;
			}

			// update multitask widget position
			VBOCore.doAjax(
				VBOCore.options.multitask_ajax_uri,
				{
					call: 'setMultitaskingWidgetPos',
					call_args: [
						e.detail.pos_list,
					],
				},
				(response) => {
					// do nothing on success
				},
				(error) => {
					// silently log the error
					console.error(error.responseText);
				}
			);
		}

		/**
		 * Registers the blur event for the search widgets input.
		 */
		static registerSearchWidgetsBlur() {
			if (VBOCore.options.active_listeners.hasOwnProperty('registerSearchWidgetsBlur')) {
				// listener is already registered
				return true;
			}

			$(VBOCore.options.panel_opts.search_selector).on('blur', function(e) {
				if (e && e.relatedTarget) {
					if (e.relatedTarget.classList.contains(VBOCore.options.panel_opts.addw_selector.replace('.', ''))) {
						// add new widget was clicked, abort hiding process or click event won't fire on target element
						return;
					}
				}
				var keyword = $(this).val();
				if (!keyword.length) {
					// hide add-widgets container
					$(VBOCore.options.panel_opts.addws_selector).hide();
				}
			});

			// register flag for listener active
			VBOCore.options.active_listeners['registerSearchWidgetsBlur'] = 1;
		}

		/**
		 * Removes the blur event handler for the search widgets input.
		 */
		static unregisterSearchWidgetsBlur() {
			if (!VBOCore.options.active_listeners.hasOwnProperty('registerSearchWidgetsBlur')) {
				// nothing to unregister
				return true;
			}

			$(VBOCore.options.panel_opts.search_selector).off('blur');

			// delete flag for listener active
			delete VBOCore.options.active_listeners['registerSearchWidgetsBlur'];
		}

		/**
		 * Adds a widget identifier to the multitask panel.
		 * 
		 * @param 	string 	widget_id 	the widget identifier string to add.
		 */
		static addWidgetToPanel(widget_id) {
			if (!VBOCore.options.widget_ajax_uri || !VBOCore.options.panel_opts || !Object.keys(VBOCore.options.panel_opts).length) {
				throw new Error('Multitask panel options are missing');
			}
			// prepend container to panel
			var widget_classes = [VBOCore.options.panel_opts.wclass_base_sel.replace('.', ''), VBOCore.options.panel_opts.cur_widget_cls];
			var widget_div = '<div class="' + widget_classes.join(' ') + '" ' + VBOCore.options.panel_opts.addw_data_attr + '="' + widget_id + '" style="display: none;"></div>';
			var widget_elem = $(widget_div);
			$(VBOCore.options.panel_opts.actws_selector).prepend(widget_elem);

			// always hide add-widgets container
			$(VBOCore.options.panel_opts.addws_selector).hide();

			// trigger debounced map saving event
			VBOCore.emitMultitaskEvent();

			// register listener for input search blur
			VBOCore.registerSearchWidgetsBlur();

			// render widget
			var call_method = 'render';
			VBOCore.doAjax(
				VBOCore.options.widget_ajax_uri,
				{
					widget_id: widget_id,
					call: 	   call_method,
					vbo_page:  VBOCore.options.current_page,
					vbo_uri:   VBOCore.options.current_page_uri,
					multitask: 1,
				},
				(response) => {
					// display widgets editing button
					VBOCore.toggleWidgetsPanelEditing(true);
					// parse response
					try {
						var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
						if (obj_res.hasOwnProperty(call_method)) {
							// populate widget HTML content and display it
							widget_elem.html(obj_res[call_method]).fadeIn();

							// always scroll active widgets list to top
							$(VBOCore.options.panel_opts.actws_selector).scrollTop(0);

							// register detach widget button
							setTimeout(() => {
								let detach_elem = $('<div></div>').addClass(VBOCore.options.panel_opts.dtcwidget_class).html(VBOCore.options.panel_opts.dtcwidget_icn);
								let detach_to_target = widget_elem.find('.' + VBOCore.options.panel_opts.dtctarget_class);
								if (!detach_to_target.length) {
									detach_to_target = widget_elem;
								}
								// move detach wrapper onto the target (widget head)
								detach_elem.prependTo(detach_to_target);
								// register detach action
								detach_elem.on('click', function() {
									// detach widget, meaning do a modal rendering
									VBOCore.renderModalWidget(widget_id);
								});
							}, 500);
						} else {
							console.error('Unexpected JSON response', obj_res);
						}
					} catch(err) {
						console.error('could not parse JSON response', err, response);
					}
				},
				(error) => {
					console.error(error.responseText);
				}
			);
		}

		/**
		 * Toggles the edit mode of the multitask widgets panel.
		 * 
		 * @param 	bool 	added 	true if a widget was just added, false if it was just removed.
		 */
		static toggleWidgetsPanelEditing(added) {
			// check if we are currently editing
			var is_editing = ($('.' + VBOCore.options.panel_opts.editmode_class).length > 0);

			// the triggerer button
			var triggerer = $(VBOCore.options.panel_opts.editw_selector);

			// check added action status
			if (added === true) {
				// show button for edit mode
				triggerer.show();
				// hide shortcut element
				$(VBOCore.options.panel_opts.shortc_selector).hide();
				return;
			}

			// grab all widgets
			var editing_widgets = $(VBOCore.options.panel_opts.wclass_base_sel);

			if (added === false) {
				if (!editing_widgets.length) {
					// hide button for edit mode after removing the last widget
					triggerer.removeClass(VBOCore.options.panel_opts.editw_selector.substr(1) + '-active').hide();
					// show shortcut element
					$(VBOCore.options.panel_opts.shortc_selector).show();
				}
				return;
			}

			if (is_editing) {
				// deactivate editing mode
				editing_widgets.removeClass(VBOCore.options.panel_opts.editmode_class);
				$('.' + VBOCore.options.panel_opts.rmwidget_class).remove();
				// toggle triggerer button active class
				triggerer.removeClass(VBOCore.options.panel_opts.editw_selector.substr(1) + '-active');
			} else {
				// activate editing mode by looping through all widgets
				editing_widgets.each(function() {
					// build remove-widget element
					var rm_widget = $('<div></div>').addClass(VBOCore.options.panel_opts.rmwidget_class).on('click', function() {
						VBOCore.removeWidgetFromPanel(this);
					}).html(VBOCore.options.panel_opts.rmwidget_icn);
					// add editing class and prepend removing element
					$(this).addClass(VBOCore.options.panel_opts.editmode_class).prepend(rm_widget);
				});
				// toggle triggerer button active class
				triggerer.addClass(VBOCore.options.panel_opts.editw_selector.substr(1) + '-active');
			}
		}

		/**
		 * Handles the removal of a widget from the multitask panel.
		 * 
		 * @param 	object 	element
		 */
		static removeWidgetFromPanel(element) {
			if (!element) {
				console.error('Invalid widget element to remove', element);
				return false;
			}
			var widget_cont = $(element).parent(VBOCore.options.panel_opts.wclass_base_sel);
			if (!widget_cont || !widget_cont.length) {
				console.error('Could not find widget container to remove', element);
				return false;
			}
			var widget_id = widget_cont.attr(VBOCore.options.panel_opts.addw_data_attr);
			if (!widget_id || !widget_id.length) {
				console.error('Empty widget id to remove', element);
				return false;
			}
			// find the index of the widget to remove in the panel
			var widget_index = $(VBOCore.options.panel_opts.wclass_base_sel).index(widget_cont);
			if (widget_index < 0) {
				console.error('Empty widget index to remove', widget_cont);
				return false;
			}
			// make sure the index in the array matches the id
			if (!VBOCore.options.admin_widgets.hasOwnProperty(widget_index) || VBOCore.options.admin_widgets[widget_index]['id'] != widget_id) {
				console.error('Unmatching widget index or id', VBOCore.options.admin_widgets, widget_index, widget_id);
				return false;
			}
			// remove this widget from the array
			VBOCore.options.admin_widgets.splice(widget_index, 1);

			// remove element from document
			widget_cont.remove();

			// check widgets editing button status
			VBOCore.toggleWidgetsPanelEditing(false);

			// trigger debounced map saving event
			VBOCore.emitMultitaskEvent();

			if (!VBOCore.options.admin_widgets.length) {
				// unregister listener for input search blur
				VBOCore.unregisterSearchWidgetsBlur();
			}
		}

		/**
		 * Emits an event related to the multitask features or a custom event, with optional data.
		 */
		static emitMultitaskEvent(ev_name, ev_data) {
			var def_ev_name = VBOCore.options.multitask_save_event;
			if (typeof ev_name === 'string') {
				def_ev_name = ev_name;
			}

			if (typeof ev_data !== 'undefined' && ev_data) {
				// trigger the custom event
				document.dispatchEvent(new CustomEvent(def_ev_name, {bubbles: true, detail: ev_data}));
				return;
			}

			// trigger the event
			document.dispatchEvent(new Event(def_ev_name));
		}

		/**
		 * Proxy for dispatching an event to the document with optional data.
		 */
		static emitEvent(ev_name, ev_data) {
			if (typeof ev_name !== 'string' || !ev_name.length) {
				return;
			}

			return VBOCore.emitMultitaskEvent(ev_name, ev_data);
		}

		/**
		 * Attempts to save the multitask widgets for this page.
		 */
		static saveMultitasking() {
			// gather the list of active widgets
			var active_widgets = [];
			var cur_admin_widgets = [];
			$(VBOCore.options.panel_opts.actws_selector).find(VBOCore.options.panel_opts.wclass_base_sel).each(function() {
				var widget_id = $(this).attr(VBOCore.options.panel_opts.addw_data_attr);
				if (widget_id && widget_id.length) {
					// push id in list
					active_widgets.push(widget_id);
					// push object with dummy name for global widgets
					cur_admin_widgets.push({
						id: widget_id,
						name: widget_id,
					});
				}
			});

			// update multitask widgets map for this page
			VBOCore.doAjax(
				VBOCore.options.multitask_ajax_uri,
				{
					call: 'updateMultitaskingMap',
					call_args: [
						VBOCore.options.current_page,
						active_widgets,
						0
					],
				},
				(response) => {
					try {
						var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
						if (obj_res.hasOwnProperty('result') && obj_res['result']) {
							// set current widgets
							VBOCore.setOptions({
								admin_widgets: cur_admin_widgets
							});
						} else {
							console.error('Unexpected or invalid JSON response', response);
						}
					} catch(err) {
						console.error('could not parse JSON response', err, response);
					}
				},
				(error) => {
					console.error(error.responseText);
				}
			);
		}

		/**
		 * Sets up the browser notifications within the multitask panel, if supported.
		 */
		static setupNotifications() {
			if (!('Notification' in window)) {
				// browser does not support notifications
				$(VBOCore.options.panel_opts.notif_selector).hide();
				return false;
			}

			if (Notification.permission && Notification.permission === 'granted') {
				// permissions were granted already
				$(VBOCore.options.panel_opts.notif_selector)
					.addClass(VBOCore.options.panel_opts.notif_on_class)
					.attr('title', VBOCore.options.tn_texts.notifs_enabled)
					.on('click', function() {
						// show congratulations notification
						VBOCore.dispatchCongratulations();

						// attempt to update the service worker installation
						VBOCore.installServiceWorker(true).then(() => {
							// all good
						}).catch((error) => {
							console.error(error);
						});
					});
				return true;
			}

			// notifications supported, but perms not granted
			$(VBOCore.options.panel_opts.notif_selector)
				.addClass(VBOCore.options.panel_opts.notif_off_class)
				.attr('title', VBOCore.options.tn_texts.notifs_disabled);

			// register click-event listener on button to enable notifications
			$(VBOCore.options.panel_opts.notif_selector).on('click', function() {
				VBOCore.requestNotifPerms();
			});

			// subscribe to the multitask-panel-open event to show the status of the notifications
			document.addEventListener(VBOCore.multitask_open_event, function() {
				if (VBOCore.notificationsEnabled() === false) {
					// add "shaking" class to notifications button
					$(VBOCore.options.panel_opts.notif_selector).addClass('shaking');
				}
			});

			// subscribe to the multitask-panel-close event to update the status of the notifications
			document.addEventListener(VBOCore.multitask_close_event, function() {
				// always remove "shaking" class from notifications button
				$(VBOCore.options.panel_opts.notif_selector).removeClass('shaking');
			});
		}

		/**
		 * Sets up the browser notifications within the given selector, if supported.
		 * 
		 * @param 	string 	selector 	the element query selector.
		 */
		static suggestNotifications(selector) {
			if (!selector) {
				return false;
			}

			if (!('Notification' in window)) {
				// browser does not support notifications
				$(selector).hide();
				return false;
			}

			if (Notification.permission && Notification.permission === 'granted') {
				// permissions were granted already
				$(selector)
					.addClass(VBOCore.options.panel_opts.notif_on_class)
					.attr('title', VBOCore.options.tn_texts.notifs_enabled)
					.on('click', function() {
						VBOCore.dispatchCongratulations();
					});
				return true;
			}

			// notifications supported, but perms not granted
			$(selector)
				.addClass(VBOCore.options.panel_opts.notif_off_class)
				.attr('title', VBOCore.options.tn_texts.notifs_disabled);

			// register click-event listener on button to enable notifications
			$(selector).on('click', function() {
				VBOCore.requestNotifPerms(selector);
			});

			// add "shaking" class to make the selector more appealing
			$(selector).addClass('shaking');

			// remove the "shaking" class after some time
			setTimeout(() => {
				$(selector).removeClass('shaking');
			}, 2000);
		}

		/**
		 * Tells whether the notifications are enabled, disabled, not supported.
		 */
		static notificationsEnabled() {
			if (!('Notification' in window)) {
				// not supported
				return null;
			}

			if (Notification.permission && Notification.permission === 'granted') {
				// enabled
				return true;
			}

			// disabled
			return false;
		}

		/**
		 * Attempts to request the notifications permissions to the browser.
		 * For security reasons, this should run upon a user gesture (click).
		 * 
		 * @param 	string 	selector 	optional element query selector.
		 */
		static requestNotifPerms(selector) {
			if (!('Notification' in window)) {
				// browser does not support notifications
				return false;
			}

			// run permissions request in a try-catch statement to support all browsers
			try {
				// handle promise-based version to request permissions
				Notification.requestPermission().then((permission) => {
					VBOCore.handleNotifPerms(permission, selector);
				});
			} catch(e) {
				// run the callback-based version
				Notification.requestPermission(function(permission) {
					VBOCore.handleNotifPerms(permission, selector);
				});
			}
		}

		/**
		 * Handles the notifications permission response (from callback or promise resolved).
		 * 
		 * @param 	any 	permission 	permission status string or NotificationPermission object.
		 * @param 	string 	selector 	optional element query selector.
		 */
		static handleNotifPerms(permission, selector) {
			// check the permission status from the Notification object interface
			if ((Notification.permission && Notification.permission === 'granted') || (typeof permission === 'string' && permission === 'granted')) {
				// permissions granted!
				$((selector || VBOCore.options.panel_opts.notif_selector))
					.removeClass(VBOCore.options.panel_opts.notif_off_class)
					.addClass(VBOCore.options.panel_opts.notif_on_class)
					.attr('title', VBOCore.options.tn_texts.notifs_enabled);

				// dispatch an immediate notification to congratulate with the activation
				VBOCore.dispatchCongratulations();

				return true;
			} else {
				// permissions denied :(
				$((selector || VBOCore.options.panel_opts.notif_selector))
					.removeClass(VBOCore.options.panel_opts.notif_on_class)
					.addClass(VBOCore.options.panel_opts.notif_off_class)
					.attr('title', VBOCore.options.tn_texts.notifs_disabled);

				// show alert message
				console.error('Permission denied for enabling browser notifications', permission);
				alert(VBOCore.options.tn_texts.notifs_disabled_help);
			}

			return false;
		}

		/**
		 * Dispatches an immediate notification with a congratulations text.
		 * 
		 * @return 	void
		 */
		static dispatchCongratulations() {
			try {
				let notif = new Notification(VBOCore.options.tn_texts.congrats, {
					body: VBOCore.options.tn_texts.notifs_enabled,
					tag:  'vbo_notification_congrats',
					silent: false
				});
			} catch(error) {
				alert(error);
			}
		}

		/**
		 * Given a date-time string, returns a Date object representation.
		 * 
		 * @param 	string 	dtime_str 	the date-time string in "Y-m-d H:i:s" format.
		 */
		static getDateTimeObject(dtime_str) {
			// instantiate a new date object
			var date_obj = new Date();

			// parse date-time string
			let dtime_parts = dtime_str.split(' ');
			let date_parts  = dtime_parts[0].split('-');
			if (dtime_parts.length != 2 || date_parts.length != 3) {
				// invalid military format
				return date_obj;
			}
			let time_parts = dtime_parts[1].split(':');

			// set accurate date-time values
			date_obj.setFullYear(date_parts[0]);
			date_obj.setMonth((parseInt(date_parts[1]) - 1));
			date_obj.setDate(parseInt(date_parts[2]));
			date_obj.setHours(parseInt(time_parts[0]));
			date_obj.setMinutes(parseInt(time_parts[1]));
			date_obj.setSeconds(0);
			date_obj.setMilliseconds(0);

			// return the accurate date object
			return date_obj;
		}

		/**
		 * Given a list of schedules, enqueues notifications to watch.
		 * 
		 * @param 	array|object 	schedules 	list of or one notification object(s).
		 * 
		 * @return 	bool
		 */
		static enqueueNotifications(schedules) {
			if (!Array.isArray(schedules) || !schedules.length) {
				if (typeof schedules === 'object' && schedules.hasOwnProperty('dtime')) {
					// convert the single schedule to an array
					schedules = [schedules];
				} else {
					// invalid argument passed
					return false;
				}
			}

			for (var i in schedules) {
				if (!schedules.hasOwnProperty(i) || typeof schedules[i] !== 'object') {
					continue;
				}
				VBOCore.notifications.push(schedules[i]);
			}

			// setup the timeouts to schedule the notifications
			return VBOCore.scheduleNotifications();
		}

		/**
		 * Schedule the trigger timings for each notification.
		 */
		static scheduleNotifications() {
			if (!VBOCore.notifications.length) {
				// no notifications to be scheduled
				return false;
			}
			if (VBOCore.notificationsEnabled() !== true) {
				// notifications not enabled
				console.info('Browser notifications disabled or unsupported.');
				return false;
			}

			// gather current date-timing information
			const now_date = new Date();
			const now_time = now_date.getTime();

			// parse all notifications to schedule the timers if not set
			for (let i = 0; i < VBOCore.notifications.length; i++) {
				let notif = VBOCore.notifications[i];

				if (typeof notif !== 'object' || !notif.hasOwnProperty('dtime')) {
					// invalid notification object, unset it
					VBOCore.notifications.splice(i, 1);
					continue;
				}

				// check if timer has been set
				if (!notif.hasOwnProperty('id_timer')) {
					// estimate trigger timing
					let in_ms = 0;
					// check for imminent notifications
					if (typeof notif.dtime === 'string' && notif.dtime.indexOf('now') >= 0) {
						// imminent ones will be delayed by one second
						in_ms = 1000;
					} else {
						// check overdue date-time (notif.dtime can also be a Date object instance)
						let nexp = VBOCore.getDateTimeObject(notif.dtime);
						in_ms = nexp.getTime() - now_time;
					}
					if (in_ms > 0) {
						// schedule notification trigger
						let id_timer = setTimeout(() => {
							VBOCore.dispatchNotification(notif);
						}, in_ms);
						// set timer on notification object
						VBOCore.notifications[i]['id_timer'] = id_timer;
					}
				}
			}

			return true;
		}

		/**
		 * Deregister all scheduled notifications.
		 */
		static unscheduleNotifications() {
			if (!VBOCore.notifications.length) {
				// no notifications scheduled
				return false;
			}

			for (let i = 0; i < VBOCore.notifications.length; i++) {
				let notif = VBOCore.notifications[i];

				if (typeof notif === 'object' && notif.hasOwnProperty('id_timer')) {
					// unset timeout for this notification
					clearTimeout(notif['id_timer']);
				}
			}

			// reset pool
			VBOCore.notifications = [];
		}

		/**
		 * Update or delete a previously scheduled notification.
		 * 
		 * @param 	object 			match_props  map of properties to match.
		 * @param 	string|number  	newdtime 	 the new date time to schedule (0 for deleting).
		 * 
		 * @return 	null|bool 					 true only if a notification matched.
		 */
		static updateNotification(match_props, newdtime) {
			if (!VBOCore.notifications.length) {
				// no notifications set, terminate
				return null;
			}

			if (typeof match_props !== 'object') {
				// no properties to match the notification
				return null;
			}

			// gather current date-timing information
			const now_date = new Date();
			const now_time = now_date.getTime();

			// parse all notifications scheduled
			for (let i = 0; i < VBOCore.notifications.length; i++) {
				let notif = VBOCore.notifications[i];

				let all_matched = true;
				let to_matching = false;
				for (let prop in match_props) {
					if (!match_props.hasOwnProperty(prop)) {
						continue;
					}
					to_matching = true;
					if (!notif.hasOwnProperty(prop) || notif[prop] != match_props[prop]) {
						all_matched = false;
						break;
					}
				}

				if (all_matched && to_matching) {
					// notification object found
					if (notif.hasOwnProperty('id_timer')) {
						// unset previous timeout for this notification
						clearTimeout(notif['id_timer']);
					}
					// update or delete scheduled notification
					if (newdtime === 0) {
						// delete notification from queue
						VBOCore.notifications.splice(i, 1);
					} else {
						// update timing scheduler
						let in_ms = 0;
						// check for imminent notifications
						if (typeof newdtime === 'string' && newdtime.indexOf('now') >= 0) {
							// imminent ones will be delayed by one second
							in_ms = 1000;
						} else {
							// check overdue date-time (newdtime can also be a Date object instance)
							let nexp = VBOCore.getDateTimeObject(newdtime);
							in_ms = nexp.getTime() - now_time;
						}
						if (in_ms > 0) {
							// schedule notification trigger
							let id_timer = setTimeout(() => {
								VBOCore.dispatchNotification(notif);
							}, in_ms);
							// set timer on notification object
							VBOCore.notifications[i]['id_timer'] = id_timer;
						}
						// update date-time value on notification object
						VBOCore.notifications[i]['dtime'] = newdtime;
					}

					// terminate parsing and return true
					return true;
				}
			}

			// notification object not found
			return false;
		}

		/**
		 * Dispatch the notification object.
		 * Expected notification properties:
		 * 
		 * {
		 *		id: 		number
		 * 		type: 		string
		 * 		dtime: 		string|Date
		 *		build_url: 	string|null
		 * }
		 * 
		 * @param 	object 	notif 	the notification object.
		 */
		static dispatchNotification(notif) {
			if (typeof notif !== 'object') {
				return false;
			}

			// subscribe to building notification data
			VBOCore.buildNotificationData(notif).then((data) => {
				// dispatch the notification

				// check if the click event should be registered
				let func_nodes;
				if (data.onclick && typeof data.onclick === 'string') {
					let callback_parts = data.onclick.split('.');
					while (callback_parts.length) {
						// compose window static method string to avoid using eval()
						let tmp = callback_parts.shift();
						if (!func_nodes) {
							func_nodes = window[tmp];
						} else {
							func_nodes = func_nodes[tmp];
						}
					}
				}

				// prepare properties to delete the notification from queue
				let match_props = {};
				for (let prop in notif) {
					if (!notif.hasOwnProperty(prop) || prop == 'id_timer') {
						continue;
					}
					match_props[prop] = notif[prop];
				}

				// check browser Notifications API
				if (VBOCore.notificationsEnabled() !== true) {
					// notifications not enabled, fallback to toast message
					let toast_notif_data = {
						title: 	data.title,
						body:  	data.message,
						icon:  	data.icon,
						delay: 	{
							min: 6000,
							max: 20000,
							tolerance: 4000,
						},
						action: () => {
							VBOToast.dispose(true);
						},
						sound: VBOCore.options.notif_audio_url
					};
					if (func_nodes) {
						toast_notif_data.action = function() {
							func_nodes(data);
							VBOToast.dispose(true);
						};
					} else if (typeof data.onclick === 'function') {
						toast_notif_data.action = function() {
							data.onclick.call(data);
							VBOToast.dispose(true);
						};
					}
					VBOToast.enqueue(new VBOToastMessage(toast_notif_data));

					// delete dispatched notification from queue
					VBOCore.updateNotification(match_props, 0);

					return;
				}

				// use the browser's native Notifications API
				let browser_notif = new Notification(data.title, {
					body: data.message,
					icon: data.icon,
					tag:  'vbo_notification',
					silent: false
				});

				// check if support for Web App badge is available
				if (typeof navigator.setAppBadge !== 'undefined') {
					navigator.setAppBadge(1);
				}

				browser_notif.addEventListener('click', (e) => {
					// check if support for Web App badge is available
					if (typeof navigator.setAppBadge !== 'undefined') {
						navigator.clearAppBadge();
					}
					// close the notification
					e.target.close();
				});

				if (func_nodes) {
					// register notification click event
					browser_notif.addEventListener('click', () => {
						func_nodes(data);
					});
				} else if (typeof data.onclick === 'function') {
					browser_notif.addEventListener('click', () => {
						data.onclick.call(data);
					});
				}

				// delete dispatched notification from queue
				VBOCore.updateNotification(match_props, 0);

			}).catch((error) => {
				console.error(error);
			});
		}

		/**
		 * Asynchronous build of the notification data object for dispatch.
		 * Minimum expected notification display data properties:
		 * 
		 * {
		 *		title: 	 string
		 * 		message: string
		 * 		icon: 	 string
		 *		onclick: function
		 * }
		 * 
		 * @param 	object 	notif 	the scheduled notification object.
		 * 
		 * @return 	Promise
		 */
		static buildNotificationData(notif) {
			return new Promise((resolve, reject) => {
				// notification object validation
				if (typeof notif !== 'object') {
					reject('Invalid notification object');
					return;
				}

				if (!notif.hasOwnProperty('build_url') || !notif.build_url) {
					// building callback not necessary
					if (!notif.title && !notif.message) {
						reject('Unexpected notification object');
						return;
					}
					// we expect the notification to be built already
					resolve(notif);
					return;
				}

				// build the notification data
				VBOCore.doAjax(
					notif.build_url,
					{
						payload: JSON.stringify(notif)
					},
					(response) => {
						// parse response
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (obj_res.hasOwnProperty('title')) {
								resolve(obj_res);
							} else {
								reject('Unexpected JSON response');
							}
						} catch(err) {
							reject('could not parse JSON response');
						}
					},
					(error) => {
						reject(error.responseText);
					}
				);
			});
		}

		/**
		 * Handle a navigation towards a given URL.
		 * Common handler for browser notifications click.
		 * 
		 * @param 	object 	data 	notification display data payload.
		 */
		static handleGoto(data) {
			if (typeof data !== 'object' || !data.hasOwnProperty('gotourl') || !data.gotourl) {
				console.error('Could not handle the goto operation', data);
				return;
			}

			if (typeof data.openWindow !== 'undefined' || typeof document === 'undefined') {
				// open a new window
				window.open(data.gotourl);
				return;
			}

			// redirect
			document.location.href = data.gotourl;
		}

		/**
		 * Opens a new window with the URI to render the Push notification data.
		 * 
		 * @param 	object 	options  admin widget rendering options to bind.
		 * 
		 * @return 	void
		 */
		static openAdminPushURI(options) {
			if (typeof options !== 'object' || !options) {
				throw new Error('Unable to build Admin Push URI');
			}

			let vbo_admin_push_uri = VBOCore.options.root_uri;

			if (VBOCore.options.cms === 'wordpress') {
				vbo_admin_push_uri += 'wp-admin/admin.php?page=vikbooking';
			} else {
				vbo_admin_push_uri += 'administrator/index.php?option=com_vikbooking';
			}

			// build Push notification payload for rendering
			let push_data = {
				type: 	 options.type || '',
				title: 	 options.title || '',
				message: options.message || '',
				content: options,
			};

			// open page in a new window
			window.open(vbo_admin_push_uri + '&push_notification=' + btoa(JSON.stringify(push_data)), '_blank');
		}

		/**
		 * Handle the display of a notification through a widget.
		 * Common handler for browser notifications displayed through
		 * a widget modal rendering.
		 * 
		 * @param 	object 	data 	 notification display data payload.
		 * @param 	object 	options  optional extra options for the admin widget.
		 * @param 	boolean is_push  whether we are coming from a Push notification.
		 * 
		 * @return 	void
		 */
		static handleDisplayWidgetNotification(data, options, is_push) {
			try {
				// validate handler
				if (!VBOCore.options.is_vbo && !VBOCore.options.is_vcm) {
					throw new Error('Unable to handle the notification display from the current page');
				}

				// validate payload
				if (typeof data !== 'object' || !data.hasOwnProperty('widget_id') || !data['widget_id']) {
					throw new Error('Invalid widget payload');
				}

				// parse handler
				if (VBOCore.options.is_vcm || (is_push && !VBOCore.options.is_vbo)) {
					// the operation is handled by VCM (or by an external admin resource, if it's a Push notification)
					VBOCore.loadAdminWidgetAssets(data).then((assets) => {
						// append assets to DOM
						assets.forEach((asset) => {
							if (!$('link#' + asset['id']).length) {
								$('head').append('<link rel="stylesheet" id="' + asset['id'] + '" href="' + asset['href'] + '" media="all" />');
							}
						});
						// widget modal rendering handled by VCM (or an external admin resource)
						let hide_panel = VBOCore.options.is_vcm && $('.' + VBOCore.options.panel_opts.open_class).length ? true : false;
						let modal_data = VBOCore.renderModalWidget(data['widget_id'], data, options, hide_panel);
						if (modal_data.hasOwnProperty('dismissed_event') && (modal_data['suffix'] || '').indexOf('inner') < 0) {
							// register event to unload all assets (only if not from an inner modal)
							document.addEventListener(modal_data['dismissed_event'], () => {
								assets.forEach((asset) => {
									if ($('link#' + asset['id']).length) {
										$('link#' + asset['id']).remove();
									}
								});
							});
						}
					}).catch((error) => {
						throw new Error(error);
					});
				} else {
					// widget modal rendering handled by Vik Booking
					VBOCore.renderModalWidget(data['widget_id'], data, options, false);
				}
			} catch(e) {
				if (is_push && options.type) {
					// fallback to opening a new window to render the clicked Push notification
					VBOCore.openAdminPushURI(options);
				} else {
					// fallback to a regular link opening, if set
					VBOCore.handleGoto(data);
				}
			}
		}

		/**
		 * Asynchronous loading of CSS assets required to render
		 * an admin widget outside Vik Booking.
		 * 
		 * @param 	object 	data 	the optional widget payload data.
		 * 
		 * @return 	Promise
		 */
		static loadAdminWidgetAssets(data) {
			return new Promise((resolve, reject) => {
				// the remote assets URI must be set
				if (!VBOCore.options.assets_ajax_uri) {
					reject('Missing remote assets URI');
					return;
				}

				if (typeof data !== 'object') {
					data = {};
				}

				// make the request
				VBOCore.doAjax(
					VBOCore.options.assets_ajax_uri,
					data,
					(response) => {
						// parse response
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!Array.isArray(obj_res)) {
								reject('Unexpected JSON response');
							}
							resolve(obj_res);
						} catch(err) {
							reject('could not parse JSON response');
						}
					},
					(error) => {
						reject(error.responseText);
					}
				);
			});
		}

		/**
		 * Register the latest data to watch for the preloaded admin widgets.
		 * 
		 * @param 	object 	watch_data
		 */
		static registerWatchData(watch_data) {
			if (typeof watch_data !== 'object' || watch_data == null) {
				VBOCore.widgets_watch_data = null;
				return false;
			}

			// set watch-data map
			VBOCore.widgets_watch_data = watch_data;

			// schedule watching interval
			if (VBOCore.watch_data_interval == null) {
				VBOCore.watch_data_interval = window.setInterval(VBOCore.watchWidgetsData, 60000);
			}

			// set up broadcast channels to connect all browsing contexts
			if (typeof BroadcastChannel !== 'undefined') {
				// set up watch-data broadcast channel
				if (!VBOCore.broadcast_watch_data) {
					// start broadcast channel
					VBOCore.broadcast_watch_data = new BroadcastChannel('vikbooking_watch_data');

					// register to the "on broadcast message received" event
					VBOCore.broadcast_watch_data.onmessage = (event) => {
						if (event && event.data) {
							// update watch data map for next schedule to avoid dispatching duplicate notifications
							VBOCore.widgets_watch_data = event.data;
						}
					};
				}

				// set up push-data broadcast channel
				if (!VBOCore.broadcast_push_data) {
					// start broadcast channel
					VBOCore.broadcast_push_data = new BroadcastChannel('vikbooking_push_data');

					// register to the "on broadcast message received" event
					VBOCore.broadcast_push_data.onmessage = (event) => {
						if (event && event.data) {
							// update pushed data map for the next watching event
							VBOCore.widgets_pushed_data.push(event.data);
						}
					};
				}

				// set up watch-events broadcast channel
				if (!VBOCore.broadcast_watch_events) {
					// start broadcast channel
					VBOCore.broadcast_watch_events = new BroadcastChannel('vikbooking_watch_events');

					// register to the "on broadcast message received" event
					VBOCore.broadcast_watch_events.onmessage = (event) => {
						if (event && event.data && typeof event.data === 'object') {
							// scan and dispatch the events data received
							let events_data = event.data;
							for (let ev_name in events_data) {
								if (!events_data.hasOwnProperty(ev_name)) {
									continue;
								}
								// emit the event
								VBOCore.emitEvent(ev_name, events_data[ev_name]);
							}
						}
					};
				}
			}
		}

		/**
		 * Periodic widgets data watching for new events.
		 */
		static watchWidgetsData() {
			if (typeof VBOCore.widgets_watch_data !== 'object' || VBOCore.widgets_watch_data == null) {
				return;
			}

			// call on new events
			VBOCore.doAjax(
				VBOCore.options.watchdata_ajax_uri,
				{
					watch_data:  JSON.stringify(VBOCore.widgets_watch_data),
					pushed_data: JSON.stringify(VBOCore.widgets_pushed_data),
				},
				(response) => {
					try {
						var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
						if (obj_res.hasOwnProperty('watch_data')) {
							// update watch data map for next schedule
							VBOCore.widgets_watch_data = obj_res['watch_data'];

							// check for notifications
							if (obj_res.hasOwnProperty('notifications') && Array.isArray(obj_res['notifications'])) {
								// dispatch notifications
								for (var i = 0; i < obj_res['notifications'].length; i++) {
									VBOCore.dispatchNotification(obj_res['notifications'][i]);
								}

								// post message onto broadcast channel for any other browsing context
								if (VBOCore.broadcast_watch_data && obj_res['notifications'].length) {
									// this will avoid dispatching duplicate notifications
									VBOCore.broadcast_watch_data.postMessage(VBOCore.widgets_watch_data);
								}
							}

							// check for notification events to dispatch
							if (obj_res.hasOwnProperty('events') && Array.isArray(obj_res['events'])) {
								// parse and dispatch all the events
								obj_res['events'].forEach((events_data) => {
									if (typeof events_data !== 'object') {
										return;
									}

									// parse all the events for this widget watched data
									for (let ev_name in events_data) {
										if (!events_data.hasOwnProperty(ev_name)) {
											continue;
										}
										// emit the event
										VBOCore.emitEvent(ev_name, events_data[ev_name]);
									}

									// post message onto broadcast channel for any other browsing context
									if (VBOCore.broadcast_watch_events) {
										// this will trigger the events on any other browsing context
										VBOCore.broadcast_watch_events.postMessage(events_data);
									}
								});
							}
						} else {
							console.error('Unexpected or invalid JSON response', response);
						}
					} catch(err) {
						console.error('could not parse JSON response', err, response);
					}
				},
				(error) => {
					console.error(error.responseText);
				}
			);
		}

		/**
		 * Widget modal rendering.
		 * 
		 * @param 	string 	widget_id 	the widget identifier to render.
		 * @param 	any 	data 		the optional multitask data to inject.
		 * @param 	object 	options 	optional list of extra options to render the widget with Multitask data.
		 * @param 	bool 	hide_panel 	if false, the multitask panel elements will remain unchanged.
		 * 
		 * @return 	object 				the multitask data injected object merged with modal options.
		 */
		static renderModalWidget(widget_id, data, options, hide_panel) {
			/**
			 * Adjust arguments for BC with previous ordering between options
			 * and hide_panel, which used to be inverted. Useful also to shorten
			 * the way the method can be invoked in case no options are needed.
			 */
			if (typeof options === 'boolean') {
				// switch argument values
				hide_panel = options;
				options    = null;
			}

			if (typeof data !== 'object' || data == null) {
				// always treat data as an object
				data = {};
			}

			if (typeof options !== 'object' || options == null) {
				// always treat options as an object
				options = data._options || {};
			}

			// build the default widget payload
			let modal_js_id = Math.floor(Math.random() * 100000);
			let modal_title = options._push && options.title ? options.title : VBOCore.options.tn_texts.admin_widget;
			let widget_data = {
				_modalRendering: 1,
				_modalJsId: modal_js_id,
				_modalTitle: modal_title,
				_options: options,
			};

			// merge default payload options with given options
			data = Object.assign(widget_data, data);

			// define unique modal event names to avoid conflicts
			let dismiss_event = 'vbo-dismiss-widget-modal' + modal_js_id;
			let loading_event = 'vbo-loading-widget-modal' + modal_js_id;
			let resize_event  = 'vbo-resize-widget-modal' + modal_js_id;

			// define the modal options
			let modal_options = {
				suffix: 	     'widget_modal',
				extra_class:     'vbo-modal-widget vbo-modal-rounded vbo-modal-tall vbo-modal-nofooter',
				title: 		     data._modalTitle,
				body_prepend: 	 true,
				lock_scroll: 	 true,
				draggable: 	 	 true,
				enlargeable:     true,
				minimizeable:    VBOCore.options.is_vbo,
				resize_event:    resize_event,
				dismiss_event:   dismiss_event,
				loading_event:   loading_event,
				loading_body:    VBOCore.options.default_loading_body,
				dismissed_event: VBOCore.options.widget_modal_dismissed + modal_js_id,
				event_data: 	 widget_data,
			};

			// check if options should rewrite some modal-options
			if (options.modal_options) {
				modal_options = Object.assign(modal_options, options.modal_options);
			}

			// display modal
			let widget_modal = VBOCore.displayModal(modal_options);

			if (hide_panel !== false) {
				// blur search widget input, hide multitask panel
				$(VBOCore.options.panel_opts.search_selector).trigger('blur');
				VBOCore.emitEvent(VBOCore.multitask_shortcut_event);
			}

			// start loading
			VBOCore.emitEvent(loading_event);

			// render admin widget
			VBOCore.renderAdminWidget(widget_id, data).then((content) => {
				// stop loading and append widget content to modal
				VBOCore.emitEvent(loading_event);
				widget_modal.append(content);

				// register an admin menu action for the rendered widget
				VBOCore.fetchWidgetDetails(widget_id).then((details) => {
					// update modal title, if default title is present
					if (modal_options.title == VBOCore.options.tn_texts.admin_widget) {
						widget_modal
							.closest('.vbo-modal-overlay-content')
							.find('.vbo-modal-overlay-content-head-title')
							.text(data._modalTitle + ' - ' + details.name);
					}

					// check if this widget returned a particular modal setup
					if (details?.modal) {
						if (details.modal?.add_class) {
							// add custom modal class
							widget_modal
								.closest('.vbo-modal-overlay-content')
								.addClass(details.modal.add_class);

							// fire the "resize" event with a delay to support the CSS transition
							setTimeout(() => {
								VBOCore.emitEvent(resize_event, {
									content: widget_modal,
								});
							}, 400);
						}
					}

					// set data for widget details
					widget_modal.data('details', JSON.stringify(details));

					// register admin menu action
					try {
						// work on Local Storage to register the widget data
						VBOCore.registerAdminMenuAction({
							name:    details.name,
							href:    'JavaScript: void(0);',
							widget:  widget_id,
							icon:    details.icon,
							style:   details.style,
						}, 'widgets');
					} catch(e) {
						console.error(e);
					}
				}).catch((error) => {
					console.error(error);
				});
			}).catch((error) => {
				// dismiss modal and display error
				VBOCore.emitEvent(dismiss_event);
				alert(error);
			});

			return Object.assign(data, modal_options);
		}

		/**
		 * Renders an admin widget.
		 * 
		 * @param 	string 	widget_id 	the widget identifier string to add.
		 * @param 	any 	data 		the optional multitask data to inject.
		 * 
		 * @return 	Promise
		 */
		static renderAdminWidget(widget_id, data) {
			return new Promise((resolve, reject) => {
				if (!VBOCore.options.widget_ajax_uri) {
					reject('Could not load admin widget');
					return;
				}

				var call_method = 'render';
				VBOCore.doAjax(
					VBOCore.options.widget_ajax_uri,
					{
						widget_id: 		widget_id,
						call: 	   		call_method,
						vbo_page:  		VBOCore.options.current_page,
						vbo_uri:   		VBOCore.options.current_page_uri,
						multitask: 		1,
						multitask_data: data,
					},
					(response) => {
						// parse response
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method)) {
								reject('Unexpected JSON response');
								return;
							}
							resolve(obj_res[call_method]);
						} catch(err) {
							reject('could not parse JSON response');
						}
					},
					(error) => {
						reject(error.responseText);
					}
				);
			});
		}

		/**
		 * Renders an admin widget "inline", by loading the necessary assets.
		 * To be called outside VikBooking for displaying an admin widget.
		 * 
		 * @param 	string 	widget_id 	the widget identifier string to add.
		 * @param 	any 	data 		the optional multitask data to inject.
		 * 
		 * @return 	Promise
		 */
		static handleDisplayInlineWidget(widget_id, data) {
			return new Promise((resolve, reject) => {
				if (VBOCore.options.is_vbo) {
					reject('Unable to display the inline widget within VikBooking.');
					return;
				}

				VBOCore.loadAdminWidgetAssets(data).then((assets) => {
					// append assets to DOM
					assets.forEach((asset) => {
						if (!$('link#' + asset['id']).length) {
							$('head').append('<link rel="stylesheet" id="' + asset['id'] + '" href="' + asset['href'] + '" media="all" />');
						}
					});
					VBOCore.renderAdminWidget(widget_id, data).then((content) => {
						resolve(content);
					}).catch((error) => {
						reject(error);
					});
				}).catch((error) => {
					reject(error);
				});
			});
		}

		/**
		 * Fetches the details for a specific widget.
		 * 
		 * @param 	string 	widget_id 	the widget identifier string to fetch.
		 * 
		 * @return 	Promise
		 * 
		 * @since 	1.6.7
		 */
		static fetchWidgetDetails(widget_id) {
			return new Promise((resolve, reject) => {
				if (!VBOCore.options.widget_ajax_uri) {
					reject('Could not load admin widget');
					return;
				}

				var call_method = 'getWidgetDetails';
				VBOCore.doAjax(
					VBOCore.options.widget_ajax_uri,
					{
						widget_id: widget_id,
						call: 	   call_method,
						return:    1,
					},
					(response) => {
						// parse response
						try {
							var obj_res = typeof response === 'string' ? JSON.parse(response) : response;
							if (!obj_res.hasOwnProperty(call_method)) {
								reject('Unexpected JSON response');
								return;
							}
							resolve(obj_res[call_method]);
						} catch(err) {
							reject('could not parse JSON response');
						}
					},
					(error) => {
						reject(error.responseText);
					}
				);
			});
		}

		/**
		 * Helper method used to copy the text of an
		 * input element within the clipboard.
		 *
		 * Clipboard copy will take effect only in case the
		 * function is handled by a DOM event explicitly
		 * triggered by the user, such as a "click".
		 *
		 * @param 	any 	input 	The input containing the text to copy.
		 *
		 * @return 	Promise
		 */
		static copyToClipboard(input) {
			// register and return promise
			return new Promise((resolve, reject) => {
				// define a fallback function
				var fallback = function(input) {
					// focus the input
					input.focus();
					// select the text inside the input
					input.select();

					try {
						// try to copy with shell command
						var copy = document.execCommand('copy');

						if (copy) {
							// copied successfully
							resolve(copy);
						} else {
							// unable to copy
							reject(copy);
						}
					} catch (error) {
						// unable to exec the command
						reject(error);
					}
				};

				// look for navigator clipboard
				if (!navigator || !navigator.clipboard) {
					// navigator clipboard not supported, use fallback
					fallback(input);
					return;
				}

				// try to copy within the clipboard by using the navigator
				navigator.clipboard.writeText((input.val ? input.val() : input.value)).then(() => {
					// copied successfully
					resolve(true);
				}).catch((error) => {
					// revert to the fallback
					fallback(input);
				});
			});
		}

		/**
		 * Helper method used to display a modal window dinamycally.
		 *
		 * @param   object  options     The options to render the modal.
		 * @param   object  bindDetails Optional data to bind to the modal content.
		 *
		 * @return  object              The modal content element wrapper.
		 */
		static displayModal(options, bindDetails) {
			var def_options = {
				suffix:          (Math.floor(Math.random() * 100000)) + '',
				extra_class:     null,
				header:          true,
				title:           '',
				body:            '',
				body_prepend:    false,
				lock_scroll:     false,
				draggable:       false,
				enlargeable:     false,
				minimizeable:    false,
				escape_dismiss:  true,
				footer_left:     null,
				footer_right:    null,
				resize_event:    null,
				dismiss_event:   null,
				dismissed_event: 'vbo-modal-dismissed',
				onDismiss:       null,
				onMinimize:      null,
				onRestore:       null,
				loading_event:   null,
				loading_body:    VBOCore.options.default_loading_body,
				progress_event:  null,
				event_data:      null,
			};

			if (options.event_data && typeof options.event_data === 'object') {
				// get rid of possible cyclic object references
				options.event_data = Object.assign({}, options.event_data);
			}

			// merge default options with given options
			options = Object.assign(def_options, options);

			// create the modal destroy function
			const modal_destroy_fn = (e) => {
				// invoke callback for onDismiss
				if (typeof options.onDismiss === 'function') {
					options.onDismiss.call(custom_modal, e);
				}

				// check if modal did register to the loading event
				if (options.loading_event) {
					// we can now un-register from the loading event until a new modal is displayed and will register to it again
					document.removeEventListener(options.loading_event, modal_handle_loading_event_fn);
					if (options.progress_event) {
						// we can now un-register from the progress event
						document.removeEventListener(options.progress_event, modal_handle_progress_event_fn);
					}
				}

				// check if we should fire the given modal dismissed event
				if (options.dismissed_event) {
					VBOCore.emitEvent(options.dismissed_event, options.event_data);
				}

				// check if body scroll lock should be removed
				if (options.lock_scroll) {
					$('body').removeClass('vbo-modal-lock-scroll');
				}

				// remove modal from DOM
				custom_modal.remove();
			};

			// create the modal dismiss function
			const modal_dismiss_fn = (e) => {
				custom_modal.fadeOut(400, () => {
					// destroy the modal
					modal_destroy_fn.call(custom_modal, e);
				});
			};

			// create the modal loading event handler function
			const modal_handle_loading_event_fn = (e) => {
				// toggle modal loading
				if ($('.vbo-modal-overlay-content-backdrop').length) {
					// hide loading
					$('.vbo-modal-overlay-content-backdrop').remove();

					// do not proceed
					return;
				}

				// show loading
				var modal_loading = $('<div></div>').addClass('vbo-modal-overlay-content-backdrop');
				var modal_loading_body = $('<div></div>').addClass('vbo-modal-overlay-content-backdrop-body');
				if (options.loading_body) {
					modal_loading_body.append(options.loading_body);
				}
				modal_loading.append(modal_loading_body);

				// append backdrop loading to modal content
				modal_content.prepend(modal_loading);
			};

			// create the modal progress event handler function
			const modal_handle_progress_event_fn = (e) => {
				if (!e || !e.detail || !e.detail.progress_content) {
					// do not proceed
					return;
				}

				// identify the current loading backdrop body
				let backdrop_body = modal_content.find('.vbo-modal-overlay-content-backdrop-body');
				if (!backdrop_body.length) {
					// loading body not found
					return;
				}

				let backdrop_txt_el = $('<div></div>').addClass('vbo-modal-overlay-content-backdrop-text');
				if (typeof e.detail.progress_content === 'string') {
					backdrop_txt_el.html(e.detail.progress_content);
				} else {
					backdrop_txt_el.append(e.detail.progress_content);
				}

				let backdrop_txt_old = backdrop_body.find('.vbo-modal-overlay-content-backdrop-text');
				if (backdrop_txt_old.length) {
					// remove the previous text element
					backdrop_txt_old.remove();
				}

				// set the loading progress content
				backdrop_body.append(backdrop_txt_el);
			};

			// create the modal enlarge (toggle) function
			const modal_enlarge_fn = (e) => {
				// toggle modal fullscreen class
				modal_content.toggleClass('vbo-modal-fullscreen');

				// check if modal did register a resize event
				if (options.resize_event) {
					// fire the requested event with a delay to support the CSS transition
					setTimeout(() => {
						VBOCore.emitEvent(options.resize_event, {
							content: modal_content,
						});
					}, 400);
				}
			};

			// create the modal minimize function
			const modal_minimize_fn = (e) => {
				// invoke callback for onMinimize
				if (typeof options.onMinimize === 'function') {
					options.onMinimize.call(custom_modal, e);
				}

				// start minimizing animation
				custom_modal.removeClass('vbo-restoring');
				modal_content.removeClass('vbo-restoring');
				custom_modal.addClass('vbo-minimizing');
				modal_content.addClass('vbo-minimizing');

				// access the modal body details data, if any
				let details_data = modal_content_wrapper.data('details');
				try {
					if (details_data && typeof details_data === 'string') {
						details_data = JSON.parse(details_data);
					}
				} catch(e) {
					details_data = {};
				}

				// register delayed partial-distruction
				setTimeout(() => {
					// hide modal
					custom_modal.hide();

					// check if body scroll lock should be removed
					if (options.lock_scroll) {
						$('body').removeClass('vbo-modal-lock-scroll');
					}

					// add the minimized widget to dock
					VBOCore.getAdminDock().addWidget(details_data, options, modal_content_wrapper, modal_destroy_fn);

					// remove modal from DOM without firing the dismiss events (do not destroy the modal)
					custom_modal.remove();
				}, 400);
			};

			// start the modal position variables
			var modal_pos_x = 0, modal_pos_y = 0;

			// create the modal drag-start (mousedown) event handler function
			const modal_dragstart_fn = (e) => {
				e = e || window.event;
				e.preventDefault();

				if (typeof e.clientX === 'undefined' || typeof e.clientY === 'undefined') {
					// unsupported
					return;
				}

				if (e.target && !e.target.matches('.vbo-modal-overlay-cmd')) {
					e.target.style.cursor = 'move';
				}

				// store the initial modal (cursor) position
				modal_pos_x = e.clientX;
				modal_pos_y = e.clientY;

				// register mouseup and mousemove events
				document.onmouseup   = modal_dragstop_fn;
				document.onmousemove = modal_dragmove_fn;
			};

			// create the modal drag-stop (mouseup) event handler function
			const modal_dragstop_fn = (e) => {
				e = e || window.event;

				if (e.target && !e.target.matches('.vbo-modal-overlay-cmd')) {
					e.target.style.cursor = 'auto';
				}

				// unregister mousemove event
				if (document.onmousemove == modal_dragmove_fn) {
					document.onmousemove = null;
				}

				// unregister mouseup event
				if (document.onmouseup == modal_dragstop_fn) {
					document.onmouseup = null;
				}
			};

			// create the modal drag-move (mousemove) event handler function
			const modal_dragmove_fn = (e) => {
				e = e || window.event;
				e.preventDefault();

				if (typeof e.clientX === 'undefined' || typeof e.clientY === 'undefined') {
					// unsupported
					return;
				}

				// calculate the new modal (cursor) position
				let new_modal_pos_x = modal_pos_x - e.clientX;
				let new_modal_pos_y = modal_pos_y - e.clientY;

				// update current modal (cursor) position
				modal_pos_x = e.clientX;
				modal_pos_y = e.clientY;

				// find the modal element
				let modal_element = e?.target?.closest('.vbo-modal-overlay-content');
				if (!modal_element) {
					return;
				}

				// set the modal position
				modal_element.style.top  = (modal_element.offsetTop - new_modal_pos_y) + 'px';
				modal_element.style.left = (modal_element.offsetLeft - new_modal_pos_x) + 'px';
			};

			// build modal content
			const custom_modal = $('<div></div>').addClass('vbo-modal-overlay-block vbo-modal-overlay-' + options.suffix).css('display', 'block');
			var modal_dismiss = $('<a></a>').addClass('vbo-modal-overlay-close');
			modal_dismiss.on('click', modal_dismiss_fn);
			custom_modal.append(modal_dismiss);

			const modal_content = $('<div></div>').addClass('vbo-modal-overlay-content vbo-modal-overlay-content-' + options.suffix);
			if (options.extra_class && typeof options.extra_class === 'string') {
				modal_content.addClass(options.extra_class);
			}

			// modal head and title
			const modal_head = $('<div></div>').addClass('vbo-modal-overlay-content-head');
			if (options.title) {
				let modal_title = $('<span></span>').addClass('vbo-modal-overlay-content-head-title').html(options.title);
				modal_head.append(modal_title);
			} else {
				modal_head.addClass('vbo-modal-head-no-title');
			}
			// modal head commands
			var modal_head_cmds = $('<span></span>').addClass('vbo-modal-overlay-cmds');
			var modal_head_close = $('<span></span>').addClass('vbo-modal-overlay-cmd vbo-modal-overlay-close-times').html('&times;');
			modal_head_close.on('click', modal_dismiss_fn);
			modal_head_cmds.append(modal_head_close);
			if (options.enlargeable) {
				var modal_head_enlarge = $('<span></span>').addClass('vbo-modal-overlay-cmd vbo-modal-overlay-cmd-enlarge').html('&square;');
				modal_head_enlarge.on('click', modal_enlarge_fn);
				modal_head_cmds.append(modal_head_enlarge);
				modal_head.on('dblclick', modal_enlarge_fn);
			}
			if (options.minimizeable && options.event_data) {
				// set up the minimize command
				var modal_head_minimize = $('<span></span>').addClass('vbo-modal-overlay-cmd vbo-modal-overlay-cmd-minimize').html('&minus;');
				modal_head_minimize.on('click', modal_minimize_fn);
				modal_head_cmds.append(modal_head_minimize);
			}
			// set commands
			modal_head.append(modal_head_cmds);

			// check if the modal head should be draggable
			if (options.draggable) {
				// register the event(s) to allow dragging
				modal_head.addClass('vbo-modal-head-draggable');
				modal_head.on('contextmenu', (e) => {
					e.preventDefault();
				});
				modal_head.on('mousedown', modal_dragstart_fn);
			}

			const modal_body = $('<div></div>').addClass('vbo-modal-overlay-content-body vbo-modal-overlay-content-body-scroll');
			const modal_content_wrapper = $('<div></div>').addClass('vbo-modal-' + options.suffix + '-wrap');
			if (options.suffix != 'widget_modal') {
				modal_content_wrapper.addClass('vbo-modal-widget_modal-wrap');
			}
			if (typeof options.body === 'string') {
				modal_content_wrapper.html(options.body);
			} else {
				modal_content_wrapper.append(options.body);
			}
			modal_body.append(modal_content_wrapper);

			// modal footer
			let modal_footer = null;
			if (options.footer_left || options.footer_right) {
				modal_footer = $('<div></div>').addClass('vbo-modal-overlay-content-footer');
				if (options.footer_left) {
					let modal_footer_left = $('<div></div>').addClass('vbo-modal-overlay-content-footer-left').append(options.footer_left);
					modal_footer.append(modal_footer_left);
				}
				if (options.footer_right) {
					let modal_footer_right = $('<div></div>').addClass('vbo-modal-overlay-content-footer-right').append(options.footer_right);
					modal_footer.append(modal_footer_right);
				}

			}

			// finalize modal contents
			if (options.header) {
				// append header
				modal_content.append(modal_head);
			}
			// append body
			modal_content.append(modal_body);
			if (modal_footer) {
				// append footer
				modal_content.append(modal_footer);
			}
			custom_modal.append(modal_content);

			// register to the dismiss event
			if (options.dismiss_event) {
				// listen to the event that will dismiss the modal
				document.addEventListener(options.dismiss_event, function vbo_core_handle_dismiss_event(e) {
					// make sure the same event won't propagate again, unless a new modal is displayed (multiple displayModal calls)
					e.target.removeEventListener(e.type, vbo_core_handle_dismiss_event);

					// invoke the modal dismiss function
					modal_dismiss_fn(e);
				});

				// declare the function to detect the Escape key pressed
				const vbo_core_dismiss_event_modal_escape = (e) => {
					if (!e.key || e.key != 'Escape') {
						return;
					}

					// immediately unregister from this event once fired
					window.removeEventListener(e.type, vbo_core_dismiss_event_modal_escape);

					// trigger the actual dismiss event
					VBOCore.emitEvent(options.dismiss_event);
				};

				if (options.escape_dismiss) {
					// listen to the Escape keyup event to dismiss the modal
					// listen on window to allow admin-widgets to prevent the default behavior and stop the propagation
					window.addEventListener('keyup', vbo_core_dismiss_event_modal_escape);
				}
			}

			// register to the toggle-loading event
			if (options.loading_event) {
				// let a function handle it so that removing the event listener will be doable
				document.addEventListener(options.loading_event, modal_handle_loading_event_fn);
				if (options.progress_event) {
					// let a function handle the progress event so that removing the listener will be doable
					document.addEventListener(options.progress_event, modal_handle_progress_event_fn);
				}
			}

			// append (or prepend) modal to body
			if ($('.vbo-modal-overlay-' + options.suffix).length) {
				$('.vbo-modal-overlay-' + options.suffix).remove();
			}
			if (options.body_prepend) {
				// prepend to body
				if ($('body > .vbo-modal-overlay-block').length) {
					// we've got other modals prepended to the body, so go after the last one
					$('body > .vbo-modal-overlay-block').last().after(custom_modal);
				} else {
					// place the modal right as the first child node of body
					$('body').prepend(custom_modal);
				}
			} else {
				// append to body
				$('body').append(custom_modal);
			}

			// check if scroll should be locked on the whole page body for a "sticky" modal
			if (options.lock_scroll) {
				$('body').addClass('vbo-modal-lock-scroll');
			}

			if (typeof bindDetails === 'object') {
				try {
					// bind widget details data
					modal_content_wrapper.data('details', JSON.stringify(bindDetails));
				} catch(e) {
					// do nothing
				}
			}

			// return the content wrapper element of the new modal
			return modal_content_wrapper;
		}

		/**
		 * Debounce technique to group a flurry of events into one single event.
		 */
		static debounceEvent(func, wait, immediate) {
			var timeout;
			return function() {
				var context = this, args = arguments;
				var later = function() {
					timeout = null;
					if (!immediate) func.apply(context, args);
				};
				var callNow = immediate && !timeout;
				clearTimeout(timeout);
				timeout = setTimeout(later, wait);
				if (callNow) {
					func.apply(context, args);
				}
			}
		}

		/**
		 * Throttle guarantees a constant flow of events at a given time interval.
		 * Runs immediately when the event takes place, but can be delayed.
		 */
		static throttleEvent(method, delay) {
			var time = Date.now();
			return function() {
				if ((time + delay - Date.now()) < 0) {
					method();
					time = Date.now();
				}
			}
		}

		/**
		 * Alternative throttle technique for event listeners.
		 * 
		 * @param 	function 	callback 	the callback to invoke.
		 * @param 	int 		time 		the time (in ms) to throttle.
		 * 
		 * @return 	void
		 * 
		 * @since 	1.6.8
		 */
		static throttleTimer(callback, time) {
			if (VBOCore.throttle_timer) {
				// prevent more executions
				return;
			}

			// turn throttle timer on
			VBOCore.throttle_timer = true;

			setTimeout(() => {
				// run the callback with the given delay
				callback();

				// turn throttle timer off
				VBOCore.throttle_timer = false;
			}, time);
		}

		/**
		 * Tells whether localStorage is supported.
		 * 
		 * @return 	boolean
		 */
		static storageSupported() {
			return typeof localStorage !== 'undefined';
		}

		/**
		 * Gets an item from localStorage.
		 * 
		 * @param 	string 	keyName 	the storage key identifier.
		 * 
		 * @return 	any
		 */
		static storageGetItem(keyName) {
			if (!VBOCore.storageSupported()) {
				return null;
			}

			return localStorage.getItem(keyName);
		}

		/**
		 * Sets an item to localStorage.
		 * 
		 * @param 	string 	keyName 	the storage key identifier.
		 * @param 	any 	value 		the value to store.
		 * 
		 * @return 	boolean
		 */
		static storageSetItem(keyName, value) {
			if (!VBOCore.storageSupported()) {
				return false;
			}

			try {
				if (typeof value === 'object') {
					value = JSON.stringify(value);
				}

				localStorage.setItem(keyName, value);
			} catch(e) {
				console.error(e);
				return false;
			}

			return true;
		}

		/**
		 * Removes an item from localStorage.
		 * 
		 * @param 	string 	keyName 	the storage key identifier.
		 * 
		 * @return 	boolean
		 */
		static storageRemoveItem(keyName) {
			if (!VBOCore.storageSupported()) {
				return false;
			}

			localStorage.removeItem(keyName);

			return true;
		}

		/**
		 * Returns the name of the storage identifier for the given scope.
		 * 
		 * @param 	string 	scope 	the admin menu scope.
		 * 
		 * @return 	string 			the requested admin menu storage identifier.
		 */
		static getStorageScopeName(scope) {
			let storage_scope_name = VBOCore.options.admin_menu_actions_nm;

			if (typeof scope === 'string' && scope.length) {
				if (scope.indexOf('.') !== 0) {
					scope = '.' + scope;
				}
				storage_scope_name += scope;
			}

			return storage_scope_name;
		}

		/**
		 * Returns a list of admin menu action objects or an empty array.
		 * 
		 * @param 	string 	scope 	the admin menu scope.
		 * 
		 * @return 	Array
		 */
		static getAdminMenuActions(scope) {
			let menu_actions = VBOCore.storageGetItem(VBOCore.getStorageScopeName(scope));

			if (!menu_actions) {
				return [];
			}

			try {
				menu_actions = JSON.parse(menu_actions);
				if (!Array.isArray(menu_actions) || !menu_actions.length) {
					menu_actions = [];
				}
			} catch(e) {
				return [];
			}

			return menu_actions;
		}

		/**
		 * Builds an admin menu action object with a proper href property.
		 * 
		 * @param 	object 	action 	the action to build.
		 * 
		 * @return 	object
		 */
		static buildAdminMenuAction(action) {
			if (typeof action !== 'object' || !action || !action.hasOwnProperty('name')) {
				throw new Error('Invalid action object');
			}

			var action_base = action.hasOwnProperty('href') && typeof action['href'] == 'string' ? action['href'] : window.location.href;
			var action_url;

			if (action_base.toLowerCase().indexOf('javascript') === 0 && action.hasOwnProperty('widget')) {
				// no need to prepare the action URL ("JavaScript: void(0)") as the link will use a JS callback
				return action;
			}

			if (action_base.indexOf('http') !== 0) {
				// relative URL
				action_url = new URL(action_base, window.location.href);
			} else {
				// absolute URL
				action_url = new URL(action_base);
			}

			// build proper href with a relative URL
			action['href'] = action_url.pathname + action_url.search;

			return action;
		}

		/**
		 * Registers an admin menu action object.
		 * 
		 * @param 	object 	action 	the action to build.
		 * @param 	string 	scope 	the admin menu scope.
		 * 
		 * @return 	boolean
		 */
		static registerAdminMenuAction(action, scope) {
			// build menu action object
			let menu_action_entry = VBOCore.buildAdminMenuAction(action);

			let menu_actions = VBOCore.getAdminMenuActions(scope);

			// make sure we are not pushing a duplicate and count pinned actions
			let pinned_actions = 0;
			let unpinned_index = [];
			for (let i = 0; i < menu_actions.length; i++) {
				// avoid duplicate entries
				if (!menu_action_entry.hasOwnProperty('widget') && menu_actions[i]['href'] == menu_action_entry['href']) {
					// duplicate link
					return false;
				}
				if (menu_action_entry.hasOwnProperty('widget') && menu_actions[i].hasOwnProperty('widget') && menu_actions[i]['widget'] == menu_action_entry['widget']) {
					// duplicate widget
					return false;
				}
				if (menu_actions[i].hasOwnProperty('pinned') && menu_actions[i]['pinned']) {
					pinned_actions++;
				} else {
					unpinned_index.push(i);
				}
			}

			if (pinned_actions >= VBOCore.options.admin_menu_maxactions) {
				// no more space to register a new menu action for this admin menu
				return false;
			}

			// splice or pop before prepending to keep current indexes
			let tot_menu_actions = menu_actions.length;
			if (++tot_menu_actions > VBOCore.options.admin_menu_maxactions) {
				if (unpinned_index.length) {
					menu_actions.splice(unpinned_index[unpinned_index.length - 1], 1);
				} else {
					menu_actions.pop();
				}
			}

			// prepend new admin menu action
			menu_actions.unshift(menu_action_entry);

			return VBOCore.storageSetItem(VBOCore.getStorageScopeName(scope), menu_actions);
		}

		/**
		 * Updates an existing admin menu action object.
		 * 
		 * @param 	object 	action 	the action to build.
		 * @param 	string 	scope 	the admin menu scope.
		 * @param 	number 	index 	optional menu action index.
		 * 
		 * @return 	boolean
		 */
		static updateAdminMenuAction(action, scope, index) {
			// build menu action object
			let menu_action_entry = VBOCore.buildAdminMenuAction(action);

			let menu_actions = VBOCore.getAdminMenuActions(scope);

			if (!menu_actions.length) {
				return false;
			}

			if (typeof index === 'undefined') {
				// find the proper index to update by href
				for (let i = 0; i < menu_actions.length; i++) {
					if (menu_actions[i].hasOwnProperty('widget') && menu_action_entry.hasOwnProperty('widget') && menu_actions[i]['widget'] == menu_action_entry['widget']) {
						// existing entry for widget found
						index = i;
						break;
					} else if (!menu_action_entry.hasOwnProperty('widget') && menu_actions[i]['href'] == menu_action_entry['href']) {
						// existing entry for link found
						index = i;
						break;
					}
				}
			}

			if (isNaN(index) || !(index in menu_actions)) {
				// menu entry index not found
				return false;
			}

			menu_actions[index] = menu_action_entry;

			return VBOCore.storageSetItem(VBOCore.getStorageScopeName(scope), menu_actions);
		}

		/**
		 * Checks if the current menu actions should be filled with some other actions.
		 * No update is made over the Local Storage through this method.
		 * 
		 * @param 	array 	menu_actions  	 menu actions to fill.
		 * @param 	array 	widgets_actions  default actions to use for filling.
		 * @param 	string 	scope 			 the admin menu scope.
		 * 
		 * @return 	array 					 the menu actions eventually filled.
		 */
		static fillAdminMenuActions(menu_actions, widgets_actions, scope) {
			if (!Array.isArray(menu_actions) || !Array.isArray(widgets_actions)) {
				return [];
			}

			if (!menu_actions.length || !widgets_actions.length || menu_actions.length >= VBOCore.options.admin_menu_maxactions) {
				return menu_actions;
			}

			var current_widgets = [];
			menu_actions.forEach((action, index) => {
				current_widgets.push(action['widget']);
			});

			for (var i = 0; i < widgets_actions.length; i++) {
				if (menu_actions.length >= VBOCore.options.admin_menu_maxactions) {
					// abort for filling completed
					break;
				}

				if (!widgets_actions[i].hasOwnProperty('widget')) {
					// action must be for a widget
					continue;
				}

				if (current_widgets.includes(widgets_actions[i]['widget'])) {
					// there cannot be duplicate entries
					continue;
				}

				// fill menu action
				menu_actions.push(widgets_actions[i]);
			}

			return menu_actions;
		}

		/**
		 * Formats a date object by accepting "Y", "m" and "d".
		 * 
		 * @param 	Date 	date 	The date object to format.
		 * @param 	string 	format 	The date format to use.
		 * 
		 * @return 	string
		 */
		static formatDate(date, format) {
			if (!date instanceof Date) {
				throw new Error('Invalid date object given.');
			}

			if (!format || typeof format !== 'string') {
				// default to military format
				format = 'Y-m-d';
			}

			let year = date.getFullYear();
			let month = (date.getMonth() + 1) + '';
			let mday = (date.getDate()) + '';

			month = month.length < 2 ? '0' + month : month;
			mday = mday.length < 2 ? '0' + mday : mday;

			// use a regex to capture the date separator and format identifiers
			const regexp = /^([ymd])([\s\.\-\/])([ymd])([\s\.\-\/])([ymd])$/gi;

			// turn the iterable iterator object into an array by using the spread syntax
			let formatArray = [...format.matchAll(regexp)];

			if (!formatArray.length || !Array.isArray(formatArray[0]) || formatArray[0].length != 6) {
				throw new Error('Invalid date format given.');
			}

			let firstIdentifier = (formatArray[0][1] + '').toLowerCase();
			let separatorChar = formatArray[0][2];
			let secondIdentifier = (formatArray[0][3] + '').toLowerCase();
			let thirdIdentifier = (formatArray[0][5] + '').toLowerCase();

			if (!separatorChar) {
				throw new Error('Invalid date format separator given.');
			}

			let dateParts = [];

			if (firstIdentifier == 'y') {
				dateParts.push(year);
			} else if (firstIdentifier == 'm') {
				dateParts.push(month);
			} else {
				dateParts.push(mday);
			}

			if (secondIdentifier == 'y') {
				dateParts.push(year);
			} else if (secondIdentifier == 'm') {
				dateParts.push(month);
			} else {
				dateParts.push(mday);
			}

			if (thirdIdentifier == 'y') {
				dateParts.push(year);
			} else if (thirdIdentifier == 'm') {
				dateParts.push(month);
			} else {
				dateParts.push(mday);
			}

			return dateParts.join(separatorChar);
		}

		/**
		 * Proxy to access the VBOCurrency object.
		 * 
		 * @param 	object 	options The currency options.
		 * 
		 * @return 	VBOCurrency
		 */
		static getCurrency(options) {
			return VBOCurrency.getInstance(options);
		}

		/**
		 * Proxy to access the VBOAdminDock object.
		 * 
		 * @return 	VBOAdminDock
		 */
		static getAdminDock() {
			return VBOAdminDock.getInstance();
		}
	}

	/**
	 * These used to be private static properties (static #options),
	 * but they are only supported by quite recent browsers (especially Safari).
	 * It's too premature, so we decided to keep the class properties public
	 * without declaring them as static inside the class declaration.
	 * 
	 * @var  object
	 */
	VBOCore.options = CORE_OPTIONS || {
		is_vbo: 				false,
		is_vcm: 				false,
		cms: 					'wordpress',
		widget_ajax_uri: 		null,
		assets_ajax_uri: 		null,
		multitask_ajax_uri: 	null,
		watchdata_ajax_uri: 	null,
		current_page: 			null,
		current_page_uri: 		null,
		root_uri: 				'/',
		client: 				'admin',
		panel_opts: 			{},
		admin_widgets: 			[],
		events_delegated:       [],
		notif_audio_url: 		'',
		active_listeners: 		{},
		tn_texts: 				{
			notifs_enabled: 		'Browser notifications are enabled!',
			notifs_disabled: 		'Browser notifications are disabled',
			notifs_disabled_help: 	"Could not enable browser notifications.\nThis feature is available only in secure contexts (HTTPS).",
			admin_widget: 			'Admin widget',
			congrats: 				'Congratulations!',
		},
		default_loading_body: 	'....',
		multitask_save_event: 	'vbo-admin-multitask-save',
		multitask_open_event: 	'vbo-admin-multitask-open',
		multitask_close_event: 	'vbo-admin-multitask-close',
		multitask_shortcut_ev: 	'vbo_multitask_shortcut',
		multitask_searchfs_ev: 	'vbo_multitask_search_focus',
		widget_modal_rendered: 	'vbo-admin-widget-modal-rendered',
		widget_modal_dismissed: 'vbo-widget-modal-dismissed',
		admin_menu_maxactions: 	3,
		admin_menu_actions_nm: 	'vikbooking.admin_menu.actions',
		service_worker_path: 	'',
		service_worker_scope: 	'./',
		push: 					{
			application_key: '',
			ajax_url: 		 '',
		},
		push_options: {
			storage_endp_id: 	 'vbo_push_subscr_endp',
			allowed_notif_types: [
				'Book',
				'Modify',
				'Cancel',
				'Request',
				'CancelRequest',
				'Inquiry',
				'CancelInquiry',
				'Chat',
				'Info',
			],
		},
	};

	/**
	 * @var  bool
	 */
	VBOCore.side_panel_on = false;

	/**
	 * @var  	bool
	 * @since 	1.6.8
	 */
	VBOCore.throttle_timer = false;

	/**
	 * @var  array
	 */
	VBOCore.notifications = [];

	/**
	 * @var  object
	 */
	VBOCore.widgets_watch_data = null;

	/**
	 * @var  number
	 */
	VBOCore.watch_data_interval = null;

	/**
	 * @var  	object
	 * @since 	1.6.3
	 */
	VBOCore.broadcast_watch_data = null;

	/**
	 * @var  	object
	 * @since 	1.6.5
	 */
	VBOCore.broadcast_push_data = null;

	/**
	 * @var  	object
	 * @since 	1.6.8
	 */
	VBOCore.broadcast_watch_events = null;

	/**
	 * @var  	array<object>
	 * @since 	1.6.5
	 */
	VBOCore.widgets_pushed_data = [];

	/**
	 * Checks if the KeyBoard event matches the given shortcut.
	 *
	 * @param 	array 	 keys 	The shortcut representation.
	 *
	 * @return 	boolean  True if matches, otherwise false.
	 * 
	 * @since 	1.7.0
	 */
	KeyboardEvent.prototype.shortcut = function(keys) {
		// get modifiers list
		var modifiers = keys.slice(0);
		// pop character from modifiers
		var keyCode = modifiers.pop();

		if (typeof keyCode === 'string') {
			// get ASCII
			keyCode = keyCode.toUpperCase().charCodeAt(0);
		}

		// make sure the modifiers are lower case
		modifiers = modifiers.map(function(mod) {
			return mod.toLowerCase();
		});

		var ok = false;

		// validate key code
		if (this.keyCode == keyCode) {
			// validate modifiers
			ok = true;
			var lookup = ['meta', 'shift', 'alt', 'ctrl'];

			for (var i = 0; i < lookup.length && ok; i++) {
				// check if modifiers is pressed
				var mod = this[lookup[i] + 'Key'];

				if (mod) {
					// if pressed, the shortcut must specify it
					ok &= modifiers.indexOf(lookup[i]) !== -1;
				} else {
					// if not pressed, the shortcut must not include it
					ok &= modifiers.indexOf(lookup[i]) === -1;
				}
			}
		}

		return ok;
	}

	/**
	 * VBOCurrency class implementation.
	 */
	w['VBOCurrency'] = class VBOCurrency {
		/**
		 * Singleton entry-point.
		 * 
		 * @see construct()
		 */
		static getInstance(options) {
			if (typeof VBOCurrency.instance === 'undefined') {
				VBOCurrency.instance = new VBOCurrency(options);
			}

			return VBOCurrency.instance;
		}

		/**
		 * Class constructor.
		 * 
		 * @param  object  options  The currency options object:
		 *                          - symbol           string  The currency symbol (such as €, $, £ and so on).
		 *                          - position         int     The position of the currency (1 before, 2 after). In case the amount is negative
		 *                                                     the space between the currency and the amount won't be used.
		 *                          - decimals         string  The decimals separator character ("." or ",").
		 *                          - thousands        string  The thousands separator character ("," or ".").
		 *                          - digits           int     The number of decimal digits.
		 *                          - noDecimals       int     Whether empty decimals should be omitted (1 true, 0 false).
		 *                          - conversionRate   float   The currency conversion rate.
		 */
		constructor(options) {
			this.setOptions(options);
		}

		/**
		 * Sets the currency options.
		 * 
		 * @param  object  options  The currency options object.
		 * 
		 * @see    construct()
		 */
		setOptions(options) {
			if (options === undefined) {
				options = {};
			}

			// define default currency options for eventually merging with new options
			let def_symbol      = this.symbol !== undefined ? this.symbol : '$';
			let def_position    = this.position !== undefined ? this.position : 1;
			let def_decimals    = this.decimals !== undefined ? this.decimals : '.';
			let def_thousands   = this.thousands !== undefined ? this.thousands : ',';
			let def_digits      = this.digits !== undefined ? this.digits : 2;
			let def_no_decimals = this.noDecimals !== undefined ? this.noDecimals : 1;
			let def_conv_rate   = this.conversionRate !== undefined ? this.conversionRate : 1;

			// normalize option properties
			if (options.position && /^[a-zA-Z]+$/.test(options.position)) {
				// convert alphanumeric position to integer
				options.position = options.position.toLowerCase() === 'after' ? 2 : 1;
			}

			// set currency options
			this.symbol      = (options.hasOwnProperty('symbol')      ? options.symbol    : def_symbol);
			this.position    = (options.hasOwnProperty('position')    ? options.position  : def_position);
			this.decimals    = (options.hasOwnProperty('decimals')    ? options.decimals  : def_decimals);
			this.thousands   = (options.hasOwnProperty('thousands')   ? options.thousands : def_thousands);
			this.digits      = (options.hasOwnProperty('digits')      ? parseInt(options.digits) : def_digits);
			this.noDecimals  = (options.hasOwnProperty('noDecimals')  ? parseInt(options.noDecimals) : def_no_decimals);
			this.conversionRate = Math.abs((options.hasOwnProperty('conversionRate') ? parseFloat(options.conversionRate) : 1));
		}

		/**
		 * Gets the current currency options.
		 * 
		 * @return 	object
		 */
		getOptions() {
			let options = {};

			Object.keys(this).forEach((option) => {
				if (this.hasOwnProperty(option)) {
					options[option] = this[option];
				}
			});

			return options;
		}

		/**
		 * Formats the given price according to the configuration preferences.
		 * 
		 * @param   float   price    The price to format.
		 * @param   object  options  Temporarily overrides the currency options.
		 * 
		 * @return  string  The formatted price.
		 */
		format(price, options) {
			// merge currency settings
			options = Object.assign(this.getOptions(), (options || {}));

			let no_decimals = options.noDecimals;
			let dig = options.digits;

			if (no_decimals && parseInt(price) == price) {
				// no decimal digits in case of empty decimals
				dig = 0;
			}

			price = parseFloat(price) / options.conversionRate;

			// check whether the price is negative
			const isNegative = price < 0;

			// adjust to given decimals
			price = Math.abs(price).toFixed(dig);

			let _d = options.decimals;
			let _t = options.thousands;

			// make sure the decimal separator is a valid character
			if (!_d.match(/[.,\s]/)) {
				// revert to default one
				_d = '.';
			}

			// make sure the thousands separator is a valid character
			if (!_t.match(/[.,\s]/)) {
				// revert to default one
				_t = ',';
			}

			// make sure both the separators are not equals
			if (_d == _t) {
				_t = _d == ',' ? '.' : ',';
			}

			price = price.split('.');

			price[0] = price[0].replace(/./g, function(c, i, a) {
				return i > 0 && (a.length - i) % 3 === 0 ? _t + c : c;
			});

			if (isNegative) {
				// re-add negative sign
				price[0] = '-' + price[0];
			}

			if (price.length > 1) {
				price = price[0] + _d + price[1];
			} else {
				price = price[0];
			}

			if (Math.abs(options.position) == 1) {
				// do not use space in case the position is "-1"
				return options.symbol + (options.position == 1 ? ' ' : '') + price;
			}

			// do not use space in case the position is "-2"
			return price + (options.position == 2 ? ' ' : '') + options.symbol;
		}

		/**
		 * Displays the given (formatted) price according to the currency settings.
		 * 
		 * @param   string  price    The price to display (expected to be already formatted).
		 * @param   object  options  Temporarily overrides the currency options.
		 * 
		 * @return  string  The currency and price final string to display.
		 * 
		 * @since 	1.8.3
		 */
		display(price, options) {
			// merge currency settings
			options = Object.assign(this.getOptions(), (options || {}));

			if (Math.abs(options.position) == 1) {
				// do not use space in case the position is "-1"
				return options.symbol + (options.position == 1 ? ' ' : '') + price;
			}

			// do not use space in case the position is "-2"
			return price + (options.position == 2 ? ' ' : '') + options.symbol;
		}

		/**
		 * Safely sums 2 prices (a + b).
		 * 
		 * @param   float  a
		 * @param   float  b
		 * 
		 * @return  The resulting sum.
		 */
		sum(a, b) {
			// get rid of decimals for higher precision
			a *= Math.pow(10, this.digits);
			b *= Math.pow(10, this.digits);

			// do sum and go back to decimal
			return (Math.round(a) + Math.round(b)) / Math.pow(10, this.digits);
		}

		/**
		 * Safely subtracts 2 prices (a - b).
		 * 
		 * @param   float  a
		 * @param   float  b
		 * 
		 * @return  The resulting difference.
		 */
		diff(a, b) {
			// get rid of decimals for higher precision
			a *= Math.pow(10, this.digits);
			b *= Math.pow(10, this.digits);

			// do difference and go back to decimal
			return (Math.round(a) - Math.round(b)) / Math.pow(10, this.digits);
		}

		/**
		 * Safely multiplies 2 prices (a * b).
		 * 
		 * @param   float  a
		 * @param   float  b
		 * 
		 * @return  The resulting multiplication.
		 */
		multiply(a, b) {
			// get rid of decimals for higher precision
			a *= Math.pow(10, this.digits);
			b *= Math.pow(10, this.digits);

			// do multiplication and go back to decimal
			return (Math.round(a) * Math.round(b)) / Math.pow(10, this.digits * 2);
		}
	}

	/**
	 * VBOAdminDock class implementation.
	 */
	w['VBOAdminDock'] = class VBOAdminDock {
		/**
		 * Singleton entry-point.
		 * 
		 * @see construct()
		 */
		static getInstance(options) {
			if (typeof VBOAdminDock.instance === 'undefined') {
				VBOAdminDock.instance = new VBOAdminDock(options);
			}

			return VBOAdminDock.instance;
		}

		/**
		 * Class constructor.
		 * 
		 * @param  object  options  The admin dock options object.
		 */
		constructor(options) {
			// set options
			this.setOptions(options);

			// start empty dock elements property
			this._elements = [];

			// set dock storage identifier property
			this._storageId = 'vikbooking.admin_dock.elements';

			// set event name for updating the dock element badge counters
			this._updateBadgeEv = 'vbo-admin-dock-update-badge';

			// build dock node
			this.buildDockNode();

			// load dock elements
			this.loadDockElements();
		}

		/**
		 * Sets the options.
		 * 
		 * @param  object  options  The dock options object.
		 * 
		 * @see    construct()
		 */
		setOptions(options) {
			if (options === undefined) {
				options = {};
			}

			// default options
			let defaultOptions = {
				dockDisplayStyle: 'flex',
			};

			// set options
			this._options = Object.assign(defaultOptions, options);
		}

		/**
		 * Gets the current dock options.
		 * 
		 * @return 	object
		 */
		getOptions() {
			let options = {};

			Object.keys(this._options).forEach((option) => {
				if (this._options.hasOwnProperty(option)) {
					options[option] = this._options[option];
				}
			});

			return options;
		}

		/**
		 * Builds the admin dock and adds it to the DOM.
		 * 
		 * @return 	HTMLElement
		 */
		buildDockNode() {
			if (this._dock) {
				return;
			}

			// create element
			this._dock = document.createElement('div');
			this._dock.classList.add('vbo-admin-dock-wrapper');

			// listen to the event for updating the element badge counters
			document.addEventListener(this._updateBadgeEv, this.updateElementsBadgeCounter);

			// append element to body
			document.querySelector('body').appendChild(this._dock);

			return this._dock;
		}

		/**
		 * Returns the admin dock node.
		 * 
		 * @return 	HTMLElement
		 */
		getDockNode() {
			return this._dock || this.buildDockNode();
		}

		/**
		 * Removes a given element index from the dock and saves on local storage.
		 * This method should be called after having removed the element from DOM.
		 * 
		 * @param 	number 	index 	The element's array index to remove.
		 * 
		 * @return 	bool 			True if the localStorage was updated or false.
		 */
		removeDockElement(index) {
			// access the previous element
			let previousElement = this._elements[index];

			// splice the elements list
			this._elements.splice(index, 1);

			if (!this._elements.length) {
				// hide the dock
				this.hideDock();
			} else {
				// reset dock element indexes
				let dom_elements = this.getDockNode().querySelectorAll('.vbo-admin-dock-element');
				this._elements.forEach((element, new_index) => {
					let widget_id = element.id;
					if (!dom_elements[new_index] || dom_elements[new_index].getAttribute('data-id') != widget_id) {
						return;
					}
					dom_elements[new_index].setAttribute('data-index', new_index);
				});
			}

			if (previousElement && previousElement.id == '_tmp' && typeof previousElement?.details?.persist_id === 'string') {
				// we have removed a temporary dock element with persisting data so try to clear the localStorage
				VBOCore.storageRemoveItem(this._storageId + '.' + previousElement.details.persist_id);
			}

			// update dock elements on localStorage
			let updated = VBOCore.storageSetItem(this._storageId, this._elements);

			return updated;
		}

		/**
		 * Removes the first dock element found from the given ID.
		 * 
		 * @param 	number 	id 	The dock element type ID.
		 * 
		 * @return 	bool 	True if element was found, removed and updated on localStorage.
		 */
		removeDockElementById(id) {
			let remove_index = this.getDockElementById(id);

			if (remove_index >= 0) {
				return this.removeDockElement(remove_index);
			}

			return false;
		}

		/**
		 * Returns the index of the first dock element found from the given ID.
		 * 
		 * @param 	string 	id 	The dock element type ID.
		 * 
		 * @return 	number 		The index found or -1 if nothing is found.
		 */
		getDockElementById(id) {
			let index_found = -1;

			this._elements.forEach((element, index) => {
				if (index_found >= 0) {
					return;
				}

				if (element.id == id) {
					index_found = index;
					return;
				}
			});

			return index_found;
		}

		/**
		 * Builds a dock element node.
		 * 
		 * @param   object       details    The element details.
		 * @param   object       data 	    The element data.
		 * @param   number       index      The element index number.
		 * @param   HTMLElement  body       Optional widget modal body to restore.
		 * @param   function     destroyFn  Optional dismiss callback.
		 * 
		 * @return  HTMLElement
		 */
		buildDockElement(details, data, index, body, destroyFn) {
			if (!details?.id) {
				throw new Error('Unknown widget id');
			}

			const widgetId = details.id;

			const element = document.createElement('div');
			element.classList.add('vbo-admin-dock-element');
			element.setAttribute('data-id', widgetId);
			element.setAttribute('data-index', index);
			element.setAttribute('data-badge-count', '');

			let content = document.createElement('div');
			content.classList.add('vbo-admin-dock-element-cont');
			content.addEventListener('click', (e) => {
				// get content target
				let target = e.target;
				if (!target.matches('.vbo-admin-dock-element-cont')) {
					target = target.closest('.vbo-admin-dock-element-cont');
				}

				// reset badge count
				target.closest('.vbo-admin-dock-element').setAttribute('data-badge-count', '');

				// get widget data, if any
				let widgetData = data?.event_data?._options || data || {};

				// get modal body if NOT from localStorage
				let prevBody = target.querySelector('.vbo-admin-dock-element-modalbody');

				if (!Object.keys(widgetData).length && prevBody && prevBody.children && prevBody.children[0] && prevBody.children[0]?.children?.length) {
					// unset dock-minimized attribute on main element with class "vbo-modal-widget_modal-wrap"
					prevBody.children[0].setAttribute('data-dock-minimized', 0);
					// get the previous style attribute
					let prevBodyStyle = prevBody.children[0].getAttribute('style');

					// restore admin widget body previously minimized
					let prevTitle = data?.title || '';
					let nameSuffix = ' - ' + (details?.name || '');
					let modalRestore = {
						title: prevTitle + (prevTitle.indexOf(nameSuffix) < 0 ? nameSuffix : ''),
						// do not immediately set the restored modal body to prevBody.children[0] in order
						// to avoid getting duplicate nested elements with class "vbo-modal-widget_modal-wrap"
						// body: prevBody.children[0],
					};

					if (details?.modal?.add_class && data?.extra_class && (data.extra_class + '').indexOf((details.modal.add_class) + '') < 0) {
						// restore widget custom class
						modalRestore.extra_class = data.extra_class + ' ' + details.modal.add_class;
					}

					// add modal restoring class
					data.extra_class = ((data.extra_class || '') + ' vbo-restoring').trim();

					// display modal with previous content and details to bind
					let restoredBody = VBOCore.displayModal(
						Object.assign(data, modalRestore),
						Object.assign({}, details)
					);

					if (prevBodyStyle) {
						(restoredBody[0] || restoredBody).setAttribute('style', prevBodyStyle);
					}

					// iterate all children elements of main modal body element with class "vbo-modal-widget_modal-wrap"
					// to append and restore the original child nodes and to avoid duplicate container elements
					Array.from(prevBody.children[0].children).forEach((child) => {
						// append child node to the restored modal body
						(restoredBody[0] || restoredBody).append(child);
					});

					try {
						if (typeof data?.onRestore === 'function') {
							// call the restoring function from the original modal
							data.onRestore.call(restoredBody, e);
						}

						// always emit the native restoring event for the current widget
						VBOCore.emitEvent('vbo-admin-dock-restore-' + widgetId, {
							data: data?.event_data || {},
						});
					} catch(e) {
						// do nothing
					}
				} else {
					// re-render admin widget from scratch
					VBOCore.handleDisplayWidgetNotification({
						widget_id: widgetId,
					}, widgetData);
				}

				// remove element from DOM
				let elementIndex = element.getAttribute('data-index');
				element.remove();

				// remove element index from dock
				this.removeDockElement(elementIndex);
			});

			let content_icon = document.createElement('span');
			content_icon.classList.add('vbo-admin-dock-element-icn');
			if (details?.style) {
				content_icon.classList.add('vbo-admin-widget-style-' + details.style);
			}
			if (details?.icon) {
				content_icon.innerHTML = details.icon;
			}

			if (body) {
				// create hidden node
				let modal_body = document.createElement('div');
				modal_body.classList.add('vbo-admin-dock-element-modalbody');
				modal_body.style.display = 'none';

				try {
					// move modal body to hidden node
					modal_body.append((body[0] || body));

					// set dock-minimized attribute
					(body[0] || body).setAttribute('data-dock-minimized', 1);

					// always dispatch the native minimize event for the current widget
					VBOCore.emitEvent('vbo-admin-dock-minimize-' + widgetId, {
						data: data?.event_data || {},
					});
				} catch(e) {
					// do nothing
				}

				// append hidden node to content
				content.appendChild(modal_body);
			}

			let content_name = document.createElement('span');
			content_name.classList.add('vbo-admin-dock-element-name');
			content_name.innerText = details?.name || '';

			let dismiss = document.createElement('span');
			dismiss.classList.add('vbo-admin-dock-element-dismiss');
			dismiss.innerHTML = '&times;';
			dismiss.addEventListener('click', (e) => {
				try {
					if (typeof destroyFn === 'function') {
						// destroy the original modal by firing any dismiss event
						destroyFn.call(body, e);
					}
				} catch(e) {
					// do nothing
				}

				// remove element from DOM
				let elementIndex = element.getAttribute('data-index');
				element.remove();

				// remove element index from dock
				this.removeDockElement(elementIndex);
			});

			// append to content
			content.appendChild(content_icon);
			content.appendChild(content_name);

			// append content to element
			element.appendChild(content);

			// append dismiss to element
			element.appendChild(dismiss);

			// return the HTMLElement object
			return element;
		}

		/**
		 * Builds a temporary dock element node.
		 * 
		 * @param   object      details 	The element details.
		 * @param   object      data 		The element data, usually an array of objects.
		 * @param   number      index 		The element index number.
		 * @param   function    restoreFn 	The callback for restoring the data.
		 * @param 	function 	destroyFn 	The callback for destroying the data.
		 * @param   number  	badge 		Optional badge number to set.
		 * 
		 * @return  HTMLElement
		 */
		buildDockTemporaryElement(details, data, index, restoreFn, destroyFn, badge) {
			if (!details?.id || details.id != '_tmp') {
				throw new Error('Invalid temporary element data.');
			}

			const dataId = '_tmp';

			const element = document.createElement('div');
			element.classList.add('vbo-admin-dock-element');
			element.setAttribute('data-id', dataId);
			element.setAttribute('data-index', index);
			element.setAttribute('data-badge-count', (badge || ''));

			let content = document.createElement('div');
			content.classList.add('vbo-admin-dock-element-cont');
			content.addEventListener('click', (e) => {
				// get content target
				let target = e.target;
				if (!target.matches('.vbo-admin-dock-element-cont')) {
					target = target.closest('.vbo-admin-dock-element-cont');
				}

				// reset badge count
				target.closest('.vbo-admin-dock-element').setAttribute('data-badge-count', '');

				if (typeof restoreFn === 'function') {
					this._elements.forEach((dockEl) => {
						if (dockEl.id == dataId) {
							// invoke the callback by passing the current element data
							restoreFn(dockEl?.data);

							// abort
							return;
						}
					});
				}

				// remove element from DOM
				let elementIndex = element.getAttribute('data-index');
				element.remove();

				// remove element index from dock
				this.removeDockElement(elementIndex);
			});

			let content_icon = document.createElement('span');
			content_icon.classList.add('vbo-admin-dock-element-icn');
			if (details?.style) {
				content_icon.classList.add('vbo-admin-widget-style-' + details.style);
			}
			if (details?.icon) {
				content_icon.innerHTML = details.icon;
			}

			let content_name = document.createElement('span');
			content_name.classList.add('vbo-admin-dock-element-name');
			content_name.innerText = details?.name || '';

			let dismiss = document.createElement('span');
			dismiss.classList.add('vbo-admin-dock-element-dismiss');
			dismiss.innerHTML = '&times;';
			dismiss.addEventListener('click', (e) => {
				if (typeof destroyFn === 'function') {
					this._elements.forEach((dockEl) => {
						if (dockEl.id == dataId) {
							// invoke the callback by passing the current element data
							destroyFn(dockEl?.data);

							// abort
							return;
						}
					});
				}

				// remove element from DOM
				let elementIndex = element.getAttribute('data-index');
				element.remove();

				// remove element index from dock
				this.removeDockElement(elementIndex);
			});

			// append to content
			content.appendChild(content_icon);
			content.appendChild(content_name);

			// append content to element
			element.appendChild(content);

			// append dismiss to element
			element.appendChild(dismiss);

			// return the HTMLElement object
			return element;
		}

		/**
		 * Adds a widget to the dock.
		 * 
		 * @param  object       details    The widget details.
		 * @param  object       data 	   The widget restoring data.
		 * @param  HTMLElement  body       Optional widget modal body to restore.
		 * @param  function     destroyFn  Optional dismiss callback.
		 */
		addWidget(details, data, body, destroyFn) {
			if (!VBOCore.options.widget_ajax_uri) {
				throw new Error('Wrong environment');
			}

			if (typeof details !== 'object') {
				details = {};
			}

			if (!details?.id) {
				throw new Error('Unknown widget id');
			}

			// add element to dock in the DOM at first
			this.getDockNode().appendChild(
				this.buildDockElement(details, data, this._elements.length, body, destroyFn)
			);

			// push dock element after it was added to the DOM
			this._elements.push({
				id: details.id,
				details: Object.assign({}, details),
				data: Object.assign({}, (data?.event_data?._options || {})),
			});

			// ensure dock is visible
			this.showDock();

			// update dock elements on localStorage at last
			VBOCore.storageSetItem(this._storageId, this._elements);
		}

		/**
		 * Adds temporary data to the dock. Data will NOT persist on the same localStorage key.
		 * Originally introduced to handle the rates update requests within a queue.
		 * 
		 * @param 	object 		details 	The data details.
		 * @param 	object 		data 		The data to store, usually an array of objects.
		 * @param 	function 	restoreFn 	The callback for restoring the data.
		 * @param 	function 	destroyFn 	The callback for destroying the data.
		 * @param 	number 		badge 		Optional badge number to set.
		 */
		addTemporaryData(details, data, restoreFn, destroyFn, badge) {
			if (!VBOCore.options.widget_ajax_uri) {
				throw new Error('Wrong environment');
			}

			if (typeof details !== 'object') {
				details = {};
			}

			// temporary data will always get a private ID to avoid duplicate entries in the dock
			details.id = '_tmp';

			// check if the same temporary data element type exists
			let previousElement = null;
			let previousIndex = null;
			this.getElements().forEach((element, index) => {
				if (previousElement) {
					return;
				}
				if (element.id == details.id) {
					// previous temporary data element type found
					previousElement = element;
					previousIndex = index;
					return;
				}
			});

			if (!previousElement) {
				// add temporary element to dock in the DOM at first
				this.getDockNode().appendChild(
					this.buildDockTemporaryElement(details, data, this._elements.length, restoreFn, destroyFn, (badge ? badge : (Array.isArray(data) ? data.length : null)))
				);

				// push dock element after it was added to the DOM
				this._elements.push({
					id: details.id,
					details: Object.assign({}, details),
					data: Array.isArray(data) ? [...data] : Object.assign({}, data),
				});
			} else {
				// update previous temporary data element type
				let updatedData = Array.isArray(data) && Array.isArray(previousElement.data) ? [...previousElement.data].concat([...data]) : [...data];
				let updatedBadge = badge ? badge : (Array.isArray(updatedData) ? updatedData.length : previousElement.badge);

				// update existing dock element
				this._elements[previousIndex] = {
					id: details.id,
					details: Object.assign({}, previousElement.details, details),
					data: updatedData,
				};

				if (updatedBadge) {
					// update DOM element
					let dom_elements = this.getDockNode().querySelectorAll('.vbo-admin-dock-element');
					this._elements.forEach((element, cur_index) => {
						if (!dom_elements[cur_index] || dom_elements[cur_index].getAttribute('data-id') != element.id) {
							return;
						}
						if (dom_elements[cur_index].getAttribute('data-id') != details.id) {
							return;
						}
						// update badge attribute
						dom_elements[cur_index].setAttribute('data-badge-count', updatedBadge);
					});
				}
			}

			// ensure dock is visible
			this.showDock();

			if (details.persist_id && typeof details.persist_id === 'string') {
				// update dock element on a different localStorage key at last
				VBOCore.storageSetItem(this._storageId + '.' + details.persist_id, (previousIndex ? this._elements[previousIndex] : this._elements[this._elements.length - 1]));
			}
		}

		/**
		 * Loads temporary data onto the dock by using an ID and type identifier.
		 * Originally introduced to handle the rates update requests within a queue.
		 * 
		 * @param 	object 		details 	The data details to load.
		 * @param 	function 	restoreFn 	The callback for restoring the data.
		 * @param 	function 	destroyFn 	The callback for destroying the data.
		 * @param 	number 		badge 		Optional badge number to set.
		 * 
		 * @return 	any 					Data object loaded on success or null.
		 */
		loadTemporaryData(details, restoreFn, destroyFn, badge) {
			if (!VBOCore.options.widget_ajax_uri) {
				throw new Error('Wrong environment');
			}

			if (typeof details !== 'object' || !details.id || !details.persist_id || typeof details.persist_id !== 'string') {
				return null;
			}

			// temporary data will always get a private ID to avoid duplicate entries in the dock
			details.id = '_tmp';

			// check if the same temporary data element type exists
			let previousElement = null;
			this.getElements().forEach((element, index) => {
				if (previousElement) {
					return;
				}
				if (element.id == details.id) {
					// previous temporary data element type found
					previousElement = element;
					return;
				}
			});

			if (previousElement) {
				// temporary data already loaded in dock
				return previousElement;
			}

			// load the requested temporary and persisting data
			let storageElement = VBOCore.storageGetItem(this._storageId + '.' + details.persist_id);

			try {
				if (typeof storageElement === 'string') {
					storageElement = JSON.parse(storageElement);
				}
			} catch(e) {
				storageElement = null;
			}

			if (!storageElement || typeof storageElement !== 'object' || !storageElement.data) {
				return null;
			}

			// add the temporary data just loaded to the dock
			this.addTemporaryData(Object.assign({}, (storageElement.details || {}), details), storageElement.data, restoreFn, destroyFn, badge);

			// return the data loaded
			return storageElement;
		}

		/**
		 * Returns the current dock elements.
		 * 
		 * @return   Array
		 */
		getElements() {
			return this._elements;
		}

		/**
		 * Loads widget dock elements from localStorage and populates them, if any.
		 */
		loadDockElements() {
			let storageElements = VBOCore.storageGetItem(this._storageId) || [];

			try {
				if (typeof storageElements === 'string') {
					storageElements = JSON.parse(storageElements);
				}
			} catch(e) {
				storageElements = [];
			}

			if (Array.isArray(storageElements)) {
				// set current elements
				this._elements = storageElements;
			}

			// scan all elements to ensure no temporary data was stored upon deleting or adding new widgets
			this._elements.forEach((element, index) => {
				if (element?.id == '_tmp') {
					// splice the elements list
					this._elements.splice(index, 1);

					// update dock elements on localStorage by only keeping real widgets
					VBOCore.storageSetItem(this._storageId, this._elements);

					// abort
					return;
				}
			});

			if (this._elements.length) {
				// populate dock elements
				this.populateDockElements();

				// show the dock
				this.showDock();
			} else {
				// hide the dock
				this.hideDock();
			}
		}

		/**
		 * Populates the current dock elements.
		 */
		populateDockElements() {
			const dockNode = this.getDockNode();

			// empty the dock
			dockNode.innerHTML = '';

			// scan all elements
			this._elements.forEach((element, index) => {
				// add element to dock in the DOM at first
				dockNode.appendChild(
					this.buildDockElement(element?.details, element?.data, index)
				);
			});
		}

		/**
		 * Hides the dock node.
		 */
		hideDock() {
			this.getDockNode().style.display = 'none';
		}

		/**
		 * Shows the dock node.
		 */
		showDock() {
			if (!this.getDockNode().checkVisibility()) {
				this.getDockNode().style.display = this._options.dockDisplayStyle;
			}
		}

		/**
		 * Event callback fired to update the element(s) badge counter.
		 */
		updateElementsBadgeCounter(e) {
			if (!e || !e.detail || !e.detail?.widgetId) {
				return;
			}

			let elements = VBOAdminDock.getInstance().getElements();

			if (!elements.length) {
				return;
			}

			let widgetId = e.detail.widgetId;
			let badgeCount = parseInt(e.detail?.badgeCount || 0);
			let badgeValue = badgeCount > 0 ? badgeCount : '';

			elements.forEach((element) => {
				if (element.id == widgetId) {
					document.querySelectorAll('.vbo-admin-dock-element[data-id="' + widgetId + '"]').forEach((elNode) => {
						elNode.setAttribute('data-badge-count', badgeValue);
					});
				}
			});
		}
	}

})(jQuery, window);
// source --> https://lipper-quartiere.de/wp-content/plugins/vikbooking/admin/resources/js/system.js?ver=1.8.7 
/**
 * Joomla Core
 */

function JoomlaCore() {
	// instantiate only once because iframe pages might invoke this method again
	if (!JoomlaCore.instance) {
		// init pagination handler
		this.paginations = {};
		// init translations handler
		this.JText = new JText();
		// init editors instances
		this.editors = {instances: {}};

		// register singleton
		JoomlaCore.instance = this;
	}
	
	return JoomlaCore.instance;
}

JoomlaCore.prototype.getPagination = function(prefix) {
	key = prefix || '__default__';

	if (!this.paginations.hasOwnProperty(key)) {
		this.paginations[key] = new JPagination();
		this.paginations[key].setPrefix(prefix)
	}

	return this.paginations[key];
}

JoomlaCore.prototype.checkAll = function(checkbox) {
	// Use :visible selector in order to skip hidden checkboxes.
	// This is helpful to ignore hidden inputs while filtering the list.
	jQuery('#adminForm input[name="cid[]"]:visible').prop('checked', checkbox.checked);
}

JoomlaCore.prototype.isChecked = function(checked) {
	// get toggle-all checkbox
	var allBox = jQuery('#adminForm thead input[type="checkbox"]');

	if (!checked || jQuery('#adminForm input[name="cid[]"]').length != this.hasChecked()) {
		allBox.prop('checked', false);
	} else {
		allBox.prop('checked', true);
	}
}

JoomlaCore.prototype.hasChecked = function() {
	return jQuery('#adminForm input[name="cid[]"]:checked').length;
}

JoomlaCore.prototype.submitform = function(task, form) {
	if (task && form.task) {
		form.task.value = task;
	}

	jQuery(form).submit();
}

JoomlaCore.prototype.submitbutton = function(task) {
	this.submitform(task, document.adminForm);
}

JoomlaCore.prototype.tableOrdering = function(column, direction, task, form) {
	if (form === undefined) {
		form = document.adminForm;
	}

	if (form.filter_order === undefined) {
		var orderInput = document.createElement('input');
		orderInput.type  = 'hidden';
		orderInput.name  = 'filter_order';

		form.appendChild(orderInput);
	}

	form.filter_order.value = column;

	if (form.filter_order_Dir === undefined) {
		var directionInput = document.createElement('input');
		directionInput.type  = 'hidden';
		directionInput.name  = 'filter_order_Dir';

		form.appendChild(directionInput);
	}

	form.filter_order_Dir.value = direction;

	this.submitform(task, form);
}

JoomlaCore.getOptions = function(key, def) {
	// load options if they not exists
	if (!JoomlaCore.optionsStorage) {
		JoomlaCore.loadOptions();
	}

	return JoomlaCore.optionsStorage[key] !== undefined ? JoomlaCore.optionsStorage[key] : def;
};

JoomlaCore.loadOptions = function(options) {
	if (!options) {
		var elements = jQuery('script.joomla-options.new');
		var counter  = 0;

		for (var i = 0, l = elements.length; i < l; i++) {
			var element = elements[i];
			var str     = element.text || element.textContent;
			var option  = {};

			try {
				option = JSON.parse(str);
			} catch (err) {
				console.log(err);
			}

			if (option) {
				JoomlaCore.loadOptions(option);
				counter++;
			}

			// mark element as loaded
			jQuery(element).removeClass('new').addClass('loaded');
		}

		if (counter) {
			return;
		}
	}

	// initial loading
	if (!JoomlaCore.optionsStorage) {
		JoomlaCore.optionsStorage = options || {};
	}
	// Merge with existing
	else if (options ) {
		for (var p in options) {
			if (options.hasOwnProperty(p)) {
				JoomlaCore.optionsStorage[p] = options[p];
			}
		}
	}
};

JoomlaCore.isAdmin = function() {
	return document.location.href.match(/\/wp-admin\//i) ? true : false;
}

/**
 * Pagination
 */

function JPagination(total, limit, start, listener) {

	if (total === undefined) {
		total = 0;
	}

	if (limit === undefined) {
		limit = 0;
	}

	if (start === undefined) {
		start = 0;
	}

	if (listener === undefined) {
		listener = null;
	}

	this.total 	= total;
	this.limit 	= limit;
	this.start 	= start;
	this.prefix = '';

	this.listener = listener;

	return this;
}

JPagination.prototype.setTotal = function(total) {
	this.total = total;

	return this;
}

JPagination.prototype.setLimit = function(limit) {
	this.limit = limit;

	return this;
}

JPagination.prototype.setStart = function(start) {
	this.start = start;

	return this;
}

JPagination.prototype.setListener = function(listener) {
	this.listener = listener;

	return this;
}

JPagination.prototype.setPrefix = function(prefix) {
	this.prefix = prefix || '';

	return this;
}

JPagination.prototype.submit = function() {

	if (this.listener[this.prefix + 'limitstart'] === undefined) {
		var limitstart = document.createElement('input');
		limitstart.type  = 'hidden';
		limitstart.name  = this.prefix + 'limitstart';

		this.listener.appendChild(limitstart);
	}

	if (this.listener[this.prefix + 'limit'] === undefined) {
		var limit = document.createElement('input');
		limit.type  = 'hidden';
		limit.name  = this.prefix + 'limit';

		this.listener.appendChild(limit);
	}

	this.listener[this.prefix + 'limitstart'].value = this.start;
	this.listener[this.prefix + 'limit'].value      = this.limit;

	// submit through jQuery in order to
	// properly emit the "submit" event
	jQuery(this.listener).submit();
}

JPagination.prototype.first = function() {
	this.start = 0;
	this.submit();
}

JPagination.prototype.prev = function() {
	this.start -= this.limit;
	this.submit();
}

JPagination.prototype.next = function() {
	this.start += this.limit;
	this.submit();
}

JPagination.prototype.last = function() {
	this.start = (Math.ceil(this.total / this.limit) - 1) * this.limit;
	this.submit();
}

/**
 * Text
 */

function JText() {
	this.strings = {};

	return this;
}

JText.prototype._ = function(key, def) {
	// check for new strings in the optionsStorage, and load them
	var newStrings = JoomlaCore.getOptions('joomla.jtext');

	if (newStrings) {
		this.load(newStrings);

		// Clean up the optionsStorage from useless data
		JoomlaCore.loadOptions({'joomla.jtext': null});
	}

	def = def === undefined ? '' : def;
	key = key.toUpperCase();

	return this.strings[key] !== undefined ? this.strings[key] : def;
}

JText.prototype.load = function(object) {
	for (var key in object) {
		if (object.hasOwnProperty(key)) {
			this.strings[key.toUpperCase()] = object[key];
		}
	}

	return this;
}

/*
 * FORM VALIDATION
 */

function JFormValidator(form, clazz) {
	this.form = form;

	if (typeof clazz === 'undefined') {
		clazz = 'invalid';
	}

	this.clazz  = clazz;
	this.labels = {};

	// prevent the form submission on enter keydown

	jQuery(this.form).on('keyup', function(e) {
		var keyCode = e.keyCode || e.which;
		
		if (keyCode === 13) { 
			e.preventDefault();
			return false;
		}
	});

	this.registerFields('.required');
}

JFormValidator.prototype.isValid = function(input) {
	var val = jQuery(input).val();

	return val !== null && val.length > 0;
}

JFormValidator.prototype.registerFields = function(selector) {

	var _this = this;

	jQuery(this.form).find(selector).on('blur', function() {
		if (_this.isValid(this)) {
			_this.unsetInvalid(this);
		} else {
			_this.setInvalid(this);
		}
	});

	return this;
}

JFormValidator.prototype.unregisterFields = function(selector) {

	jQuery(this.form).find(selector).off('blur')

	return this;
}

JFormValidator.prototype.validate = function(callback) {
	var ok = true;

	var _this = this;

	this.clearInvalidTabPane();

	jQuery(this.form).find('.required:input').each(function() {
		if (_this.isValid(this)) {
			_this.unsetInvalid(this);
		} else {
			_this.setInvalid(this);
			ok = false;

			if (!jQuery(this).is(':visible')) {
				// the input is probably hidden behind
				// an unactive tab pane
				_this.setInvalidTabPane(this);
			}
		}
	});

	if (typeof callback !== 'undefined') {
		ok = callback() && ok;
	}

	return ok;
}

JFormValidator.prototype.setLabel = function(input, label) {
	this.labels[jQuery(input).attr('name')] = label;

	return this;
}

JFormValidator.prototype.getLabel = function(input) {
	var name = jQuery(input).attr('name');	

	if (this.labels.hasOwnProperty(name)) {
		return jQuery(this.labels[name]);
	}

	return jQuery(input).closest('.control').children().filter('b,label');
}

JFormValidator.prototype.setInvalid = function(input) {
	jQuery(input).addClass(this.clazz);
	this.getLabel(input).addClass(this.clazz);

	return this;
}

JFormValidator.prototype.unsetInvalid = function(input) {
	jQuery(input).removeClass(this.clazz);
	this.getLabel(input).removeClass(this.clazz);

	return this;
}

JFormValidator.prototype.isInvalid = function(input) {
	return jQuery(input).hasClass(this.clazz);
}

JFormValidator.prototype.clearInvalidTabPane = function() {
	jQuery('ul.nav-tabs li a').removeClass(this.clazz);

	return this;
}

JFormValidator.prototype.setInvalidTabPane = function(input) {
	var pane = jQuery(input).closest('.tab-pane');

	if (pane.length) {
		var id 	 = jQuery(pane).attr('id');
		var link = jQuery('ul.nav-tabs li a[href="#' + id + '"]');

		if (link.length) {
			link.addClass(this.clazz);
		}
	}

	return this;
}

/**
 * TRIGGER JMODAL
 */

function wpOpenJModal(id, href, onShow, onHide) {

	if (onShow !== undefined)
	{
		jQuery('#jmodal-' + id).on('show', onShow);
	}

	if (onHide !== undefined)
	{
		jQuery('#jmodal-' + id).on('hide', onHide);
	}

	if (!href) {
		// try to extract url from modal URL input
		href = jQuery('#jmodal-' + id + ' > input[name="url"]').val();
	}

	var hideOnEsc = null;

	// check if the modal can be closed using the ESC button
	if (jQuery('#jmodal-' + id).data('esc') == 1) {
		hideOnEsc = function(event) {
			if (event.keyCode == 27) {
				// close modal when ESC is pressed
				wpCloseJModal(id);
			}
		};

		jQuery(window).on('keydown', hideOnEsc);
	}

	jQuery('#jmodal-' + id).on('hide.bs.modal', function() {
		// we should remove the body only whether it has been loaded asynchronously
		if (href) {
			jQuery(this).find('.modal-body').remove();
		}

		jQuery('#jmodal-' + id).off('show.bs.modal');
		jQuery('#jmodal-' + id).off('hide.bs.modal');

		if (hideOnEsc) {
			// turn off esc handler too after disposing the modal
			jQuery(window).off('keydown', hideOnEsc);
		}
	});

	// trigger "show" event to support external listeners
	jQuery('#jmodal-' + id).modal('show').trigger('show');

	var closeBtn = jQuery('#jmodal-' + id).find('button[data-dismiss]');

	// add workaround to trigger hide|hidden events also when
	// clicking the dismiss button of the modal
	closeBtn.on('click', function() {
		jQuery('#jmodal-' + id).trigger('hide').trigger('hidden').trigger('hide.bs.modal');
	});

	// hide on backdrop click only in case the modal is dismissable
	if (closeBtn.length || hideOnEsc) {
		jQuery('.modal-backdrop').on('click', function() {
			wpCloseJModal(id);
		});
	}

	if (href) 
	{
		wpAppendModalContent('jmodal-box-' + id, href);
	}
}

function wpCloseJModal(id) {
	if (id.match(/^jmodal-/)) {
		// full ID without "#"
		id = "#" + id;
	} else if (!id.match(/^#jmodal-/)) {
		// modal ID only
		id = "#jmodal-" + id;
	}

	// close modal and trigger hide|hidden events
	jQuery(id).modal('hide').trigger('hide').trigger('hidden').trigger('hide.bs.modal');
}

function wpAppendModalContent(id, href) {

	var data = {};

	if (typeof href === 'object') {
		data = href.serialize();
		href = 'admin-ajax.php';
	} else if (typeof href === 'string') {
		href = href.replace('index.php', 'admin-ajax.php');
		href = href.replace('admin.php', 'admin-ajax.php');
	}

	setTimeout(function() {

		doAjax(
			href,
			data,
			function(resp) {

				try {
					resp = JSON.parse(resp);
					
					if (Array.isArray(resp)) {
						resp = resp.shift();
					}
				} catch (err) {
					// the response is already plain HTML
				}

				// tries to fix any ID conflict
				resp = makeResponseUnique(resp);

				jQuery('#' + id).html('<div class="modal-body">' + resp + '</div>');

				// route targets for back-end only
				if (JoomlaCore.isAdmin()) {
					// replaces any index.php with admin.php
					routePageTargets('#' + id);
				}

				ajaxPreventFormSubmit(id);
			},
			function(resp) {
				alert(Joomla.JText._('CONNECTION_LOST'));
			}
		);

	}, 128 + Math.random() * 512);

}

function makeResponseUnique(resp) {
	resp = resp.replace(/adminForm/g, 'innerAdminForm');

	return resp;
}

function ajaxPreventFormSubmit(id) {
	jQuery('#' + id).find('form').on('submit', function(e) {
		e.preventDefault();

		wpAppendModalContent(id, jQuery(this));

		return false;
	});

	jQuery('#' + id).find('a[target!="_blank"]').filter('a:not([href^="javascript:"],[href^="#"])').on('click', function(e) {
		e.preventDefault();

		wpAppendModalContent(id, jQuery(this).attr('href'));

		return false;
	});
}

function routePageTargets(container) {
	jQuery(container).find('a[href^="index.php"], form[action^="index.php"]').each(function() {
		var attr;

		if (jQuery(this).is('a')) {
			attr = 'href';
		} else {
			attr = 'action';
		}

		var value = jQuery(this).attr(attr);

		jQuery(this).attr(attr, value.replace(/^index\.php/, 'admin.php'));
	});

	jQuery(container).find('button[onclick^="document.location.href"]').each(function() {
		// get current event string
		var onclick = jQuery(this).attr('onclick');
		// replace index.php into admin.php
		onclick = onclick.replace(/index\.php/, 'admin.php');
		// update element attribute
		jQuery(this).attr('onclick', onclick);
	});
}

/**
 * Returns a promise that resolves when the specified instance
 * gets defined.
 *
 * @param 	function  check      The callback to invoke to check whether the instance is ready.
 * @param   mixed     threshold  An optional threshold to estabilish the max number of attempts.
 *
 * @return 	Promise
 */
function __isReady(check, threshold) {
	return new Promise((resolve, reject) => {
		// prepare safe counter
		var count = 0;

		var callback = function() {
			// increase counter
			count++;

			// check whether the instance is ready
			var instance = check();

			if (instance) {
				// object is now ready
				resolve(instance);
			} else {
				if (!threshold || count < Math.abs(threshold)) {
					// check again
					setTimeout(callback, 32 + Math.floor(Math.random() * 128));
				} else {
					// instance not ready
					reject();
				}
			}
		};

		// check
		callback();
	});
}

/**
 * AJAX UTILS
 */
 
function normalizePostData(data) {

	if (data === undefined) {
		data = {};
	} else if (Array.isArray(data)) {
		// the form data is serialized @see jQuery.serializeArray()
		var form = data;

		data = {};

		for (var i = 0; i < form.length; i++) {
			// if the field ends with [] it should be an array
			if (form[i].name.endsWith("[]")) {
				// if the field doesn't exist yet, create a new list
				if (!data.hasOwnProperty(form[i].name)) {
					data[form[i].name] = new Array();
				}

				// append the value to the array
				data[form[i].name].push(form[i].value);
			} else {
				// otherwise overwrite the value (if any)
				data[form[i].name] = form[i].value;
			}
		}
	}

	return data;
}

function doAjax(url, data, success, failure, attempt) {

	var AJAX_MAX_ATTEMPTS = 3;

	if (attempt === undefined) {
		attempt = 1;
	}

	// return same object if data has been already normalized
	data = normalizePostData(data);

	return jQuery.ajax({
		type: 'post',
		url: url,
		data: data
	}).done(function(resp) {

		if (success !== undefined) {
			success(resp);
		}

	}).fail(function(err) {
		// If the error has been raised by a connection failure, 
		// retry automatically the same request. Do not retry if the
		// number of attempts is higher than the maximum number allowed.
		if (attempt < AJAX_MAX_ATTEMPTS && isConnectionLostError(err)) {

			// wait 128 milliseconds before launching the request
			setTimeout(function() {
				// relaunch same action and increase number of attempts by 1
				doAjax(url, data, success, failure, attempt + 1);
			}, 128);

		} else {

			// otherwise raise the failure method
			if (failure !== undefined) {
				failure(err);
			}

		}

		console.log('failure', err);

		if (err.status == 500) {
			console.log(err.responseText);
		}

	});
}

function isConnectionLostError(err) {
	return (
		err.statusText == 'error'
		&& err.status == 0
		&& (err.readyState == 0 || err.readyState == 4)
		&& (!err.hasOwnProperty('responseText') || err.responseText == '')
	);
}

/**
 * BROWSER BACKWARD COMPATIBILITY
 */

if (!Array.isArray) {
	Array.isArray = function(arg) {
		return Object.prototype.toString.call(arg) === '[object Array]';
	}
}

/**
 * Joomla instance is now available on both admin and site sections.
 * In order to avoid delays with the loading of this class, maybe because of lazy-loading
 * techniques of the Theme with "deferred" scripts, we no longer use inline JS code.
 * 
 * @since 	1.4.0
 */
if (typeof Joomla === 'undefined') {
	var Joomla = new JoomlaCore();
} else {
	// reload options
	JoomlaCore.loadOptions();
};