/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2023 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Florian Müller <mueller@infomax-it.de>
 * @since      26.10.23
 */

/**
 * This storage also works even if the browser does not support sessionStorage (private browser mode, forbitten third party cookies, etc.)
 * @type {{removeItem: removeItem, clear: clear, getItem: ((function(*): (*|undefined))|*), setItem: setItem}}
 */
failSaveStorage = (function () {
  var items = {};
  var getItem = function (key) {
    try {
      return sessionStorage.getItem(key);
    } catch (e) {
      return items[key] || null;
    }
  };
  var setItem = function (key, value) {
    try {
      sessionStorage.setItem(key, value);
    } catch (e) {
      items[key] = value;
    }
  };
  var removeItem = function (key) {
    try {
      sessionStorage.removeItem(key);
    } catch (e) {
      delete items[key];
    }
  };
  var clear = function () {
    try {
      sessionStorage.clear();
    } catch (e) {
      items = {};
    }
  };
  return {
    getItem: getItem,
    setItem: setItem,
    removeItem: removeItem,
    clear: clear
  };
}());

/*! URI.js v1.15.2 http://medialize.github.io/URI.js/ */
/* build contains: URI.js */
(function(n,v){"object"===typeof exports?module.exports=v(require("./punycode"),require("./IPv6"),require("./SecondLevelDomains")):"function"===typeof define&&define.amd?define(["./punycode","./IPv6","./SecondLevelDomains"],v):n.URI=v(n.punycode,n.IPv6,n.SecondLevelDomains,n)})(this,function(n,v,t,h){function d(a,b){var c=1<=arguments.length,f=2<=arguments.length;if(!(this instanceof d))return c?f?new d(a,b):new d(a):new d;if(void 0===a){if(c)throw new TypeError("undefined is not a valid argument for URI");
a="undefined"!==typeof location?location.href+"":""}this.href(a);return void 0!==b?this.absoluteTo(b):this}function q(a){return a.replace(/([.*+?^=!:${}()|[\]\/\\])/g,"\\$1")}function w(a){return void 0===a?"Undefined":String(Object.prototype.toString.call(a)).slice(8,-1)}function k(a){return"Array"===w(a)}function C(a,b){var c={},d,g;if("RegExp"===w(b))c=null;else if(k(b))for(d=0,g=b.length;d<g;d++)c[b[d]]=!0;else c[b]=!0;d=0;for(g=a.length;d<g;d++)if(c&&void 0!==c[a[d]]||!c&&b.test(a[d]))a.splice(d,
1),g--,d--;return a}function z(a,b){var c,d;if(k(b)){c=0;for(d=b.length;c<d;c++)if(!z(a,b[c]))return!1;return!0}var g=w(b);c=0;for(d=a.length;c<d;c++)if("RegExp"===g){if("string"===typeof a[c]&&a[c].match(b))return!0}else if(a[c]===b)return!0;return!1}function D(a,b){if(!k(a)||!k(b)||a.length!==b.length)return!1;a.sort();b.sort();for(var c=0,d=a.length;c<d;c++)if(a[c]!==b[c])return!1;return!0}function F(a){return escape(a)}function A(a){return encodeURIComponent(a).replace(/[!'()*]/g,F).replace(/\*/g,
"%2A")}function x(a){return function(b,c){if(void 0===b)return this._parts[a]||"";this._parts[a]=b||null;this.build(!c);return this}}function E(a,b){return function(c,d){if(void 0===c)return this._parts[a]||"";null!==c&&(c+="",c.charAt(0)===b&&(c=c.substring(1)));this._parts[a]=c;this.build(!d);return this}}var G=h&&h.URI;d.version="1.15.2";var e=d.prototype,p=Object.prototype.hasOwnProperty;d._parts=function(){return{protocol:null,username:null,password:null,hostname:null,urn:null,port:null,path:null,
query:null,fragment:null,duplicateQueryParameters:d.duplicateQueryParameters,escapeQuerySpace:d.escapeQuerySpace}};d.duplicateQueryParameters=!1;d.escapeQuerySpace=!0;d.protocol_expression=/^[a-z][a-z0-9.+-]*$/i;d.idn_expression=/[^a-z0-9\.-]/i;d.punycode_expression=/(xn--)/i;d.ip4_expression=/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/;d.ip6_expression=/^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/;
d.find_uri_expression=/\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u2018\u2019]))/ig;d.findUri={start:/\b(?:([a-z][a-z0-9.+-]*:\/\/)|www\.)/gi,end:/[\s\r\n]|$/,trim:/[`!()\[\]{};:'".,<>?\u00ab\u00bb\u201c\u201d\u201e\u2018\u2019]+$/};d.defaultPorts={http:"80",https:"443",ftp:"21",gopher:"70",ws:"80",wss:"443"};d.invalid_hostname_characters=
/[^a-zA-Z0-9\.-]/;d.domAttributes={a:"href",blockquote:"cite",link:"href",base:"href",script:"src",form:"action",img:"src",area:"href",iframe:"src",embed:"src",source:"src",track:"src",input:"src",audio:"src",video:"src"};d.getDomAttribute=function(a){if(a&&a.nodeName){var b=a.nodeName.toLowerCase();return"input"===b&&"image"!==a.type?void 0:d.domAttributes[b]}};d.encode=A;d.decode=decodeURIComponent;d.iso8859=function(){d.encode=escape;d.decode=unescape};d.unicode=function(){d.encode=A;d.decode=
decodeURIComponent};d.characters={pathname:{encode:{expression:/%(24|26|2B|2C|3B|3D|3A|40)/ig,map:{"%24":"$","%26":"&","%2B":"+","%2C":",","%3B":";","%3D":"=","%3A":":","%40":"@"}},decode:{expression:/[\/\?#]/g,map:{"/":"%2F","?":"%3F","#":"%23"}}},reserved:{encode:{expression:/%(21|23|24|26|27|28|29|2A|2B|2C|2F|3A|3B|3D|3F|40|5B|5D)/ig,map:{"%3A":":","%2F":"/","%3F":"?","%23":"#","%5B":"[","%5D":"]","%40":"@","%21":"!","%24":"$","%26":"&","%27":"'","%28":"(","%29":")","%2A":"*","%2B":"+","%2C":",",
"%3B":";","%3D":"="}}},urnpath:{encode:{expression:/%(21|24|27|28|29|2A|2B|2C|3B|3D|40)/ig,map:{"%21":"!","%24":"$","%27":"'","%28":"(","%29":")","%2A":"*","%2B":"+","%2C":",","%3B":";","%3D":"=","%40":"@"}},decode:{expression:/[\/\?#:]/g,map:{"/":"%2F","?":"%3F","#":"%23",":":"%3A"}}}};d.encodeQuery=function(a,b){var c=d.encode(a+"");void 0===b&&(b=d.escapeQuerySpace);return b?c.replace(/%20/g,"+"):c};d.decodeQuery=function(a,b){a+="";void 0===b&&(b=d.escapeQuerySpace);try{return d.decode(b?a.replace(/\+/g,
"%20"):a)}catch(c){return a}};var r={encode:"encode",decode:"decode"},y,B=function(a,b){return function(c){try{return d[b](c+"").replace(d.characters[a][b].expression,function(c){return d.characters[a][b].map[c]})}catch(f){return c}}};for(y in r)d[y+"PathSegment"]=B("pathname",r[y]),d[y+"UrnPathSegment"]=B("urnpath",r[y]);r=function(a,b,c){return function(f){var g;g=c?function(a){return d[b](d[c](a))}:d[b];f=(f+"").split(a);for(var e=0,l=f.length;e<l;e++)f[e]=g(f[e]);return f.join(a)}};d.decodePath=
r("/","decodePathSegment");d.decodeUrnPath=r(":","decodeUrnPathSegment");d.recodePath=r("/","encodePathSegment","decode");d.recodeUrnPath=r(":","encodeUrnPathSegment","decode");d.encodeReserved=B("reserved","encode");d.parse=function(a,b){var c;b||(b={});c=a.indexOf("#");-1<c&&(b.fragment=a.substring(c+1)||null,a=a.substring(0,c));c=a.indexOf("?");-1<c&&(b.query=a.substring(c+1)||null,a=a.substring(0,c));"//"===a.substring(0,2)?(b.protocol=null,a=a.substring(2),a=d.parseAuthority(a,b)):(c=a.indexOf(":"),
-1<c&&(b.protocol=a.substring(0,c)||null,b.protocol&&!b.protocol.match(d.protocol_expression)?b.protocol=void 0:"//"===a.substring(c+1,c+3)?(a=a.substring(c+3),a=d.parseAuthority(a,b)):(a=a.substring(c+1),b.urn=!0)));b.path=a;return b};d.parseHost=function(a,b){var c=a.indexOf("/"),d;-1===c&&(c=a.length);if("["===a.charAt(0))d=a.indexOf("]"),b.hostname=a.substring(1,d)||null,b.port=a.substring(d+2,c)||null,"/"===b.port&&(b.port=null);else{var g=a.indexOf(":");d=a.indexOf("/");g=a.indexOf(":",g+1);
-1!==g&&(-1===d||g<d)?(b.hostname=a.substring(0,c)||null,b.port=null):(d=a.substring(0,c).split(":"),b.hostname=d[0]||null,b.port=d[1]||null)}b.hostname&&"/"!==a.substring(c).charAt(0)&&(c++,a="/"+a);return a.substring(c)||"/"};d.parseAuthority=function(a,b){a=d.parseUserinfo(a,b);return d.parseHost(a,b)};d.parseUserinfo=function(a,b){var c=a.indexOf("/"),f=a.lastIndexOf("@",-1<c?c:a.length-1);-1<f&&(-1===c||f<c)?(c=a.substring(0,f).split(":"),b.username=c[0]?d.decode(c[0]):null,c.shift(),b.password=
c[0]?d.decode(c.join(":")):null,a=a.substring(f+1)):(b.username=null,b.password=null);return a};d.parseQuery=function(a,b){if(!a)return{};a=a.replace(/&+/g,"&").replace(/^\?*&*|&+$/g,"");if(!a)return{};for(var c={},f=a.split("&"),g=f.length,e,l,m=0;m<g;m++)if(e=f[m].split("="),l=d.decodeQuery(e.shift(),b),e=e.length?d.decodeQuery(e.join("="),b):null,p.call(c,l)){if("string"===typeof c[l]||null===c[l])c[l]=[c[l]];c[l].push(e)}else c[l]=e;return c};d.build=function(a){var b="";a.protocol&&(b+=a.protocol+
":");a.urn||!b&&!a.hostname||(b+="//");b+=d.buildAuthority(a)||"";"string"===typeof a.path&&("/"!==a.path.charAt(0)&&"string"===typeof a.hostname&&(b+="/"),b+=a.path);"string"===typeof a.query&&a.query&&(b+="?"+a.query);"string"===typeof a.fragment&&a.fragment&&(b+="#"+a.fragment);return b};d.buildHost=function(a){var b="";if(a.hostname)b=d.ip6_expression.test(a.hostname)?b+("["+a.hostname+"]"):b+a.hostname;else return"";a.port&&(b+=":"+a.port);return b};d.buildAuthority=function(a){return d.buildUserinfo(a)+
d.buildHost(a)};d.buildUserinfo=function(a){var b="";a.username&&(b+=d.encode(a.username),a.password&&(b+=":"+d.encode(a.password)),b+="@");return b};d.buildQuery=function(a,b,c){var f="",g,e,l,m;for(e in a)if(p.call(a,e)&&e)if(k(a[e]))for(g={},l=0,m=a[e].length;l<m;l++)void 0!==a[e][l]&&void 0===g[a[e][l]+""]&&(f+="&"+d.buildQueryParameter(e,a[e][l],c),!0!==b&&(g[a[e][l]+""]=!0));else void 0!==a[e]&&(f+="&"+d.buildQueryParameter(e,a[e],c));return f.substring(1)};d.buildQueryParameter=function(a,
b,c){return d.encodeQuery(a,c)+(null!==b?"="+d.encodeQuery(b,c):"")};d.addQuery=function(a,b,c){if("object"===typeof b)for(var f in b)p.call(b,f)&&d.addQuery(a,f,b[f]);else if("string"===typeof b)void 0===a[b]?a[b]=c:("string"===typeof a[b]&&(a[b]=[a[b]]),k(c)||(c=[c]),a[b]=(a[b]||[]).concat(c));else throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");};d.removeQuery=function(a,b,c){var f;if(k(b))for(c=0,f=b.length;c<f;c++)a[b[c]]=void 0;else if("RegExp"===w(b))for(f in a)b.test(f)&&
(a[f]=void 0);else if("object"===typeof b)for(f in b)p.call(b,f)&&d.removeQuery(a,f,b[f]);else if("string"===typeof b)void 0!==c?"RegExp"===w(c)?!k(a[b])&&c.test(a[b])?a[b]=void 0:a[b]=C(a[b],c):a[b]===c?a[b]=void 0:k(a[b])&&(a[b]=C(a[b],c)):a[b]=void 0;else throw new TypeError("URI.removeQuery() accepts an object, string, RegExp as the first parameter");};d.hasQuery=function(a,b,c,f){if("object"===typeof b){for(var e in b)if(p.call(b,e)&&!d.hasQuery(a,e,b[e]))return!1;return!0}if("string"!==typeof b)throw new TypeError("URI.hasQuery() accepts an object, string as the name parameter");
switch(w(c)){case "Undefined":return b in a;case "Boolean":return a=Boolean(k(a[b])?a[b].length:a[b]),c===a;case "Function":return!!c(a[b],b,a);case "Array":return k(a[b])?(f?z:D)(a[b],c):!1;case "RegExp":return k(a[b])?f?z(a[b],c):!1:Boolean(a[b]&&a[b].match(c));case "Number":c=String(c);case "String":return k(a[b])?f?z(a[b],c):!1:a[b]===c;default:throw new TypeError("URI.hasQuery() accepts undefined, boolean, string, number, RegExp, Function as the value parameter");}};d.commonPath=function(a,b){var c=
Math.min(a.length,b.length),d;for(d=0;d<c;d++)if(a.charAt(d)!==b.charAt(d)){d--;break}if(1>d)return a.charAt(0)===b.charAt(0)&&"/"===a.charAt(0)?"/":"";if("/"!==a.charAt(d)||"/"!==b.charAt(d))d=a.substring(0,d).lastIndexOf("/");return a.substring(0,d+1)};d.withinString=function(a,b,c){c||(c={});var f=c.start||d.findUri.start,e=c.end||d.findUri.end,u=c.trim||d.findUri.trim,l=/[a-z0-9-]=["']?$/i;for(f.lastIndex=0;;){var m=f.exec(a);if(!m)break;m=m.index;if(c.ignoreHtml){var k=a.slice(Math.max(m-3,0),
m);if(k&&l.test(k))continue}var k=m+a.slice(m).search(e),h=a.slice(m,k).replace(u,"");c.ignore&&c.ignore.test(h)||(k=m+h.length,h=b(h,m,k,a),a=a.slice(0,m)+h+a.slice(k),f.lastIndex=m+h.length)}f.lastIndex=0;return a};d.ensureValidHostname=function(a){if(a.match(d.invalid_hostname_characters)){if(!n)throw new TypeError('Hostname "'+a+'" contains characters other than [A-Z0-9.-] and Punycode.js is not available');if(n.toASCII(a).match(d.invalid_hostname_characters))throw new TypeError('Hostname "'+
a+'" contains characters other than [A-Z0-9.-]');}};d.noConflict=function(a){if(a)return a={URI:this.noConflict()},h.URITemplate&&"function"===typeof h.URITemplate.noConflict&&(a.URITemplate=h.URITemplate.noConflict()),h.IPv6&&"function"===typeof h.IPv6.noConflict&&(a.IPv6=h.IPv6.noConflict()),h.SecondLevelDomains&&"function"===typeof h.SecondLevelDomains.noConflict&&(a.SecondLevelDomains=h.SecondLevelDomains.noConflict()),a;h.URI===this&&(h.URI=G);return this};e.build=function(a){if(!0===a)this._deferred_build=
!0;else if(void 0===a||this._deferred_build)this._string=d.build(this._parts),this._deferred_build=!1;return this};e.clone=function(){return new d(this)};e.valueOf=e.toString=function(){return this.build(!1)._string};e.protocol=x("protocol");e.username=x("username");e.password=x("password");e.hostname=x("hostname");e.port=x("port");e.query=E("query","?");e.fragment=E("fragment","#");e.search=function(a,b){var c=this.query(a,b);return"string"===typeof c&&c.length?"?"+c:c};e.hash=function(a,b){var c=
this.fragment(a,b);return"string"===typeof c&&c.length?"#"+c:c};e.pathname=function(a,b){if(void 0===a||!0===a){var c=this._parts.path||(this._parts.hostname?"/":"");return a?(this._parts.urn?d.decodeUrnPath:d.decodePath)(c):c}this._parts.path=this._parts.urn?a?d.recodeUrnPath(a):"":a?d.recodePath(a):"/";this.build(!b);return this};e.path=e.pathname;e.href=function(a,b){var c;if(void 0===a)return this.toString();this._string="";this._parts=d._parts();var f=a instanceof d,e="object"===typeof a&&(a.hostname||
a.path||a.pathname);a.nodeName&&(e=d.getDomAttribute(a),a=a[e]||"",e=!1);!f&&e&&void 0!==a.pathname&&(a=a.toString());if("string"===typeof a||a instanceof String)this._parts=d.parse(String(a),this._parts);else if(f||e)for(c in f=f?a._parts:a,f)p.call(this._parts,c)&&(this._parts[c]=f[c]);else throw new TypeError("invalid input");this.build(!b);return this};e.is=function(a){var b=!1,c=!1,f=!1,e=!1,u=!1,l=!1,k=!1,h=!this._parts.urn;this._parts.hostname&&(h=!1,c=d.ip4_expression.test(this._parts.hostname),
f=d.ip6_expression.test(this._parts.hostname),b=c||f,u=(e=!b)&&t&&t.has(this._parts.hostname),l=e&&d.idn_expression.test(this._parts.hostname),k=e&&d.punycode_expression.test(this._parts.hostname));switch(a.toLowerCase()){case "relative":return h;case "absolute":return!h;case "domain":case "name":return e;case "sld":return u;case "ip":return b;case "ip4":case "ipv4":case "inet4":return c;case "ip6":case "ipv6":case "inet6":return f;case "idn":return l;case "url":return!this._parts.urn;case "urn":return!!this._parts.urn;
case "punycode":return k}return null};var H=e.protocol,I=e.port,J=e.hostname;e.protocol=function(a,b){if(void 0!==a&&a&&(a=a.replace(/:(\/\/)?$/,""),!a.match(d.protocol_expression)))throw new TypeError('Protocol "'+a+"\" contains characters other than [A-Z0-9.+-] or doesn't start with [A-Z]");return H.call(this,a,b)};e.scheme=e.protocol;e.port=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0!==a&&(0===a&&(a=null),a&&(a+="",":"===a.charAt(0)&&(a=a.substring(1)),a.match(/[^0-9]/))))throw new TypeError('Port "'+
a+'" contains characters other than [0-9]');return I.call(this,a,b)};e.hostname=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0!==a){var c={};d.parseHost(a,c);a=c.hostname}return J.call(this,a,b)};e.host=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a)return this._parts.hostname?d.buildHost(this._parts):"";d.parseHost(a,this._parts);this.build(!b);return this};e.authority=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a)return this._parts.hostname?
d.buildAuthority(this._parts):"";d.parseAuthority(a,this._parts);this.build(!b);return this};e.userinfo=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a){if(!this._parts.username)return"";var c=d.buildUserinfo(this._parts);return c.substring(0,c.length-1)}"@"!==a[a.length-1]&&(a+="@");d.parseUserinfo(a,this._parts);this.build(!b);return this};e.resource=function(a,b){var c;if(void 0===a)return this.path()+this.search()+this.hash();c=d.parse(a);this._parts.path=c.path;this._parts.query=
c.query;this._parts.fragment=c.fragment;this.build(!b);return this};e.subdomain=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.length-this.domain().length-1;return this._parts.hostname.substring(0,c)||""}c=this._parts.hostname.length-this.domain().length;c=this._parts.hostname.substring(0,c);c=new RegExp("^"+q(c));a&&"."!==a.charAt(a.length-1)&&(a+=".");a&&d.ensureValidHostname(a);this._parts.hostname=
this._parts.hostname.replace(c,a);this.build(!b);return this};e.domain=function(a,b){if(this._parts.urn)return void 0===a?"":this;"boolean"===typeof a&&(b=a,a=void 0);if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.match(/\./g);if(c&&2>c.length)return this._parts.hostname;c=this._parts.hostname.length-this.tld(b).length-1;c=this._parts.hostname.lastIndexOf(".",c-1)+1;return this._parts.hostname.substring(c)||""}if(!a)throw new TypeError("cannot set domain empty");
d.ensureValidHostname(a);!this._parts.hostname||this.is("IP")?this._parts.hostname=a:(c=new RegExp(q(this.domain())+"$"),this._parts.hostname=this._parts.hostname.replace(c,a));this.build(!b);return this};e.tld=function(a,b){if(this._parts.urn)return void 0===a?"":this;"boolean"===typeof a&&(b=a,a=void 0);if(void 0===a){if(!this._parts.hostname||this.is("IP"))return"";var c=this._parts.hostname.lastIndexOf("."),c=this._parts.hostname.substring(c+1);return!0!==b&&t&&t.list[c.toLowerCase()]?t.get(this._parts.hostname)||
c:c}if(a)if(a.match(/[^a-zA-Z0-9-]/))if(t&&t.is(a))c=new RegExp(q(this.tld())+"$"),this._parts.hostname=this._parts.hostname.replace(c,a);else throw new TypeError('TLD "'+a+'" contains characters other than [A-Z0-9]');else{if(!this._parts.hostname||this.is("IP"))throw new ReferenceError("cannot set TLD on non-domain host");c=new RegExp(q(this.tld())+"$");this._parts.hostname=this._parts.hostname.replace(c,a)}else throw new TypeError("cannot set TLD empty");this.build(!b);return this};e.directory=
function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path&&!this._parts.hostname)return"";if("/"===this._parts.path)return"/";var c=this._parts.path.length-this.filename().length-1,c=this._parts.path.substring(0,c)||(this._parts.hostname?"/":"");return a?d.decodePath(c):c}c=this._parts.path.length-this.filename().length;c=this._parts.path.substring(0,c);c=new RegExp("^"+q(c));this.is("relative")||(a||(a="/"),"/"!==a.charAt(0)&&(a="/"+a));a&&"/"!==a.charAt(a.length-
1)&&(a+="/");a=d.recodePath(a);this._parts.path=this._parts.path.replace(c,a);this.build(!b);return this};e.filename=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";var c=this._parts.path.lastIndexOf("/"),c=this._parts.path.substring(c+1);return a?d.decodePathSegment(c):c}c=!1;"/"===a.charAt(0)&&(a=a.substring(1));a.match(/\.?\//)&&(c=!0);var f=new RegExp(q(this.filename())+"$");a=d.recodePath(a);this._parts.path=
this._parts.path.replace(f,a);c?this.normalizePath(b):this.build(!b);return this};e.suffix=function(a,b){if(this._parts.urn)return void 0===a?"":this;if(void 0===a||!0===a){if(!this._parts.path||"/"===this._parts.path)return"";var c=this.filename(),f=c.lastIndexOf(".");if(-1===f)return"";c=c.substring(f+1);c=/^[a-z0-9%]+$/i.test(c)?c:"";return a?d.decodePathSegment(c):c}"."===a.charAt(0)&&(a=a.substring(1));if(c=this.suffix())f=a?new RegExp(q(c)+"$"):new RegExp(q("."+c)+"$");else{if(!a)return this;
this._parts.path+="."+d.recodePath(a)}f&&(a=d.recodePath(a),this._parts.path=this._parts.path.replace(f,a));this.build(!b);return this};e.segment=function(a,b,c){var d=this._parts.urn?":":"/",e=this.path(),u="/"===e.substring(0,1),e=e.split(d);void 0!==a&&"number"!==typeof a&&(c=b,b=a,a=void 0);if(void 0!==a&&"number"!==typeof a)throw Error('Bad segment "'+a+'", must be 0-based integer');u&&e.shift();0>a&&(a=Math.max(e.length+a,0));if(void 0===b)return void 0===a?e:e[a];if(null===a||void 0===e[a])if(k(b)){e=
[];a=0;for(var l=b.length;a<l;a++)if(b[a].length||e.length&&e[e.length-1].length)e.length&&!e[e.length-1].length&&e.pop(),e.push(b[a])}else{if(b||"string"===typeof b)""===e[e.length-1]?e[e.length-1]=b:e.push(b)}else b?e[a]=b:e.splice(a,1);u&&e.unshift("");return this.path(e.join(d),c)};e.segmentCoded=function(a,b,c){var e,g;"number"!==typeof a&&(c=b,b=a,a=void 0);if(void 0===b){a=this.segment(a,b,c);if(k(a))for(e=0,g=a.length;e<g;e++)a[e]=d.decode(a[e]);else a=void 0!==a?d.decode(a):void 0;return a}if(k(b))for(e=
0,g=b.length;e<g;e++)b[e]=d.encode(b[e]);else b="string"===typeof b||b instanceof String?d.encode(b):b;return this.segment(a,b,c)};var K=e.query;e.query=function(a,b){if(!0===a)return d.parseQuery(this._parts.query,this._parts.escapeQuerySpace);if("function"===typeof a){var c=d.parseQuery(this._parts.query,this._parts.escapeQuerySpace),e=a.call(this,c);this._parts.query=d.buildQuery(e||c,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);this.build(!b);return this}return void 0!==
a&&"string"!==typeof a?(this._parts.query=d.buildQuery(a,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace),this.build(!b),this):K.call(this,a,b)};e.setQuery=function(a,b,c){var e=d.parseQuery(this._parts.query,this._parts.escapeQuerySpace);if("string"===typeof a||a instanceof String)e[a]=void 0!==b?b:null;else if("object"===typeof a)for(var g in a)p.call(a,g)&&(e[g]=a[g]);else throw new TypeError("URI.addQuery() accepts an object, string as the name parameter");this._parts.query=
d.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(c=b);this.build(!c);return this};e.addQuery=function(a,b,c){var e=d.parseQuery(this._parts.query,this._parts.escapeQuerySpace);d.addQuery(e,a,void 0===b?null:b);this._parts.query=d.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(c=b);this.build(!c);return this};e.removeQuery=function(a,b,c){var e=d.parseQuery(this._parts.query,this._parts.escapeQuerySpace);
d.removeQuery(e,a,b);this._parts.query=d.buildQuery(e,this._parts.duplicateQueryParameters,this._parts.escapeQuerySpace);"string"!==typeof a&&(c=b);this.build(!c);return this};e.hasQuery=function(a,b,c){var e=d.parseQuery(this._parts.query,this._parts.escapeQuerySpace);return d.hasQuery(e,a,b,c)};e.setSearch=e.setQuery;e.addSearch=e.addQuery;e.removeSearch=e.removeQuery;e.hasSearch=e.hasQuery;e.normalize=function(){return this._parts.urn?this.normalizeProtocol(!1).normalizePath(!1).normalizeQuery(!1).normalizeFragment(!1).build():
this.normalizeProtocol(!1).normalizeHostname(!1).normalizePort(!1).normalizePath(!1).normalizeQuery(!1).normalizeFragment(!1).build()};e.normalizeProtocol=function(a){"string"===typeof this._parts.protocol&&(this._parts.protocol=this._parts.protocol.toLowerCase(),this.build(!a));return this};e.normalizeHostname=function(a){this._parts.hostname&&(this.is("IDN")&&n?this._parts.hostname=n.toASCII(this._parts.hostname):this.is("IPv6")&&v&&(this._parts.hostname=v.best(this._parts.hostname)),this._parts.hostname=
this._parts.hostname.toLowerCase(),this.build(!a));return this};e.normalizePort=function(a){"string"===typeof this._parts.protocol&&this._parts.port===d.defaultPorts[this._parts.protocol]&&(this._parts.port=null,this.build(!a));return this};e.normalizePath=function(a){var b=this._parts.path;if(!b)return this;if(this._parts.urn)return this._parts.path=d.recodeUrnPath(this._parts.path),this.build(!a),this;if("/"===this._parts.path)return this;var c,e="",g,k;"/"!==b.charAt(0)&&(c=!0,b="/"+b);if("/.."===
b.slice(-3)||"/."===b.slice(-2))b+="/";b=b.replace(/(\/(\.\/)+)|(\/\.$)/g,"/").replace(/\/{2,}/g,"/");c&&(e=b.substring(1).match(/^(\.\.\/)+/)||"")&&(e=e[0]);for(;;){g=b.indexOf("/..");if(-1===g)break;else if(0===g){b=b.substring(3);continue}k=b.substring(0,g).lastIndexOf("/");-1===k&&(k=g);b=b.substring(0,k)+b.substring(g+3)}c&&this.is("relative")&&(b=e+b.substring(1));b=d.recodePath(b);this._parts.path=b;this.build(!a);return this};e.normalizePathname=e.normalizePath;e.normalizeQuery=function(a){"string"===
typeof this._parts.query&&(this._parts.query.length?this.query(d.parseQuery(this._parts.query,this._parts.escapeQuerySpace)):this._parts.query=null,this.build(!a));return this};e.normalizeFragment=function(a){this._parts.fragment||(this._parts.fragment=null,this.build(!a));return this};e.normalizeSearch=e.normalizeQuery;e.normalizeHash=e.normalizeFragment;e.iso8859=function(){var a=d.encode,b=d.decode;d.encode=escape;d.decode=decodeURIComponent;try{this.normalize()}finally{d.encode=a,d.decode=b}return this};
e.unicode=function(){var a=d.encode,b=d.decode;d.encode=A;d.decode=unescape;try{this.normalize()}finally{d.encode=a,d.decode=b}return this};e.readable=function(){var a=this.clone();a.username("").password("").normalize();var b="";a._parts.protocol&&(b+=a._parts.protocol+"://");a._parts.hostname&&(a.is("punycode")&&n?(b+=n.toUnicode(a._parts.hostname),a._parts.port&&(b+=":"+a._parts.port)):b+=a.host());a._parts.hostname&&a._parts.path&&"/"!==a._parts.path.charAt(0)&&(b+="/");b+=a.path(!0);if(a._parts.query){for(var c=
"",e=0,g=a._parts.query.split("&"),k=g.length;e<k;e++){var l=(g[e]||"").split("="),c=c+("&"+d.decodeQuery(l[0],this._parts.escapeQuerySpace).replace(/&/g,"%26"));void 0!==l[1]&&(c+="="+d.decodeQuery(l[1],this._parts.escapeQuerySpace).replace(/&/g,"%26"))}b+="?"+c.substring(1)}return b+=d.decodeQuery(a.hash(),!0)};e.absoluteTo=function(a){var b=this.clone(),c=["protocol","username","password","hostname","port"],e,g;if(this._parts.urn)throw Error("URNs do not have any generally defined hierarchical components");
a instanceof d||(a=new d(a));b._parts.protocol||(b._parts.protocol=a._parts.protocol);if(this._parts.hostname)return b;for(e=0;g=c[e];e++)b._parts[g]=a._parts[g];b._parts.path?".."===b._parts.path.substring(-2)&&(b._parts.path+="/"):(b._parts.path=a._parts.path,b._parts.query||(b._parts.query=a._parts.query));"/"!==b.path().charAt(0)&&(c=(c=a.directory())?c:0===a.path().indexOf("/")?"/":"",b._parts.path=(c?c+"/":"")+b._parts.path,b.normalizePath());b.build();return b};e.relativeTo=function(a){var b=
this.clone().normalize(),c,e,g;if(b._parts.urn)throw Error("URNs do not have any generally defined hierarchical components");a=(new d(a)).normalize();c=b._parts;e=a._parts;g=b.path();a=a.path();if("/"!==g.charAt(0))throw Error("URI is already relative");if("/"!==a.charAt(0))throw Error("Cannot calculate a URI relative to another relative URI");c.protocol===e.protocol&&(c.protocol=null);if(c.username===e.username&&c.password===e.password&&null===c.protocol&&null===c.username&&null===c.password&&c.hostname===
e.hostname&&c.port===e.port)c.hostname=null,c.port=null;else return b.build();if(g===a)return c.path="",b.build();g=d.commonPath(g,a);if(!g)return b.build();e=e.path.substring(g.length).replace(/[^\/]*$/,"").replace(/.*?\//g,"../");c.path=e+c.path.substring(g.length)||"./";return b.build()};e.equals=function(a){var b=this.clone();a=new d(a);var c={},e={},g={},h;b.normalize();a.normalize();if(b.toString()===a.toString())return!0;c=b.query();e=a.query();b.query("");a.query("");if(b.toString()!==a.toString()||
c.length!==e.length)return!1;c=d.parseQuery(c,this._parts.escapeQuerySpace);e=d.parseQuery(e,this._parts.escapeQuerySpace);for(h in c)if(p.call(c,h)){if(!k(c[h])){if(c[h]!==e[h])return!1}else if(!D(c[h],e[h]))return!1;g[h]=!0}for(h in e)if(p.call(e,h)&&!g[h])return!1;return!0};e.duplicateQueryParameters=function(a){this._parts.duplicateQueryParameters=!!a;return this};e.escapeQuerySpace=function(a){this._parts.escapeQuerySpace=!!a;return this};return d});

/*************************************************************************************
 * INFOMAX CUSTOMIZED SELECTION/HOVER BEHAVIOUR! BE AWARE WHEN UPDATING THIS LIBRARY.
 * (BCS #33821)
 ************************************************************************************/

/*! jQuery UI - v1.11.4 - 2017-04-19
* http://jqueryui.com
* Includes: core.js, widget.js, position.js, button.js, datepicker.js, menu.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */

(function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define([ "jquery" ], factory );
	} else {

		// Browser globals
		factory( jQuery );
	}
}(function( $ ) {
/*!
 * jQuery UI Core 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/category/ui-core/
 */


// $.ui might exist from components with no dependencies, e.g., $.ui.position
$.ui = $.ui || {};

$.extend( $.ui, {
	version: "1.11.4",

	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
	}
});

// plugins
$.fn.extend({
	scrollParent: function( includeHidden ) {
		var position = this.css( "position" ),
			excludeStaticParent = position === "absolute",
			overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
			scrollParent = this.parents().filter( function() {
				var parent = $( this );
				if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
					return false;
				}
				return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + parent.css( "overflow-x" ) );
			}).eq( 0 );

		return position === "fixed" || !scrollParent.length ? $( this[ 0 ].ownerDocument || document ) : scrollParent;
	},

	uniqueId: (function() {
		var uuid = 0;

		return function() {
			return this.each(function() {
				if ( !this.id ) {
					this.id = "ui-id-" + ( ++uuid );
				}
			});
		};
	})(),

	removeUniqueId: function() {
		return this.each(function() {
			if ( /^ui-id-\d+$/.test( this.id ) ) {
				$( this ).removeAttr( "id" );
			}
		});
	}
});

// selectors
function focusable( element, isTabIndexNotNaN ) {
	var map, mapName, img,
		nodeName = element.nodeName.toLowerCase();
	if ( "area" === nodeName ) {
		map = element.parentNode;
		mapName = map.name;
		if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
			return false;
		}
		img = $( "img[usemap='#" + mapName + "']" )[ 0 ];
		return !!img && visible( img );
	}
	return ( /^(input|select|textarea|button|object)$/.test( nodeName ) ?
		!element.disabled :
		"a" === nodeName ?
			element.href || isTabIndexNotNaN :
			isTabIndexNotNaN) &&
		// the element and all of its ancestors must be visible
		visible( element );
}

function visible( element ) {
	return $.expr.filters.visible( element ) &&
		!$( element ).parents().addBack().filter(function() {
			return $.css( this, "visibility" ) === "hidden";
		}).length;
}

$.extend( $.expr[ ":" ], {
	data: $.expr.createPseudo ?
		$.expr.createPseudo(function( dataName ) {
			return function( elem ) {
				return !!$.data( elem, dataName );
			};
		}) :
		// support: jQuery <1.8
		function( elem, i, match ) {
			return !!$.data( elem, match[ 3 ] );
		},

	focusable: function( element ) {
		return focusable( element, !isNaN( $.attr( element, "tabindex" ) ) );
	},

	tabbable: function( element ) {
		var tabIndex = $.attr( element, "tabindex" ),
			isTabIndexNaN = isNaN( tabIndex );
		return ( isTabIndexNaN || tabIndex >= 0 ) && focusable( element, !isTabIndexNaN );
	}
});

// support: jQuery <1.8
if ( !$( "<a>" ).outerWidth( 1 ).jquery ) {
	$.each( [ "Width", "Height" ], function( i, name ) {
		var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
			type = name.toLowerCase(),
			orig = {
				innerWidth: $.fn.innerWidth,
				innerHeight: $.fn.innerHeight,
				outerWidth: $.fn.outerWidth,
				outerHeight: $.fn.outerHeight
			};

		function reduce( elem, size, border, margin ) {
			$.each( side, function() {
				size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
				if ( border ) {
					size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
				}
				if ( margin ) {
					size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
				}
			});
			return size;
		}

		$.fn[ "inner" + name ] = function( size ) {
			if ( size === undefined ) {
				return orig[ "inner" + name ].call( this );
			}

			return this.each(function() {
				$( this ).css( type, reduce( this, size ) + "px" );
			});
		};

		$.fn[ "outer" + name] = function( size, margin ) {
			if ( typeof size !== "number" ) {
				return orig[ "outer" + name ].call( this, size );
			}

			return this.each(function() {
				$( this).css( type, reduce( this, size, true, margin ) + "px" );
			});
		};
	});
}

// support: jQuery <1.8
if ( !$.fn.addBack ) {
	$.fn.addBack = function( selector ) {
		return this.add( selector == null ?
			this.prevObject : this.prevObject.filter( selector )
		);
	};
}

// support: jQuery 1.6.1, 1.6.2 (http://bugs.jquery.com/ticket/9413)
if ( $( "<a>" ).data( "a-b", "a" ).removeData( "a-b" ).data( "a-b" ) ) {
	$.fn.removeData = (function( removeData ) {
		return function( key ) {
			if ( arguments.length ) {
				return removeData.call( this, $.camelCase( key ) );
			} else {
				return removeData.call( this );
			}
		};
	})( $.fn.removeData );
}

// deprecated
$.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );

$.fn.extend({
	focus: (function( orig ) {
		return function( delay, fn ) {
			return typeof delay === "number" ?
				this.each(function() {
					var elem = this;
					setTimeout(function() {
						$( elem ).focus();
						if ( fn ) {
							fn.call( elem );
						}
					}, delay );
				}) :
				orig.apply( this, arguments );
		};
	})( $.fn.focus ),

	disableSelection: (function() {
		var eventType = "onselectstart" in document.createElement( "div" ) ?
			"selectstart" :
			"mousedown";

		return function() {
			return this.bind( eventType + ".ui-disableSelection", function( event ) {
				event.preventDefault();
			});
		};
	})(),

	enableSelection: function() {
		return this.unbind( ".ui-disableSelection" );
	},

	zIndex: function( zIndex ) {
		if ( zIndex !== undefined ) {
			return this.css( "zIndex", zIndex );
		}

		if ( this.length ) {
			var elem = $( this[ 0 ] ), position, value;
			while ( elem.length && elem[ 0 ] !== document ) {
				// Ignore z-index if position is set to a value where z-index is ignored by the browser
				// This makes behavior of this function consistent across browsers
				// WebKit always returns auto if the element is positioned
				position = elem.css( "position" );
				if ( position === "absolute" || position === "relative" || position === "fixed" ) {
					// IE returns 0 when zIndex is not specified
					// other browsers return a string
					// we ignore the case of nested elements with an explicit value of 0
					// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
					value = parseInt( elem.css( "zIndex" ), 10 );
					if ( !isNaN( value ) && value !== 0 ) {
						return value;
					}
				}
				elem = elem.parent();
			}
		}

		return 0;
	}
});

// $.ui.plugin is deprecated. Use $.widget() extensions instead.
$.ui.plugin = {
	add: function( module, option, set ) {
		var i,
			proto = $.ui[ module ].prototype;
		for ( i in set ) {
			proto.plugins[ i ] = proto.plugins[ i ] || [];
			proto.plugins[ i ].push( [ option, set[ i ] ] );
		}
	},
	call: function( instance, name, args, allowDisconnected ) {
		var i,
			set = instance.plugins[ name ];

		if ( !set ) {
			return;
		}

		if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode || instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
			return;
		}

		for ( i = 0; i < set.length; i++ ) {
			if ( instance.options[ set[ i ][ 0 ] ] ) {
				set[ i ][ 1 ].apply( instance.element, args );
			}
		}
	}
};


/*!
 * jQuery UI Widget 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/jQuery.widget/
 */


var widget_uuid = 0,
	widget_slice = Array.prototype.slice;

$.cleanData = (function( orig ) {
	return function( elems ) {
		var events, elem, i;
		for ( i = 0; (elem = elems[i]) != null; i++ ) {
			try {

				// Only trigger remove when necessary to save time
				events = $._data( elem, "events" );
				if ( events && events.remove ) {
					$( elem ).triggerHandler( "remove" );
				}

			// http://bugs.jquery.com/ticket/8235
			} catch ( e ) {}
		}
		orig( elems );
	};
})( $.cleanData );

$.widget = function( name, base, prototype ) {
	var fullName, existingConstructor, constructor, basePrototype,
		// proxiedPrototype allows the provided prototype to remain unmodified
		// so that it can be used as a mixin for multiple widgets (#8876)
		proxiedPrototype = {},
		namespace = name.split( "." )[ 0 ];

	name = name.split( "." )[ 1 ];
	fullName = namespace + "-" + name;

	if ( !prototype ) {
		prototype = base;
		base = $.Widget;
	}

	// create selector for plugin
	$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
		return !!$.data( elem, fullName );
	};

	$[ namespace ] = $[ namespace ] || {};
	existingConstructor = $[ namespace ][ name ];
	constructor = $[ namespace ][ name ] = function( options, element ) {
		// allow instantiation without "new" keyword
		if ( !this._createWidget ) {
			return new constructor( options, element );
		}

		// allow instantiation without initializing for simple inheritance
		// must use "new" keyword (the code above always passes args)
		if ( arguments.length ) {
			this._createWidget( options, element );
		}
	};
	// extend with the existing constructor to carry over any static properties
	$.extend( constructor, existingConstructor, {
		version: prototype.version,
		// copy the object used to create the prototype in case we need to
		// redefine the widget later
		_proto: $.extend( {}, prototype ),
		// track widgets that inherit from this widget in case this widget is
		// redefined after a widget inherits from it
		_childConstructors: []
	});

	basePrototype = new base();
	// we need to make the options hash a property directly on the new instance
	// otherwise we'll modify the options hash on the prototype that we're
	// inheriting from
	basePrototype.options = $.widget.extend( {}, basePrototype.options );
	$.each( prototype, function( prop, value ) {
		if ( !$.isFunction( value ) ) {
			proxiedPrototype[ prop ] = value;
			return;
		}
		proxiedPrototype[ prop ] = (function() {
			var _super = function() {
					return base.prototype[ prop ].apply( this, arguments );
				},
				_superApply = function( args ) {
					return base.prototype[ prop ].apply( this, args );
				};
			return function() {
				var __super = this._super,
					__superApply = this._superApply,
					returnValue;

				this._super = _super;
				this._superApply = _superApply;

				returnValue = value.apply( this, arguments );

				this._super = __super;
				this._superApply = __superApply;

				return returnValue;
			};
		})();
	});
	constructor.prototype = $.widget.extend( basePrototype, {
		// TODO: remove support for widgetEventPrefix
		// always use the name + a colon as the prefix, e.g., draggable:start
		// don't prefix for widgets that aren't DOM-based
		widgetEventPrefix: existingConstructor ? (basePrototype.widgetEventPrefix || name) : name
	}, proxiedPrototype, {
		constructor: constructor,
		namespace: namespace,
		widgetName: name,
		widgetFullName: fullName
	});

	// If this widget is being redefined then we need to find all widgets that
	// are inheriting from it and redefine all of them so that they inherit from
	// the new version of this widget. We're essentially trying to replace one
	// level in the prototype chain.
	if ( existingConstructor ) {
		$.each( existingConstructor._childConstructors, function( i, child ) {
			var childPrototype = child.prototype;

			// redefine the child widget using the same prototype that was
			// originally used, but inherit from the new version of the base
			$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto );
		});
		// remove the list of existing child constructors from the old constructor
		// so the old child constructors can be garbage collected
		delete existingConstructor._childConstructors;
	} else {
		base._childConstructors.push( constructor );
	}

	$.widget.bridge( name, constructor );

	return constructor;
};

$.widget.extend = function( target ) {
	var input = widget_slice.call( arguments, 1 ),
		inputIndex = 0,
		inputLength = input.length,
		key,
		value;
	for ( ; inputIndex < inputLength; inputIndex++ ) {
		for ( key in input[ inputIndex ] ) {
			value = input[ inputIndex ][ key ];
			if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
				// Clone objects
				if ( $.isPlainObject( value ) ) {
					target[ key ] = $.isPlainObject( target[ key ] ) ?
						$.widget.extend( {}, target[ key ], value ) :
						// Don't extend strings, arrays, etc. with objects
						$.widget.extend( {}, value );
				// Copy everything else by reference
				} else {
					target[ key ] = value;
				}
			}
		}
	}
	return target;
};

$.widget.bridge = function( name, object ) {
	var fullName = object.prototype.widgetFullName || name;
	$.fn[ name ] = function( options ) {
		var isMethodCall = typeof options === "string",
			args = widget_slice.call( arguments, 1 ),
			returnValue = this;

		if ( isMethodCall ) {
			this.each(function() {
				var methodValue,
					instance = $.data( this, fullName );
				if ( options === "instance" ) {
					returnValue = instance;
					return false;
				}
				if ( !instance ) {
					return $.error( "cannot call methods on " + name + " prior to initialization; " +
						"attempted to call method '" + options + "'" );
				}
				if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) {
					return $.error( "no such method '" + options + "' for " + name + " widget instance" );
				}
				methodValue = instance[ options ].apply( instance, args );
				if ( methodValue !== instance && methodValue !== undefined ) {
					returnValue = methodValue && methodValue.jquery ?
						returnValue.pushStack( methodValue.get() ) :
						methodValue;
					return false;
				}
			});
		} else {

			// Allow multiple hashes to be passed on init
			if ( args.length ) {
				options = $.widget.extend.apply( null, [ options ].concat(args) );
			}

			this.each(function() {
				var instance = $.data( this, fullName );
				if ( instance ) {
					instance.option( options || {} );
					if ( instance._init ) {
						instance._init();
					}
				} else {
					$.data( this, fullName, new object( options, this ) );
				}
			});
		}

		return returnValue;
	};
};

$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];

$.Widget.prototype = {
	widgetName: "widget",
	widgetEventPrefix: "",
	defaultElement: "<div>",
	options: {
		disabled: false,

		// callbacks
		create: null
	},
	_createWidget: function( options, element ) {
		element = $( element || this.defaultElement || this )[ 0 ];
		this.element = $( element );
		this.uuid = widget_uuid++;
		this.eventNamespace = "." + this.widgetName + this.uuid;

		this.bindings = $();
		this.hoverable = $();
		this.focusable = $();

		if ( element !== this ) {
			$.data( element, this.widgetFullName, this );
			this._on( true, this.element, {
				remove: function( event ) {
					if ( event.target === element ) {
						this.destroy();
					}
				}
			});
			this.document = $( element.style ?
				// element within the document
				element.ownerDocument :
				// element is window or document
				element.document || element );
			this.window = $( this.document[0].defaultView || this.document[0].parentWindow );
		}

		this.options = $.widget.extend( {},
			this.options,
			this._getCreateOptions(),
			options );

		this._create();
		this._trigger( "create", null, this._getCreateEventData() );
		this._init();
	},
	_getCreateOptions: $.noop,
	_getCreateEventData: $.noop,
	_create: $.noop,
	_init: $.noop,

	destroy: function() {
		this._destroy();
		// we can probably remove the unbind calls in 2.0
		// all event bindings should go through this._on()
		this.element
			.unbind( this.eventNamespace )
			.removeData( this.widgetFullName )
			// support: jquery <1.6.3
			// http://bugs.jquery.com/ticket/9413
			.removeData( $.camelCase( this.widgetFullName ) );
		this.widget()
			.unbind( this.eventNamespace )
			.removeAttr( "aria-disabled" )
			.removeClass(
				this.widgetFullName + "-disabled " +
				"ui-state-disabled" );

		// clean up events and states
		this.bindings.unbind( this.eventNamespace );
		this.hoverable.removeClass( "ui-state-hover" );
		this.focusable.removeClass( "ui-state-focus" );
	},
	_destroy: $.noop,

	widget: function() {
		return this.element;
	},

	option: function( key, value ) {
		var options = key,
			parts,
			curOption,
			i;

		if ( arguments.length === 0 ) {
			// don't return a reference to the internal hash
			return $.widget.extend( {}, this.options );
		}

		if ( typeof key === "string" ) {
			// handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
			options = {};
			parts = key.split( "." );
			key = parts.shift();
			if ( parts.length ) {
				curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
				for ( i = 0; i < parts.length - 1; i++ ) {
					curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
					curOption = curOption[ parts[ i ] ];
				}
				key = parts.pop();
				if ( arguments.length === 1 ) {
					return curOption[ key ] === undefined ? null : curOption[ key ];
				}
				curOption[ key ] = value;
			} else {
				if ( arguments.length === 1 ) {
					return this.options[ key ] === undefined ? null : this.options[ key ];
				}
				options[ key ] = value;
			}
		}

		this._setOptions( options );

		return this;
	},
	_setOptions: function( options ) {
		var key;

		for ( key in options ) {
			this._setOption( key, options[ key ] );
		}

		return this;
	},
	_setOption: function( key, value ) {
		this.options[ key ] = value;

		if ( key === "disabled" ) {
			this.widget()
				.toggleClass( this.widgetFullName + "-disabled", !!value );

			// If the widget is becoming disabled, then nothing is interactive
			if ( value ) {
				this.hoverable.removeClass( "ui-state-hover" );
				this.focusable.removeClass( "ui-state-focus" );
			}
		}

		return this;
	},

	enable: function() {
		return this._setOptions({ disabled: false });
	},
	disable: function() {
		return this._setOptions({ disabled: true });
	},

	_on: function( suppressDisabledCheck, element, handlers ) {
		var delegateElement,
			instance = this;

		// no suppressDisabledCheck flag, shuffle arguments
		if ( typeof suppressDisabledCheck !== "boolean" ) {
			handlers = element;
			element = suppressDisabledCheck;
			suppressDisabledCheck = false;
		}

		// no element argument, shuffle and use this.element
		if ( !handlers ) {
			handlers = element;
			element = this.element;
			delegateElement = this.widget();
		} else {
			element = delegateElement = $( element );
			this.bindings = this.bindings.add( element );
		}

		$.each( handlers, function( event, handler ) {
			function handlerProxy() {
				// allow widgets to customize the disabled handling
				// - disabled as an array instead of boolean
				// - disabled class as method for disabling individual parts
				if ( !suppressDisabledCheck &&
						( instance.options.disabled === true ||
							$( this ).hasClass( "ui-state-disabled" ) ) ) {
					return;
				}
				return ( typeof handler === "string" ? instance[ handler ] : handler )
					.apply( instance, arguments );
			}

			// copy the guid so direct unbinding works
			if ( typeof handler !== "string" ) {
				handlerProxy.guid = handler.guid =
					handler.guid || handlerProxy.guid || $.guid++;
			}

			var match = event.match( /^([\w:-]*)\s*(.*)$/ ),
				eventName = match[1] + instance.eventNamespace,
				selector = match[2];
			if ( selector ) {
				delegateElement.delegate( selector, eventName, handlerProxy );
			} else {
				element.bind( eventName, handlerProxy );
			}
		});
	},

	_off: function( element, eventName ) {
		eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) +
			this.eventNamespace;
		element.unbind( eventName ).undelegate( eventName );

		// Clear the stack to avoid memory leaks (#10056)
		this.bindings = $( this.bindings.not( element ).get() );
		this.focusable = $( this.focusable.not( element ).get() );
		this.hoverable = $( this.hoverable.not( element ).get() );
	},

	_delay: function( handler, delay ) {
		function handlerProxy() {
			return ( typeof handler === "string" ? instance[ handler ] : handler )
				.apply( instance, arguments );
		}
		var instance = this;
		return setTimeout( handlerProxy, delay || 0 );
	},

	_hoverable: function( element ) {
		this.hoverable = this.hoverable.add( element );
		this._on( element, {
			mouseenter: function( event ) {
				$( event.currentTarget ).addClass( "ui-state-hover" );
			},
			mouseleave: function( event ) {
				$( event.currentTarget ).removeClass( "ui-state-hover" );
			}
		});
	},

	_focusable: function( element ) {
		this.focusable = this.focusable.add( element );
		this._on( element, {
			focusin: function( event ) {
				$( event.currentTarget ).addClass( "ui-state-focus" );
			},
			focusout: function( event ) {
				$( event.currentTarget ).removeClass( "ui-state-focus" );
			}
		});
	},

	_trigger: function( type, event, data ) {
		var prop, orig,
			callback = this.options[ type ];

		data = data || {};
		event = $.Event( event );
		event.type = ( type === this.widgetEventPrefix ?
			type :
			this.widgetEventPrefix + type ).toLowerCase();
		// the original event may come from any element
		// so we need to reset the target on the new event
		event.target = this.element[ 0 ];

		// copy original event properties over to the new event
		orig = event.originalEvent;
		if ( orig ) {
			for ( prop in orig ) {
				if ( !( prop in event ) ) {
					event[ prop ] = orig[ prop ];
				}
			}
		}

		this.element.trigger( event, data );
		return !( $.isFunction( callback ) &&
			callback.apply( this.element[0], [ event ].concat( data ) ) === false ||
			event.isDefaultPrevented() );
	}
};

$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
	$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
		if ( typeof options === "string" ) {
			options = { effect: options };
		}
		var hasOptions,
			effectName = !options ?
				method :
				options === true || typeof options === "number" ?
					defaultEffect :
					options.effect || defaultEffect;
		options = options || {};
		if ( typeof options === "number" ) {
			options = { duration: options };
		}
		hasOptions = !$.isEmptyObject( options );
		options.complete = callback;
		if ( options.delay ) {
			element.delay( options.delay );
		}
		if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
			element[ method ]( options );
		} else if ( effectName !== method && element[ effectName ] ) {
			element[ effectName ]( options.duration, options.easing, callback );
		} else {
			element.queue(function( next ) {
				$( this )[ method ]();
				if ( callback ) {
					callback.call( element[ 0 ] );
				}
				next();
			});
		}
	};
});

var widget = $.widget;


/*!
 * jQuery UI Position 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/position/
 */

(function() {

$.ui = $.ui || {};

var cachedScrollbarWidth, supportsOffsetFractions,
	max = Math.max,
	abs = Math.abs,
	round = Math.round,
	rhorizontal = /left|center|right/,
	rvertical = /top|center|bottom/,
	roffset = /[\+\-]\d+(\.[\d]+)?%?/,
	rposition = /^\w+/,
	rpercent = /%$/,
	_position = $.fn.position;

function getOffsets( offsets, width, height ) {
	return [
		parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
		parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
	];
}

function parseCss( element, property ) {
	return parseInt( $.css( element, property ), 10 ) || 0;
}

function getDimensions( elem ) {
	var raw = elem[0];
	if ( raw.nodeType === 9 ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: 0, left: 0 }
		};
	}
	if ( $.isWindow( raw ) ) {
		return {
			width: elem.width(),
			height: elem.height(),
			offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
		};
	}
	if ( raw.preventDefault ) {
		return {
			width: 0,
			height: 0,
			offset: { top: raw.pageY, left: raw.pageX }
		};
	}
	return {
		width: elem.outerWidth(),
		height: elem.outerHeight(),
		offset: elem.offset()
	};
}

$.position = {
	scrollbarWidth: function() {
		if ( cachedScrollbarWidth !== undefined ) {
			return cachedScrollbarWidth;
		}
		var w1, w2,
			div = $( "<div style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'><div style='height:100px;width:auto;'></div></div>" ),
			innerDiv = div.children()[0];

		$( "body" ).append( div );
		w1 = innerDiv.offsetWidth;
		div.css( "overflow", "scroll" );

		w2 = innerDiv.offsetWidth;

		if ( w1 === w2 ) {
			w2 = div[0].clientWidth;
		}

		div.remove();

		return (cachedScrollbarWidth = w1 - w2);
	},
	getScrollInfo: function( within ) {
		var overflowX = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-x" ),
			overflowY = within.isWindow || within.isDocument ? "" :
				within.element.css( "overflow-y" ),
			hasOverflowX = overflowX === "scroll" ||
				( overflowX === "auto" && within.width < within.element[0].scrollWidth ),
			hasOverflowY = overflowY === "scroll" ||
				( overflowY === "auto" && within.height < within.element[0].scrollHeight );
		return {
			width: hasOverflowY ? $.position.scrollbarWidth() : 0,
			height: hasOverflowX ? $.position.scrollbarWidth() : 0
		};
	},
	getWithinInfo: function( element ) {
		var withinElement = $( element || window ),
			isWindow = $.isWindow( withinElement[0] ),
			isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9;
		return {
			element: withinElement,
			isWindow: isWindow,
			isDocument: isDocument,
			offset: withinElement.offset() || { left: 0, top: 0 },
			scrollLeft: withinElement.scrollLeft(),
			scrollTop: withinElement.scrollTop(),

			// support: jQuery 1.6.x
			// jQuery 1.6 doesn't support .outerWidth/Height() on documents or windows
			width: isWindow || isDocument ? withinElement.width() : withinElement.outerWidth(),
			height: isWindow || isDocument ? withinElement.height() : withinElement.outerHeight()
		};
	}
};

$.fn.position = function( options ) {
	if ( !options || !options.of ) {
		return _position.apply( this, arguments );
	}

	// make a copy, we don't want to modify arguments
	options = $.extend( {}, options );

	var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
		target = $( options.of ),
		within = $.position.getWithinInfo( options.within ),
		scrollInfo = $.position.getScrollInfo( within ),
		collision = ( options.collision || "flip" ).split( " " ),
		offsets = {};

	dimensions = getDimensions( target );
	if ( target[0].preventDefault ) {
		// force left top to allow flipping
		options.at = "left top";
	}
	targetWidth = dimensions.width;
	targetHeight = dimensions.height;
	targetOffset = dimensions.offset;
	// clone to reuse original targetOffset later
	basePosition = $.extend( {}, targetOffset );

	// force my and at to have valid horizontal and vertical positions
	// if a value is missing or invalid, it will be converted to center
	$.each( [ "my", "at" ], function() {
		var pos = ( options[ this ] || "" ).split( " " ),
			horizontalOffset,
			verticalOffset;

		if ( pos.length === 1) {
			pos = rhorizontal.test( pos[ 0 ] ) ?
				pos.concat( [ "center" ] ) :
				rvertical.test( pos[ 0 ] ) ?
					[ "center" ].concat( pos ) :
					[ "center", "center" ];
		}
		pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
		pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";

		// calculate offsets
		horizontalOffset = roffset.exec( pos[ 0 ] );
		verticalOffset = roffset.exec( pos[ 1 ] );
		offsets[ this ] = [
			horizontalOffset ? horizontalOffset[ 0 ] : 0,
			verticalOffset ? verticalOffset[ 0 ] : 0
		];

		// reduce to just the positions without the offsets
		options[ this ] = [
			rposition.exec( pos[ 0 ] )[ 0 ],
			rposition.exec( pos[ 1 ] )[ 0 ]
		];
	});

	// normalize collision option
	if ( collision.length === 1 ) {
		collision[ 1 ] = collision[ 0 ];
	}

	if ( options.at[ 0 ] === "right" ) {
		basePosition.left += targetWidth;
	} else if ( options.at[ 0 ] === "center" ) {
		basePosition.left += targetWidth / 2;
	}

	if ( options.at[ 1 ] === "bottom" ) {
		basePosition.top += targetHeight;
	} else if ( options.at[ 1 ] === "center" ) {
		basePosition.top += targetHeight / 2;
	}

	atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
	basePosition.left += atOffset[ 0 ];
	basePosition.top += atOffset[ 1 ];

	return this.each(function() {
		var collisionPosition, using,
			elem = $( this ),
			elemWidth = elem.outerWidth(),
			elemHeight = elem.outerHeight(),
			marginLeft = parseCss( this, "marginLeft" ),
			marginTop = parseCss( this, "marginTop" ),
			collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + scrollInfo.width,
			collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + scrollInfo.height,
			position = $.extend( {}, basePosition ),
			myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );

		if ( options.my[ 0 ] === "right" ) {
			position.left -= elemWidth;
		} else if ( options.my[ 0 ] === "center" ) {
			position.left -= elemWidth / 2;
		}

		if ( options.my[ 1 ] === "bottom" ) {
			position.top -= elemHeight;
		} else if ( options.my[ 1 ] === "center" ) {
			position.top -= elemHeight / 2;
		}

		position.left += myOffset[ 0 ];
		position.top += myOffset[ 1 ];

		// if the browser doesn't support fractions, then round for consistent results
		if ( !supportsOffsetFractions ) {
			position.left = round( position.left );
			position.top = round( position.top );
		}

		collisionPosition = {
			marginLeft: marginLeft,
			marginTop: marginTop
		};

		$.each( [ "left", "top" ], function( i, dir ) {
			if ( $.ui.position[ collision[ i ] ] ) {
				$.ui.position[ collision[ i ] ][ dir ]( position, {
					targetWidth: targetWidth,
					targetHeight: targetHeight,
					elemWidth: elemWidth,
					elemHeight: elemHeight,
					collisionPosition: collisionPosition,
					collisionWidth: collisionWidth,
					collisionHeight: collisionHeight,
					offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
					my: options.my,
					at: options.at,
					within: within,
					elem: elem
				});
			}
		});

		if ( options.using ) {
			// adds feedback as second argument to using callback, if present
			using = function( props ) {
				var left = targetOffset.left - position.left,
					right = left + targetWidth - elemWidth,
					top = targetOffset.top - position.top,
					bottom = top + targetHeight - elemHeight,
					feedback = {
						target: {
							element: target,
							left: targetOffset.left,
							top: targetOffset.top,
							width: targetWidth,
							height: targetHeight
						},
						element: {
							element: elem,
							left: position.left,
							top: position.top,
							width: elemWidth,
							height: elemHeight
						},
						horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
						vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
					};
				if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
					feedback.horizontal = "center";
				}
				if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
					feedback.vertical = "middle";
				}
				if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
					feedback.important = "horizontal";
				} else {
					feedback.important = "vertical";
				}
				options.using.call( this, props, feedback );
			};
		}

		elem.offset( $.extend( position, { using: using } ) );
	});
};

$.ui.position = {
	fit: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
				outerWidth = within.width,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = withinOffset - collisionPosLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
				newOverRight;

			// element is wider than within
			if ( data.collisionWidth > outerWidth ) {
				// element is initially over the left side of within
				if ( overLeft > 0 && overRight <= 0 ) {
					newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - withinOffset;
					position.left += overLeft - newOverRight;
				// element is initially over right side of within
				} else if ( overRight > 0 && overLeft <= 0 ) {
					position.left = withinOffset;
				// element is initially over both left and right sides of within
				} else {
					if ( overLeft > overRight ) {
						position.left = withinOffset + outerWidth - data.collisionWidth;
					} else {
						position.left = withinOffset;
					}
				}
			// too far left -> align with left edge
			} else if ( overLeft > 0 ) {
				position.left += overLeft;
			// too far right -> align with right edge
			} else if ( overRight > 0 ) {
				position.left -= overRight;
			// adjust based on position and margin
			} else {
				position.left = max( position.left - collisionPosLeft, position.left );
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
				outerHeight = data.within.height,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = withinOffset - collisionPosTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
				newOverBottom;

			// element is taller than within
			if ( data.collisionHeight > outerHeight ) {
				// element is initially over the top of within
				if ( overTop > 0 && overBottom <= 0 ) {
					newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - withinOffset;
					position.top += overTop - newOverBottom;
				// element is initially over bottom of within
				} else if ( overBottom > 0 && overTop <= 0 ) {
					position.top = withinOffset;
				// element is initially over both top and bottom of within
				} else {
					if ( overTop > overBottom ) {
						position.top = withinOffset + outerHeight - data.collisionHeight;
					} else {
						position.top = withinOffset;
					}
				}
			// too far up -> align with top
			} else if ( overTop > 0 ) {
				position.top += overTop;
			// too far down -> align with bottom edge
			} else if ( overBottom > 0 ) {
				position.top -= overBottom;
			// adjust based on position and margin
			} else {
				position.top = max( position.top - collisionPosTop, position.top );
			}
		}
	},
	flip: {
		left: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.left + within.scrollLeft,
				outerWidth = within.width,
				offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
				collisionPosLeft = position.left - data.collisionPosition.marginLeft,
				overLeft = collisionPosLeft - offsetLeft,
				overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
				myOffset = data.my[ 0 ] === "left" ?
					-data.elemWidth :
					data.my[ 0 ] === "right" ?
						data.elemWidth :
						0,
				atOffset = data.at[ 0 ] === "left" ?
					data.targetWidth :
					data.at[ 0 ] === "right" ?
						-data.targetWidth :
						0,
				offset = -2 * data.offset[ 0 ],
				newOverRight,
				newOverLeft;

			if ( overLeft < 0 ) {
				newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - outerWidth - withinOffset;
				if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
					position.left += myOffset + atOffset + offset;
				}
			} else if ( overRight > 0 ) {
				newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + atOffset + offset - offsetLeft;
				if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
					position.left += myOffset + atOffset + offset;
				}
			}
		},
		top: function( position, data ) {
			var within = data.within,
				withinOffset = within.offset.top + within.scrollTop,
				outerHeight = within.height,
				offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
				collisionPosTop = position.top - data.collisionPosition.marginTop,
				overTop = collisionPosTop - offsetTop,
				overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
				top = data.my[ 1 ] === "top",
				myOffset = top ?
					-data.elemHeight :
					data.my[ 1 ] === "bottom" ?
						data.elemHeight :
						0,
				atOffset = data.at[ 1 ] === "top" ?
					data.targetHeight :
					data.at[ 1 ] === "bottom" ?
						-data.targetHeight :
						0,
				offset = -2 * data.offset[ 1 ],
				newOverTop,
				newOverBottom;
			if ( overTop < 0 ) {
				newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - outerHeight - withinOffset;
				if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
					position.top += myOffset + atOffset + offset;
				}
			} else if ( overBottom > 0 ) {
				newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + offset - offsetTop;
				if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
					position.top += myOffset + atOffset + offset;
				}
			}
		}
	},
	flipfit: {
		left: function() {
			$.ui.position.flip.left.apply( this, arguments );
			$.ui.position.fit.left.apply( this, arguments );
		},
		top: function() {
			$.ui.position.flip.top.apply( this, arguments );
			$.ui.position.fit.top.apply( this, arguments );
		}
	}
};

// fraction support test
(function() {
	var testElement, testElementParent, testElementStyle, offsetLeft, i,
		body = document.getElementsByTagName( "body" )[ 0 ],
		div = document.createElement( "div" );

	//Create a "fake body" for testing based on method used in jQuery.support
	testElement = document.createElement( body ? "div" : "body" );
	testElementStyle = {
		visibility: "hidden",
		width: 0,
		height: 0,
		border: 0,
		margin: 0,
		background: "none"
	};
	if ( body ) {
		$.extend( testElementStyle, {
			position: "absolute",
			left: "-1000px",
			top: "-1000px"
		});
	}
	for ( i in testElementStyle ) {
		testElement.style[ i ] = testElementStyle[ i ];
	}
	testElement.appendChild( div );
	testElementParent = body || document.documentElement;
	testElementParent.insertBefore( testElement, testElementParent.firstChild );

	div.style.cssText = "position: absolute; left: 10.7432222px;";

	offsetLeft = $( div ).offset().left;
	supportsOffsetFractions = offsetLeft > 10 && offsetLeft < 11;

	testElement.innerHTML = "";
	testElementParent.removeChild( testElement );
})();

})();

var position = $.ui.position;


/*!
 * jQuery UI Button 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/button/
 */


var lastActive,
	baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
	typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
	formResetHandler = function() {
		var form = $( this );
		setTimeout(function() {
			form.find( ":ui-button" ).button( "refresh" );
		}, 1 );
	},
	radioGroup = function( radio ) {
		var name = radio.name,
			form = radio.form,
			radios = $( [] );
		if ( name ) {
			name = name.replace( /'/g, "\\'" );
			if ( form ) {
				radios = $( form ).find( "[name='" + name + "'][type=radio]" );
			} else {
				radios = $( "[name='" + name + "'][type=radio]", radio.ownerDocument )
					.filter(function() {
						return !this.form;
					});
			}
		}
		return radios;
	};

$.widget( "ui.button", {
	version: "1.11.4",
	defaultElement: "<button>",
	options: {
		disabled: null,
		text: true,
		label: null,
		icons: {
			primary: null,
			secondary: null
		}
	},
	_create: function() {
		this.element.closest( "form" )
			.unbind( "reset" + this.eventNamespace )
			.bind( "reset" + this.eventNamespace, formResetHandler );

		if ( typeof this.options.disabled !== "boolean" ) {
			this.options.disabled = !!this.element.prop( "disabled" );
		} else {
			this.element.prop( "disabled", this.options.disabled );
		}

		this._determineButtonType();
		this.hasTitle = !!this.buttonElement.attr( "title" );

		var that = this,
			options = this.options,
			toggleButton = this.type === "checkbox" || this.type === "radio",
			activeClass = !toggleButton ? "ui-state-active" : "";

		if ( options.label === null ) {
			options.label = (this.type === "input" ? this.buttonElement.val() : this.buttonElement.html());
		}

		this._hoverable( this.buttonElement );

		this.buttonElement
			.addClass( baseClasses )
			.attr( "role", "button" )
			.bind( "mouseenter" + this.eventNamespace, function() {
				if ( options.disabled ) {
					return;
				}
				if ( this === lastActive ) {
					$( this ).addClass( "ui-state-active" );
				}
			})
			.bind( "mouseleave" + this.eventNamespace, function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( activeClass );
			})
			.bind( "click" + this.eventNamespace, function( event ) {
				if ( options.disabled ) {
					event.preventDefault();
					event.stopImmediatePropagation();
				}
			});

		// Can't use _focusable() because the element that receives focus
		// and the element that gets the ui-state-focus class are different
		this._on({
			focus: function() {
				this.buttonElement.addClass( "ui-state-focus" );
			},
			blur: function() {
				this.buttonElement.removeClass( "ui-state-focus" );
			}
		});

		if ( toggleButton ) {
			this.element.bind( "change" + this.eventNamespace, function() {
				that.refresh();
			});
		}

		if ( this.type === "checkbox" ) {
			this.buttonElement.bind( "click" + this.eventNamespace, function() {
				if ( options.disabled ) {
					return false;
				}
			});
		} else if ( this.type === "radio" ) {
			this.buttonElement.bind( "click" + this.eventNamespace, function() {
				if ( options.disabled ) {
					return false;
				}
				$( this ).addClass( "ui-state-active" );
				that.buttonElement.attr( "aria-pressed", "true" );

				var radio = that.element[ 0 ];
				radioGroup( radio )
					.not( radio )
					.map(function() {
						return $( this ).button( "widget" )[ 0 ];
					})
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			});
		} else {
			this.buttonElement
				.bind( "mousedown" + this.eventNamespace, function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).addClass( "ui-state-active" );
					lastActive = this;
					that.document.one( "mouseup", function() {
						lastActive = null;
					});
				})
				.bind( "mouseup" + this.eventNamespace, function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).removeClass( "ui-state-active" );
				})
				.bind( "keydown" + this.eventNamespace, function(event) {
					if ( options.disabled ) {
						return false;
					}
					if ( event.keyCode === $.ui.keyCode.SPACE || event.keyCode === $.ui.keyCode.ENTER ) {
						$( this ).addClass( "ui-state-active" );
					}
				})
				// see #8559, we bind to blur here in case the button element loses
				// focus between keydown and keyup, it would be left in an "active" state
				.bind( "keyup" + this.eventNamespace + " blur" + this.eventNamespace, function() {
					$( this ).removeClass( "ui-state-active" );
				});

			if ( this.buttonElement.is("a") ) {
				this.buttonElement.keyup(function(event) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						// TODO pass through original event correctly (just as 2nd argument doesn't work)
						$( this ).click();
					}
				});
			}
		}

		this._setOption( "disabled", options.disabled );
		this._resetButton();
	},

	_determineButtonType: function() {
		var ancestor, labelSelector, checked;

		if ( this.element.is("[type=checkbox]") ) {
			this.type = "checkbox";
		} else if ( this.element.is("[type=radio]") ) {
			this.type = "radio";
		} else if ( this.element.is("input") ) {
			this.type = "input";
		} else {
			this.type = "button";
		}

		if ( this.type === "checkbox" || this.type === "radio" ) {
			// we don't search against the document in case the element
			// is disconnected from the DOM
			ancestor = this.element.parents().last();
			labelSelector = "label[for='" + this.element.attr("id") + "']";
			this.buttonElement = ancestor.find( labelSelector );
			if ( !this.buttonElement.length ) {
				ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
				this.buttonElement = ancestor.filter( labelSelector );
				if ( !this.buttonElement.length ) {
					this.buttonElement = ancestor.find( labelSelector );
				}
			}
			this.element.addClass( "ui-helper-hidden-accessible" );

			checked = this.element.is( ":checked" );
			if ( checked ) {
				this.buttonElement.addClass( "ui-state-active" );
			}
			this.buttonElement.prop( "aria-pressed", checked );
		} else {
			this.buttonElement = this.element;
		}
	},

	widget: function() {
		return this.buttonElement;
	},

	_destroy: function() {
		this.element
			.removeClass( "ui-helper-hidden-accessible" );
		this.buttonElement
			.removeClass( baseClasses + " ui-state-active " + typeClasses )
			.removeAttr( "role" )
			.removeAttr( "aria-pressed" )
			.html( this.buttonElement.find(".ui-button-text").html() );

		if ( !this.hasTitle ) {
			this.buttonElement.removeAttr( "title" );
		}
	},

	_setOption: function( key, value ) {
		this._super( key, value );
		if ( key === "disabled" ) {
			this.widget().toggleClass( "ui-state-disabled", !!value );
			this.element.prop( "disabled", !!value );
			if ( value ) {
				if ( this.type === "checkbox" || this.type === "radio" ) {
					this.buttonElement.removeClass( "ui-state-focus" );
				} else {
					this.buttonElement.removeClass( "ui-state-focus ui-state-active" );
				}
			}
			return;
		}
		this._resetButton();
	},

	refresh: function() {
		//See #8237 & #8828
		var isDisabled = this.element.is( "input, button" ) ? this.element.is( ":disabled" ) : this.element.hasClass( "ui-button-disabled" );

		if ( isDisabled !== this.options.disabled ) {
			this._setOption( "disabled", isDisabled );
		}
		if ( this.type === "radio" ) {
			radioGroup( this.element[0] ).each(function() {
				if ( $( this ).is( ":checked" ) ) {
					$( this ).button( "widget" )
						.addClass( "ui-state-active" )
						.attr( "aria-pressed", "true" );
				} else {
					$( this ).button( "widget" )
						.removeClass( "ui-state-active" )
						.attr( "aria-pressed", "false" );
				}
			});
		} else if ( this.type === "checkbox" ) {
			if ( this.element.is( ":checked" ) ) {
				this.buttonElement
					.addClass( "ui-state-active" )
					.attr( "aria-pressed", "true" );
			} else {
				this.buttonElement
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			}
		}
	},

	_resetButton: function() {
		if ( this.type === "input" ) {
			if ( this.options.label ) {
				this.element.val( this.options.label );
			}
			return;
		}
		var buttonElement = this.buttonElement.removeClass( typeClasses ),
			buttonText = $( "<span></span>", this.document[0] )
				.addClass( "ui-button-text" )
				.html( this.options.label )
				.appendTo( buttonElement.empty() )
				.text(),
			icons = this.options.icons,
			multipleIcons = icons.primary && icons.secondary,
			buttonClasses = [];

		if ( icons.primary || icons.secondary ) {
			if ( this.options.text ) {
				buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
			}

			if ( icons.primary ) {
				buttonElement.prepend( "<span class='ui-button-icon-primary ui-icon " + icons.primary + "'></span>" );
			}

			if ( icons.secondary ) {
				buttonElement.append( "<span class='ui-button-icon-secondary ui-icon " + icons.secondary + "'></span>" );
			}

			if ( !this.options.text ) {
				buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );

				if ( !this.hasTitle ) {
					buttonElement.attr( "title", $.trim( buttonText ) );
				}
			}
		} else {
			buttonClasses.push( "ui-button-text-only" );
		}
		buttonElement.addClass( buttonClasses.join( " " ) );
	}
});

$.widget( "ui.buttonset", {
	version: "1.11.4",
	options: {
		items: "button, input[type=button], input[type=submit], input[type=reset], input[type=checkbox], input[type=radio], a, :data(ui-button)"
	},

	_create: function() {
		this.element.addClass( "ui-buttonset" );
	},

	_init: function() {
		this.refresh();
	},

	_setOption: function( key, value ) {
		if ( key === "disabled" ) {
			this.buttons.button( "option", key, value );
		}

		this._super( key, value );
	},

	refresh: function() {
		var rtl = this.element.css( "direction" ) === "rtl",
			allButtons = this.element.find( this.options.items ),
			existingButtons = allButtons.filter( ":ui-button" );

		// Initialize new buttons
		allButtons.not( ":ui-button" ).button();

		// Refresh existing buttons
		existingButtons.button( "refresh" );

		this.buttons = allButtons
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
				.filter( ":first" )
					.addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
				.end()
				.filter( ":last" )
					.addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
				.end()
			.end();
	},

	_destroy: function() {
		this.element.removeClass( "ui-buttonset" );
		this.buttons
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-left ui-corner-right" )
			.end()
			.button( "destroy" );
	}
});

var button = $.ui.button;


/*!
 * jQuery UI Datepicker 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/datepicker/
 */


$.extend($.ui, { datepicker: { version: "1.11.4" } });

var datepicker_instActive;

function datepicker_getZindex( elem ) {
	var position, value;
	while ( elem.length && elem[ 0 ] !== document ) {
		// Ignore z-index if position is set to a value where z-index is ignored by the browser
		// This makes behavior of this function consistent across browsers
		// WebKit always returns auto if the element is positioned
		position = elem.css( "position" );
		if ( position === "absolute" || position === "relative" || position === "fixed" ) {
			// IE returns 0 when zIndex is not specified
			// other browsers return a string
			// we ignore the case of nested elements with an explicit value of 0
			// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
			value = parseInt( elem.css( "zIndex" ), 10 );
			if ( !isNaN( value ) && value !== 0 ) {
				return value;
			}
		}
		elem = elem.parent();
	}

	return 0;
}
/* Date picker manager.
   Use the singleton instance of this class, $.datepicker, to interact with the date picker.
   Settings for (groups of) date pickers are maintained in an instance object,
   allowing multiple different settings on the same page. */

function Datepicker() {
	this._curInst = null; // The current instance in use
	this._keyEvent = false; // If the last event was a key event
	this._disabledInputs = []; // List of date picker inputs that have been disabled
	this._datepickerShowing = false; // True if the popup picker is showing , false if not
	this._inDialog = false; // True if showing within a "dialog", false if not
	this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
	this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
	this._appendClass = "ui-datepicker-append"; // The name of the append marker class
	this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
	this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
	this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
	this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
	this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
	this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
	this._borderDayClass = 'ui-datepicker-border-day';
	this._hoverRangeClass = 'ui-datepicker-hover-range';
	this.regional = []; // Available regional settings, indexed by language code
	this.regional[""] = { // Default regional settings
		closeText: "Done", // Display text for close link
		prevText: "Prev", // Display text for previous month link
		nextText: "Next", // Display text for next month link
		currentText: "Today", // Display text for current month link
		monthNames: ["January","February","March","April","May","June",
			"July","August","September","October","November","December"], // Names of months for drop-down and formatting
		monthNamesShort: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"], // For formatting
		dayNames: ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"], // For formatting
		dayNamesShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"], // For formatting
		dayNamesMin: ["Su","Mo","Tu","We","Th","Fr","Sa"], // Column headings for days starting at Sunday
		weekHeader: "Wk", // Column header for week of the year
		dateFormat: "mm/dd/yy", // See format options on parseDate
		firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
		isRTL: false, // True if right-to-left language, false if left-to-right
		showMonthAfterYear: false, // True if the year select precedes month, false for month then year
		yearSuffix: "" // Additional text to append to the year in the month headers
	};
	this._defaults = { // Global defaults for all the date picker instances
		showOn: "focus", // "focus" for popup on focus,
			// "button" for trigger button, or "both" for either
		showAnim: "fadeIn", // Name of jQuery animation for popup
		showOptions: {}, // Options for enhanced animations
		defaultDate: null, // Used when field is blank: actual date,
			// +/-number for offset from today, null for today
		appendText: "", // Display text following the input box, e.g. showing the format
		buttonText: "...", // Text for trigger button
		buttonImage: "", // URL for trigger button image
		buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
		hideIfNoPrevNext: false, // True to hide next/previous month links
			// if not applicable, false to just disable them
		navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
		gotoCurrent: false, // True if today link goes back to current selection instead
		changeMonth: false, // True if month can be selected directly, false if only prev/next
		changeYear: false, // True if year can be selected directly, false if only prev/next
		yearRange: "c-10:c+10", // Range of years to display in drop-down,
			// either relative to today's year (-nn:+nn), relative to currently displayed year
			// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
		showOtherMonths: false, // True to show dates in other months, false to leave blank
		selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
		showWeek: false, // True to show week of the year, false to not show it
		calculateWeek: this.iso8601Week, // How to calculate the week of the year,
			// takes a Date and returns the number of the week for it
		shortYearCutoff: "+10", // Short year values < this are in the current century,
			// > this are in the previous century,
			// string value starting with "+" for current year + value
		minDate: null, // The earliest selectable date, or null for no limit
		maxDate: null, // The latest selectable date, or null for no limit
		duration: "fast", // Duration of display/closure
		beforeShowDay: null, // Function that takes a date and returns an array with
			// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
			// [2] = cell title (optional), e.g. $.datepicker.noWeekends
		beforeShow: null, // Function that takes an input field and
			// returns a set of custom settings for the date picker
		onSelect: null, // Define a callback function when a date is selected
		onChangeMonthYear: null, // Define a callback function when the month or year is changed
		onClose: null, // Define a callback function when the datepicker is closed
		onHover: null, // Define a callback function when a date is hovered
		onUnhover: null,
		numberOfMonths: 1, // Number of months to show at a time
		showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
		stepMonths: 1, // Number of months to step back/forward
		stepBigMonths: 12, // Number of months to step back/forward for the big links
		altField: "", // Selector for an alternate field to store selected dates into
		altFormat: "", // The date format to use for the alternate field
		constrainInput: true, // The input is constrained by the current date format
		showButtonPanel: false, // True to show button panel, false to not show it
		autoSize: false, // True to size the input for the date format, false to leave as is
		disabled: false // The initial disabled state
	};
	$.extend(this._defaults, this.regional[""]);
	this.regional.en = $.extend( true, {}, this.regional[ "" ]);
	this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
	this.dpDiv = datepicker_bindHover($("<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>"));
}

$.extend(Datepicker.prototype, {
	/* Class name added to elements to indicate already configured with a date picker. */
	markerClassName: "hasDatepicker",

	//Keep track of the maximum number of rows displayed (see #7043)
	maxRows: 4,

	// TODO rename to "widget" when switching to widget factory
	_widgetDatepicker: function() {
		return this.dpDiv;
	},

	/* Override the default settings for all instances of the date picker.
	 * @param  settings  object - the new settings to use as defaults (anonymous object)
	 * @return the manager object
	 */
	setDefaults: function(settings) {
		datepicker_extendRemove(this._defaults, settings || {});
		return this;
	},

	/* Attach the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 * @param  settings  object - the new settings to use for this date picker instance (anonymous)
	 */
	_attachDatepicker: function(target, settings) {
		var nodeName, inline, inst;
		nodeName = target.nodeName.toLowerCase();
		inline = (nodeName === "div" || nodeName === "span");
		if (!target.id) {
			this.uuid += 1;
			target.id = "dp" + this.uuid;
		}
		inst = this._newInst($(target), inline);
		inst.settings = $.extend({}, settings || {});
		if (nodeName === "input") {
			this._connectDatepicker(target, inst);
		} else if (inline) {
			this._inlineDatepicker(target, inst);
		}
	},

	/* Create a new instance object. */
	_newInst: function(target, inline) {
		var id = target[0].id.replace(/([^A-Za-z0-9_\-])/g, "\\\\$1"); // escape jQuery meta chars
		return {id: id, input: target, // associated target
			selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
			drawMonth: 0, drawYear: 0, // month being drawn
			inline: inline, // is datepicker inline or not
			dpDiv: (!inline ? this.dpDiv : // presentation div
			datepicker_bindHover($("<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>")))};
	},

	/* Attach the date picker to an input field. */
	_connectDatepicker: function(target, inst) {
		var input = $(target);
		inst.append = $([]);
		inst.trigger = $([]);
		if (input.hasClass(this.markerClassName)) {
			return;
		}
		this._attachments(input, inst);
		input.addClass(this.markerClassName).keydown(this._doKeyDown).
			keypress(this._doKeyPress).keyup(this._doKeyUp);
		this._autoSize(inst);
		$.data(target, "datepicker", inst);
		//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
		if( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}
	},

	/* Make attachments based on settings. */
	_attachments: function(input, inst) {
		var showOn, buttonText, buttonImage,
			appendText = this._get(inst, "appendText"),
			isRTL = this._get(inst, "isRTL");

		if (inst.append) {
			inst.append.remove();
		}
		if (appendText) {
			inst.append = $("<span class='" + this._appendClass + "'>" + appendText + "</span>");
			input[isRTL ? "before" : "after"](inst.append);
		}

		input.unbind("focus", this._showDatepicker);

		if (inst.trigger) {
			inst.trigger.remove();
		}

		showOn = this._get(inst, "showOn");
		if (showOn === "focus" || showOn === "both") { // pop-up date picker when in the marked field
			input.focus(this._showDatepicker);
		}
		if (showOn === "button" || showOn === "both") { // pop-up date picker when button clicked
			buttonText = this._get(inst, "buttonText");
			buttonImage = this._get(inst, "buttonImage");
			inst.trigger = $(this._get(inst, "buttonImageOnly") ?
				$("<img/>").addClass(this._triggerClass).
					attr({ src: buttonImage, alt: buttonText, title: buttonText }) :
				$("<button type='button'></button>").addClass(this._triggerClass).
					html(!buttonImage ? buttonText : $("<img/>").attr(
					{ src:buttonImage, alt:buttonText, title:buttonText })));
			input[isRTL ? "before" : "after"](inst.trigger);
			inst.trigger.click(function() {
				if ($.datepicker._datepickerShowing && $.datepicker._lastInput === input[0]) {
					$.datepicker._hideDatepicker();
				} else if ($.datepicker._datepickerShowing && $.datepicker._lastInput !== input[0]) {
					$.datepicker._hideDatepicker();
					$.datepicker._showDatepicker(input[0]);
				} else {
					$.datepicker._showDatepicker(input[0]);
				}
				return false;
			});
		}
	},

	/* Apply the maximum length for the date format. */
	_autoSize: function(inst) {
		if (this._get(inst, "autoSize") && !inst.inline) {
			var findMax, max, maxI, i,
				date = new Date(2009, 12 - 1, 20), // Ensure double digits
				dateFormat = this._get(inst, "dateFormat");

			if (dateFormat.match(/[DM]/)) {
				findMax = function(names) {
					max = 0;
					maxI = 0;
					for (i = 0; i < names.length; i++) {
						if (names[i].length > max) {
							max = names[i].length;
							maxI = i;
						}
					}
					return maxI;
				};
				date.setMonth(findMax(this._get(inst, (dateFormat.match(/MM/) ?
					"monthNames" : "monthNamesShort"))));
				date.setDate(findMax(this._get(inst, (dateFormat.match(/DD/) ?
					"dayNames" : "dayNamesShort"))) + 20 - date.getDay());
			}
			inst.input.attr("size", this._formatDate(inst, date).length);
		}
	},

	/* Attach an inline date picker to a div. */
	_inlineDatepicker: function(target, inst) {
		var divSpan = $(target);
		if (divSpan.hasClass(this.markerClassName)) {
			return;
		}
		divSpan.addClass(this.markerClassName).append(inst.dpDiv);
		$.data(target, "datepicker", inst);
		this._setDate(inst, this._getDefaultDate(inst), true);
		this._updateDatepicker(inst);
		this._updateAlternate(inst);
		//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
		if( inst.settings.disabled ) {
			this._disableDatepicker( target );
		}
		// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
		// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
		inst.dpDiv.css( "display", "block" );
	},

	/* Pop-up the date picker in a "dialog" box.
	 * @param  input element - ignored
	 * @param  date	string or Date - the initial date to display
	 * @param  onSelect  function - the function to call when a date is selected
	 * @param  settings  object - update the dialog date picker instance's settings (anonymous object)
	 * @param  pos int[2] - coordinates for the dialog's position within the screen or
	 *					event - with x/y coordinates or
	 *					leave empty for default (screen centre)
	 * @return the manager object
	 */
	_dialogDatepicker: function(input, date, onSelect, settings, pos) {
		var id, browserWidth, browserHeight, scrollX, scrollY,
			inst = this._dialogInst; // internal instance

		if (!inst) {
			this.uuid += 1;
			id = "dp" + this.uuid;
			this._dialogInput = $("<input type='text' id='" + id +
				"' style='position: absolute; top: -100px; width: 0px;'/>");
			this._dialogInput.keydown(this._doKeyDown);
			$("body").append(this._dialogInput);
			inst = this._dialogInst = this._newInst(this._dialogInput, false);
			inst.settings = {};
			$.data(this._dialogInput[0], "datepicker", inst);
		}
		datepicker_extendRemove(inst.settings, settings || {});
		date = (date && date.constructor === Date ? this._formatDate(inst, date) : date);
		this._dialogInput.val(date);

		this._pos = (pos ? (pos.length ? pos : [pos.pageX, pos.pageY]) : null);
		if (!this._pos) {
			browserWidth = document.documentElement.clientWidth;
			browserHeight = document.documentElement.clientHeight;
			scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
			scrollY = document.documentElement.scrollTop || document.body.scrollTop;
			this._pos = // should use actual width/height below
				[(browserWidth / 2) - 100 + scrollX, (browserHeight / 2) - 150 + scrollY];
		}

		// move input on screen for focus, but hidden behind dialog
		this._dialogInput.css("left", (this._pos[0] + 20) + "px").css("top", this._pos[1] + "px");
		inst.settings.onSelect = onSelect;
		this._inDialog = true;
		this.dpDiv.addClass(this._dialogClass);
		this._showDatepicker(this._dialogInput[0]);
		if ($.blockUI) {
			$.blockUI(this.dpDiv);
		}
		$.data(this._dialogInput[0], "datepicker", inst);
		return this;
	},

	/* Detach a datepicker from its control.
	 * @param  target	element - the target input field or division or span
	 */
	_destroyDatepicker: function(target) {
		var nodeName,
			$target = $(target),
			inst = $.data(target, "datepicker");

		if (!$target.hasClass(this.markerClassName)) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		$.removeData(target, "datepicker");
		if (nodeName === "input") {
			inst.append.remove();
			inst.trigger.remove();
			$target.removeClass(this.markerClassName).
				unbind("focus", this._showDatepicker).
				unbind("keydown", this._doKeyDown).
				unbind("keypress", this._doKeyPress).
				unbind("keyup", this._doKeyUp);
		} else if (nodeName === "div" || nodeName === "span") {
			$target.removeClass(this.markerClassName).empty();
		}

		if ( datepicker_instActive === inst ) {
			datepicker_instActive = null;
		}
	},

	/* Enable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_enableDatepicker: function(target) {
		var nodeName, inline,
			$target = $(target),
			inst = $.data(target, "datepicker");

		if (!$target.hasClass(this.markerClassName)) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if (nodeName === "input") {
			target.disabled = false;
			inst.trigger.filter("button").
				each(function() { this.disabled = false; }).end().
				filter("img").css({opacity: "1.0", cursor: ""});
		} else if (nodeName === "div" || nodeName === "span") {
			inline = $target.children("." + this._inlineClass);
			inline.children().removeClass("ui-state-disabled");
			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
				prop("disabled", false);
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value === target ? null : value); }); // delete entry
	},

	/* Disable the date picker to a jQuery selection.
	 * @param  target	element - the target input field or division or span
	 */
	_disableDatepicker: function(target) {
		var nodeName, inline,
			$target = $(target),
			inst = $.data(target, "datepicker");

		if (!$target.hasClass(this.markerClassName)) {
			return;
		}

		nodeName = target.nodeName.toLowerCase();
		if (nodeName === "input") {
			target.disabled = true;
			inst.trigger.filter("button").
				each(function() { this.disabled = true; }).end().
				filter("img").css({opacity: "0.5", cursor: "default"});
		} else if (nodeName === "div" || nodeName === "span") {
			inline = $target.children("." + this._inlineClass);
			inline.children().addClass("ui-state-disabled");
			inline.find("select.ui-datepicker-month, select.ui-datepicker-year").
				prop("disabled", true);
		}
		this._disabledInputs = $.map(this._disabledInputs,
			function(value) { return (value === target ? null : value); }); // delete entry
		this._disabledInputs[this._disabledInputs.length] = target;
	},

	/* Is the first field in a jQuery collection disabled as a datepicker?
	 * @param  target	element - the target input field or division or span
	 * @return boolean - true if disabled, false if enabled
	 */
	_isDisabledDatepicker: function(target) {
		if (!target) {
			return false;
		}
		for (var i = 0; i < this._disabledInputs.length; i++) {
			if (this._disabledInputs[i] === target) {
				return true;
			}
		}
		return false;
	},

	/* Retrieve the instance data for the target control.
	 * @param  target  element - the target input field or division or span
	 * @return  object - the associated instance data
	 * @throws  error if a jQuery problem getting data
	 */
	_getInst: function(target) {
		try {
			return $.data(target, "datepicker");
		}
		catch (err) {
			throw "Missing instance data for this datepicker";
		}
	},

	/* Update or retrieve the settings for a date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 * @param  name	object - the new settings to update or
	 *				string - the name of the setting to change or retrieve,
	 *				when retrieving also "all" for all instance settings or
	 *				"defaults" for all global defaults
	 * @param  value   any - the new value for the setting
	 *				(omit if above is an object or to retrieve a value)
	 */
	_optionDatepicker: function(target, name, value) {
		var settings, date, minDate, maxDate,
			inst = this._getInst(target);

		if (arguments.length === 2 && typeof name === "string") {
			return (name === "defaults" ? $.extend({}, $.datepicker._defaults) :
				(inst ? (name === "all" ? $.extend({}, inst.settings) :
				this._get(inst, name)) : null));
		}

		settings = name || {};
		if (typeof name === "string") {
			settings = {};
			settings[name] = value;
		}

		if (inst) {
			if (this._curInst === inst) {
				this._hideDatepicker();
			}

			date = this._getDateDatepicker(target, true);
			minDate = this._getMinMaxDate(inst, "min");
			maxDate = this._getMinMaxDate(inst, "max");
			datepicker_extendRemove(inst.settings, settings);
			// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
			if (minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined) {
				inst.settings.minDate = this._formatDate(inst, minDate);
			}
			if (maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined) {
				inst.settings.maxDate = this._formatDate(inst, maxDate);
			}
			if ( "disabled" in settings ) {
				if ( settings.disabled ) {
					this._disableDatepicker(target);
				} else {
					this._enableDatepicker(target);
				}
			}
			this._attachments($(target), inst);
			this._autoSize(inst);
			this._setDate(inst, date);
			this._updateAlternate(inst);
			this._updateDatepicker(inst);
		}
	},

	// change method deprecated
	_changeDatepicker: function(target, name, value) {
		this._optionDatepicker(target, name, value);
	},

	/* Redraw the date picker attached to an input field or division.
	 * @param  target  element - the target input field or division or span
	 */
	_refreshDatepicker: function(target) {
		var inst = this._getInst(target);
		if (inst) {
			this._updateDatepicker(inst);
		}
	},

	/* Set the dates for a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  date	Date - the new date
	 */
	_setDateDatepicker: function(target, date) {
		var inst = this._getInst(target);
		if (inst) {
			this._setDate(inst, date);
			this._updateDatepicker(inst);
			this._updateAlternate(inst);
		}
	},

	/* Get the date(s) for the first entry in a jQuery selection.
	 * @param  target element - the target input field or division or span
	 * @param  noDefault boolean - true if no default date is to be used
	 * @return Date - the current date
	 */
	_getDateDatepicker: function(target, noDefault) {
		var inst = this._getInst(target);
		if (inst && !inst.inline) {
			this._setDateFromField(inst, noDefault);
		}
		return (inst ? this._getDate(inst) : null);
	},

	/* Handle keystrokes. */
	_doKeyDown: function(event) {
		var onSelect, dateStr, sel,
			inst = $.datepicker._getInst(event.target),
			handled = true,
			isRTL = inst.dpDiv.is(".ui-datepicker-rtl");

		inst._keyEvent = true;
		if ($.datepicker._datepickerShowing) {
			switch (event.keyCode) {
				case 9: $.datepicker._hideDatepicker();
						handled = false;
						break; // hide on tab out
				case 13: sel = $("td." + $.datepicker._dayOverClass + ":not(." +
									$.datepicker._currentClass + ")", inst.dpDiv);
						if (sel[0]) {
							$.datepicker._selectDay(event.target, inst.selectedMonth, inst.selectedYear, sel[0]);
						}

						onSelect = $.datepicker._get(inst, "onSelect");
						if (onSelect) {
							dateStr = $.datepicker._formatDate(inst);

							// trigger custom callback
							onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);
						} else {
							$.datepicker._hideDatepicker();
						}

						return false; // don't submit the form
				case 27: $.datepicker._hideDatepicker();
						break; // hide on escape
				case 33: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
							-$.datepicker._get(inst, "stepBigMonths") :
							-$.datepicker._get(inst, "stepMonths")), "M");
						break; // previous month/year on page up/+ ctrl
				case 34: $.datepicker._adjustDate(event.target, (event.ctrlKey ?
							+$.datepicker._get(inst, "stepBigMonths") :
							+$.datepicker._get(inst, "stepMonths")), "M");
						break; // next month/year on page down/+ ctrl
				case 35: if (event.ctrlKey || event.metaKey) {
							$.datepicker._clearDate(event.target);
						}
						handled = event.ctrlKey || event.metaKey;
						break; // clear on ctrl or command +end
				case 36: if (event.ctrlKey || event.metaKey) {
							$.datepicker._gotoToday(event.target);
						}
						handled = event.ctrlKey || event.metaKey;
						break; // current on ctrl or command +home
				case 37: if (event.ctrlKey || event.metaKey) {
							$.datepicker._adjustDate(event.target, (isRTL ? +1 : -1), "D");
						}
						handled = event.ctrlKey || event.metaKey;
						// -1 day on ctrl or command +left
						if (event.originalEvent.altKey) {
							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
								-$.datepicker._get(inst, "stepBigMonths") :
								-$.datepicker._get(inst, "stepMonths")), "M");
						}
						// next month/year on alt +left on Mac
						break;
				case 38: if (event.ctrlKey || event.metaKey) {
							$.datepicker._adjustDate(event.target, -7, "D");
						}
						handled = event.ctrlKey || event.metaKey;
						break; // -1 week on ctrl or command +up
				case 39: if (event.ctrlKey || event.metaKey) {
							$.datepicker._adjustDate(event.target, (isRTL ? -1 : +1), "D");
						}
						handled = event.ctrlKey || event.metaKey;
						// +1 day on ctrl or command +right
						if (event.originalEvent.altKey) {
							$.datepicker._adjustDate(event.target, (event.ctrlKey ?
								+$.datepicker._get(inst, "stepBigMonths") :
								+$.datepicker._get(inst, "stepMonths")), "M");
						}
						// next month/year on alt +right
						break;
				case 40: if (event.ctrlKey || event.metaKey) {
							$.datepicker._adjustDate(event.target, +7, "D");
						}
						handled = event.ctrlKey || event.metaKey;
						break; // +1 week on ctrl or command +down
				default: handled = false;
			}
		} else if (event.keyCode === 36 && event.ctrlKey) { // display the date picker on ctrl+home
			$.datepicker._showDatepicker(this);
		} else {
			handled = false;
		}

		if (handled) {
			event.preventDefault();
			event.stopPropagation();
		}
	},

	/* Filter entered characters - based on date format. */
	_doKeyPress: function(event) {
		var chars, chr,
			inst = $.datepicker._getInst(event.target);

		if ($.datepicker._get(inst, "constrainInput")) {
			chars = $.datepicker._possibleChars($.datepicker._get(inst, "dateFormat"));
			chr = String.fromCharCode(event.charCode == null ? event.keyCode : event.charCode);
			return event.ctrlKey || event.metaKey || (chr < " " || !chars || chars.indexOf(chr) > -1);
		}
	},

	/* Synchronise manual entry and field/alternate field. */
	_doKeyUp: function(event) {
		var date,
			inst = $.datepicker._getInst(event.target);

		if (inst.input.val() !== inst.lastVal) {
			try {
				date = $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
					(inst.input ? inst.input.val() : null),
					$.datepicker._getFormatConfig(inst));

				if (date) { // only if valid
					$.datepicker._setDateFromField(inst);
					$.datepicker._updateAlternate(inst);
					$.datepicker._updateDatepicker(inst);
				}
			}
			catch (err) {
			}
		}
		return true;
	},

	/* Pop-up the date picker for a given input field.
	 * If false returned from beforeShow event handler do not show.
	 * @param  input  element - the input field attached to the date picker or
	 *					event - if triggered by focus
	 */
	_showDatepicker: function(input) {
		input = input.target || input;
		if (input.nodeName.toLowerCase() !== "input") { // find from button/image trigger
			input = $("input", input.parentNode)[0];
		}

		if ($.datepicker._isDisabledDatepicker(input) || $.datepicker._lastInput === input) { // already here
			return;
		}

		var inst, beforeShow, beforeShowSettings, isFixed,
			offset, showAnim, duration;

		inst = $.datepicker._getInst(input);
		if ($.datepicker._curInst && $.datepicker._curInst !== inst) {
			$.datepicker._curInst.dpDiv.stop(true, true);
			if ( inst && $.datepicker._datepickerShowing ) {
				$.datepicker._hideDatepicker( $.datepicker._curInst.input[0] );
			}
		}

		beforeShow = $.datepicker._get(inst, "beforeShow");
		beforeShowSettings = beforeShow ? beforeShow.apply(input, [input, inst]) : {};
		if(beforeShowSettings === false){
			return;
		}
		datepicker_extendRemove(inst.settings, beforeShowSettings);

		inst.lastVal = null;
		$.datepicker._lastInput = input;
		$.datepicker._setDateFromField(inst);

		if ($.datepicker._inDialog) { // hide cursor
			input.value = "";
		}
		if (!$.datepicker._pos) { // position below input
			$.datepicker._pos = $.datepicker._findPos(input);
			$.datepicker._pos[1] += input.offsetHeight; // add the height
		}

		isFixed = false;
		$(input).parents().each(function() {
			isFixed |= $(this).css("position") === "fixed";
			return !isFixed;
		});

		offset = {left: $.datepicker._pos[0], top: $.datepicker._pos[1]};
		$.datepicker._pos = null;
		//to avoid flashes on Firefox
		inst.dpDiv.empty();
		// determine sizing offscreen
		inst.dpDiv.css({position: "absolute", display: "block", top: "-1000px"});
		$.datepicker._updateDatepicker(inst);
		// fix width for dynamic number of date pickers
		// and adjust position before showing
		offset = $.datepicker._checkOffset(inst, offset, isFixed);
		inst.dpDiv.css({position: ($.datepicker._inDialog && $.blockUI ?
			"static" : (isFixed ? "fixed" : "absolute")), display: "none",
			left: offset.left + "px", top: offset.top + "px"});

		if (!inst.inline) {
			showAnim = $.datepicker._get(inst, "showAnim");
			duration = $.datepicker._get(inst, "duration");
			inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
			$.datepicker._datepickerShowing = true;

			if ( $.effects && $.effects.effect[ showAnim ] ) {
				inst.dpDiv.show(showAnim, $.datepicker._get(inst, "showOptions"), duration);
			} else {
				inst.dpDiv[showAnim || "show"](showAnim ? duration : null);
			}

			if ( $.datepicker._shouldFocusInput( inst ) ) {
				inst.input.focus();
			}

			$.datepicker._curInst = inst;
		}
	},

	/* Generate the date picker content. */
	_updateDatepicker: function(inst) {
		this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
		datepicker_instActive = inst; // for delegate hover events
		inst.dpDiv.empty().append(this._generateHTML(inst));
		this._attachHandlers(inst);

		var origyearshtml,
			numMonths = this._getNumberOfMonths(inst),
			cols = numMonths[1],
			width = 17,
			activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );

		if ( activeCell.length > 0 ) {
			datepicker_handleMouseover.apply( activeCell.get( 0 ) );
		}

		inst.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");
		if (cols > 1) {
			inst.dpDiv.addClass("ui-datepicker-multi-" + cols).css("width", (width * cols) + "em");
		}
		inst.dpDiv[(numMonths[0] !== 1 || numMonths[1] !== 1 ? "add" : "remove") +
			"Class"]("ui-datepicker-multi");
		inst.dpDiv[(this._get(inst, "isRTL") ? "add" : "remove") +
			"Class"]("ui-datepicker-rtl");

		if (inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
			inst.input.focus();
		}

		// deffered render of the years select (to avoid flashes on Firefox)
		if( inst.yearshtml ){
			origyearshtml = inst.yearshtml;
			setTimeout(function(){
				//assure that inst.yearshtml didn't change.
				if( origyearshtml === inst.yearshtml && inst.yearshtml ){
					inst.dpDiv.find("select.ui-datepicker-year:first").replaceWith(inst.yearshtml);
				}
				origyearshtml = inst.yearshtml = null;
			}, 0);
		}
	},

	// #6694 - don't focus the input if it's already focused
	// this breaks the change event in IE
	// Support: IE and jQuery <1.9
	_shouldFocusInput: function( inst ) {
		return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
	},

	/* Check positioning to remain on screen. */
	_checkOffset: function(inst, offset, isFixed) {
		var dpWidth = inst.dpDiv.outerWidth(),
			dpHeight = inst.dpDiv.outerHeight(),
			inputWidth = inst.input ? inst.input.outerWidth() : 0,
			inputHeight = inst.input ? inst.input.outerHeight() : 0,
			viewWidth = document.documentElement.clientWidth + (isFixed ? 0 : $(document).scrollLeft()),
			viewHeight = document.documentElement.clientHeight + (isFixed ? 0 : $(document).scrollTop());

		offset.left -= (this._get(inst, "isRTL") ? (dpWidth - inputWidth) : 0);
		offset.left -= (isFixed && offset.left === inst.input.offset().left) ? $(document).scrollLeft() : 0;
		offset.top -= (isFixed && offset.top === (inst.input.offset().top + inputHeight)) ? $(document).scrollTop() : 0;

		// now check if datepicker is showing outside window viewport - move to a better place if so.
		offset.left -= Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
			Math.abs(offset.left + dpWidth - viewWidth) : 0);
		offset.top -= Math.min(offset.top, (offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
			Math.abs(dpHeight + inputHeight) : 0);

		return offset;
	},

	/* Find an object's position on the screen. */
	_findPos: function(obj) {
		var position,
			inst = this._getInst(obj),
			isRTL = this._get(inst, "isRTL");

		while (obj && (obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden(obj))) {
			obj = obj[isRTL ? "previousSibling" : "nextSibling"];
		}

		position = $(obj).offset();
		return [position.left, position.top];
	},

	/* Hide the date picker from view.
	 * @param  input  element - the input field attached to the date picker
	 */
	_hideDatepicker: function(input) {
		var showAnim, duration, postProcess, onClose,
			inst = this._curInst;

		if (!inst || (input && inst !== $.data(input, "datepicker"))) {
			return;
		}

		if (this._datepickerShowing) {
			showAnim = this._get(inst, "showAnim");
			duration = this._get(inst, "duration");
			postProcess = function() {
				$.datepicker._tidyDialog(inst);
			};

			// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
			if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
				inst.dpDiv.hide(showAnim, $.datepicker._get(inst, "showOptions"), duration, postProcess);
			} else {
				inst.dpDiv[(showAnim === "slideDown" ? "slideUp" :
					(showAnim === "fadeIn" ? "fadeOut" : "hide"))]((showAnim ? duration : null), postProcess);
			}

			if (!showAnim) {
				postProcess();
			}
			this._datepickerShowing = false;

			onClose = this._get(inst, "onClose");
			if (onClose) {
				onClose.apply((inst.input ? inst.input[0] : null), [(inst.input ? inst.input.val() : ""), inst]);
			}

			this._lastInput = null;
			if (this._inDialog) {
				this._dialogInput.css({ position: "absolute", left: "0", top: "-100px" });
				if ($.blockUI) {
					$.unblockUI();
					$("body").append(this.dpDiv);
				}
			}
			this._inDialog = false;
		}
	},

	/* Tidy up after a dialog display. */
	_tidyDialog: function(inst) {
		inst.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar");
	},

	/* Close date picker if clicked elsewhere. */
	_checkExternalClick: function(event) {
		if (!$.datepicker._curInst) {
			return;
		}

		var $target = $(event.target),
			inst = $.datepicker._getInst($target[0]);

		if ( ( ( $target[0].id !== $.datepicker._mainDivId &&
				$target.parents("#" + $.datepicker._mainDivId).length === 0 &&
				!$target.hasClass($.datepicker.markerClassName) &&
				!$target.closest("." + $.datepicker._triggerClass).length &&
				$.datepicker._datepickerShowing && !($.datepicker._inDialog && $.blockUI) ) ) ||
			( $target.hasClass($.datepicker.markerClassName) && $.datepicker._curInst !== inst ) ) {
				$.datepicker._hideDatepicker();
		}
	},

	/* Adjust one of the date sub-fields. */
	_adjustDate: function(id, offset, period) {
		var target = $(id),
			inst = this._getInst(target[0]);

		if (this._isDisabledDatepicker(target[0])) {
			return;
		}
		this._adjustInstDate(inst, offset +
			(period === "M" ? this._get(inst, "showCurrentAtPos") : 0), // undo positioning
			period);
		this._updateDatepicker(inst);
	},

	/* Action for current link. */
	_gotoToday: function(id) {
		var date,
			target = $(id),
			inst = this._getInst(target[0]);

		if (this._get(inst, "gotoCurrent") && inst.currentDay) {
			inst.selectedDay = inst.currentDay;
			inst.drawMonth = inst.selectedMonth = inst.currentMonth;
			inst.drawYear = inst.selectedYear = inst.currentYear;
		} else {
			date = new Date();
			inst.selectedDay = date.getDate();
			inst.drawMonth = inst.selectedMonth = date.getMonth();
			inst.drawYear = inst.selectedYear = date.getFullYear();
		}
		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Action for selecting a new month/year. */
	_selectMonthYear: function(id, select, period) {
		var target = $(id),
			inst = this._getInst(target[0]);

		inst["selected" + (period === "M" ? "Month" : "Year")] =
		inst["draw" + (period === "M" ? "Month" : "Year")] =
			parseInt(select.options[select.selectedIndex].value,10);

		this._notifyChange(inst);
		this._adjustDate(target);
	},

	/* Action for selecting a day. */
	_selectDay: function(id, month, year, td) {
		var inst,
			target = $(id);

		if ($(td).hasClass(this._unselectableClass) || this._isDisabledDatepicker(target[0])) {
			return;
		}

		inst = this._getInst(target[0]);
		inst.selectedDay = inst.currentDay = $("a", td).html();
		inst.selectedMonth = inst.currentMonth = month;
		inst.selectedYear = inst.currentYear = year;
		this._selectDate(id, this._formatDate(inst,
			inst.currentDay, inst.currentMonth, inst.currentYear));
	},

	/* Erase the input field and hide the date picker. */
	_clearDate: function(id) {
		var target = $(id);
		this._selectDate(target, "");
	},

	/* Update the input field with the selected date. */
	_selectDate: function(id, dateStr) {
		var onSelect,
			target = $(id),
			inst = this._getInst(target[0]);

		dateStr = (dateStr != null ? dateStr : this._formatDate(inst));
		if (inst.input) {
			inst.input.val(dateStr);
		}
		this._updateAlternate(inst);

		onSelect = this._get(inst, "onSelect");
		if (onSelect) {
			onSelect.apply((inst.input ? inst.input[0] : null), [dateStr, inst]);  // trigger custom callback
		} else if (inst.input) {
			inst.input.trigger("change"); // fire the change event
		}

		if (inst.inline){
			this._updateDatepicker(inst);
		} else {
			this._hideDatepicker();
			this._lastInput = inst.input[0];
			if (typeof(inst.input[0]) !== "object") {
				inst.input.focus(); // restore focus
			}
			this._lastInput = null;
		}
	},

	/* Update any alternate field to synchronise with the main field. */
	_updateAlternate: function(inst) {
		var altFormat, date, dateStr,
			altField = this._get(inst, "altField");

		if (altField) { // update alternate field too
			altFormat = this._get(inst, "altFormat") || this._get(inst, "dateFormat");
			date = this._getDate(inst);
			dateStr = this.formatDate(altFormat, date, this._getFormatConfig(inst));
			$(altField).each(function() { $(this).val(dateStr); });
		}
	},

	/* Set as beforeShowDay function to prevent selection of weekends.
	 * @param  date  Date - the date to customise
	 * @return [boolean, string] - is this date selectable?, what is its CSS class?
	 */
	noWeekends: function(date) {
		var day = date.getDay();
		return [(day > 0 && day < 6), ""];
	},

	/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
	 * @param  date  Date - the date to get the week for
	 * @return  number - the number of the week within the year that contains this date
	 */
	iso8601Week: function(date) {
		var time,
			checkDate = new Date(date.getTime());

		// Find Thursday of this week starting on Monday
		checkDate.setDate(checkDate.getDate() + 4 - (checkDate.getDay() || 7));

		time = checkDate.getTime();
		checkDate.setMonth(0); // Compare with Jan 1
		checkDate.setDate(1);
		return Math.floor(Math.round((time - checkDate) / 86400000) / 7) + 1;
	},

	/* Parse a string value into a date object.
	 * See formatDate below for the possible formats.
	 *
	 * @param  format string - the expected format of the date
	 * @param  value string - the date in the above format
	 * @param  settings Object - attributes include:
	 *					shortYearCutoff  number - the cutoff year for determining the century (optional)
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  Date - the extracted date value or null if value is blank
	 */
	parseDate: function (format, value, settings) {
		if (format == null || value == null) {
			throw "Invalid arguments";
		}

		value = (typeof value === "object" ? value.toString() : value + "");
		if (value === "") {
			return null;
		}

		var iFormat, dim, extra,
			iValue = 0,
			shortYearCutoffTemp = (settings ? settings.shortYearCutoff : null) || this._defaults.shortYearCutoff,
			shortYearCutoff = (typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
				new Date().getFullYear() % 100 + parseInt(shortYearCutoffTemp, 10)),
			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
			year = -1,
			month = -1,
			day = -1,
			doy = -1,
			literal = false,
			date,
			// Check whether a format character is doubled
			lookAhead = function(match) {
				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
				if (matches) {
					iFormat++;
				}
				return matches;
			},
			// Extract a number from the string value
			getNumber = function(match) {
				var isDoubled = lookAhead(match),
					size = (match === "@" ? 14 : (match === "!" ? 20 :
					(match === "y" && isDoubled ? 4 : (match === "o" ? 3 : 2)))),
					minSize = (match === "y" ? size : 1),
					digits = new RegExp("^\\d{" + minSize + "," + size + "}"),
					num = value.substring(iValue).match(digits);
				if (!num) {
					throw "Missing number at position " + iValue;
				}
				iValue += num[0].length;
				return parseInt(num[0], 10);
			},
			// Extract a name from the string value and convert to an index
			getName = function(match, shortNames, longNames) {
				var index = -1,
					names = $.map(lookAhead(match) ? longNames : shortNames, function (v, k) {
						return [ [k, v] ];
					}).sort(function (a, b) {
						return -(a[1].length - b[1].length);
					});

				$.each(names, function (i, pair) {
					var name = pair[1];
					if (value.substr(iValue, name.length).toLowerCase() === name.toLowerCase()) {
						index = pair[0];
						iValue += name.length;
						return false;
					}
				});
				if (index !== -1) {
					return index + 1;
				} else {
					throw "Unknown name at position " + iValue;
				}
			},
			// Confirm that a literal character matches the string value
			checkLiteral = function() {
				if (value.charAt(iValue) !== format.charAt(iFormat)) {
					throw "Unexpected literal at position " + iValue;
				}
				iValue++;
			};

		for (iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal) {
				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
					literal = false;
				} else {
					checkLiteral();
				}
			} else {
				switch (format.charAt(iFormat)) {
					case "d":
						day = getNumber("d");
						break;
					case "D":
						getName("D", dayNamesShort, dayNames);
						break;
					case "o":
						doy = getNumber("o");
						break;
					case "m":
						month = getNumber("m");
						break;
					case "M":
						month = getName("M", monthNamesShort, monthNames);
						break;
					case "y":
						year = getNumber("y");
						break;
					case "@":
						date = new Date(getNumber("@"));
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "!":
						date = new Date((getNumber("!") - this._ticksTo1970) / 10000);
						year = date.getFullYear();
						month = date.getMonth() + 1;
						day = date.getDate();
						break;
					case "'":
						if (lookAhead("'")){
							checkLiteral();
						} else {
							literal = true;
						}
						break;
					default:
						checkLiteral();
				}
			}
		}

		if (iValue < value.length){
			extra = value.substr(iValue);
			if (!/^\s+/.test(extra)) {
				throw "Extra/unparsed characters found in date: " + extra;
			}
		}

		if (year === -1) {
			year = new Date().getFullYear();
		} else if (year < 100) {
			year += new Date().getFullYear() - new Date().getFullYear() % 100 +
				(year <= shortYearCutoff ? 0 : -100);
		}

		if (doy > -1) {
			month = 1;
			day = doy;
			do {
				dim = this._getDaysInMonth(year, month - 1);
				if (day <= dim) {
					break;
				}
				month++;
				day -= dim;
			} while (true);
		}

		date = this._daylightSavingAdjust(new Date(year, month - 1, day));
		if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) {
			throw "Invalid date"; // E.g. 31/02/00
		}
		return date;
	},

	/* Standard date formats. */
	ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
	COOKIE: "D, dd M yy",
	ISO_8601: "yy-mm-dd",
	RFC_822: "D, d M y",
	RFC_850: "DD, dd-M-y",
	RFC_1036: "D, d M y",
	RFC_1123: "D, d M yy",
	RFC_2822: "D, d M yy",
	RSS: "D, d M y", // RFC 822
	TICKS: "!",
	TIMESTAMP: "@",
	W3C: "yy-mm-dd", // ISO 8601

	_ticksTo1970: (((1970 - 1) * 365 + Math.floor(1970 / 4) - Math.floor(1970 / 100) +
		Math.floor(1970 / 400)) * 24 * 60 * 60 * 10000000),

	/* Format a date object into a string value.
	 * The format can be combinations of the following:
	 * d  - day of month (no leading zero)
	 * dd - day of month (two digit)
	 * o  - day of year (no leading zeros)
	 * oo - day of year (three digit)
	 * D  - day name short
	 * DD - day name long
	 * m  - month of year (no leading zero)
	 * mm - month of year (two digit)
	 * M  - month name short
	 * MM - month name long
	 * y  - year (two digit)
	 * yy - year (four digit)
	 * @ - Unix timestamp (ms since 01/01/1970)
	 * ! - Windows ticks (100ns since 01/01/0001)
	 * "..." - literal text
	 * '' - single quote
	 *
	 * @param  format string - the desired format of the date
	 * @param  date Date - the date value to format
	 * @param  settings Object - attributes include:
	 *					dayNamesShort	string[7] - abbreviated names of the days from Sunday (optional)
	 *					dayNames		string[7] - names of the days from Sunday (optional)
	 *					monthNamesShort string[12] - abbreviated names of the months (optional)
	 *					monthNames		string[12] - names of the months (optional)
	 * @return  string - the date in the above format
	 */
	formatDate: function (format, date, settings) {
		if (!date) {
			return "";
		}

		var iFormat,
			dayNamesShort = (settings ? settings.dayNamesShort : null) || this._defaults.dayNamesShort,
			dayNames = (settings ? settings.dayNames : null) || this._defaults.dayNames,
			monthNamesShort = (settings ? settings.monthNamesShort : null) || this._defaults.monthNamesShort,
			monthNames = (settings ? settings.monthNames : null) || this._defaults.monthNames,
			// Check whether a format character is doubled
			lookAhead = function(match) {
				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
				if (matches) {
					iFormat++;
				}
				return matches;
			},
			// Format a number, with leading zero if necessary
			formatNumber = function(match, value, len) {
				var num = "" + value;
				if (lookAhead(match)) {
					while (num.length < len) {
						num = "0" + num;
					}
				}
				return num;
			},
			// Format a name, short or long as requested
			formatName = function(match, value, shortNames, longNames) {
				return (lookAhead(match) ? longNames[value] : shortNames[value]);
			},
			output = "",
			literal = false;

		if (date) {
			for (iFormat = 0; iFormat < format.length; iFormat++) {
				if (literal) {
					if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
						literal = false;
					} else {
						output += format.charAt(iFormat);
					}
				} else {
					switch (format.charAt(iFormat)) {
						case "d":
							output += formatNumber("d", date.getDate(), 2);
							break;
						case "D":
							output += formatName("D", date.getDay(), dayNamesShort, dayNames);
							break;
						case "o":
							output += formatNumber("o",
								Math.round((new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime() - new Date(date.getFullYear(), 0, 0).getTime()) / 86400000), 3);
							break;
						case "m":
							output += formatNumber("m", date.getMonth() + 1, 2);
							break;
						case "M":
							output += formatName("M", date.getMonth(), monthNamesShort, monthNames);
							break;
						case "y":
							output += (lookAhead("y") ? date.getFullYear() :
								(date.getYear() % 100 < 10 ? "0" : "") + date.getYear() % 100);
							break;
						case "@":
							output += date.getTime();
							break;
						case "!":
							output += date.getTime() * 10000 + this._ticksTo1970;
							break;
						case "'":
							if (lookAhead("'")) {
								output += "'";
							} else {
								literal = true;
							}
							break;
						default:
							output += format.charAt(iFormat);
					}
				}
			}
		}
		return output;
	},

	/* Extract all possible characters from the date format. */
	_possibleChars: function (format) {
		var iFormat,
			chars = "",
			literal = false,
			// Check whether a format character is doubled
			lookAhead = function(match) {
				var matches = (iFormat + 1 < format.length && format.charAt(iFormat + 1) === match);
				if (matches) {
					iFormat++;
				}
				return matches;
			};

		for (iFormat = 0; iFormat < format.length; iFormat++) {
			if (literal) {
				if (format.charAt(iFormat) === "'" && !lookAhead("'")) {
					literal = false;
				} else {
					chars += format.charAt(iFormat);
				}
			} else {
				switch (format.charAt(iFormat)) {
					case "d": case "m": case "y": case "@":
						chars += "0123456789";
						break;
					case "D": case "M":
						return null; // Accept anything
					case "'":
						if (lookAhead("'")) {
							chars += "'";
						} else {
							literal = true;
						}
						break;
					default:
						chars += format.charAt(iFormat);
				}
			}
		}
		return chars;
	},

	/* Get a setting value, defaulting if necessary. */
	_get: function(inst, name) {
		return inst.settings[name] !== undefined ?
			inst.settings[name] : this._defaults[name];
	},

	/* Parse existing date and initialise date picker. */
	_setDateFromField: function(inst, noDefault) {
		if (inst.input.val() === inst.lastVal) {
			return;
		}

		var dateFormat = this._get(inst, "dateFormat"),
			dates = inst.lastVal = inst.input ? inst.input.val() : null,
			defaultDate = this._getDefaultDate(inst),
			date = defaultDate,
			settings = this._getFormatConfig(inst);

		try {
			date = this.parseDate(dateFormat, dates, settings) || defaultDate;
		} catch (event) {
			dates = (noDefault ? "" : dates);
		}
		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		inst.currentDay = (dates ? date.getDate() : 0);
		inst.currentMonth = (dates ? date.getMonth() : 0);
		inst.currentYear = (dates ? date.getFullYear() : 0);
		this._adjustInstDate(inst);
	},

	/* Retrieve the default date shown on opening. */
	_getDefaultDate: function(inst) {
		return this._restrictMinMax(inst,
			this._determineDate(inst, this._get(inst, "defaultDate"), new Date()));
	},

	/* A date may be specified as an exact value or a relative one. */
	_determineDate: function(inst, date, defaultDate) {
		var offsetNumeric = function(offset) {
				var date = new Date();
				date.setDate(date.getDate() + offset);
				return date;
			},
			offsetString = function(offset) {
				try {
					return $.datepicker.parseDate($.datepicker._get(inst, "dateFormat"),
						offset, $.datepicker._getFormatConfig(inst));
				}
				catch (e) {
					// Ignore
				}

				var date = (offset.toLowerCase().match(/^c/) ?
					$.datepicker._getDate(inst) : null) || new Date(),
					year = date.getFullYear(),
					month = date.getMonth(),
					day = date.getDate(),
					pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
					matches = pattern.exec(offset);

				while (matches) {
					switch (matches[2] || "d") {
						case "d" : case "D" :
							day += parseInt(matches[1],10); break;
						case "w" : case "W" :
							day += parseInt(matches[1],10) * 7; break;
						case "m" : case "M" :
							month += parseInt(matches[1],10);
							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
							break;
						case "y": case "Y" :
							year += parseInt(matches[1],10);
							day = Math.min(day, $.datepicker._getDaysInMonth(year, month));
							break;
					}
					matches = pattern.exec(offset);
				}
				return new Date(year, month, day);
			},
			newDate = (date == null || date === "" ? defaultDate : (typeof date === "string" ? offsetString(date) :
				(typeof date === "number" ? (isNaN(date) ? defaultDate : offsetNumeric(date)) : new Date(date.getTime()))));

		newDate = (newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate);
		if (newDate) {
			newDate.setHours(0);
			newDate.setMinutes(0);
			newDate.setSeconds(0);
			newDate.setMilliseconds(0);
		}
		return this._daylightSavingAdjust(newDate);
	},

	/* Handle switch to/from daylight saving.
	 * Hours may be non-zero on daylight saving cut-over:
	 * > 12 when midnight changeover, but then cannot generate
	 * midnight datetime, so jump to 1AM, otherwise reset.
	 * @param  date  (Date) the date to check
	 * @return  (Date) the corrected date
	 */
	_daylightSavingAdjust: function(date) {
		if (!date) {
			return null;
		}
		date.setHours(date.getHours() > 12 ? date.getHours() + 2 : 0);
		return date;
	},

	/* Set the date(s) directly. */
	_setDate: function(inst, date, noChange) {
		var clear = !date,
			origMonth = inst.selectedMonth,
			origYear = inst.selectedYear,
			newDate = this._restrictMinMax(inst, this._determineDate(inst, date, new Date()));

		inst.selectedDay = inst.currentDay = newDate.getDate();
		inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
		inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
		if ((origMonth !== inst.selectedMonth || origYear !== inst.selectedYear) && !noChange) {
			this._notifyChange(inst);
		}
		this._adjustInstDate(inst);
		if (inst.input) {
			inst.input.val(clear ? "" : this._formatDate(inst));
		}
	},

	/* Retrieve the date(s) directly. */
	_getDate: function(inst) {
		var startDate = (!inst.currentYear || (inst.input && inst.input.val() === "") ? null :
			this._daylightSavingAdjust(new Date(
			inst.currentYear, inst.currentMonth, inst.currentDay)));
			return startDate;
	},

	/* Attach the onxxx handlers.  These are declared statically so
	 * they work with static code transformers like Caja.
	 */
	_attachHandlers: function(inst) {
		var stepMonths = this._get(inst, "stepMonths"),
			id = "#" + inst.id.replace( /\\\\/g, "\\" );
		inst.dpDiv.find("[data-handler]").map(function () {
			var handler = {
				prev: function () {
					$.datepicker._adjustDate(id, -stepMonths, "M");
				},
				next: function () {
					$.datepicker._adjustDate(id, +stepMonths, "M");
				},
				hide: function () {
					$.datepicker._hideDatepicker();
				},
				today: function () {
					$.datepicker._gotoToday(id);
				},
				selectDay: function () {
					$.datepicker._selectDay(id, +this.getAttribute("data-month"), +this.getAttribute("data-year"), this);
					return false;
				},
				selectMonth: function () {
					$.datepicker._selectMonthYear(id, this, "M");
					return false;
				},
				selectYear: function () {
					$.datepicker._selectMonthYear(id, this, "Y");
					return false;
				}
			};
			$(this).bind(this.getAttribute("data-event"), handler[this.getAttribute("data-handler")]);
		});
	},

	/* Generate the HTML for the current state of the date picker. */
	_generateHTML: function(inst) {
		var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
			controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
			monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
			selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
			cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
			printDate, dRow, tbody, daySettings, otherMonth, unselectable,
			tempDate = new Date(),
			today = this._daylightSavingAdjust(
				new Date(tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate())), // clear time
			isRTL = this._get(inst, "isRTL"),
			showButtonPanel = this._get(inst, "showButtonPanel"),
			hideIfNoPrevNext = this._get(inst, "hideIfNoPrevNext"),
			navigationAsDateFormat = this._get(inst, "navigationAsDateFormat"),
			numMonths = this._getNumberOfMonths(inst),
			showCurrentAtPos = this._get(inst, "showCurrentAtPos"),
			stepMonths = this._get(inst, "stepMonths"),
			isMultiMonth = (numMonths[0] !== 1 || numMonths[1] !== 1),
			currentDate = this._daylightSavingAdjust((!inst.currentDay ? new Date(9999, 9, 9) :
				new Date(inst.currentYear, inst.currentMonth, inst.currentDay))),
			minDate = this._getMinMaxDate(inst, "min"),
			maxDate = this._getMinMaxDate(inst, "max"),
			drawMonth = inst.drawMonth - showCurrentAtPos,
			drawYear = inst.drawYear;

		if (drawMonth < 0) {
			drawMonth += 12;
			drawYear--;
		}
		if (maxDate) {
			maxDraw = this._daylightSavingAdjust(new Date(maxDate.getFullYear(),
				maxDate.getMonth() - (numMonths[0] * numMonths[1]) + 1, maxDate.getDate()));
			maxDraw = (minDate && maxDraw < minDate ? minDate : maxDraw);
			while (this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1)) > maxDraw) {
				drawMonth--;
				if (drawMonth < 0) {
					drawMonth = 11;
					drawYear--;
				}
			}
		}
		inst.drawMonth = drawMonth;
		inst.drawYear = drawYear;

		prevText = this._get(inst, "prevText");
		prevText = (!navigationAsDateFormat ? prevText : this.formatDate(prevText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth - stepMonths, 1)),
			this._getFormatConfig(inst)));

		prev = (this._canAdjustMonth(inst, -1, drawYear, drawMonth) ?
			"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
			" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>" :
			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='"+ prevText +"'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w") + "'>" + prevText + "</span></a>"));

		nextText = this._get(inst, "nextText");
		nextText = (!navigationAsDateFormat ? nextText : this.formatDate(nextText,
			this._daylightSavingAdjust(new Date(drawYear, drawMonth + stepMonths, 1)),
			this._getFormatConfig(inst)));

		next = (this._canAdjustMonth(inst, +1, drawYear, drawMonth) ?
			"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
			" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>" :
			(hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='"+ nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e") + "'>" + nextText + "</span></a>"));

		currentText = this._get(inst, "currentText");
		gotoDate = (this._get(inst, "gotoCurrent") && inst.currentDay ? currentDate : today);
		currentText = (!navigationAsDateFormat ? currentText :
			this.formatDate(currentText, gotoDate, this._getFormatConfig(inst)));

		controls = (!inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
			this._get(inst, "closeText") + "</button>" : "");

		buttonPanel = (showButtonPanel) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + (isRTL ? controls : "") +
			(this._isInRange(inst, gotoDate) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
			">" + currentText + "</button>" : "") + (isRTL ? "" : controls) + "</div>" : "";

		firstDay = parseInt(this._get(inst, "firstDay"),10);
		firstDay = (isNaN(firstDay) ? 0 : firstDay);

		showWeek = this._get(inst, "showWeek");
		dayNames = this._get(inst, "dayNames");
		dayNamesMin = this._get(inst, "dayNamesMin");
		monthNames = this._get(inst, "monthNames");
		monthNamesShort = this._get(inst, "monthNamesShort");
		beforeShowDay = this._get(inst, "beforeShowDay");
		showOtherMonths = this._get(inst, "showOtherMonths");
		selectOtherMonths = this._get(inst, "selectOtherMonths");
		defaultDate = this._getDefaultDate(inst);
		html = "";
		dow;
		for (row = 0; row < numMonths[0]; row++) {
			group = "";
			this.maxRows = 4;
			for (col = 0; col < numMonths[1]; col++) {
				selectedDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, inst.selectedDay));
				cornerClass = " ui-corner-all";
				calender = "";
				if (isMultiMonth) {
					calender += "<div class='ui-datepicker-group";
					if (numMonths[1] > 1) {
						switch (col) {
							case 0: calender += " ui-datepicker-group-first";
								cornerClass = " ui-corner-" + (isRTL ? "right" : "left"); break;
							case numMonths[1]-1: calender += " ui-datepicker-group-last";
								cornerClass = " ui-corner-" + (isRTL ? "left" : "right"); break;
							default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
						}
					}
					calender += "'>";
				}
				calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
					(/all|left/.test(cornerClass) && row === 0 ? (isRTL ? next : prev) : "") +
					(/all|right/.test(cornerClass) && row === 0 ? (isRTL ? prev : next) : "") +
					this._generateMonthYearHeader(inst, drawMonth, drawYear, minDate, maxDate,
					row > 0 || col > 0, monthNames, monthNamesShort) + // draw month headers
					"</div><table class='ui-datepicker-calendar'><thead>" +
					"<tr>";
				thead = (showWeek ? "<th class='ui-datepicker-week-col'>" + this._get(inst, "weekHeader") + "</th>" : "");
				for (dow = 0; dow < 7; dow++) { // days of the week
					day = (dow + firstDay) % 7;
					thead += "<th scope='col'" + ((dow + firstDay + 6) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "") + ">" +
						"<span title='" + dayNames[day] + "'>" + dayNamesMin[day] + "</span></th>";
				}
				calender += thead + "</tr></thead><tbody>";
				daysInMonth = this._getDaysInMonth(drawYear, drawMonth);
				if (drawYear === inst.selectedYear && drawMonth === inst.selectedMonth) {
					inst.selectedDay = Math.min(inst.selectedDay, daysInMonth);
				}
				leadDays = (this._getFirstDayOfMonth(drawYear, drawMonth) - firstDay + 7) % 7;
				curRows = Math.ceil((leadDays + daysInMonth) / 7); // calculate the number of rows to generate
				numRows = (isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows); //If multiple months, use the higher number of rows (see #7043)
				this.maxRows = numRows;
				printDate = this._daylightSavingAdjust(new Date(drawYear, drawMonth, 1 - leadDays));
				for (dRow = 0; dRow < numRows; dRow++) { // create date picker rows
					calender += "<tr>";
					tbody = (!showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
						this._get(inst, "calculateWeek")(printDate) + "</td>");
					for (dow = 0; dow < 7; dow++) { // create date picker days
						daySettings = (beforeShowDay ?
							beforeShowDay.apply((inst.input ? inst.input[0] : null), [printDate]) : [true, ""]);
						otherMonth = (printDate.getMonth() !== drawMonth);
						unselectable = (otherMonth && !selectOtherMonths) || !daySettings[0] ||
							(minDate && printDate < minDate) || (maxDate && printDate > maxDate);
						tbody += "<td class='" +
							((dow + firstDay + 6) % 7 >= 5 ? " ui-datepicker-week-end" : "") + // highlight weekends
							(otherMonth ? " ui-datepicker-other-month" : "") + // highlight days from other months
							((printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent) || // user pressed key
							(defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime()) ?
							// or defaultDate is current printedDate and defaultDate is selectedDate
							" " + this._dayOverClass : "") + // highlight selected day
							(unselectable ? " " + this._unselectableClass + " ui-state-disabled": "") +  // highlight unselectable days
							(otherMonth && !showOtherMonths ? "" : " " + daySettings[1] + // highlight custom dates
							(printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "") + // highlight selected day
							(printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "")) + "'" + // highlight today (if different)
							((!otherMonth || showOtherMonths) && daySettings[2] ? " title='" + daySettings[2].replace(/'/g, "&#39;") + "'" : "") + // cell title
							(unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'") + ">" + // actions
							(otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
							(unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
							(printDate.getTime() === today.getTime() ? " ui-state-highlight" : "") +
							(printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "") + // highlight selected day
							(otherMonth ? " ui-priority-secondary" : "") + // distinguish dates from other months
							"' href='#'>" + printDate.getDate() + "</a>")) + "</td>"; // display selectable date
						printDate.setDate(printDate.getDate() + 1);
						printDate = this._daylightSavingAdjust(printDate);
					}
					calender += tbody + "</tr>";
				}
				drawMonth++;
				if (drawMonth > 11) {
					drawMonth = 0;
					drawYear++;
				}
				calender += "</tbody></table>" + (isMultiMonth ? "</div>" +
							((numMonths[0] > 0 && col === numMonths[1]-1) ? "<div class='ui-datepicker-row-break'></div>" : "") : "");
				group += calender;
			}
			html += group;
		}
		html += buttonPanel;
		inst._keyEvent = false;
		return html;
	},

	/* Generate the month and year header. */
	_generateMonthYearHeader: function(inst, drawMonth, drawYear, minDate, maxDate,
			secondary, monthNames, monthNamesShort) {

		var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
			changeMonth = this._get(inst, "changeMonth"),
			changeYear = this._get(inst, "changeYear"),
			showMonthAfterYear = this._get(inst, "showMonthAfterYear"),
			html = "<div class='ui-datepicker-title'>",
			monthHtml = "";

		// month selection
		if (secondary || !changeMonth) {
			monthHtml += "<span class='ui-datepicker-month'>" + monthNames[drawMonth] + "</span>";
		} else {
			inMinYear = (minDate && minDate.getFullYear() === drawYear);
			inMaxYear = (maxDate && maxDate.getFullYear() === drawYear);
			monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
			for ( month = 0; month < 12; month++) {
				if ((!inMinYear || month >= minDate.getMonth()) && (!inMaxYear || month <= maxDate.getMonth())) {
					monthHtml += "<option value='" + month + "'" +
						(month === drawMonth ? " selected='selected'" : "") +
						">" + monthNamesShort[month] + "</option>";
				}
			}
			monthHtml += "</select>";
		}

		if (!showMonthAfterYear) {
			html += monthHtml + (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "");
		}

		// year selection
		if ( !inst.yearshtml ) {
			inst.yearshtml = "";
			if (secondary || !changeYear) {
				html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
			} else {
				// determine range of years to display
				years = this._get(inst, "yearRange").split(":");
				thisYear = new Date().getFullYear();
				determineYear = function(value) {
					var year = (value.match(/c[+\-].*/) ? drawYear + parseInt(value.substring(1), 10) :
						(value.match(/[+\-].*/) ? thisYear + parseInt(value, 10) :
						parseInt(value, 10)));
					return (isNaN(year) ? thisYear : year);
				};
				year = determineYear(years[0]);
				endYear = Math.max(year, determineYear(years[1] || ""));
				year = (minDate ? Math.max(year, minDate.getFullYear()) : year);
				endYear = (maxDate ? Math.min(endYear, maxDate.getFullYear()) : endYear);
				inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
				for (; year <= endYear; year++) {
					inst.yearshtml += "<option value='" + year + "'" +
						(year === drawYear ? " selected='selected'" : "") +
						">" + year + "</option>";
				}
				inst.yearshtml += "</select>";

				html += inst.yearshtml;
				inst.yearshtml = null;
			}
		}

		html += this._get(inst, "yearSuffix");
		if (showMonthAfterYear) {
			html += (secondary || !(changeMonth && changeYear) ? "&#xa0;" : "") + monthHtml;
		}
		html += "</div>"; // Close datepicker_header
		return html;
	},

	/* Adjust one of the date sub-fields. */
	_adjustInstDate: function(inst, offset, period) {
		var year = inst.drawYear + (period === "Y" ? offset : 0),
			month = inst.drawMonth + (period === "M" ? offset : 0),
			day = Math.min(inst.selectedDay, this._getDaysInMonth(year, month)) + (period === "D" ? offset : 0),
			date = this._restrictMinMax(inst, this._daylightSavingAdjust(new Date(year, month, day)));

		inst.selectedDay = date.getDate();
		inst.drawMonth = inst.selectedMonth = date.getMonth();
		inst.drawYear = inst.selectedYear = date.getFullYear();
		if (period === "M" || period === "Y") {
			this._notifyChange(inst);
		}
	},

	/* Ensure a date is within any min/max bounds. */
	_restrictMinMax: function(inst, date) {
		var minDate = this._getMinMaxDate(inst, "min"),
			maxDate = this._getMinMaxDate(inst, "max"),
			newDate = (minDate && date < minDate ? minDate : date);
		return (maxDate && newDate > maxDate ? maxDate : newDate);
	},

	/* Notify change of month/year. */
	_notifyChange: function(inst) {
		var onChange = this._get(inst, "onChangeMonthYear");
		if (onChange) {
			onChange.apply((inst.input ? inst.input[0] : null),
				[inst.selectedYear, inst.selectedMonth + 1, inst]);
		}
	},

	/* Determine the number of months to show. */
	_getNumberOfMonths: function(inst) {
		var numMonths = this._get(inst, "numberOfMonths");
		return (numMonths == null ? [1, 1] : (typeof numMonths === "number" ? [1, numMonths] : numMonths));
	},

	/* Determine the current maximum date - ensure no time components are set. */
	_getMinMaxDate: function(inst, minMax) {
		return this._determineDate(inst, this._get(inst, minMax + "Date"), null);
	},

	/* Find the number of days in a given month. */
	_getDaysInMonth: function(year, month) {
		return 32 - this._daylightSavingAdjust(new Date(year, month, 32)).getDate();
	},

	/* Find the day of the week of the first of a month. */
	_getFirstDayOfMonth: function(year, month) {
		return new Date(year, month, 1).getDay();
	},

	/* Determines if we should allow a "next/prev" month display change. */
	_canAdjustMonth: function(inst, offset, curYear, curMonth) {
		var numMonths = this._getNumberOfMonths(inst),
			date = this._daylightSavingAdjust(new Date(curYear,
			curMonth + (offset < 0 ? offset : numMonths[0] * numMonths[1]), 1));

		if (offset < 0) {
			date.setDate(this._getDaysInMonth(date.getFullYear(), date.getMonth()));
		}
		return this._isInRange(inst, date);
	},

	/* Is the given date in the accepted range? */
	_isInRange: function(inst, date) {
		var yearSplit, currentYear,
			minDate = this._getMinMaxDate(inst, "min"),
			maxDate = this._getMinMaxDate(inst, "max"),
			minYear = null,
			maxYear = null,
			years = this._get(inst, "yearRange");
			if (years){
				yearSplit = years.split(":");
				currentYear = new Date().getFullYear();
				minYear = parseInt(yearSplit[0], 10);
				maxYear = parseInt(yearSplit[1], 10);
				if ( yearSplit[0].match(/[+\-].*/) ) {
					minYear += currentYear;
				}
				if ( yearSplit[1].match(/[+\-].*/) ) {
					maxYear += currentYear;
				}
			}

		return ((!minDate || date.getTime() >= minDate.getTime()) &&
			(!maxDate || date.getTime() <= maxDate.getTime()) &&
			(!minYear || date.getFullYear() >= minYear) &&
			(!maxYear || date.getFullYear() <= maxYear));
	},

	/* Provide the configuration settings for formatting/parsing. */
	_getFormatConfig: function(inst) {
		var shortYearCutoff = this._get(inst, "shortYearCutoff");
		shortYearCutoff = (typeof shortYearCutoff !== "string" ? shortYearCutoff :
			new Date().getFullYear() % 100 + parseInt(shortYearCutoff, 10));
		return {shortYearCutoff: shortYearCutoff,
			dayNamesShort: this._get(inst, "dayNamesShort"), dayNames: this._get(inst, "dayNames"),
			monthNamesShort: this._get(inst, "monthNamesShort"), monthNames: this._get(inst, "monthNames")};
	},

	/* Format the given date for display. */
	_formatDate: function(inst, day, month, year) {
		if (!day) {
			inst.currentDay = inst.selectedDay;
			inst.currentMonth = inst.selectedMonth;
			inst.currentYear = inst.selectedYear;
		}
		var date = (day ? (typeof day === "object" ? day :
			this._daylightSavingAdjust(new Date(year, month, day))) :
			this._daylightSavingAdjust(new Date(inst.currentYear, inst.currentMonth, inst.currentDay)));
		return this.formatDate(this._get(inst, "dateFormat"), date, this._getFormatConfig(inst));
	}
});

/*
 * Bind hover events for datepicker elements.
 * Done via delegate so the binding only occurs once in the lifetime of the parent div.
 * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
 */
  function datepicker_bindHover(dpDiv) {
    var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td";
    return dpDiv.delegate(selector, "mouseout", function (ev) {
      $(this).removeClass("ui-state-hover");

      if (ev && ev.currentTarget.nodeName.toLowerCase() === 'td') {
        if (datepicker_instActive.settings.onUnhover) {
          datepicker_instActive.settings.onUnhover.apply((datepicker_instActive.input ? datepicker_instActive.input[0] : null));
        }
      }

      if (this.className.indexOf("ui-datepicker-prev") !== -1) {
        $(this).removeClass("ui-datepicker-prev-hover");
      }
      if (this.className.indexOf("ui-datepicker-next") !== -1) {
        $(this).removeClass("ui-datepicker-next-hover");
      }
    })
      .delegate(selector, "mouseover", datepicker_handleMouseover);
  }

function datepicker_handleMouseover(ev) {
	if (!$.datepicker._isDisabledDatepicker( datepicker_instActive.inline? datepicker_instActive.dpDiv.parent()[0] : datepicker_instActive.input[0])) {
    $(this).addClass("ui-state-hover");
		if (this.className.indexOf("ui-datepicker-prev") !== -1) {
			$(this).addClass("ui-datepicker-prev-hover");
		}
		if (this.className.indexOf("ui-datepicker-next") !== -1) {
			$(this).addClass("ui-datepicker-next-hover");
		}

    if (ev && ev.currentTarget.nodeName.toLowerCase() === 'td' && !$(ev.currentTarget).hasClass('ui-datepicker-unselectable')) {
      var inst = $.datepicker._getInst(ev.currentTarget);

      var day = +$("a", $(ev.currentTarget)).html();
      var month = +$(ev.currentTarget).data('month');
      var year = +$(ev.currentTarget).data('year');

      if(datepicker_instActive.settings.onHover) {
        datepicker_instActive.settings.onHover.apply((datepicker_instActive.input ? datepicker_instActive.input[0] : null), [year, month, day]);
      }
    }
	}
}

/* jQuery extend now ignores nulls! */
function datepicker_extendRemove(target, props) {
	$.extend(target, props);
	for (var name in props) {
		if (props[name] == null) {
			target[name] = props[name];
		}
	}
	return target;
}

/* Invoke the datepicker functionality.
   @param  options  string - a command, optionally followed by additional parameters or
					Object - settings for attaching new datepicker functionality
   @return  jQuery object */
$.fn.datepicker = function(options){

	/* Verify an empty collection wasn't passed - Fixes #6976 */
	if ( !this.length ) {
		return this;
	}

	/* Initialise the date picker. */
	if (!$.datepicker.initialized) {
		$(document).mousedown($.datepicker._checkExternalClick);
		$.datepicker.initialized = true;
	}

	/* Append datepicker main container to body if not exist. */
	if ($("#"+$.datepicker._mainDivId).length === 0) {
		$("body").append($.datepicker.dpDiv);
	}

	var otherArgs = Array.prototype.slice.call(arguments, 1);
	if (typeof options === "string" && (options === "isDisabled" || options === "getDate" || options === "widget")) {
		return $.datepicker["_" + options + "Datepicker"].
			apply($.datepicker, [this[0]].concat(otherArgs));
	}
	if (options === "option" && arguments.length === 2 && typeof arguments[1] === "string") {
		return $.datepicker["_" + options + "Datepicker"].
			apply($.datepicker, [this[0]].concat(otherArgs));
	}
	return this.each(function() {
		typeof options === "string" ?
			$.datepicker["_" + options + "Datepicker"].
				apply($.datepicker, [this].concat(otherArgs)) :
			$.datepicker._attachDatepicker(this, options);
	});
};

$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.11.4";

var datepicker = $.datepicker;


/*!
 * jQuery UI Menu 1.11.4
 * http://jqueryui.com
 *
 * Copyright jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/menu/
 */


var menu = $.widget( "ui.menu", {
	version: "1.11.4",
	defaultElement: "<ul>",
	delay: 300,
	options: {
		icons: {
			submenu: "ui-icon-carat-1-e"
		},
		items: "> *",
		menus: "ul",
		position: {
			my: "left-1 top",
			at: "right top"
		},
		role: "menu",

		// callbacks
		blur: null,
		focus: null,
		select: null
	},

	_create: function() {
		this.activeMenu = this.element;

		// Flag used to prevent firing of the click handler
		// as the event bubbles up through nested menus
		this.mouseHandled = false;
		this.element
			.uniqueId()
			.addClass( "ui-menu ui-widget ui-widget-content" )
			.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length )
			.attr({
				role: this.options.role,
				tabIndex: 0
			});

		if ( this.options.disabled ) {
			this.element
				.addClass( "ui-state-disabled" )
				.attr( "aria-disabled", "true" );
		}

		this._on({
			// Prevent focus from sticking to links inside menu after clicking
			// them (focus should always stay on UL during navigation).
			"mousedown .ui-menu-item": function( event ) {
				event.preventDefault();
			},
			"click .ui-menu-item": function( event ) {
				var target = $( event.target );
				if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
					this.select( event );

					// Only set the mouseHandled flag if the event will bubble, see #9469.
					if ( !event.isPropagationStopped() ) {
						this.mouseHandled = true;
					}

					// Open submenu on click
					if ( target.has( ".ui-menu" ).length ) {
						this.expand( event );
					} else if ( !this.element.is( ":focus" ) && $( this.document[ 0 ].activeElement ).closest( ".ui-menu" ).length ) {

						// Redirect focus to the menu
						this.element.trigger( "focus", [ true ] );

						// If the active item is on the top level, let it stay active.
						// Otherwise, blur the active item since it is no longer visible.
						if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
							clearTimeout( this.timer );
						}
					}
				}
			},
			"mouseenter .ui-menu-item": function( event ) {
				// Ignore mouse events while typeahead is active, see #10458.
				// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
				// is over an item in the menu
				if ( this.previousFilter ) {
					return;
				}
				var target = $( event.currentTarget );
				// Remove ui-state-active class from siblings of the newly focused menu item
				// to avoid a jump caused by adjacent elements both having a class with a border
				target.siblings( ".ui-state-active" ).removeClass( "ui-state-active" );
				this.focus( event, target );
			},
			mouseleave: "collapseAll",
			"mouseleave .ui-menu": "collapseAll",
			focus: function( event, keepActiveItem ) {
				// If there's already an active item, keep it active
				// If not, activate the first item
				var item = this.active || this.element.find( this.options.items ).eq( 0 );

				if ( !keepActiveItem ) {
					this.focus( event, item );
				}
			},
			blur: function( event ) {
				this._delay(function() {
					if ( !$.contains( this.element[0], this.document[0].activeElement ) ) {
						this.collapseAll( event );
					}
				});
			},
			keydown: "_keydown"
		});

		this.refresh();

		// Clicks outside of a menu collapse any open menus
		this._on( this.document, {
			click: function( event ) {
				if ( this._closeOnDocumentClick( event ) ) {
					this.collapseAll( event );
				}

				// Reset the mouseHandled flag
				this.mouseHandled = false;
			}
		});
	},

	_destroy: function() {
		// Destroy (sub)menus
		this.element
			.removeAttr( "aria-activedescendant" )
			.find( ".ui-menu" ).addBack()
				.removeClass( "ui-menu ui-widget ui-widget-content ui-menu-icons ui-front" )
				.removeAttr( "role" )
				.removeAttr( "tabIndex" )
				.removeAttr( "aria-labelledby" )
				.removeAttr( "aria-expanded" )
				.removeAttr( "aria-hidden" )
				.removeAttr( "aria-disabled" )
				.removeUniqueId()
				.show();

		// Destroy menu items
		this.element.find( ".ui-menu-item" )
			.removeClass( "ui-menu-item" )
			.removeAttr( "role" )
			.removeAttr( "aria-disabled" )
			.removeUniqueId()
			.removeClass( "ui-state-hover" )
			.removeAttr( "tabIndex" )
			.removeAttr( "role" )
			.removeAttr( "aria-haspopup" )
			.children().each( function() {
				var elem = $( this );
				if ( elem.data( "ui-menu-submenu-carat" ) ) {
					elem.remove();
				}
			});

		// Destroy menu dividers
		this.element.find( ".ui-menu-divider" ).removeClass( "ui-menu-divider ui-widget-content" );
	},

	_keydown: function( event ) {
		var match, prev, character, skip,
			preventDefault = true;

		switch ( event.keyCode ) {
		case $.ui.keyCode.PAGE_UP:
			this.previousPage( event );
			break;
		case $.ui.keyCode.PAGE_DOWN:
			this.nextPage( event );
			break;
		case $.ui.keyCode.HOME:
			this._move( "first", "first", event );
			break;
		case $.ui.keyCode.END:
			this._move( "last", "last", event );
			break;
		case $.ui.keyCode.UP:
			this.previous( event );
			break;
		case $.ui.keyCode.DOWN:
			this.next( event );
			break;
		case $.ui.keyCode.LEFT:
			this.collapse( event );
			break;
		case $.ui.keyCode.RIGHT:
			if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
				this.expand( event );
			}
			break;
		case $.ui.keyCode.ENTER:
		case $.ui.keyCode.SPACE:
			this._activate( event );
			break;
		case $.ui.keyCode.ESCAPE:
			this.collapse( event );
			break;
		default:
			preventDefault = false;
			prev = this.previousFilter || "";
			character = String.fromCharCode( event.keyCode );
			skip = false;

			clearTimeout( this.filterTimer );

			if ( character === prev ) {
				skip = true;
			} else {
				character = prev + character;
			}

			match = this._filterMenuItems( character );
			match = skip && match.index( this.active.next() ) !== -1 ?
				this.active.nextAll( ".ui-menu-item" ) :
				match;

			// If no matches on the current filter, reset to the last character pressed
			// to move down the menu to the first item that starts with that character
			if ( !match.length ) {
				character = String.fromCharCode( event.keyCode );
				match = this._filterMenuItems( character );
			}

			if ( match.length ) {
				this.focus( event, match );
				this.previousFilter = character;
				this.filterTimer = this._delay(function() {
					delete this.previousFilter;
				}, 1000 );
			} else {
				delete this.previousFilter;
			}
		}

		if ( preventDefault ) {
			event.preventDefault();
		}
	},

	_activate: function( event ) {
		if ( !this.active.is( ".ui-state-disabled" ) ) {
			if ( this.active.is( "[aria-haspopup='true']" ) ) {
				this.expand( event );
			} else {
				this.select( event );
			}
		}
	},

	refresh: function() {
		var menus, items,
			that = this,
			icon = this.options.icons.submenu,
			submenus = this.element.find( this.options.menus );

		this.element.toggleClass( "ui-menu-icons", !!this.element.find( ".ui-icon" ).length );

		// Initialize nested menus
		submenus.filter( ":not(.ui-menu)" )
			.addClass( "ui-menu ui-widget ui-widget-content ui-front" )
			.hide()
			.attr({
				role: this.options.role,
				"aria-hidden": "true",
				"aria-expanded": "false"
			})
			.each(function() {
				var menu = $( this ),
					item = menu.parent(),
					submenuCarat = $( "<span>" )
						.addClass( "ui-menu-icon ui-icon " + icon )
						.data( "ui-menu-submenu-carat", true );

				item
					.attr( "aria-haspopup", "true" )
					.prepend( submenuCarat );
				menu.attr( "aria-labelledby", item.attr( "id" ) );
			});

		menus = submenus.add( this.element );
		items = menus.find( this.options.items );

		// Initialize menu-items containing spaces and/or dashes only as dividers
		items.not( ".ui-menu-item" ).each(function() {
			var item = $( this );
			if ( that._isDivider( item ) ) {
				item.addClass( "ui-widget-content ui-menu-divider" );
			}
		});

		// Don't refresh list items that are already adapted
		items.not( ".ui-menu-item, .ui-menu-divider" )
			.addClass( "ui-menu-item" )
			.uniqueId()
			.attr({
				tabIndex: -1,
				role: this._itemRole()
			});

		// Add aria-disabled attribute to any disabled menu item
		items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );

		// If the active item has been removed, blur the menu
		if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
			this.blur();
		}
	},

	_itemRole: function() {
		return {
			menu: "menuitem",
			listbox: "option"
		}[ this.options.role ];
	},

	_setOption: function( key, value ) {
		if ( key === "icons" ) {
			this.element.find( ".ui-menu-icon" )
				.removeClass( this.options.icons.submenu )
				.addClass( value.submenu );
		}
		if ( key === "disabled" ) {
			this.element
				.toggleClass( "ui-state-disabled", !!value )
				.attr( "aria-disabled", value );
		}
		this._super( key, value );
	},

	focus: function( event, item ) {
		var nested, focused;
		this.blur( event, event && event.type === "focus" );

		this._scrollIntoView( item );

		this.active = item.first();
		focused = this.active.addClass( "ui-state-focus" ).removeClass( "ui-state-active" );
		// Only update aria-activedescendant if there's a role
		// otherwise we assume focus is managed elsewhere
		if ( this.options.role ) {
			this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
		}

		// Highlight active parent menu item, if any
		this.active
			.parent()
			.closest( ".ui-menu-item" )
			.addClass( "ui-state-active" );

		if ( event && event.type === "keydown" ) {
			this._close();
		} else {
			this.timer = this._delay(function() {
				this._close();
			}, this.delay );
		}

		nested = item.children( ".ui-menu" );
		if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
			this._startOpening(nested);
		}
		this.activeMenu = item.parent();

		this._trigger( "focus", event, { item: item } );
	},

	_scrollIntoView: function( item ) {
		var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
		if ( this._hasScroll() ) {
			borderTop = parseFloat( $.css( this.activeMenu[0], "borderTopWidth" ) ) || 0;
			paddingTop = parseFloat( $.css( this.activeMenu[0], "paddingTop" ) ) || 0;
			offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
			scroll = this.activeMenu.scrollTop();
			elementHeight = this.activeMenu.height();
			itemHeight = item.outerHeight();

			if ( offset < 0 ) {
				this.activeMenu.scrollTop( scroll + offset );
			} else if ( offset + itemHeight > elementHeight ) {
				this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
			}
		}
	},

	blur: function( event, fromFocus ) {
		if ( !fromFocus ) {
			clearTimeout( this.timer );
		}

		if ( !this.active ) {
			return;
		}

		this.active.removeClass( "ui-state-focus" );
		this.active = null;

		this._trigger( "blur", event, { item: this.active } );
	},

	_startOpening: function( submenu ) {
		clearTimeout( this.timer );

		// Don't open if already open fixes a Firefox bug that caused a .5 pixel
		// shift in the submenu position when mousing over the carat icon
		if ( submenu.attr( "aria-hidden" ) !== "true" ) {
			return;
		}

		this.timer = this._delay(function() {
			this._close();
			this._open( submenu );
		}, this.delay );
	},

	_open: function( submenu ) {
		var position = $.extend({
			of: this.active
		}, this.options.position );

		clearTimeout( this.timer );
		this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
			.hide()
			.attr( "aria-hidden", "true" );

		submenu
			.show()
			.removeAttr( "aria-hidden" )
			.attr( "aria-expanded", "true" )
			.position( position );
	},

	collapseAll: function( event, all ) {
		clearTimeout( this.timer );
		this.timer = this._delay(function() {
			// If we were passed an event, look for the submenu that contains the event
			var currentMenu = all ? this.element :
				$( event && event.target ).closest( this.element.find( ".ui-menu" ) );

			// If we found no valid submenu ancestor, use the main menu to close all sub menus anyway
			if ( !currentMenu.length ) {
				currentMenu = this.element;
			}

			this._close( currentMenu );

			this.blur( event );
			this.activeMenu = currentMenu;
		}, this.delay );
	},

	// With no arguments, closes the currently active menu - if nothing is active
	// it closes all menus.  If passed an argument, it will search for menus BELOW
	_close: function( startMenu ) {
		if ( !startMenu ) {
			startMenu = this.active ? this.active.parent() : this.element;
		}

		startMenu
			.find( ".ui-menu" )
				.hide()
				.attr( "aria-hidden", "true" )
				.attr( "aria-expanded", "false" )
			.end()
			.find( ".ui-state-active" ).not( ".ui-state-focus" )
				.removeClass( "ui-state-active" );
	},

	_closeOnDocumentClick: function( event ) {
		return !$( event.target ).closest( ".ui-menu" ).length;
	},

	_isDivider: function( item ) {

		// Match hyphen, em dash, en dash
		return !/[^\-\u2014\u2013\s]/.test( item.text() );
	},

	collapse: function( event ) {
		var newItem = this.active &&
			this.active.parent().closest( ".ui-menu-item", this.element );
		if ( newItem && newItem.length ) {
			this._close();
			this.focus( event, newItem );
		}
	},

	expand: function( event ) {
		var newItem = this.active &&
			this.active
				.children( ".ui-menu " )
				.find( this.options.items )
				.first();

		if ( newItem && newItem.length ) {
			this._open( newItem.parent() );

			// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
			this._delay(function() {
				this.focus( event, newItem );
			});
		}
	},

	next: function( event ) {
		this._move( "next", "first", event );
	},

	previous: function( event ) {
		this._move( "prev", "last", event );
	},

	isFirstItem: function() {
		return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
	},

	isLastItem: function() {
		return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
	},

	_move: function( direction, filter, event ) {
		var next;
		if ( this.active ) {
			if ( direction === "first" || direction === "last" ) {
				next = this.active
					[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
					.eq( -1 );
			} else {
				next = this.active
					[ direction + "All" ]( ".ui-menu-item" )
					.eq( 0 );
			}
		}
		if ( !next || !next.length || !this.active ) {
			next = this.activeMenu.find( this.options.items )[ filter ]();
		}

		this.focus( event, next );
	},

	nextPage: function( event ) {
		var item, base, height;

		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isLastItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.height();
			this.active.nextAll( ".ui-menu-item" ).each(function() {
				item = $( this );
				return item.offset().top - base - height < 0;
			});

			this.focus( event, item );
		} else {
			this.focus( event, this.activeMenu.find( this.options.items )
				[ !this.active ? "first" : "last" ]() );
		}
	},

	previousPage: function( event ) {
		var item, base, height;
		if ( !this.active ) {
			this.next( event );
			return;
		}
		if ( this.isFirstItem() ) {
			return;
		}
		if ( this._hasScroll() ) {
			base = this.active.offset().top;
			height = this.element.height();
			this.active.prevAll( ".ui-menu-item" ).each(function() {
				item = $( this );
				return item.offset().top - base + height > 0;
			});

			this.focus( event, item );
		} else {
			this.focus( event, this.activeMenu.find( this.options.items ).first() );
		}
	},

	_hasScroll: function() {
		return this.element.outerHeight() < this.element.prop( "scrollHeight" );
	},

	select: function( event ) {
		// TODO: It should never be possible to not have an active item at this
		// point, but the tests don't trigger mouseenter before click.
		this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
		var ui = { item: this.active };
		if ( !this.active.has( ".ui-menu" ).length ) {
			this.collapseAll( event, true );
		}
		this._trigger( "select", event, ui );
	},

	_filterMenuItems: function(character) {
		var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
			regex = new RegExp( "^" + escapedCharacter, "i" );

		return this.activeMenu
			.find( this.options.items )

			// Only match on items, not dividers or other content (#10571)
			.filter( ".ui-menu-item" )
			.filter(function() {
				return regex.test( $.trim( $( this ).text() ) );
			});
	}
});



}));
var imxQuery = (function(){
  
  /**
   * get the total top offset of an object to the window object, not only to the next positioned object
   * @param {object} targetNode
   * @returns {Number}
   */
  var offsetTop = function(targetNode, stopElement){
    var offsetTopValue = targetNode.offsetTop;
    var currentNode = targetNode.parentNode;
    
    if(!stopElement){
      stopElement = document.querySelector('body');
    };
    
    while(currentNode && currentNode !== stopElement){
      var elementPositionStyle = window.getComputedStyle(currentNode).getPropertyValue('position');
      
      if(elementPositionStyle === 'relative' || elementPositionStyle === 'absolute'){
        offsetTopValue += currentNode.offsetTop;
      };
      
      currentNode = (currentNode.parentNode !== stopElement) ? currentNode.parentNode : null;
    };
    
    return offsetTopValue;
  };
  
  /**
   * animated scrolling to a specific position
   * @param {int} positionX
   * @param {int} positionY
   * @param {int} duration
   * @returns null
   */
  var scrollTo = function(positionX, positionY, duration){
    var _getCurrentScrollPositions = function(){
      return {
        x : window.pageXOffset,
        y : window.pageYOffset
      };
    };
    
    var _isTargetPositionReached = function(){
      var currentScrollPosition = _getCurrentScrollPositions();
      var flags = {
        x : false,
        y : false
      }
      
      if(scrollSteps.x < 0){
        if(currentScrollPosition.x <= positionX){
          flags.x = true;
        };
      }else{
        if(currentScrollPosition.x >= positionX){
          flags.x = true;
        };
      };
      
      if(scrollSteps.y < 0){
        if(currentScrollPosition.y <= positionY){
          flags.y = true;
        };
      }else{
        if(currentScrollPosition.y >= positionY){
          flags.y = true;
        };
      };
      
      if(flags.x && flags.y){
        return true;
      }else{
        return false;
      };
    };
    
    var intervalGap = 15;
    var currentScrollPosition = _getCurrentScrollPositions();
    
    var scrollSteps = {
      x : (positionX - currentScrollPosition.x) / (duration / intervalGap),
      y : (positionY - currentScrollPosition.y) / (duration / intervalGap)
    };
    
    var scrollInterval = setInterval(function(){

      if(_isTargetPositionReached()){
        clearInterval(scrollInterval);
        window.scrollTo(positionX, positionY);
      }else{
        window.scrollBy(scrollSteps.x, scrollSteps.y);
      }
    }, intervalGap);
  };
  
  /**
   * wrapper to access html5 data set (use this for ie10 compatibility)
   * @param {htlmnode} object
   * @param {string} value
   * @returns {mixed}
   */
  var accessDataset = function(object, value){
    if(object.dataset) {
      return object.dataset[value];
    }else{
      return object.getAttribute('data-' + value);
    };
  };
  
  /**
   * extend an object with another object, adding missing fields, overwriting existing fields
   * @param {object} objectForExtension
   * @param {object} extensionObject
   * @returns {object}
   */
  var extendObject = function(objectForExtension, extensionObject){
    for(var property in extensionObject){
      if(!objectForExtension.hasOwnProperty(property)){
        objectForExtension[property] = extensionObject[property];
      };
    };
    return objectForExtension;
  };
  
  return {
    offsetTop : offsetTop,
    scrollTo : scrollTo,
    accessDataset : accessDataset,
    extendObject : extendObject
  };
})();
/* German initialisation for the jQuery UI date picker plugin. */
/* Written by Milian Wolff (mail@milianw.de). */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define([ "../widgets/datepicker" ], factory );
	} else {

		// Browser globals
		factory( jQuery.datepicker );
	}
}(function( datepicker ) {

datepicker.regional['de'] = {
	closeText: 'Schließen',
	prevText: '&#x3C;Zurück',
	nextText: 'Vor&#x3E;',
	currentText: 'Heute',
	monthNames: ['Januar','Februar','März','April','Mai','Juni',
	'Juli','August','September','Oktober','November','Dezember'],
	monthNamesShort: ['Jan','Feb','Mär','Apr','Mai','Jun',
	'Jul','Aug','Sep','Okt','Nov','Dez'],
	dayNames: ['Sonntag','Montag','Dienstag','Mittwoch','Donnerstag','Freitag','Samstag'],
	dayNamesShort: ['So','Mo','Di','Mi','Do','Fr','Sa'],
	dayNamesMin: ['So','Mo','Di','Mi','Do','Fr','Sa'],
	weekHeader: 'KW',
	dateFormat: 'dd.mm.yy',
	firstDay: 1,
	isRTL: false,
	showMonthAfterYear: false,
	yearSuffix: ''};
datepicker.setDefaults(datepicker.regional['de']);

return datepicker.regional['de'];

}));

/* English/UK initialisation for the jQuery UI date picker plugin. */
/* Written by Stuart. */
(function( factory ) {
	if ( typeof define === "function" && define.amd ) {

		// AMD. Register as an anonymous module.
		define([ "../widgets/datepicker" ], factory );
	} else {

		// Browser globals
		factory( jQuery.datepicker );
	}
}(function( datepicker ) {

datepicker.regional['en'] = {
	closeText: 'Done',
	prevText: 'Prev',
	nextText: 'Next',
	currentText: 'Today',
	monthNames: ['January','February','March','April','May','June',
	'July','August','September','October','November','December'],
	monthNamesShort: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
	'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
	dayNames: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
	dayNamesShort: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
	dayNamesMin: ['Su','Mo','Tu','We','Th','Fr','Sa'],
	weekHeader: 'Wk',
	dateFormat: 'dd/mm/yy',
	firstDay: 1,
	isRTL: false,
	showMonthAfterYear: false,
	yearSuffix: ''};
datepicker.setDefaults(datepicker.regional['en']);

return datepicker.regional['en'];

}));

/*!

    Copyright (c) 2011 Peter van der Spek

    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in
    all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    THE SOFTWARE.
    
 */


(function($) {

    /**
     * Hash containing mapping of selectors to settings hashes for target selectors that should be live updated.
     *
     * @type {Object.<string, Object>}
     * @private
     */
    var liveUpdatingTargetSelectors = {};

    /**
     * Interval ID for live updater. Contains interval ID when the live updater interval is active, or is undefined
     * otherwise.
     *
     * @type {number}
     * @private
     */
    var liveUpdaterIntervalId;

    /**
     * Boolean indicating whether the live updater is running.
     *
     * @type {boolean}
     * @private
     */
    var liveUpdaterRunning = false;

    /**
     * Set of default settings.
     *
     * @type {Object.<string, string>}
     * @private
     */
    var defaultSettings = {
                ellipsis: '...',
                setTitle: 'never',
                live: false
            };

    /**
     * Perform ellipsis on selected elements.
     *
     * @param {string} selector the inner selector of elements that ellipsis may work on. Inner elements not referred to by this
     *      selector are left untouched.
     * @param {Object.<string, string>=} options optional options to override default settings.
     * @return {jQuery} the current jQuery object for chaining purposes.
     * @this {jQuery} the current jQuery object.
     */
    $.fn.ellipsis = function(selector, options) {
        var subjectElements, settings;

        subjectElements = $(this);

        // Check for options argument only.
        if (typeof selector !== 'string') {
            options = selector;
            selector = undefined;
        }

        // Create the settings from the given options and the default settings.
        settings = $.extend({}, defaultSettings, options);

        // If selector is not set, work on immediate children (default behaviour).
        settings.selector = selector;

        // Do ellipsis on each subject element.
        subjectElements.each(function() {
            var elem = $(this);

            // Do ellipsis on subject element.
            ellipsisOnElement(elem, settings);
        });

        // If live option is enabled, add subject elements to live updater. Otherwise remove from live updater.
        if (settings.live) {
            addToLiveUpdater(subjectElements.selector, settings);

        } else {
            removeFromLiveUpdater(subjectElements.selector);
        }

        // Return jQuery object for chaining.
        return this;
    };


    /**
     * Perform ellipsis on the given container.
     *
     * @param {jQuery} containerElement jQuery object containing one DOM element to perform ellipsis on.
     * @param {Object.<string, string>} settings the settings for this ellipsis operation.
     * @private
     */
    function ellipsisOnElement(containerElement, settings) {
        var containerData = containerElement.data('jqae');
        if (!containerData) containerData = {};

        // Check if wrapper div was already created and bound to the container element.
        var wrapperElement = containerData.wrapperElement;

        // If not, create wrapper element.
        if (!wrapperElement) {
            wrapperElement = containerElement.wrapInner('<div/>').find('>div');

            // Wrapper div should not add extra size.
            wrapperElement.css({
                margin: 0,
                padding: 0,
                border: 0
            });
        }

        // Check if the original wrapper element content was already bound to the wrapper element.
        var wrapperElementData = wrapperElement.data('jqae');
        if (!wrapperElementData) wrapperElementData = {};

        var wrapperOriginalContent = wrapperElementData.originalContent;

        // If so, clone the original content, re-bind the original wrapper content to the clone, and replace the
        // wrapper with the clone.
        if (wrapperOriginalContent) {
            wrapperElement = wrapperElementData.originalContent.clone(true)
                    .data('jqae', {originalContent: wrapperOriginalContent}).replaceAll(wrapperElement);

        } else {
            // Otherwise, clone the current wrapper element and bind it as original content to the wrapper element.

            wrapperElement.data('jqae', {originalContent: wrapperElement.clone(true)});
        }

        // Bind the wrapper element and current container width and height to the container element. Current container
        // width and height are stored to detect changes to the container size.
        containerElement.data('jqae', {
            wrapperElement: wrapperElement,
            containerWidth: containerElement.width(),
            containerHeight: containerElement.height()
        });

        // Calculate with current container element height.
        var containerElementHeight = containerElement.height();

        // Calculate wrapper offset.
        var wrapperOffset = (parseInt(containerElement.css('padding-top'), 10) || 0) + (parseInt(containerElement.css('border-top-width'), 10) || 0) - (wrapperElement.offset().top - containerElement.offset().top);

        // Normally the ellipsis characters are applied to the last non-empty text-node in the selected element. If the
        // selected element becomes empty during ellipsis iteration, the ellipsis characters cannot be applied to that
        // selected element, and must be deferred to the previous selected element. This parameter keeps track of that.
        var deferAppendEllipsis = false;

        // Loop through all selected elements in reverse order.
        var selectedElements = wrapperElement;
        if (settings.selector) selectedElements = $(wrapperElement.find(settings.selector).get().reverse());

        selectedElements.each(function() {
            var selectedElement = $(this),
                    originalText = selectedElement.text(),
                    ellipsisApplied = false;

            // Check if we can safely remove the selected element. This saves a lot of unnecessary iterations.
            if (wrapperElement.innerHeight() - selectedElement.innerHeight() > containerElementHeight + wrapperOffset) {
                selectedElement.remove();

            } else {
                // Reverse recursively remove empty elements, until the element that contains a non-empty text-node.
                removeLastEmptyElements(selectedElement);

                // If the selected element has not become empty, start ellipsis iterations on the selected element.
                if (selectedElement.contents().length) {

                    // If a deffered ellipsis is still pending, apply it now to the last text-node.
                    if (deferAppendEllipsis && getLastTextNode(selectedElement).get(0)) {
                        getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis;
                        deferAppendEllipsis = false;
                    }

                    // Iterate until wrapper element height is less than or equal to the original container element
                    // height plus possible wrapperOffset.
                    while (wrapperElement.innerHeight() > containerElementHeight + wrapperOffset) {
                        // Apply ellipsis on last text node, by removing one word.
                        ellipsisApplied = ellipsisOnLastTextNode(selectedElement);

                        // If ellipsis was succesfully applied, remove any remaining empty last elements and append the
                        // ellipsis characters.
                        if (ellipsisApplied) {
                            removeLastEmptyElements(selectedElement);

                            // If the selected element is not empty, append the ellipsis characters.
                            if (selectedElement.contents().length && getLastTextNode(selectedElement).get(0)) {
                                getLastTextNode(selectedElement).get(0).nodeValue += settings.ellipsis;

                            } else {
                                // If the selected element has become empty, defer the appending of the ellipsis characters
                                // to the previous selected element.
                                deferAppendEllipsis = true;
                                selectedElement.remove();
                                break;
                            }

                        } else {
                            // If ellipsis could not be applied, defer the appending of the ellipsis characters to the
                            // previous selected element.
                            deferAppendEllipsis = true;
                            selectedElement.remove();
                            break;
                        }
                    }

                    // If the "setTitle" property is set to "onEllipsis" and the ellipsis has been applied, or if the
                    // property is set to "always", the add the "title" attribute with the original text. Else remove the
                    // "title" attribute. When the "setTitle" property is set to "never" we do not touch the "title"
                    // attribute.
                    if (((settings.setTitle == 'onEllipsis') && ellipsisApplied) || (settings.setTitle == 'always')) {
                        selectedElement.attr('title', originalText);

                    } else if (settings.setTitle != 'never') {
                        selectedElement.removeAttr('title');
                    }
                }
            }
        });
    }

    /**
     * Performs ellipsis on the last text node of the given element. Ellipsis is done by removing a full word.
     *
     * @param {jQuery} element jQuery object containing a single DOM element.
     * @return {boolean} true when ellipsis has been done, false otherwise.
     * @private
     */
    function ellipsisOnLastTextNode(element) {
        var lastTextNode = getLastTextNode(element);

        // If the last text node is found, do ellipsis on that node.
        if (lastTextNode.length > 0) {
            var text = lastTextNode.get(0).nodeValue;

            // Find last space character, and remove text from there. If no space is found the full remaining text is
            // removed.
            var pos = text.lastIndexOf(' ');
            if (pos > -1) {
                text = $.trim(text.substring(0, pos));
                lastTextNode.get(0).nodeValue = text;

            } else {
                lastTextNode.get(0).nodeValue = '';
            }

            return true;
        }

        return false;
    }

    /**
     * Get last text node of the given element.
     *
     * @param {jQuery} element jQuery object containing a single element.
     * @return {jQuery} jQuery object containing a single text node.
     * @private
     */
    function getLastTextNode(element) {
        if (element.contents().length) {

            // Get last child node.
            var contents = element.contents();
            var lastNode = contents.eq(contents.length - 1);

            // If last node is a text node, return it.
            if (lastNode.filter(textNodeFilter).length) {
                return lastNode;

            } else {
                // Else it is an element node, and we recurse into it.

                return getLastTextNode(lastNode);
            }

        } else {
            // If there is no last child node, we append an empty text node and return that. Normally this should not
            // happen, as we test for emptiness before calling getLastTextNode.

            element.append('');
            var contents = element.contents();
            return contents.eq(contents.length - 1);
        }
    }

    /**
     * Remove last empty elements. This is done recursively until the last element contains a non-empty text node.
     *
     * @param {jQuery} element jQuery object containing a single element.
     * @return {boolean} true when elements have been removed, false otherwise.
     * @private
     */
    function removeLastEmptyElements(element) {
        if (element.contents().length) {

            // Get last child node.
            var contents = element.contents();
            var lastNode = contents.eq(contents.length - 1);

            // If last child node is a text node, check for emptiness.
            if (lastNode.filter(textNodeFilter).length) {
                var text = lastNode.get(0).nodeValue;
                text = $.trim(text);

                if (text == '') {
                    // If empty, remove the text node.
                    lastNode.remove();

                    return true;

                } else {
                    return false;
                }

            } else {
                // If the last child node is an element node, remove the last empty child nodes on that node.
                while (removeLastEmptyElements(lastNode)) {
                }

                // If the last child node contains no more child nodes, remove the last child node.
                if (lastNode.contents().length) {
                    return false;

                } else {
                    lastNode.remove();

                    return true;
                }
            }
        }   

        return false;
    }

    /**
     * Filter for testing on text nodes.
     *
     * @return {boolean} true when this node is a text node, false otherwise.
     * @this {Node}
     * @private
     */
    function textNodeFilter() {
        return this.nodeType === 3;
    }

    /**
     * Add target selector to hash of target selectors. If this is the first target selector added, start the live
     * updater.
     *
     * @param {string} targetSelector the target selector to run the live updater for.
     * @param {Object.<string, string>} settings the settings to apply on this target selector.
     * @private
     */
    function addToLiveUpdater(targetSelector, settings) {
        // Store target selector with its settings.
        liveUpdatingTargetSelectors[targetSelector] = settings;

        // If the live updater has not yet been started, start it now.
        if (!liveUpdaterIntervalId) {
            liveUpdaterIntervalId = window.setInterval(function() {
                doLiveUpdater();
            }, 200);
        }
    }

    /**
     * Remove the target selector from the hash of target selectors. It this is the last remaining target selector
     * being removed, stop the live updater.
     *
     * @param {string} targetSelector the target selector to stop running the live updater for.
     * @private
     */
    function removeFromLiveUpdater(targetSelector) {
        // If the hash contains the target selector, remove it.
        if (liveUpdatingTargetSelectors[targetSelector]) {
            delete liveUpdatingTargetSelectors[targetSelector];

            // If no more target selectors are in the hash, stop the live updater.
            if (!liveUpdatingTargetSelectors.length) {
                if (liveUpdaterIntervalId) {
                    window.clearInterval(liveUpdaterIntervalId);
                    liveUpdaterIntervalId = undefined;
                }
            }
        }
    };

    /**
     * Run the live updater. The live updater is periodically run to check if its monitored target selectors require
     * re-applying of the ellipsis.
     *
     * @private
     */
    function doLiveUpdater() {
        // If the live updater is already running, skip this time. We only want one instance running at a time.
        if (!liveUpdaterRunning) {
            liveUpdaterRunning = true;

            // Loop through target selectors.
            for (var targetSelector in liveUpdatingTargetSelectors) {
                $(targetSelector).each(function() {
                    var containerElement, containerData;

                    containerElement = $(this);
                    containerData = containerElement.data('jqae');

                    // If container element dimensions have changed, or the container element is new, run ellipsis on
                    // that container element.
                    if ((containerData.containerWidth != containerElement.width()) ||
                            (containerData.containerHeight != containerElement.height())) {
                        ellipsisOnElement(containerElement, liveUpdatingTargetSelectors[targetSelector]);
                    }
                });
            }

            liveUpdaterRunning = false;
        }
    };

})(jQuery);
/*!
 * jQuery UI date range picker widget
 * Copyright (c) 2015 Tamble, Inc.
 * Licensed under MIT (https://github.com/tamble/jquery-ui-daterangepicker/raw/master/LICENSE.txt)
 *
 * Depends:
 *   - jQuery 1.8.3+
 *   - jQuery UI 1.9.0+ (widget factory, position utility, button, menu, datepicker)
 *   - moment.js 2.3.0+
 */

/*************************************************************************************
 * INFOMAX CUSTOMIZED CLOSING BEHAVIOUR! BE AWARE WHEN UPDATING THIS LIBRARY.
 * (BCS #24035)
 ************************************************************************************/

/*************************************************************************************
 * INFOMAX CUSTOMIZED SELECTION/HOVER BEHAVIOUR! BE AWARE WHEN UPDATING THIS LIBRARY.
 * (BCS #33821)
 ************************************************************************************/

/*************************************************************************************
 * INFOMAX CUSTOMIZED onClear function "resetWhenArea" AND CUSTOMIZED BUTTON CLASSES!
 *  BE AWARE WHEN UPDATING THIS LIBRARY.
 * (BCS #54984)
 ************************************************************************************/

/*************************************************************************************
 * INFOMAX CUSTOMIZED Added custom heading bar with close icon (buildHeading)
 *  BE AWARE WHEN UPDATING THIS LIBRARY.
 * (BCS #55150)
 ************************************************************************************/

(function ($, window, undefined) {

  var uniqueId = 0; // used for unique ID generation within multiple plugin instances

  $.widget('comiseo.daterangepicker', {
    version: '0.4.2',

    options: {
      // presetRanges: array of objects; each object describes an item in the presets menu
      // and must have the properties: text, dateStart, dateEnd.
      // dateStart, dateEnd are functions returning a moment object
      presetRanges: [
        {
          text: 'Today', dateStart: function () {
          return moment()
        }, dateEnd: function () {
          return moment()
        }
        },
        {
          text: 'Yesterday', dateStart: function () {
          return moment().subtract('days', 1)
        }, dateEnd: function () {
          return moment().subtract('days', 1)
        }
        },
        {
          text: 'Last 7 Days', dateStart: function () {
          return moment().subtract('days', 6)
        }, dateEnd: function () {
          return moment()
        }
        },
        {
          text: 'Last Week (Mo-Su)', dateStart: function () {
          return moment().subtract('days', 7).isoWeekday(1)
        }, dateEnd: function () {
          return moment().subtract('days', 7).isoWeekday(7)
        }
        },
        {
          text: 'Month to Date', dateStart: function () {
          return moment().startOf('month')
        }, dateEnd: function () {
          return moment()
        }
        },
        {
          text: 'Previous Month', dateStart: function () {
          return moment().subtract('month', 1).startOf('month')
        }, dateEnd: function () {
          return moment().subtract('month', 1).endOf('month')
        }
        },
        {
          text: 'Year to Date', dateStart: function () {
          return moment().startOf('year')
        }, dateEnd: function () {
          return moment()
        }
        }
      ],
      verticalOffset: 0,
      initialText: 'Select date range...', // placeholder text - shown when nothing is selected
      icon: 'ui-icon-triangle-1-s',
      applyButtonText: 'Apply',
      clearButtonText: 'Clear',
      cancelButtonText: 'Cancel',
      rangeSplitter: ' - ', // string to use between dates
      dateFormat: 'M d, yy', // displayed date format. Available formats: http://api.jqueryui.com/datepicker/#utility-formatDate
      altFormat: 'yy-mm-dd', // submitted date format - inside JSON {"start":"...","end":"..."}
      mirrorOnCollision: false, // reverse layout when there is not enough space on the right
      applyOnMenuSelect: false, // auto apply menu selections
      autoFitCalendars: true, // override numberOfMonths option in order to fit widget width
      onOpen: null, // callback that executes when the dropdown opens
      onClose: null, // callback that executes when the dropdown closes
      onChange: null, // callback that executes when the date range changes
      datepickerOptions: { // object containing datepicker options. See http://api.jqueryui.com/datepicker/#options
        numberOfMonths: 3,
//				showCurrentAtPos: 1 // bug; use maxDate instead
        maxDate: 0 // the maximum selectable date is today (also current month is displayed on the last position)
      }
    },

    _create: function () {
      this._dateRangePicker = buildDateRangePicker(this.element, this.options);
    },

    _destroy: function () {
      this._dateRangePicker.destroy();
    },

    _setOptions: function (options) {
      this._super(options);
      this._dateRangePicker.enforceOptions();
    },

    open: function () {
      this._dateRangePicker.open();
    },

    close: function () {
      this._dateRangePicker.close();
    },

    setRange: function (range) {
      this._dateRangePicker.setRange(range);
    },

    getRange: function () {
      return this._dateRangePicker.getRange();
    },

    clearRange: function () {
      this._dateRangePicker.clearRange();
    },

    widget: function () {
      return this._dateRangePicker.getContainer();
    }
  });

  /**
   * factory for the trigger button (which visually replaces the original input form element)
   *
   * @param {jQuery} $originalElement jQuery object containing the input form element used to instantiate this widget instance
   * @param {String} classnameContext classname of the parent container
   * @param {Object} options
   */
  function buildTriggerButton($originalElement, classnameContext, options) {
    var $self, id;

    function fixReferences() {
      id = 'drp_autogen' + uniqueId++;
      $('label[for="' + $originalElement.attr('id') + '"]')
        .attr('for', id);
    }

    function init() {
      fixReferences();
      $self = $('<button type="button"></button>')
        .addClass(classnameContext + '-triggerbutton')
        .attr({'title': $originalElement.attr('title'), 'tabindex': $originalElement.attr('tabindex'), id: id})
        .button({
          icons: {
            secondary: options.icon
          },
          label: options.initialText
        });
    }

    function getLabel() {
      return $self.button('option', 'label');
    }

    function setLabel(value) {
      $self.button('option', 'label', value);
    }

    function reset() {
      $originalElement.val('').change();
      setLabel(options.initialText);
    }

    function enforceOptions() {
      $self.button('option', {
        icons: {
          secondary: options.icon
        },
        label: options.initialText
      });
    }

    init();
    return {
      getElement: function () {
        return $self;
      },
      getLabel: getLabel,
      setLabel: setLabel,
      reset: reset,
      enforceOptions: enforceOptions
    };
  }

  /**
   * factory for the presets menu (containing built-in date ranges)
   *
   * @param {String} classnameContext classname of the parent container
   * @param {Object} options
   * @param {Function} onClick callback that executes when a preset is clicked
   */
  function buildPresetsMenu(classnameContext, options, onClick) {
    var $self,
      $menu;

    function init() {
      $self = $('<div></div>')
        .addClass(classnameContext + '-presets');

      $menu = $('<ul></ul>');

      $.each(options.presetRanges, function () {
        $('<li><a href="#">' + this.text + '</a></li>')
          .data('dateStart', this.dateStart)
          .data('dateEnd', this.dateEnd)
          .click(onClick)
          .appendTo($menu);
      });

      $self.append($menu);

      $menu.menu()
        .data('ui-menu').delay = 0; // disable submenu delays
    }

    init();
    return {
      getElement: function () {
        return $self;
      }
    };
  }

  /**
   * factory for the multiple month date picker
   *
   * @param {String} classnameContext classname of the parent container
   * @param {Object} options
   */
  function buildCalendar(classnameContext, options) {
    var $self,
      range = {start: null, end: null}; // selected range

    function init() {
      $self = $('<div></div>', {'class': classnameContext + '-calendar ui-widget-content'});

      $self.datepicker($.extend({}, options.datepickerOptions, {
        beforeShowDay: beforeShowDay,
        onSelect: onSelectDay,
        onHover: onHoverDay,
        onUnhover: onUnhoverDay
      }));
      updateAtMidnight();
    }

    function enforceOptions() {
      $self.datepicker('option', $.extend({}, options.datepickerOptions, {
        beforeShowDay: beforeShowDay,
        onSelect: onSelectDay
      }));
    }

    // called when a day is selected
    function onSelectDay(dateText, instance) {
      var dateFormat = options.datepickerOptions.dateFormat || $.datepicker._defaults.dateFormat,
        selectedDate = $.datepicker.parseDate(dateFormat, dateText);

      if (!range.start || range.end) { // start not set, or both already set
        range.start = selectedDate;
        range.end = null;
      } else if (selectedDate < range.start) { // start set, but selected date is earlier
        range.end = range.start;
        range.start = selectedDate;
      } else {
        range.end = selectedDate;
      }
      if (options.datepickerOptions.hasOwnProperty('onSelect')) {
        options.datepickerOptions.onSelect();
      }
    }

    function onHoverDay(year, month, day) {
      var hoverDay = moment({
        year:year,
        month: month,
        day: day
      });

      jQuery('.ui-datepicker-calendar td', this).removeClass('ui-state-hover-range');

      if (range.start && !range.end) {
        jQuery('.ui-datepicker-calendar td:not(.ui-datepicker-unselectable)', this).each(function(idx, elem) {
          var currentDay = moment({
            year: +jQuery(elem).data('year'),
            month: +jQuery(elem).data('month'),
            day: +jQuery('a', elem).html()
          })

          if(currentDay.isBetween(range.start, hoverDay, 'day', '[]') ||
             currentDay.isBetween(hoverDay, range.start, 'day', '[]')) {
            jQuery(elem).addClass('ui-state-hover-range');
          }
        });
      }
    }

    function onUnhoverDay() {
      jQuery('.ui-datepicker-calendar td', this).removeClass('ui-state-hover-range');
    }

    // called for each day in the datepicker before it is displayed
    function beforeShowDay(date) {
      var resultClasses = [];
      if (range.start && ((+date === +range.start) || (range.end && range.start <= date && date <= range.end))) {
        resultClasses.push('ui-state-highlight');
      }
      if ((range.start && (+date === +range.start)) || (range.end && (+date === +range.end))) {
        resultClasses.push('ui-border-day');
      }

      var result = [
          true, // selectable
          resultClasses.join(' ')
        ],
        userResult = [true, ''];

      if (options.datepickerOptions.hasOwnProperty('beforeShowDay')) {
        userResult = options.datepickerOptions.beforeShowDay(date);
      }
      return [
        result[0] && userResult[0],
        result[1] + ' ' + userResult[1]
      ];
    }

    function updateAtMidnight() {
      setTimeout(function () {
        refresh();
        updateAtMidnight();
      }, moment().endOf('day') - moment());
    }

    function scrollToRangeStart() {
      if (range.start) {
        $self.datepicker('setDate', range.start);
      }
    }

    function refresh() {
      $self.datepicker('refresh');
      $self.datepicker('setDate', null); // clear the selected date
    }

    function reset() {
      range = {start: null, end: null};
      refresh();
    }

    init();
    return {
      getElement: function () {
        return $self;
      },
      scrollToRangeStart: function () {
        return scrollToRangeStart();
      },
      getRange: function () {
        return range;
      },
      setRange: function (value) {
        range = value;
        refresh();
      },
      refresh: refresh,
      reset: reset,
      enforceOptions: enforceOptions
    };
  }

  function buildHeading(classnameContext, options, handlers) {
    var $self,
      closeButton;

    function init() {
      $self = $('<div></div>')
        .addClass(classnameContext + '-heading');

      closeButton = $('<button type="button" class="ui-close icon-closer"></button>');

      $self.append(closeButton);

      bindEvents();
    }

    function bindEvents() {
      if (handlers) {
        closeButton.click(handlers.onClose);
      }
    }

    init();
    return {
      getElement: function () {
        return $self;
      }
    };
  }

  /**
   * factory for the button panel
   *
   * @param {String} classnameContext classname of the parent container
   * @param {Object} options
   * @param {Object} handlers contains callbacks for each button
   */
  function buildButtonPanel(classnameContext, options, handlers) {
    var $self,
      applyButton,
      clearButton,
      cancelButton;

    function init() {
      $self = $('<div></div>')
        .addClass(classnameContext + '-buttonpanel');

      if (options.applyButtonText) {
        applyButton = $('<button type="button" class="ui-priority-primary ui-button-apply"></button>')
          .text(options.applyButtonText)
          .button();

        $self.append(applyButton);
      }

      if (options.clearButtonText) {
        clearButton = $('<button type="button" class="ui-priority-secondary ui-button-clear"></button>')
          .text(options.clearButtonText)
          .button();

        $self.append(clearButton);
      }

      if (options.cancelButtonText) {
        cancelButton = $('<button type="button" class="ui-priority-secondary ui-button-cancel"></button>')
          .text(options.cancelButtonText)
          .button();

        $self.append(cancelButton);
      }

      bindEvents();
    }

    function enforceOptions() {
      if (applyButton) {
        applyButton.button('option', 'label', options.applyButtonText);
      }

      if (clearButton) {
        clearButton.button('option', 'label', options.clearButtonText);
      }

      if (cancelButton) {
        cancelButton.button('option', 'label', options.cancelButtonText);
      }
    }

    function bindEvents() {
      if (handlers) {
        if (applyButton) {
          applyButton.click(handlers.onApply);
        }

        if (clearButton) {
          clearButton.click(handlers.onClear);
        }

        if (cancelButton) {
          cancelButton.click(handlers.onCancel);
        }
      }
    }

    init();
    return {
      getElement: function () {
        return $self;
      },
      enforceOptions: enforceOptions
    };
  }

  /**
   * factory for the widget
   *
   * @param {jQuery} $originalElement jQuery object containing the input form element used to instantiate this widget instance
   * @param {Object} options
   */
  function buildDateRangePicker($originalElement, options) {
    var classname = 'comiseo-daterangepicker',
      $container, // the dropdown
      $mask, // ui helper (z-index fix)
      triggerButton,
      presetsMenu,
      calendar,
      buttonPanel,
      heading,
      isOpen = false,
      autoFitNeeded = false,
      LEFT = 0,
      RIGHT = 1,
      TOP = 2,
      BOTTOM = 3,
      sides = ['left', 'right', 'top', 'bottom'],
      hSide = RIGHT, // initialized to pick layout styles from CSS
      vSide = null;

    function init() {
      heading = buildHeading(classname, options, {
        onClose: function () {
          close();
        }
      });
      triggerButton = buildTriggerButton($originalElement, classname, options);
      presetsMenu = buildPresetsMenu(classname, options, usePreset);
      calendar = buildCalendar(classname, $.extend(true, options, {datepickerOptions: {onSelect: updateOriginalElement}}));
      autoFit.numberOfMonths = options.datepickerOptions.numberOfMonths; // save initial option!
      if (autoFit.numberOfMonths instanceof Array) { // not implemented
        options.autoFitCalendars = false;
      }
      buttonPanel = buildButtonPanel(classname, options, {
        onApply: function () {
          close();
          setRange();
        },
        onClear: function () {
          close();
          clearRange();
          resetWhenArea();
        },
        onCancel: function () {
          close();
          reset();
        }
      });
      render();
      autoFit();
      reset();
      bindEvents();
    }

    function render() {
      $container = $('<div></div>', {'class': classname + ' ' + classname + '-' + sides[hSide] + ' ui-widget ui-widget-content ui-corner-all ui-front'})
        .append(heading.getElement())
        .append($('<div></div>', {'class': classname + '-main ui-widget-content'})
          .append(presetsMenu.getElement())
          .append(calendar.getElement()))
        .append($('<div class="ui-helper-clearfix"></div>')
          .append(buttonPanel.getElement()))
        .hide();
      $originalElement.hide().after(triggerButton.getElement());
      $mask = $('<div></div>', {'class': 'ui-front ' + classname + '-mask'}).hide();
      $('body').append($mask).append($container);
    }

    // auto adjusts the number of months in the date picker
    function autoFit() {
      if (options.autoFitCalendars) {
        var maxWidth = $(window).width(),
          initialWidth = $container.outerWidth(true),
          $calendar = calendar.getElement(),
          numberOfMonths = $calendar.datepicker('option', 'numberOfMonths'),
          initialNumberOfMonths = numberOfMonths;

        if (initialWidth > maxWidth) {
          while (numberOfMonths > 1 && $container.outerWidth(true) > maxWidth) {
            $calendar.datepicker('option', 'numberOfMonths', --numberOfMonths);
          }
          if (numberOfMonths !== initialNumberOfMonths) {
            autoFit.monthWidth = (initialWidth - $container.outerWidth(true)) / (initialNumberOfMonths - numberOfMonths);
          }
        } else {
          while (numberOfMonths < autoFit.numberOfMonths && (maxWidth - $container.outerWidth(true)) >= autoFit.monthWidth) {
            $calendar.datepicker('option', 'numberOfMonths', ++numberOfMonths);
          }
        }
        reposition();
        autoFitNeeded = false;
      }
    }

    function destroy() {
      $container.remove();
      triggerButton.getElement().remove();
      $originalElement.show();
    }

    function bindEvents() {
      triggerButton.getElement().click(toggle);
      triggerButton.getElement().keydown(keyPressTriggerOpenOrClose);
      $mask.click(function () {
        close();
        setRange();
      });
      $(window).resize(function () {
        isOpen ? autoFit() : autoFitNeeded = true;
      });
    }

    function formatRangeForDisplay(range) {
      var dateFormat = options.dateFormat;
      return $.datepicker.formatDate(dateFormat, range.start) + (+range.end !== +range.start && range.end ? options.rangeSplitter + $.datepicker.formatDate(dateFormat, range.end) : '');
    }

    // formats a date range as JSON
    function formatRange(range) {
      var dateFormat = options.altFormat,
        formattedRange = {};
      formattedRange.start = $.datepicker.formatDate(dateFormat, range.start);
      formattedRange.end = $.datepicker.formatDate(dateFormat, range.end);
      return JSON.stringify(formattedRange);
    }

    // parses a date range in JSON format
    function parseRange(text) {
      var dateFormat = options.altFormat,
        range = null;
      if (text) {
        try {
          range = JSON.parse(text, function (key, value) {
            return key ? $.datepicker.parseDate(dateFormat, value) : value;
          });
        } catch (e) {
        }
      }
      return range;
    }

    function reset() {
      var range = getRange();
      if (range) {
        triggerButton.setLabel(formatRangeForDisplay(range));
        calendar.setRange(range);
      } else {
        calendar.reset();
      }
    }

    function setRange(value) {
      var range = value || calendar.getRange();
      if (!range.start) {
        return;
      }
      if (!range.end) {
        range.end = range.start;
      }
      value && calendar.setRange(range);
      triggerButton.setLabel(formatRangeForDisplay(range));
      $originalElement.val(formatRange(range)).change();
      if (options.onChange) {
        options.onChange();
      }
    }

    function updateOriginalElement() {
      var range = calendar.getRange();
      if (options.onChange) {
        options.onChange(range);
      }
      triggerButton.setLabel(formatRangeForDisplay(range));
    }

    function getRange() {
      return parseRange($originalElement.val());
    }

    function clearRange() {
      triggerButton.reset();
      calendar.reset();
      $originalElement.val('');
    }

    function resetWhenArea() {
      if(document.querySelector('.-IMXEVNT-contentForm__sliderArea')){
        document.querySelector('.-IMXEVNT-contentForm__sliderArea .noUi-origin').style.left = "0";
      }

      if(document.querySelector('.-IMXEVNT-contentForm__inputDate input[name^=dateFrom]')){
        document.querySelector('.-IMXEVNT-contentForm__inputDate input[name^=dateFrom]').value = "";
      }

      if(document.querySelector('.-IMXEVNT-contentForm__inputDate input[name^=dateTo]')) {
        document.querySelector('.-IMXEVNT-contentForm__inputDate input[name^=dateTo]').value = "";
      }

      if(document.querySelector('.-IMXEVNT-contentForm__inputDate__item.-IMXEVNT-contentForm__inputDate__item--active')) {
        document.querySelector('.-IMXEVNT-contentForm__inputDate__item.-IMXEVNT-contentForm__inputDate__item--active').classList.remove('-IMXEVNT-contentForm__inputDate__item--active');
      }
    }

    // callback - used when the user clicks a preset range
    function usePreset() {
      var $this = $(this),
        start = $this.data('dateStart')().startOf('day').toDate(),
        end = $this.data('dateEnd')().startOf('day').toDate();
      calendar.setRange({start: start, end: end});
      setRange();
      if (options.applyOnMenuSelect) {
        close();
      }
      return false;
    }

    // adjusts dropdown's position taking into account the available space
    function reposition() {
      $container.position({
        my: 'left top',
        at: 'left bottom' + (options.verticalOffset < 0 ? options.verticalOffset : '+' + options.verticalOffset),
        of: triggerButton.getElement(),
        collision: 'flipfit flipfit',
        using: function (coords, feedback) {
          var containerCenterX = feedback.element.left + feedback.element.width / 2,
            triggerButtonCenterX = feedback.target.left + feedback.target.width / 2,
            prevHSide = hSide,
            last,
            containerCenterY = feedback.element.top + feedback.element.height / 2,
            triggerButtonCenterY = feedback.target.top + feedback.target.height / 2,
            prevVSide = vSide,
            vFit; // is the container fit vertically

          hSide = (containerCenterX > triggerButtonCenterX) ? RIGHT : LEFT;
          if (hSide !== prevHSide) {
            if (options.mirrorOnCollision) {
              last = (hSide === LEFT) ? presetsMenu : calendar;
              $container.children().first().append(last.getElement());
            }
            $container.removeClass(classname + '-' + sides[prevHSide]);
            $container.addClass(classname + '-' + sides[hSide]);
          }
          $container.css({
            left: coords.left,
            top: coords.top
          });

          vSide = (containerCenterY > triggerButtonCenterY) ? BOTTOM : TOP;
          if (vSide !== prevVSide) {
            if (prevVSide !== null) {
              triggerButton.getElement().removeClass(classname + '-' + sides[prevVSide]);
            }
            triggerButton.getElement().addClass(classname + '-' + sides[vSide]);
          }
          vFit = vSide === BOTTOM && feedback.element.top - feedback.target.top !== feedback.target.height + options.verticalOffset
            || vSide === TOP && feedback.target.top - feedback.element.top !== feedback.element.height + options.verticalOffset;
          triggerButton.getElement().toggleClass(classname + '-vfit', vFit);
        }
      });
    }

    function killEvent(event) {
      event.preventDefault();
      event.stopPropagation();
    }

    function keyPressTriggerOpenOrClose(event) {
      switch (event.which) {
        case $.ui.keyCode.UP:
        case $.ui.keyCode.DOWN:
          killEvent(event);
          open();
          return;
        case $.ui.keyCode.ESCAPE:
          killEvent(event);
          close();
          return;
        case $.ui.keyCode.TAB:
          close();
          return;
      }
    }

    function open() {
      if (!isOpen) {
        triggerButton.getElement().addClass(classname + '-active');
        $mask.show();
        isOpen = true;
        autoFitNeeded && autoFit();
        calendar.scrollToRangeStart();
        $container.show();
        reposition();
      }
      if (options.onOpen) {
        options.onOpen();
      }
    }

    function close() {
      if (isOpen) {
        $container.hide();
        $mask.hide();
        triggerButton.getElement().removeClass(classname + '-active');
        isOpen = false;
      }
      if (options.onClose) {
        options.onClose();
      }
    }

    function toggle() {
      isOpen ? close() : open();
    }

    function getContainer() {
      return $container;
    }

    function enforceOptions() {
      var oldPresetsMenu = presetsMenu;
      presetsMenu = buildPresetsMenu(classname, options, usePreset);
      oldPresetsMenu.getElement().replaceWith(presetsMenu.getElement());
      calendar.enforceOptions();
      buttonPanel.enforceOptions();
      triggerButton.enforceOptions();
      var range = getRange();
      if (range) {
        triggerButton.setLabel(formatRangeForDisplay(range));
      }
    }

    init();
    return {
      toggle: toggle,
      destroy: destroy,
      open: open,
      close: close,
      setRange: setRange,
      getRange: getRange,
      clearRange: clearRange,
      reset: reset,
      enforceOptions: enforceOptions,
      getContainer: getContainer
    };
  }

})(jQuery, window);

/*!
 * 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.2,
      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));
/*! Hammer.JS - v2.0.7 - 2016-04-22
 * http://hammerjs.github.io/
 *
 * Copyright (c) 2016 Jorik Tangelder;
 * Licensed under the MIT license */
!function(a,b,c,d){"use strict";function e(a,b,c){return setTimeout(j(a,c),b)}function f(a,b,c){return Array.isArray(a)?(g(a,c[b],c),!0):!1}function g(a,b,c){var e;if(a)if(a.forEach)a.forEach(b,c);else if(a.length!==d)for(e=0;e<a.length;)b.call(c,a[e],e,a),e++;else for(e in a)a.hasOwnProperty(e)&&b.call(c,a[e],e,a)}function h(b,c,d){var e="DEPRECATED METHOD: "+c+"\n"+d+" AT \n";return function(){var c=new Error("get-stack-trace"),d=c&&c.stack?c.stack.replace(/^[^\(]+?[\n$]/gm,"").replace(/^\s+at\s+/gm,"").replace(/^Object.<anonymous>\s*\(/gm,"{anonymous}()@"):"Unknown Stack Trace",f=a.console&&(a.console.warn||a.console.log);return f&&f.call(a.console,e,d),b.apply(this,arguments)}}function i(a,b,c){var d,e=b.prototype;d=a.prototype=Object.create(e),d.constructor=a,d._super=e,c&&la(d,c)}function j(a,b){return function(){return a.apply(b,arguments)}}function k(a,b){return typeof a==oa?a.apply(b?b[0]||d:d,b):a}function l(a,b){return a===d?b:a}function m(a,b,c){g(q(b),function(b){a.addEventListener(b,c,!1)})}function n(a,b,c){g(q(b),function(b){a.removeEventListener(b,c,!1)})}function o(a,b){for(;a;){if(a==b)return!0;a=a.parentNode}return!1}function p(a,b){return a.indexOf(b)>-1}function q(a){return a.trim().split(/\s+/g)}function r(a,b,c){if(a.indexOf&&!c)return a.indexOf(b);for(var d=0;d<a.length;){if(c&&a[d][c]==b||!c&&a[d]===b)return d;d++}return-1}function s(a){return Array.prototype.slice.call(a,0)}function t(a,b,c){for(var d=[],e=[],f=0;f<a.length;){var g=b?a[f][b]:a[f];r(e,g)<0&&d.push(a[f]),e[f]=g,f++}return c&&(d=b?d.sort(function(a,c){return a[b]>c[b]}):d.sort()),d}function u(a,b){for(var c,e,f=b[0].toUpperCase()+b.slice(1),g=0;g<ma.length;){if(c=ma[g],e=c?c+f:b,e in a)return e;g++}return d}function v(){return ua++}function w(b){var c=b.ownerDocument||b;return c.defaultView||c.parentWindow||a}function x(a,b){var c=this;this.manager=a,this.callback=b,this.element=a.element,this.target=a.options.inputTarget,this.domHandler=function(b){k(a.options.enable,[a])&&c.handler(b)},this.init()}function y(a){var b,c=a.options.inputClass;return new(b=c?c:xa?M:ya?P:wa?R:L)(a,z)}function z(a,b,c){var d=c.pointers.length,e=c.changedPointers.length,f=b&Ea&&d-e===0,g=b&(Ga|Ha)&&d-e===0;c.isFirst=!!f,c.isFinal=!!g,f&&(a.session={}),c.eventType=b,A(a,c),a.emit("hammer.input",c),a.recognize(c),a.session.prevInput=c}function A(a,b){var c=a.session,d=b.pointers,e=d.length;c.firstInput||(c.firstInput=D(b)),e>1&&!c.firstMultiple?c.firstMultiple=D(b):1===e&&(c.firstMultiple=!1);var f=c.firstInput,g=c.firstMultiple,h=g?g.center:f.center,i=b.center=E(d);b.timeStamp=ra(),b.deltaTime=b.timeStamp-f.timeStamp,b.angle=I(h,i),b.distance=H(h,i),B(c,b),b.offsetDirection=G(b.deltaX,b.deltaY);var j=F(b.deltaTime,b.deltaX,b.deltaY);b.overallVelocityX=j.x,b.overallVelocityY=j.y,b.overallVelocity=qa(j.x)>qa(j.y)?j.x:j.y,b.scale=g?K(g.pointers,d):1,b.rotation=g?J(g.pointers,d):0,b.maxPointers=c.prevInput?b.pointers.length>c.prevInput.maxPointers?b.pointers.length:c.prevInput.maxPointers:b.pointers.length,C(c,b);var k=a.element;o(b.srcEvent.target,k)&&(k=b.srcEvent.target),b.target=k}function B(a,b){var c=b.center,d=a.offsetDelta||{},e=a.prevDelta||{},f=a.prevInput||{};b.eventType!==Ea&&f.eventType!==Ga||(e=a.prevDelta={x:f.deltaX||0,y:f.deltaY||0},d=a.offsetDelta={x:c.x,y:c.y}),b.deltaX=e.x+(c.x-d.x),b.deltaY=e.y+(c.y-d.y)}function C(a,b){var c,e,f,g,h=a.lastInterval||b,i=b.timeStamp-h.timeStamp;if(b.eventType!=Ha&&(i>Da||h.velocity===d)){var j=b.deltaX-h.deltaX,k=b.deltaY-h.deltaY,l=F(i,j,k);e=l.x,f=l.y,c=qa(l.x)>qa(l.y)?l.x:l.y,g=G(j,k),a.lastInterval=b}else c=h.velocity,e=h.velocityX,f=h.velocityY,g=h.direction;b.velocity=c,b.velocityX=e,b.velocityY=f,b.direction=g}function D(a){for(var b=[],c=0;c<a.pointers.length;)b[c]={clientX:pa(a.pointers[c].clientX),clientY:pa(a.pointers[c].clientY)},c++;return{timeStamp:ra(),pointers:b,center:E(b),deltaX:a.deltaX,deltaY:a.deltaY}}function E(a){var b=a.length;if(1===b)return{x:pa(a[0].clientX),y:pa(a[0].clientY)};for(var c=0,d=0,e=0;b>e;)c+=a[e].clientX,d+=a[e].clientY,e++;return{x:pa(c/b),y:pa(d/b)}}function F(a,b,c){return{x:b/a||0,y:c/a||0}}function G(a,b){return a===b?Ia:qa(a)>=qa(b)?0>a?Ja:Ka:0>b?La:Ma}function H(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return Math.sqrt(d*d+e*e)}function I(a,b,c){c||(c=Qa);var d=b[c[0]]-a[c[0]],e=b[c[1]]-a[c[1]];return 180*Math.atan2(e,d)/Math.PI}function J(a,b){return I(b[1],b[0],Ra)+I(a[1],a[0],Ra)}function K(a,b){return H(b[0],b[1],Ra)/H(a[0],a[1],Ra)}function L(){this.evEl=Ta,this.evWin=Ua,this.pressed=!1,x.apply(this,arguments)}function M(){this.evEl=Xa,this.evWin=Ya,x.apply(this,arguments),this.store=this.manager.session.pointerEvents=[]}function N(){this.evTarget=$a,this.evWin=_a,this.started=!1,x.apply(this,arguments)}function O(a,b){var c=s(a.touches),d=s(a.changedTouches);return b&(Ga|Ha)&&(c=t(c.concat(d),"identifier",!0)),[c,d]}function P(){this.evTarget=bb,this.targetIds={},x.apply(this,arguments)}function Q(a,b){var c=s(a.touches),d=this.targetIds;if(b&(Ea|Fa)&&1===c.length)return d[c[0].identifier]=!0,[c,c];var e,f,g=s(a.changedTouches),h=[],i=this.target;if(f=c.filter(function(a){return o(a.target,i)}),b===Ea)for(e=0;e<f.length;)d[f[e].identifier]=!0,e++;for(e=0;e<g.length;)d[g[e].identifier]&&h.push(g[e]),b&(Ga|Ha)&&delete d[g[e].identifier],e++;return h.length?[t(f.concat(h),"identifier",!0),h]:void 0}function R(){x.apply(this,arguments);var a=j(this.handler,this);this.touch=new P(this.manager,a),this.mouse=new L(this.manager,a),this.primaryTouch=null,this.lastTouches=[]}function S(a,b){a&Ea?(this.primaryTouch=b.changedPointers[0].identifier,T.call(this,b)):a&(Ga|Ha)&&T.call(this,b)}function T(a){var b=a.changedPointers[0];if(b.identifier===this.primaryTouch){var c={x:b.clientX,y:b.clientY};this.lastTouches.push(c);var d=this.lastTouches,e=function(){var a=d.indexOf(c);a>-1&&d.splice(a,1)};setTimeout(e,cb)}}function U(a){for(var b=a.srcEvent.clientX,c=a.srcEvent.clientY,d=0;d<this.lastTouches.length;d++){var e=this.lastTouches[d],f=Math.abs(b-e.x),g=Math.abs(c-e.y);if(db>=f&&db>=g)return!0}return!1}function V(a,b){this.manager=a,this.set(b)}function W(a){if(p(a,jb))return jb;var b=p(a,kb),c=p(a,lb);return b&&c?jb:b||c?b?kb:lb:p(a,ib)?ib:hb}function X(){if(!fb)return!1;var b={},c=a.CSS&&a.CSS.supports;return["auto","manipulation","pan-y","pan-x","pan-x pan-y","none"].forEach(function(d){b[d]=c?a.CSS.supports("touch-action",d):!0}),b}function Y(a){this.options=la({},this.defaults,a||{}),this.id=v(),this.manager=null,this.options.enable=l(this.options.enable,!0),this.state=nb,this.simultaneous={},this.requireFail=[]}function Z(a){return a&sb?"cancel":a&qb?"end":a&pb?"move":a&ob?"start":""}function $(a){return a==Ma?"down":a==La?"up":a==Ja?"left":a==Ka?"right":""}function _(a,b){var c=b.manager;return c?c.get(a):a}function aa(){Y.apply(this,arguments)}function ba(){aa.apply(this,arguments),this.pX=null,this.pY=null}function ca(){aa.apply(this,arguments)}function da(){Y.apply(this,arguments),this._timer=null,this._input=null}function ea(){aa.apply(this,arguments)}function fa(){aa.apply(this,arguments)}function ga(){Y.apply(this,arguments),this.pTime=!1,this.pCenter=!1,this._timer=null,this._input=null,this.count=0}function ha(a,b){return b=b||{},b.recognizers=l(b.recognizers,ha.defaults.preset),new ia(a,b)}function ia(a,b){this.options=la({},ha.defaults,b||{}),this.options.inputTarget=this.options.inputTarget||a,this.handlers={},this.session={},this.recognizers=[],this.oldCssProps={},this.element=a,this.input=y(this),this.touchAction=new V(this,this.options.touchAction),ja(this,!0),g(this.options.recognizers,function(a){var b=this.add(new a[0](a[1]));a[2]&&b.recognizeWith(a[2]),a[3]&&b.requireFailure(a[3])},this)}function ja(a,b){var c=a.element;if(c.style){var d;g(a.options.cssProps,function(e,f){d=u(c.style,f),b?(a.oldCssProps[d]=c.style[d],c.style[d]=e):c.style[d]=a.oldCssProps[d]||""}),b||(a.oldCssProps={})}}function ka(a,c){var d=b.createEvent("Event");d.initEvent(a,!0,!0),d.gesture=c,c.target.dispatchEvent(d)}var la,ma=["","webkit","Moz","MS","ms","o"],na=b.createElement("div"),oa="function",pa=Math.round,qa=Math.abs,ra=Date.now;la="function"!=typeof Object.assign?function(a){if(a===d||null===a)throw new TypeError("Cannot convert undefined or null to object");for(var b=Object(a),c=1;c<arguments.length;c++){var e=arguments[c];if(e!==d&&null!==e)for(var f in e)e.hasOwnProperty(f)&&(b[f]=e[f])}return b}:Object.assign;var sa=h(function(a,b,c){for(var e=Object.keys(b),f=0;f<e.length;)(!c||c&&a[e[f]]===d)&&(a[e[f]]=b[e[f]]),f++;return a},"extend","Use `assign`."),ta=h(function(a,b){return sa(a,b,!0)},"merge","Use `assign`."),ua=1,va=/mobile|tablet|ip(ad|hone|od)|android/i,wa="ontouchstart"in a,xa=u(a,"PointerEvent")!==d,ya=wa&&va.test(navigator.userAgent),za="touch",Aa="pen",Ba="mouse",Ca="kinect",Da=25,Ea=1,Fa=2,Ga=4,Ha=8,Ia=1,Ja=2,Ka=4,La=8,Ma=16,Na=Ja|Ka,Oa=La|Ma,Pa=Na|Oa,Qa=["x","y"],Ra=["clientX","clientY"];x.prototype={handler:function(){},init:function(){this.evEl&&m(this.element,this.evEl,this.domHandler),this.evTarget&&m(this.target,this.evTarget,this.domHandler),this.evWin&&m(w(this.element),this.evWin,this.domHandler)},destroy:function(){this.evEl&&n(this.element,this.evEl,this.domHandler),this.evTarget&&n(this.target,this.evTarget,this.domHandler),this.evWin&&n(w(this.element),this.evWin,this.domHandler)}};var Sa={mousedown:Ea,mousemove:Fa,mouseup:Ga},Ta="mousedown",Ua="mousemove mouseup";i(L,x,{handler:function(a){var b=Sa[a.type];b&Ea&&0===a.button&&(this.pressed=!0),b&Fa&&1!==a.which&&(b=Ga),this.pressed&&(b&Ga&&(this.pressed=!1),this.callback(this.manager,b,{pointers:[a],changedPointers:[a],pointerType:Ba,srcEvent:a}))}});var Va={pointerdown:Ea,pointermove:Fa,pointerup:Ga,pointercancel:Ha,pointerout:Ha},Wa={2:za,3:Aa,4:Ba,5:Ca},Xa="pointerdown",Ya="pointermove pointerup pointercancel";a.MSPointerEvent&&!a.PointerEvent&&(Xa="MSPointerDown",Ya="MSPointerMove MSPointerUp MSPointerCancel"),i(M,x,{handler:function(a){var b=this.store,c=!1,d=a.type.toLowerCase().replace("ms",""),e=Va[d],f=Wa[a.pointerType]||a.pointerType,g=f==za,h=r(b,a.pointerId,"pointerId");e&Ea&&(0===a.button||g)?0>h&&(b.push(a),h=b.length-1):e&(Ga|Ha)&&(c=!0),0>h||(b[h]=a,this.callback(this.manager,e,{pointers:b,changedPointers:[a],pointerType:f,srcEvent:a}),c&&b.splice(h,1))}});var Za={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},$a="touchstart",_a="touchstart touchmove touchend touchcancel";i(N,x,{handler:function(a){var b=Za[a.type];if(b===Ea&&(this.started=!0),this.started){var c=O.call(this,a,b);b&(Ga|Ha)&&c[0].length-c[1].length===0&&(this.started=!1),this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}}});var ab={touchstart:Ea,touchmove:Fa,touchend:Ga,touchcancel:Ha},bb="touchstart touchmove touchend touchcancel";i(P,x,{handler:function(a){var b=ab[a.type],c=Q.call(this,a,b);c&&this.callback(this.manager,b,{pointers:c[0],changedPointers:c[1],pointerType:za,srcEvent:a})}});var cb=2500,db=25;i(R,x,{handler:function(a,b,c){var d=c.pointerType==za,e=c.pointerType==Ba;if(!(e&&c.sourceCapabilities&&c.sourceCapabilities.firesTouchEvents)){if(d)S.call(this,b,c);else if(e&&U.call(this,c))return;this.callback(a,b,c)}},destroy:function(){this.touch.destroy(),this.mouse.destroy()}});var eb=u(na.style,"touchAction"),fb=eb!==d,gb="compute",hb="auto",ib="manipulation",jb="none",kb="pan-x",lb="pan-y",mb=X();V.prototype={set:function(a){a==gb&&(a=this.compute()),fb&&this.manager.element.style&&mb[a]&&(this.manager.element.style[eb]=a),this.actions=a.toLowerCase().trim()},update:function(){this.set(this.manager.options.touchAction)},compute:function(){var a=[];return g(this.manager.recognizers,function(b){k(b.options.enable,[b])&&(a=a.concat(b.getTouchAction()))}),W(a.join(" "))},preventDefaults:function(a){var b=a.srcEvent,c=a.offsetDirection;if(this.manager.session.prevented)return void b.preventDefault();var d=this.actions,e=p(d,jb)&&!mb[jb],f=p(d,lb)&&!mb[lb],g=p(d,kb)&&!mb[kb];if(e){var h=1===a.pointers.length,i=a.distance<2,j=a.deltaTime<250;if(h&&i&&j)return}return g&&f?void 0:e||f&&c&Na||g&&c&Oa?this.preventSrc(b):void 0},preventSrc:function(a){this.manager.session.prevented=!0,a.preventDefault()}};var nb=1,ob=2,pb=4,qb=8,rb=qb,sb=16,tb=32;Y.prototype={defaults:{},set:function(a){return la(this.options,a),this.manager&&this.manager.touchAction.update(),this},recognizeWith:function(a){if(f(a,"recognizeWith",this))return this;var b=this.simultaneous;return a=_(a,this),b[a.id]||(b[a.id]=a,a.recognizeWith(this)),this},dropRecognizeWith:function(a){return f(a,"dropRecognizeWith",this)?this:(a=_(a,this),delete this.simultaneous[a.id],this)},requireFailure:function(a){if(f(a,"requireFailure",this))return this;var b=this.requireFail;return a=_(a,this),-1===r(b,a)&&(b.push(a),a.requireFailure(this)),this},dropRequireFailure:function(a){if(f(a,"dropRequireFailure",this))return this;a=_(a,this);var b=r(this.requireFail,a);return b>-1&&this.requireFail.splice(b,1),this},hasRequireFailures:function(){return this.requireFail.length>0},canRecognizeWith:function(a){return!!this.simultaneous[a.id]},emit:function(a){function b(b){c.manager.emit(b,a)}var c=this,d=this.state;qb>d&&b(c.options.event+Z(d)),b(c.options.event),a.additionalEvent&&b(a.additionalEvent),d>=qb&&b(c.options.event+Z(d))},tryEmit:function(a){return this.canEmit()?this.emit(a):void(this.state=tb)},canEmit:function(){for(var a=0;a<this.requireFail.length;){if(!(this.requireFail[a].state&(tb|nb)))return!1;a++}return!0},recognize:function(a){var b=la({},a);return k(this.options.enable,[this,b])?(this.state&(rb|sb|tb)&&(this.state=nb),this.state=this.process(b),void(this.state&(ob|pb|qb|sb)&&this.tryEmit(b))):(this.reset(),void(this.state=tb))},process:function(a){},getTouchAction:function(){},reset:function(){}},i(aa,Y,{defaults:{pointers:1},attrTest:function(a){var b=this.options.pointers;return 0===b||a.pointers.length===b},process:function(a){var b=this.state,c=a.eventType,d=b&(ob|pb),e=this.attrTest(a);return d&&(c&Ha||!e)?b|sb:d||e?c&Ga?b|qb:b&ob?b|pb:ob:tb}}),i(ba,aa,{defaults:{event:"pan",threshold:10,pointers:1,direction:Pa},getTouchAction:function(){var a=this.options.direction,b=[];return a&Na&&b.push(lb),a&Oa&&b.push(kb),b},directionTest:function(a){var b=this.options,c=!0,d=a.distance,e=a.direction,f=a.deltaX,g=a.deltaY;return e&b.direction||(b.direction&Na?(e=0===f?Ia:0>f?Ja:Ka,c=f!=this.pX,d=Math.abs(a.deltaX)):(e=0===g?Ia:0>g?La:Ma,c=g!=this.pY,d=Math.abs(a.deltaY))),a.direction=e,c&&d>b.threshold&&e&b.direction},attrTest:function(a){return aa.prototype.attrTest.call(this,a)&&(this.state&ob||!(this.state&ob)&&this.directionTest(a))},emit:function(a){this.pX=a.deltaX,this.pY=a.deltaY;var b=$(a.direction);b&&(a.additionalEvent=this.options.event+b),this._super.emit.call(this,a)}}),i(ca,aa,{defaults:{event:"pinch",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.scale-1)>this.options.threshold||this.state&ob)},emit:function(a){if(1!==a.scale){var b=a.scale<1?"in":"out";a.additionalEvent=this.options.event+b}this._super.emit.call(this,a)}}),i(da,Y,{defaults:{event:"press",pointers:1,time:251,threshold:9},getTouchAction:function(){return[hb]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime>b.time;if(this._input=a,!d||!c||a.eventType&(Ga|Ha)&&!f)this.reset();else if(a.eventType&Ea)this.reset(),this._timer=e(function(){this.state=rb,this.tryEmit()},b.time,this);else if(a.eventType&Ga)return rb;return tb},reset:function(){clearTimeout(this._timer)},emit:function(a){this.state===rb&&(a&&a.eventType&Ga?this.manager.emit(this.options.event+"up",a):(this._input.timeStamp=ra(),this.manager.emit(this.options.event,this._input)))}}),i(ea,aa,{defaults:{event:"rotate",threshold:0,pointers:2},getTouchAction:function(){return[jb]},attrTest:function(a){return this._super.attrTest.call(this,a)&&(Math.abs(a.rotation)>this.options.threshold||this.state&ob)}}),i(fa,aa,{defaults:{event:"swipe",threshold:10,velocity:.3,direction:Na|Oa,pointers:1},getTouchAction:function(){return ba.prototype.getTouchAction.call(this)},attrTest:function(a){var b,c=this.options.direction;return c&(Na|Oa)?b=a.overallVelocity:c&Na?b=a.overallVelocityX:c&Oa&&(b=a.overallVelocityY),this._super.attrTest.call(this,a)&&c&a.offsetDirection&&a.distance>this.options.threshold&&a.maxPointers==this.options.pointers&&qa(b)>this.options.velocity&&a.eventType&Ga},emit:function(a){var b=$(a.offsetDirection);b&&this.manager.emit(this.options.event+b,a),this.manager.emit(this.options.event,a)}}),i(ga,Y,{defaults:{event:"tap",pointers:1,taps:1,interval:300,time:250,threshold:9,posThreshold:10},getTouchAction:function(){return[ib]},process:function(a){var b=this.options,c=a.pointers.length===b.pointers,d=a.distance<b.threshold,f=a.deltaTime<b.time;if(this.reset(),a.eventType&Ea&&0===this.count)return this.failTimeout();if(d&&f&&c){if(a.eventType!=Ga)return this.failTimeout();var g=this.pTime?a.timeStamp-this.pTime<b.interval:!0,h=!this.pCenter||H(this.pCenter,a.center)<b.posThreshold;this.pTime=a.timeStamp,this.pCenter=a.center,h&&g?this.count+=1:this.count=1,this._input=a;var i=this.count%b.taps;if(0===i)return this.hasRequireFailures()?(this._timer=e(function(){this.state=rb,this.tryEmit()},b.interval,this),ob):rb}return tb},failTimeout:function(){return this._timer=e(function(){this.state=tb},this.options.interval,this),tb},reset:function(){clearTimeout(this._timer)},emit:function(){this.state==rb&&(this._input.tapCount=this.count,this.manager.emit(this.options.event,this._input))}}),ha.VERSION="2.0.7",ha.defaults={domEvents:!1,touchAction:gb,enable:!0,inputTarget:null,inputClass:null,preset:[[ea,{enable:!1}],[ca,{enable:!1},["rotate"]],[fa,{direction:Na}],[ba,{direction:Na},["swipe"]],[ga],[ga,{event:"doubletap",taps:2},["tap"]],[da]],cssProps:{userSelect:"none",touchSelect:"none",touchCallout:"none",contentZooming:"none",userDrag:"none",tapHighlightColor:"rgba(0,0,0,0)"}};var ub=1,vb=2;ia.prototype={set:function(a){return la(this.options,a),a.touchAction&&this.touchAction.update(),a.inputTarget&&(this.input.destroy(),this.input.target=a.inputTarget,this.input.init()),this},stop:function(a){this.session.stopped=a?vb:ub},recognize:function(a){var b=this.session;if(!b.stopped){this.touchAction.preventDefaults(a);var c,d=this.recognizers,e=b.curRecognizer;(!e||e&&e.state&rb)&&(e=b.curRecognizer=null);for(var f=0;f<d.length;)c=d[f],b.stopped===vb||e&&c!=e&&!c.canRecognizeWith(e)?c.reset():c.recognize(a),!e&&c.state&(ob|pb|qb)&&(e=b.curRecognizer=c),f++}},get:function(a){if(a instanceof Y)return a;for(var b=this.recognizers,c=0;c<b.length;c++)if(b[c].options.event==a)return b[c];return null},add:function(a){if(f(a,"add",this))return this;var b=this.get(a.options.event);return b&&this.remove(b),this.recognizers.push(a),a.manager=this,this.touchAction.update(),a},remove:function(a){if(f(a,"remove",this))return this;if(a=this.get(a)){var b=this.recognizers,c=r(b,a);-1!==c&&(b.splice(c,1),this.touchAction.update())}return this},on:function(a,b){if(a!==d&&b!==d){var c=this.handlers;return g(q(a),function(a){c[a]=c[a]||[],c[a].push(b)}),this}},off:function(a,b){if(a!==d){var c=this.handlers;return g(q(a),function(a){b?c[a]&&c[a].splice(r(c[a],b),1):delete c[a]}),this}},emit:function(a,b){this.options.domEvents&&ka(a,b);var c=this.handlers[a]&&this.handlers[a].slice();if(c&&c.length){b.type=a,b.preventDefault=function(){b.srcEvent.preventDefault()};for(var d=0;d<c.length;)c[d](b),d++}},destroy:function(){this.element&&ja(this,!1),this.handlers={},this.session={},this.input.destroy(),this.element=null}},la(ha,{INPUT_START:Ea,INPUT_MOVE:Fa,INPUT_END:Ga,INPUT_CANCEL:Ha,STATE_POSSIBLE:nb,STATE_BEGAN:ob,STATE_CHANGED:pb,STATE_ENDED:qb,STATE_RECOGNIZED:rb,STATE_CANCELLED:sb,STATE_FAILED:tb,DIRECTION_NONE:Ia,DIRECTION_LEFT:Ja,DIRECTION_RIGHT:Ka,DIRECTION_UP:La,DIRECTION_DOWN:Ma,DIRECTION_HORIZONTAL:Na,DIRECTION_VERTICAL:Oa,DIRECTION_ALL:Pa,Manager:ia,Input:x,TouchAction:V,TouchInput:P,MouseInput:L,PointerEventInput:M,TouchMouseInput:R,SingleTouchInput:N,Recognizer:Y,AttrRecognizer:aa,Tap:ga,Pan:ba,Swipe:fa,Pinch:ca,Rotate:ea,Press:da,on:m,off:n,each:g,merge:ta,extend:sa,assign:la,inherit:i,bindFn:j,prefixed:u});var wb="undefined"!=typeof a?a:"undefined"!=typeof self?self:{};wb.Hammer=ha,"function"==typeof define&&define.amd?define(function(){return ha}):"undefined"!=typeof module&&module.exports?module.exports=ha:a[c]=ha}(window,document,"Hammer");
//# sourceMappingURL=hammer.min.js.map
var CSS3Slider_Config = CSS3Slider_Config || {};
var CSS3Slider_Dom = CSS3Slider_Dom || {};
var CSS3Slider_SlidePosition = CSS3Slider_SlidePosition || {};
var CSS3Slider_SlideDirection = CSS3Slider_SlideDirection || {};

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    CSS3Slider_Config = require('./CSS3Slider.Config.js');
    CSS3Slider_Dom = require('./CSS3Slider.Dom.js');
    CSS3Slider_SlidePosition = require('./CSS3Slider.SlidePosition.js');
    CSS3Slider_SlideDirection = require('./CSS3Slider.SlideDirection.js');
    
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider = factory;
  }
})(this, CSS3Slider);


/**
 * provides easy to use horizontal sliders
 * 
 * @param {htmlNode} slideTargetNode
 * @param {object} baseConfig
 * @returns {CSS3Slider}
 */
function CSS3Slider (slideTargetNode, baseConfig) {
  
  this._Config = null;
  this._Dom = null;
  this._SlidePosition = null;
  this._SlideDirection = null;
  
  this._slideTargetNode = null;
  
  this.__allowAnimation = false;
  
  /**
   * init tasks
   * 
   * @param {htmlNode} slideTargetNode
   * @param {object} baseConfig
   * @returns {void}
   */
  this.__construct = function (slideTargetNode, baseConfig) {
    this.__setSlideTargetNode(slideTargetNode);
    
    this._Config = new CSS3Slider_Config(this, baseConfig);
    this._Dom = new CSS3Slider_Dom(this);
    this._SlidePosition = new CSS3Slider_SlidePosition(this);
    this._SlideDirection = new CSS3Slider_SlideDirection(this);
  };
  
  /**
   * @param {htmlNode} slideTargetNode
   * @returns {void}
   */
  this.__setSlideTargetNode = function (slideTargetNode) {
    this._slideTargetNode = slideTargetNode;
  };
  
  /**
   * @returns {htmlNode}
   */
  this.getSlideTargetNode = function () {
    return this._slideTargetNode;
  };
  
  /**
   * set allowAnimation flag to true
   * 
   * @returns {void}
   */
  this._allowAnimation = function () {
    this.__allowAnimation = true;
  };
  
  /**
   * set allowAnimation flag to false
   * 
   * @returns {Boolean}
   */
  this._forbidAnimation = function () {
    this.__allowAnimation = false;
  };
  
  /**
   * @returns {Boolean}
   */
  this.isAnimationAllowed = function () {
    return this.__allowAnimation;
  };
  
  
  /**
   * external access point to update the config of the CSS3Slider
   * 
   * @param {object} baseConfig
   * @returns {void}
   */
  this.updateBaseConfig = function (baseConfig) {
    this._Config.updateBaseConfig(baseConfig);
  };
  
  
  /**
   * reactivate sleepint slider
   * 
   * @returns {void}
   */
  this.reactivate = function () {
    this._Config.updateBaseConfig();
  };
  
  /**
   * set slider to sleep mode
   * 
   * @returns {void}
   */
  this.deactivate = function () {
    this._Dom.resetSlideTargetNode();
  };
  
  
  /**
   * external access point for simple slide to left
   * 
   * @returns {CSS3Slider@pro;_SlideDirection@call;directionSlide|object}
   */
  this.slideLeft = function () {
    if(this.isAnimationAllowed()){
      return this._SlideDirection.directionSlide('left');
    }
  };
  
  /**
   * external access point for simple slide to right
   * 
   * @returns {CSS3Slider@pro;_SlideDirection@call;directionSlide|object}
   */
  this.slideRight = function () {
    if(this.isAnimationAllowed()){
      return this._SlideDirection.directionSlide('right');
    }
  };
  
  /**
   * external access point for a slide to a specific position
   * 
   * @param {Number} position
   * @returns {CSS3Slider@pro;_SlidePosition@call;positionSlide|object}
   */
  this.slideTo = function (position) {
    if(this.isAnimationAllowed()){
      return this._SlidePosition.positionSlide(position);
    }
  };
  
  
  /**
   * returns the runtime config of the config object
   * 
   * @returns {CSS3Slider@pro;_Config@call;getRuntimeConfig|object}
   */
  this.getRuntimeConfig = function () {
    return this._Config.getRuntimeConfig();
  };
  
  
  /**
   * checks count of elements in a specific direction from the current position
   * 
   * @param {String} direction
   * @returns {runtimeConfig.slideChildrenVisible|Number|runtimeConfig.slidePosition|runtimeConfig.slideChildrenCount}
   */
  this.slidesAvailable = function (direction) {
    // get the config objects
    var runtimeConfig = this._Config.getRuntimeConfig();
    var baseConfig = this._Config._getBaseConfig();
    
    // get the current active slider child node
    var currentPosition = runtimeConfig.slidePosition;
    // Hack for damn IE -> default value can be 'auto'
    if (!currentPosition) { currentPosition = 0; }

    var slidesAvailable = 0;
    
    // calculate how many slider steps are available
    if (direction === 'right') {
      slidesAvailable = runtimeConfig.slideChildrenCount - currentPosition - runtimeConfig.slideChildrenVisible + runtimeConfig.slideOverflowCount;

    } else if (direction === 'left') {
      slidesAvailable = currentPosition;
    }
    
    // add the clone count if continious slide is active
    if (baseConfig.cloneMode && baseConfig.continiousSlide) {
      slidesAvailable += runtimeConfig.slideClonesCount;
    }

    return slidesAvailable;
  };
  
  
  this.__construct (slideTargetNode, baseConfig);
}

var imxQuery = imxQuery || {};

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    imxQuery = require('imxquery');
    
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider_Config = factory;
  }
})(this, CSS3Slider_Config);


/**
 * the configuration of the CSS3Slider
 * 
 * @param {CSS3Slider} CSS3Slider
 * @param {object} baseConfig
 * @returns {CSS3Slider_Config}
 */
function CSS3Slider_Config (CSS3Slider, baseConfig) {
  
  /**
   * fallback for baseConfig
   */
  this.__defaultBaseConfig = {
    maxSteps : 1,               // how many elements in the slider should one direction slide step skip
    singleStep : 100,           // slide width in percent of the width of a single slide step
    forceSingleElement : false, // better ignore this - can be used to force the slider only to show one element
    cloneMode : false,          // set to true to add clones for endless slider visuals
    continiousSlide : false,    // set to true to create an endless slider
    overflowAllowed: false,     // set to true to allow to slide the last element to the first visible position.
    calcMethod : 'floor'
  };
  
  this.__CSS3Slider = null;
  
  /**
   * contains all user given config input
   */
  this.__baseConfig = null;
  /**
   * contains calculated values
   */
  this.__runtimeConfig = null;
  
  /**
   * init tasks
   * 
   * @param {CSS3Slider} CSS3Slider
   * @param {object} baseConfig
   * @returns {void}
   */
  this.__construct = function (CSS3Slider, baseConfig) {
    this.__CSS3Slider = CSS3Slider;
    
    if (baseConfig === undefined) { baseConfig = []; }
    this._setBaseConfig(imxQuery.extendObject(baseConfig, this.__defaultBaseConfig));
    
    this._createRuntimeConfig();
  };
  
  /**
   * @param {object} baseConfig
   * @returns {void}
   */
  this._setBaseConfig = function (baseConfig) {
    this.__baseConfig = baseConfig;
  };
  
  /**
   * @returns {object}
   */
  this._getBaseConfig = function () {
    return this.__baseConfig;
  };
  
  /**
   * @param {object} runtimeConfig
   * @returns {CSS3Slider_Config@call;getRuntimeConfig|object}
   */
  this._setRuntimeConfig = function (runtimeConfig) {
    this.__runtimeConfig = runtimeConfig;
    return this.getRuntimeConfig();
  };
  
  /**
   * @returns {object}
   */
  this.getRuntimeConfig = function () {
    return this.__runtimeConfig;
  };
  
  
  /**
   * update the config, for example after a screen resize
   * 
   * @param {object} baseConfig
   * @returns {void}
   */
  this.updateBaseConfig = function (baseConfig) {
    // set the single step to the default value of 100
    this.__baseConfig.singleStep = 100;
    
    if (baseConfig !== undefined) {
      this._setBaseConfig(imxQuery.extendObject(baseConfig, this.__defaultBaseConfig));
    }
    
    this.__CSS3Slider._Dom.resetSlideTargetNode();
    
    // create a new clean runtime config
    this._createRuntimeConfig();
    
    this.__CSS3Slider._Dom.prepareSlideTarget();
    this.__CSS3Slider.slideTo(this.getRuntimeConfig().slidePosition);
  };
  
  
  /**
   * creates the runtime config
   * 
   * @returns {object|CSS3Slider_Config@call;getRuntimeConfig|object}
   */
  this._createRuntimeConfig = function () {
    var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
    
    // look up how many childnodes without clones are present
    var cloneChildrenCount = slideTargetNode.querySelectorAll('.-css3Slider-prepander').length * 2;
    var slideChildrenCount = slideTargetNode.childElementCount - cloneChildrenCount;

    // calculate how many slider nodes are visible at once
    var slideChildrenVisible = this._getChildrenVisible();
    var slideOverflowCount = this._getBaseConfig().overflowAllowed ? slideChildrenVisible - 1 : 0;

    // calculate how many clones are needed
    var slideClonesCount = 0;
    if (this._getBaseConfig().cloneMode) {

      slideClonesCount = this.__baseConfig.maxSteps + Math.floor((slideChildrenVisible - 1) / 2);
      if (slideClonesCount > slideChildrenVisible) {
        slideClonesCount = slideChildrenVisible;
      }
      if (slideClonesCount > slideChildrenCount) {
        slideClonesCount = slideChildrenCount;
      }
    }

    // calculate the movement for one single sliding attempt
    this.__baseConfig.singleStep = this.__baseConfig.singleStep / slideChildrenVisible;
    
    // general global check if animation is allowed
    if(slideChildrenCount <= slideChildrenVisible){
      this.__CSS3Slider._forbidAnimation();
    }else{
      this.__CSS3Slider._allowAnimation();
    }
        
    var slidePosition = (this.getRuntimeConfig() !== null) ? this.getRuntimeConfig().slidePosition : 0;
    
    return this._setRuntimeConfig({
      slidePosition : slidePosition,                // the current first visible element in the row
      slideValue : 0,                               // the offset of the row in percent
      slideChildrenCount : slideChildrenCount,      // how many non clone elements are in the slider
      slideChildrenVisible : slideChildrenVisible,  // how many elements are visible at once in the slider
      slideOverflowCount : slideOverflowCount,      // how many overflow steps are possible
      slideClonesCount : slideClonesCount           // how many clones are needed
    });
  };
  
  this._getChildrenVisible = function(){
    var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
    
    // the width of the container that holds the row
    var computedStyle = window.getComputedStyle(slideTargetNode.parentNode);
    var canvasWidth = parseInt(computedStyle.getPropertyValue('width'));
    
    var canvasWidth = slideTargetNode.parentNode.offsetWidth;
    
    var slideChildrenVisible = 1;
    
    // calculate how many slider nodes are visible at once
    if (!this._getBaseConfig().forceSingleElement) {
      
      var calcMethod = this.__baseConfig.calcMethod;
      var singleElementWidthInPx = this._getSingleElementWidthInPx();
      
      if(calcMethod == 'ceil'){
        slideChildrenVisible = Math.ceil(canvasWidth / singleElementWidthInPx);
        
      }else if(calcMethod == 'round'){
        slideChildrenVisible = Math.round(canvasWidth / singleElementWidthInPx);
        
      }else{
        slideChildrenVisible = Math.floor(canvasWidth / singleElementWidthInPx);
      }
    }
    
    return slideChildrenVisible;
  };
  
  
  /**
   * calculate the original widht of a single slider element in pixel
   * 
   * @returns {Number|CSS3Slider_Config._getSingleElementWidthInPx.width}
   */
  this._getSingleElementWidthInPx = function () {
    var baseObject = this.__CSS3Slider.getSlideTargetNode().children[0];
    var computedStyle = window.getComputedStyle(baseObject);

    var width = parseInt(computedStyle.getPropertyValue('width'));

    var totalWidth = width + this._getSingleElementMarginInPx();

    return totalWidth;
  };
  
  /**
   * calculate the percentage width of a single slider element
   * 
   * @returns {Number|CSS3Slider_Config.getRuntimeConfig.slideChildrenCount}
   */
  this._getSingleElementWidthInPercent = function () {
    return 100 / this.getRuntimeConfig().slideChildrenCount;
  };
  
  this._getSingleElementMarginInPx = function () {
    var baseObject = this.__CSS3Slider.getSlideTargetNode().children[0];
    var computedStyle = window.getComputedStyle(baseObject);
    
    var marginLeft = parseInt(computedStyle.getPropertyValue('margin-left')) || 0;
    var marginRight = parseInt(computedStyle.getPropertyValue('margin-right')) || 0;
    var margin = marginLeft + marginRight;
    
    return marginLeft + marginRight;
  };
  
  
  this.__construct (CSS3Slider, baseConfig);
}

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider_Dom_Clone = factory;
  }
})(this, CSS3Slider_Dom_Clone);


/**
 * handles clone nodes for endless slide effect
 * 
 * @param {CSS3Slider} CSS3Slider
 * @returns {CSS3Slider_Dom_Clone}
 */
function CSS3Slider_Dom_Clone (CSS3Slider) {
  
  this.__CSS3Slider = null;
  
  /**
   * init tasks
   * 
   * @param {CSS3Slider} CSS3Slider
   * @returns {void}
   */
  this.__construct = function (CSS3Slider) {
    this.__CSS3Slider = CSS3Slider;
    
    var cloneMode = this.__CSS3Slider._Config._getBaseConfig().cloneMode;
    
    // set slider positioning to relative - to be able to absolute position clones
    if (cloneMode) {
      this.__CSS3Slider.getSlideTargetNode().style.position = 'relative';
    }
  };
  
  
  /**
   * will add clone nodes before the first slider node and after the last slider node
   * 
   * @returns {void}
   */
  this._addClones = function () {
    var runtimeConfig = this.__CSS3Slider._Config.getRuntimeConfig();
    var singleElementWidth = this.__CSS3Slider._Config._getSingleElementWidthInPercent();
    var singleElementMargin = this.__CSS3Slider._Config._getSingleElementMarginInPx();
    var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
    
    // store all child nodes in an array cause nodeCollections are updated
    var originalChildNodeArray = [];
    for (var childNodeIndex = 0; childNodeIndex < runtimeConfig.slideChildrenCount; childNodeIndex++) {
      originalChildNodeArray.push(slideTargetNode.children[childNodeIndex]);
    }
    
    // add so much clones as the config states are needed
    for (var i = 0; i < runtimeConfig.slideClonesCount; i++) {
      this.__addSingleClone(slideTargetNode, originalChildNodeArray, i, 'prepander', singleElementWidth, singleElementMargin);
      this.__addSingleClone(slideTargetNode, originalChildNodeArray, i, 'apander', singleElementWidth, singleElementMargin);
    }
  };
  
  /**
   * adds a single clone to the slider
   * 
   * @param {object} slideTargetNode
   * @param {Array} originalChildNodeArray
   * @param {Number} index
   * @param {String} type
   * @param {Number} singleElementWidth
   * @returns {void}
   */
  this.__addSingleClone = function (slideTargetNode, originalChildNodeArray, index, type, singleElementWidth, singleElementMargin) {
    
    var nodeForCloningIndex = null;
    
    // get the index of the child node that we want to clone
    if (type === 'prepander') {
      nodeForCloningIndex = originalChildNodeArray.length - 1 - index;
    } else if (type === 'apander') {
      nodeForCloningIndex = index;
    }
    // get the actual child node we want to clone
    var nodeForCloning = originalChildNodeArray[nodeForCloningIndex];
    
    // create the clone
    var cloneNode = nodeForCloning.cloneNode(true);
    cloneNode.classList.add('-css3Slider-' + type);
    cloneNode.style.position = 'absolute';
    cloneNode.style.top = '0%';
    cloneNode.style.right = '100%';
    
    if(singleElementMargin){
      cloneNode.style.width = 'calc(' + singleElementWidth + '% - '+ singleElementMargin +'px)';
    }else{
      cloneNode.style.width = singleElementWidth + '%';
    }
    
    if (type === 'prepander') {
      // prepander will be positioned in front
      cloneNode.style.right = 100 + singleElementWidth * index + '%';
      slideTargetNode.insertBefore(cloneNode, slideTargetNode.children[0]);
      
    } else if (type === 'apander') {
      // apander will be positioned at the end
      cloneNode.style.left = 100 + singleElementWidth * index + '%';
      slideTargetNode.appendChild(cloneNode);
      
    }
  };
  
  
  /**
   * will return all clone nodes from slider
   * 
   * @returns {void}
   */
  this._removeClones = function () {
    var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
    
    // get all prepander
    var prepanderCollection = slideTargetNode.getElementsByClassName('-css3Slider-prepander');
    var prepanderLength = prepanderCollection.length;
    
    // get all apander
    var apenderCollection = slideTargetNode.getElementsByClassName('-css3Slider-apander');
    var apenderLength = apenderCollection.length;
    
    // remove all prepander
    for (var prepanderIndex = 0; prepanderIndex < prepanderLength; prepanderIndex++) {
      slideTargetNode.removeChild(prepanderCollection[0]); // allways use index 0 due to updating nodeCollections
    }
    
    // remove all apander
    for (var apenderIndex = 0; apenderIndex < apenderLength; apenderIndex++) {
      slideTargetNode.removeChild(apenderCollection[0]); // allways use index 0 due to updating nodeCollections
    }
  };
  
  
  this.__construct (CSS3Slider);
}
var CSS3Slider_Dom_Clone = CSS3Slider_Dom_Clone || {};

(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    CSS3Slider_Dom_Clone = require('./CSS3Slider.Dom.Clones.js');
    
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider_Dom = factory;
  }
})(this, CSS3Slider_Dom);


/**
 * handle the dom manipulations
 * 
 * @param {CSS3Slider} CSS3Slider
 * @returns {CSS3Slider_Dom}
 */
function CSS3Slider_Dom (CSS3Slider) {
  
  this.__CSS3Slider = null;
  this.__Clone = null;
  
  /**
   * init tasks
   * 
   * @param {CSS3Slider} CSS3Slider
   * @returns {void}
   */
  this.__construct = function (CSS3Slider) {
    this.__CSS3Slider = CSS3Slider;
    this.__Clone = new CSS3Slider_Dom_Clone(CSS3Slider);
    
    this.resetSlideTargetNode();
    this.prepareSlideTarget();
  };
  
  
  /**
   * reset the dom to the initial state (remove all inline stylings)
   * 
   * @returns {void}
   */
  this.resetSlideTargetNode = function () {
    var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
    var slideNodeChildren = slideTargetNode.children;
    
    // remove calculated widths for all slider children
    for (var i = 0; i < slideNodeChildren.length; i++) {
      slideNodeChildren[i].style.width = null;
    }

    // remove calculated width for the sliding target
    slideTargetNode.style.width = null;
    this.deactivateAnimation();

    // remove all clones
    if (this.__CSS3Slider._Config._getBaseConfig().cloneMode) {
      this.__Clone._removeClones();
    }
  };
  
  
  /**
   * set all inline stylings for the slider
   * 
   * @returns {void}
   */
  this.prepareSlideTarget = function () {
    var runtimeConfig = this.__CSS3Slider._Config.getRuntimeConfig();
    
    if(this.__CSS3Slider.isAnimationAllowed()){
      
      // calculate the width of the slider row
      var totalWidth = (runtimeConfig.slideChildrenCount / runtimeConfig.slideChildrenVisible) * 100;
      // calculate the width of one single slider child node in percent
      var singleElementWidth = this.__CSS3Slider._Config._getSingleElementWidthInPercent();
      var singleElementMargin = this.__CSS3Slider._Config._getSingleElementMarginInPx();

      var slideTargetNode = this.__CSS3Slider.getSlideTargetNode();
      var slideNodeChildren = slideTargetNode.children;

      // set the width of every slider child node
      for (var i = 0; i < slideNodeChildren.length; i++) {
        if(singleElementMargin){
          slideNodeChildren[i].style.width = 'calc(' + singleElementWidth + '% - ' + singleElementMargin + 'px - 0.01%)';
        }else{
          slideNodeChildren[i].style.width = singleElementWidth + '%';
        }
      }

      // set the width of the slider row node
      slideTargetNode.style.width = totalWidth + '%';
      this.activateAnimation();

      // add clones
      if (this.__CSS3Slider._Config._getBaseConfig().cloneMode) {
        this.__Clone._addClones();
      }
      
    }
  };
  
  /**
   * set the transition styling
   * 
   * @returns {void}
   */
  this.activateAnimation = function () {
    this.__CSS3Slider.getSlideTargetNode().style.transition = 'margin-left 0.5s ease';
  };
  
  /**
   * used to remove the transition styling
   * 
   * @returns {void}
   */
  this.deactivateAnimation = function () {
    this.__CSS3Slider.getSlideTargetNode().style.transition = null;
    this.__CSS3Slider.getSlideTargetNode().style.margin = null;
  };
  
  
  this.__construct (CSS3Slider);
}
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider_SlideDirection = factory;
  }
})(this, CSS3Slider_SlideDirection);


/**
 * handles direction slides
 * 
 * @param {CSS3Slider} CSS3Slider
 * @returns {CSS3Slider_SlideDirection}
 */
function CSS3Slider_SlideDirection (CSS3Slider) {
  
  this.__CSS3Slider = null;
  
  
  /**
   * init tasks
   * 
   * @param {CSS3Slider} CSS3Slider
   * @returns {void}
   */
  this.__construct = function (CSS3Slider) {
    this.__CSS3Slider = CSS3Slider;
  };
  
  
  /**
   * slide in a given direction
   * 
   * @param {String} direction
   * @param {Boolean} testCalculation
   * @returns {CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_SlidePosition@call;positionSlide|CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_Config@call;getRuntimeConfig|CSS3Slider_SlideDirection@call;directionSlide}
   */
  this.directionSlide = function (direction, testCalculation) {
    if (this.__CSS3Slider.isAnimationAllowed()) {
      var baseConfig = this.__CSS3Slider._Config._getBaseConfig();
      var runtimeConfig = this.__CSS3Slider._Config.getRuntimeConfig();

      if (baseConfig.continiousSlide) {
        if (baseConfig.cloneMode) {
          // handle slide if cloneMode and continious slide are active
          return this.__directionSlideContiniousClone(direction, baseConfig, runtimeConfig, testCalculation);
        } else {
          // handle slide if continious slide is active
          return this.__directionSlideContinious(direction, baseConfig, runtimeConfig, testCalculation);
        }
      } else {
        // handle simple slide
        return this.__directionSlide(direction, baseConfig, runtimeConfig, testCalculation);
        
      }
    } else {
      // simply return the runtime config without animation
      return this.__CSS3Slider._Config.getRuntimeConfig();
    }
  };
  
  
  /**
   * handle the slide if cloneMode and continious slide are active
   * 
   * @param {String} direction
   * @param {object} baseConfig
   * @param {object} runtimeConfig
   * @param {Boolean} testCalculation
   * @returns {CSS3Slider_SlideDirection@call;directionSlide|CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_SlidePosition@call;positionSlide|CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_Config@call;getRuntimeConfig}
   */
  this.__directionSlideContiniousClone = function (direction, baseConfig, runtimeConfig, testCalculation) {
    var currentPosition = runtimeConfig.slidePosition;
    var slidesAvailable = this.__CSS3Slider.slidesAvailable(direction);
    
    if (slidesAvailable < baseConfig.maxSteps) {
      // if the slider has not enough slider childs to perform a full slide
      // deactivate the transition
      this.__CSS3Slider._Dom.deactivateAnimation();

      if (direction === 'right') {
        // move the slider to the left side
        this.__CSS3Slider._SlidePosition.positionSlide(0 - (runtimeConfig.slideChildrenCount - currentPosition));

      } else if (direction === 'left') {
        // move the slider to the right side
        this.__CSS3Slider._SlidePosition.positionSlide(runtimeConfig.slideChildrenCount + currentPosition);

      }

      // after a short timeout - slide to the new position
      setTimeout(function () {
        this.__CSS3Slider._Dom.activateAnimation();
        this.directionSlide(direction);
      }.bind(this), 50);

      this.__CSS3Slider._allowAnimation();
      
      // return the future runtimeconfig using the testcalculation flag
      return this.directionSlide(direction, true);

    }
    
    // simply slide in the desired direction
    return this.__directionSlide(direction, baseConfig, runtimeConfig, testCalculation);
  };
  
  
  /**
   * handle the slide if continious slide is active
   * 
   * @param {String} direction
   * @param {object} baseConfig
   * @param {object} runtimeConfig
   * @param {Boolean} testCalculation
   * @returns {CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_Config@call;getRuntimeConfig|CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_SlidePosition@call;positionSlide}
   */
  this.__directionSlideContinious = function (direction, baseConfig, runtimeConfig, testCalculation) {
    var slidesAvailable = this.__CSS3Slider.slidesAvailable(direction);
    
    // if there are no more slides available - then slide to the other side
    if (slidesAvailable <= 0) {
      if (direction === 'left') {
        return this.__CSS3Slider._SlidePosition.positionSlide(runtimeConfig.slideChildrenCount);
        
      } else if (direction === 'right') {
        return this.__CSS3Slider._SlidePosition.positionSlide(0);
        
      }
    }

    // simply slide in the desired direction
    return this.__directionSlide(direction, baseConfig, runtimeConfig, testCalculation);
  };
  
  
  /**
   * simple slide if no special behavior is active
   * 
   * @param {String} direction
   * @param {object} baseConfig
   * @param {object} runtimeConfig
   * @param {Boolean} testCalculation
   * @returns {CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_Config@call;getRuntimeConfig|CSS3Slider_SlideDirection@pro;__CSS3Slider@pro;_SlidePosition@call;positionSlide}
   */
  this.__directionSlide = function (direction, baseConfig, runtimeConfig, testCalculation) {
    var currentPosition = runtimeConfig.slidePosition;
    var slidesAvailable = this.__CSS3Slider.slidesAvailable(direction);
    var stepsToSlide = null;
    
    // check if there are enough slider child nodes available for a slide, to perform the configured single slide
    if (slidesAvailable >= baseConfig.maxSteps) { stepsToSlide = baseConfig.maxSteps; }
    else { stepsToSlide = slidesAvailable; }

    // set the new active slider child node
    var newPosition = (direction === 'left') ? currentPosition - stepsToSlide : currentPosition + stepsToSlide;

    // check if the current active slider child node is the target slide child node
    if (newPosition !== currentPosition) {
      return this.__CSS3Slider._SlidePosition.positionSlide(newPosition, testCalculation);

    } else {
      return this.__CSS3Slider._Config.getRuntimeConfig();
    }
  };
  
  this.__construct (CSS3Slider);
}
(function (root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
    
  } else if (typeof exports === 'object') {
    // Node. Does not work with strict CommonJS, but only CommonJS-like enviroments that support module.exports, like Node.
    module.exports = factory;
    
  } else {
    // Browser globals (root is window)
    root.CSS3Slider_SlidePosition = factory;
  }
})(this, CSS3Slider_SlidePosition);


/**
 * handles slides to a specific position
 * 
 * @param {CSS3Slider} CSS3Slider
 * @returns {CSS3Slider_SlidePosition}
 */
function CSS3Slider_SlidePosition (CSS3Slider) {
  
  this.__CSS3Slider = null;
  
  
  /**
   * init tasks
   * 
   * @param {CSS3Slider} CSS3Slider
   * @returns {void}
   */
  this.__construct = function (CSS3Slider) {
    this.__CSS3Slider = CSS3Slider;
  };
  
  
  /**
   * slide to a specific position
   * 
   * @param {Number} position - the index of the slider child to slide to
   * @param {Boolean} testCalculation - set to true if you only want to calculate the runtimeconfig without actualy sliding
   * @returns {CSS3Slider_SlidePosition@pro;__CSS3Slider@pro;_Config@call;_setRuntimeConfig|CSS3Slider_SlidePosition.positionSlide.newRuntimeConfig|CSS3Slider_SlidePosition@pro;__CSS3Slider@pro;_Config@call;getRuntimeConfig}
   */
  this.positionSlide = function (position, testCalculation) {
    if (this.__CSS3Slider.isAnimationAllowed()) {
      
      this.__CSS3Slider._forbidAnimation();
      
      // check if the position is inside the slider bounds
      position = this.__getActualPositionInsideBounds(position);

      // set the new slider position in percent
      var newSlideValue = (position * this.__CSS3Slider._Config._getBaseConfig().singleStep) * -1;
      
      // set the new runtime config
      var newRuntimeConfig = {
        slidePosition: position,
        slideValue: newSlideValue,
        slideChildrenCount: this.__CSS3Slider._Config.getRuntimeConfig().slideChildrenCount,
        slideChildrenVisible: this.__CSS3Slider._Config.getRuntimeConfig().slideChildrenVisible,
        slideOverflowCount : this.__CSS3Slider._Config.getRuntimeConfig().slideOverflowCount,
        slideClonesCount : this.__CSS3Slider._Config.getRuntimeConfig().slideClonesCount
      };
      
      // check if call is not only a testCalculation
      if (!testCalculation) {
        // if so - actualy slide the slide target
        this.__CSS3Slider.getSlideTargetNode().style.marginLeft = newSlideValue + '%';
        
        // allow animation again, after the css transition took place
        setTimeout(function () {
          var runtimeConfig = this.__CSS3Slider._Config.getRuntimeConfig();
          if (runtimeConfig.slideChildrenCount > runtimeConfig.slideChildrenVisible){
            this.__CSS3Slider._allowAnimation();
          }
        }.bind(this), 500);
        
        return this.__CSS3Slider._Config._setRuntimeConfig(newRuntimeConfig);
        
      } else {
        // if not, only return the calculated but not stored runtimeconfig
        this.__CSS3Slider._allowAnimation();
        return newRuntimeConfig;
      }
      
    } else {
      // simply return the runtime config without animation
      return this.__CSS3Slider._Config.getRuntimeConfig();
    }
  };
  
  
  /**
   * return the next posible position inside the bounds of the slider
   * 
   * @param {Number} position
   * @returns {@var;minPosition|@var;maxPosition}
   */
  this.__getActualPositionInsideBounds = function (position) {
    var baseConfig = this.__CSS3Slider._Config._getBaseConfig();
    var runtimeConfig = this.__CSS3Slider._Config.getRuntimeConfig();

    var minPosition = 0;
    var maxPosition = runtimeConfig.slideChildrenCount - runtimeConfig.slideChildrenVisible + runtimeConfig.slideOverflowCount;
    if(maxPosition <= 0){
      maxPosition = 0;
    }

    // if continious slide is active, add the clones count to min and max positions
    if (baseConfig.cloneMode) {
      minPosition -= runtimeConfig.slideClonesCount;
      maxPosition += runtimeConfig.slideClonesCount;
    }

    // slide to the first slider child node, if the target is below zero
    if (position < minPosition) {
      position = minPosition;
    }
    // slide to the last slider child node, if the target is beyond the last slider child node
    if (position >= maxPosition) {
      position = maxPosition;
    }
    
    return position;
  };
  
  this.__construct (CSS3Slider);
}

/*! nanoScrollerJS - v0.8.7 - (c) 2015 James Florentino; Licensed MIT */

!function(a){return"function"==typeof define&&define.amd?define(["jquery"],function(b){return a(b,window,document)}):"object"==typeof exports?module.exports=a(require("jquery"),window,document):a(jQuery,window,document)}(function(a,b,c){"use strict";var d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D,E,F,G,H;z={paneClass:"nano-pane",sliderClass:"nano-slider",contentClass:"nano-content",enabledClass:"has-scrollbar",flashedClass:"flashed",activeClass:"active",iOSNativeScrolling:!1,preventPageScrolling:!1,disableResize:!1,alwaysVisible:!1,flashDelay:1500,sliderMinHeight:20,sliderMaxHeight:null,documentContext:null,windowContext:null},u="scrollbar",t="scroll",l="mousedown",m="mouseenter",n="mousemove",p="mousewheel",o="mouseup",s="resize",h="drag",i="enter",w="up",r="panedown",f="DOMMouseScroll",g="down",x="wheel",j="keydown",k="keyup",v="touchmove",d="Microsoft Internet Explorer"===b.navigator.appName&&/msie 7./i.test(b.navigator.appVersion)&&b.ActiveXObject,e=null,D=b.requestAnimationFrame,y=b.cancelAnimationFrame,F=c.createElement("div").style,H=function(){var a,b,c,d,e,f;for(d=["t","webkitT","MozT","msT","OT"],a=e=0,f=d.length;f>e;a=++e)if(c=d[a],b=d[a]+"ransform",b in F)return d[a].substr(0,d[a].length-1);return!1}(),G=function(a){return H===!1?!1:""===H?a:H+a.charAt(0).toUpperCase()+a.substr(1)},E=G("transform"),B=E!==!1,A=function(){var a,b,d;return a=c.createElement("div"),b=a.style,b.position="absolute",b.width="100px",b.height="100px",b.overflow=t,b.top="-9999px",c.body.appendChild(a),d=a.offsetWidth-a.clientWidth,c.body.removeChild(a),d},C=function(){var a,c,d;return c=b.navigator.userAgent,(a=/(?=.+Mac OS X)(?=.+Firefox)/.test(c))?(d=/Firefox\/\d{2}\./.exec(c),d&&(d=d[0].replace(/\D+/g,"")),a&&+d>23):!1},q=function(){function j(d,f){this.el=d,this.options=f,e||(e=A()),this.$el=a(this.el),this.doc=a(this.options.documentContext||c),this.win=a(this.options.windowContext||b),this.body=this.doc.find("body"),this.$content=this.$el.children("."+this.options.contentClass),this.$content.attr("tabindex",this.options.tabIndex||0),this.content=this.$content[0],this.previousPosition=0,this.options.iOSNativeScrolling&&null!=this.el.style.WebkitOverflowScrolling?this.nativeScrolling():this.generate(),this.createEvents(),this.addEvents(),this.reset()}return j.prototype.preventScrolling=function(a,b){if(this.isActive)if(a.type===f)(b===g&&a.originalEvent.detail>0||b===w&&a.originalEvent.detail<0)&&a.preventDefault();else if(a.type===p){if(!a.originalEvent||!a.originalEvent.wheelDelta)return;(b===g&&a.originalEvent.wheelDelta<0||b===w&&a.originalEvent.wheelDelta>0)&&a.preventDefault()}},j.prototype.nativeScrolling=function(){this.$content.css({WebkitOverflowScrolling:"touch"}),this.iOSNativeScrolling=!0,this.isActive=!0},j.prototype.updateScrollValues=function(){var a,b;a=this.content,this.maxScrollTop=a.scrollHeight-a.clientHeight,this.prevScrollTop=this.contentScrollTop||0,this.contentScrollTop=a.scrollTop,b=this.contentScrollTop>this.previousPosition?"down":this.contentScrollTop<this.previousPosition?"up":"same",this.previousPosition=this.contentScrollTop,"same"!==b&&this.$el.trigger("update",{position:this.contentScrollTop,maximum:this.maxScrollTop,direction:b}),this.iOSNativeScrolling||(this.maxSliderTop=this.paneHeight-this.sliderHeight,this.sliderTop=0===this.maxScrollTop?0:this.contentScrollTop*this.maxSliderTop/this.maxScrollTop)},j.prototype.setOnScrollStyles=function(){var a;B?(a={},a[E]="translate(0, "+this.sliderTop+"px)"):a={top:this.sliderTop},D?(y&&this.scrollRAF&&y(this.scrollRAF),this.scrollRAF=D(function(b){return function(){return b.scrollRAF=null,b.slider.css(a)}}(this))):this.slider.css(a)},j.prototype.createEvents=function(){this.events={down:function(a){return function(b){return a.isBeingDragged=!0,a.offsetY=b.pageY-a.slider.offset().top,a.slider.is(b.target)||(a.offsetY=0),a.pane.addClass(a.options.activeClass),a.doc.bind(n,a.events[h]).bind(o,a.events[w]),a.body.bind(m,a.events[i]),!1}}(this),drag:function(a){return function(b){return a.sliderY=b.pageY-a.$el.offset().top-a.paneTop-(a.offsetY||.5*a.sliderHeight),a.scroll(),a.contentScrollTop>=a.maxScrollTop&&a.prevScrollTop!==a.maxScrollTop?a.$el.trigger("scrollend"):0===a.contentScrollTop&&0!==a.prevScrollTop&&a.$el.trigger("scrolltop"),!1}}(this),up:function(a){return function(b){return a.isBeingDragged=!1,a.pane.removeClass(a.options.activeClass),a.doc.unbind(n,a.events[h]).unbind(o,a.events[w]),a.body.unbind(m,a.events[i]),!1}}(this),resize:function(a){return function(b){a.reset()}}(this),panedown:function(a){return function(b){return a.sliderY=(b.offsetY||b.originalEvent.layerY)-.5*a.sliderHeight,a.scroll(),a.events.down(b),!1}}(this),scroll:function(a){return function(b){a.updateScrollValues(),a.isBeingDragged||(a.iOSNativeScrolling||(a.sliderY=a.sliderTop,a.setOnScrollStyles()),null!=b&&(a.contentScrollTop>=a.maxScrollTop?(a.options.preventPageScrolling&&a.preventScrolling(b,g),a.prevScrollTop!==a.maxScrollTop&&a.$el.trigger("scrollend")):0===a.contentScrollTop&&(a.options.preventPageScrolling&&a.preventScrolling(b,w),0!==a.prevScrollTop&&a.$el.trigger("scrolltop"))))}}(this),wheel:function(a){return function(b){var c;if(null!=b)return c=b.delta||b.wheelDelta||b.originalEvent&&b.originalEvent.wheelDelta||-b.detail||b.originalEvent&&-b.originalEvent.detail,c&&(a.sliderY+=-c/3),a.scroll(),!1}}(this),enter:function(a){return function(b){var c;if(a.isBeingDragged)return 1!==(b.buttons||b.which)?(c=a.events)[w].apply(c,arguments):void 0}}(this)}},j.prototype.addEvents=function(){var a;this.removeEvents(),a=this.events,this.options.disableResize||this.win.bind(s,a[s]),this.iOSNativeScrolling||(this.slider.bind(l,a[g]),this.pane.bind(l,a[r]).bind(""+p+" "+f,a[x])),this.$content.bind(""+t+" "+p+" "+f+" "+v,a[t])},j.prototype.removeEvents=function(){var a;a=this.events,this.win.unbind(s,a[s]),this.iOSNativeScrolling||(this.slider.unbind(),this.pane.unbind()),this.$content.unbind(""+t+" "+p+" "+f+" "+v,a[t])},j.prototype.generate=function(){var a,c,d,f,g,h,i;return f=this.options,h=f.paneClass,i=f.sliderClass,a=f.contentClass,(g=this.$el.children("."+h)).length||g.children("."+i).length||this.$el.append('<div class="'+h+'"><div class="'+i+'" /></div>'),this.pane=this.$el.children("."+h),this.slider=this.pane.find("."+i),0===e&&C()?(d=b.getComputedStyle(this.content,null).getPropertyValue("padding-right").replace(/[^0-9.]+/g,""),c={right:-14,paddingRight:+d+14}):e&&(c={right:-e},this.$el.addClass(f.enabledClass)),null!=c&&this.$content.css(c),this},j.prototype.restore=function(){this.stopped=!1,this.iOSNativeScrolling||this.pane.show(),this.addEvents()},j.prototype.reset=function(){var a,b,c,f,g,h,i,j,k,l,m,n;return this.iOSNativeScrolling?void(this.contentHeight=this.content.scrollHeight):(this.$el.find("."+this.options.paneClass).length||this.generate().stop(),this.stopped&&this.restore(),a=this.content,f=a.style,g=f.overflowY,d&&this.$content.css({height:this.$content.height()}),b=a.scrollHeight+e,l=parseInt(this.$el.css("max-height"),10),l>0&&(this.$el.height(""),this.$el.height(a.scrollHeight>l?l:a.scrollHeight)),i=this.pane.outerHeight(!1),k=parseInt(this.pane.css("top"),10),h=parseInt(this.pane.css("bottom"),10),j=i+k+h,n=Math.round(j/b*i),n<this.options.sliderMinHeight?n=this.options.sliderMinHeight:null!=this.options.sliderMaxHeight&&n>this.options.sliderMaxHeight&&(n=this.options.sliderMaxHeight),g===t&&f.overflowX!==t&&(n+=e),this.maxSliderTop=j-n,this.contentHeight=b,this.paneHeight=i,this.paneOuterHeight=j,this.sliderHeight=n,this.paneTop=k,this.slider.height(n),this.events.scroll(),this.pane.show(),this.isActive=!0,a.scrollHeight===a.clientHeight||this.pane.outerHeight(!0)>=a.scrollHeight&&g!==t?(this.pane.hide(),this.isActive=!1):this.el.clientHeight===a.scrollHeight&&g===t?this.slider.hide():this.slider.show(),this.pane.css({opacity:this.options.alwaysVisible?1:"",visibility:this.options.alwaysVisible?"visible":""}),c=this.$content.css("position"),("static"===c||"relative"===c)&&(m=parseInt(this.$content.css("right"),10),m&&this.$content.css({right:"",marginRight:m})),this)},j.prototype.scroll=function(){return this.isActive?(this.sliderY=Math.max(0,this.sliderY),this.sliderY=Math.min(this.maxSliderTop,this.sliderY),this.$content.scrollTop(this.maxScrollTop*this.sliderY/this.maxSliderTop),this.iOSNativeScrolling||(this.updateScrollValues(),this.setOnScrollStyles()),this):void 0},j.prototype.scrollBottom=function(a){return this.isActive?(this.$content.scrollTop(this.contentHeight-this.$content.height()-a).trigger(p),this.stop().restore(),this):void 0},j.prototype.scrollTop=function(a){return this.isActive?(this.$content.scrollTop(+a).trigger(p),this.stop().restore(),this):void 0},j.prototype.scrollTo=function(a){return this.isActive?(this.scrollTop(this.$el.find(a).get(0).offsetTop),this):void 0},j.prototype.stop=function(){return y&&this.scrollRAF&&(y(this.scrollRAF),this.scrollRAF=null),this.stopped=!0,this.removeEvents(),this.iOSNativeScrolling||this.pane.hide(),this},j.prototype.destroy=function(){return this.stopped||this.stop(),!this.iOSNativeScrolling&&this.pane.length&&this.pane.remove(),d&&this.$content.height(""),this.$content.removeAttr("tabindex"),this.$el.hasClass(this.options.enabledClass)&&(this.$el.removeClass(this.options.enabledClass),this.$content.css({right:""})),this},j.prototype.flash=function(){return!this.iOSNativeScrolling&&this.isActive?(this.reset(),this.pane.addClass(this.options.flashedClass),setTimeout(function(a){return function(){a.pane.removeClass(a.options.flashedClass)}}(this),this.options.flashDelay),this):void 0},j}(),a.fn.nanoScroller=function(b){return this.each(function(){var c,d;if((d=this.nanoscroller)||(c=a.extend({},z,b),this.nanoscroller=d=new q(this,c)),b&&"object"==typeof b){if(a.extend(d.options,b),null!=b.scrollBottom)return d.scrollBottom(b.scrollBottom);if(null!=b.scrollTop)return d.scrollTop(b.scrollTop);if(b.scrollTo)return d.scrollTo(b.scrollTo);if("bottom"===b.scroll)return d.scrollBottom(0);if("top"===b.scroll)return d.scrollTop(0);if(b.scroll&&b.scroll instanceof a)return d.scrollTo(b.scroll);if(b.stop)return d.stop();if(b.destroy)return d.destroy();if(b.flash)return d.flash()}return d.reset()})},a.fn.nanoScroller.Constructor=q});
//# sourceMappingURL=jquery.nanoscroller.min.js.map
/*! nouislider - 8.0.2 - 2015-07-06 13:22:09 */

!function(a){if("function"==typeof define&&define.amd)define([],a);else if("object"==typeof exports){var b=require("fs");module.exports=a(),module.exports.css=function(){return b.readFileSync(__dirname+"/nouislider.min.css","utf8")}}else window.noUiSlider=a()}(function(){"use strict";function a(a){return a.filter(function(a){return this[a]?!1:this[a]=!0},{})}function b(a,b){return Math.round(a/b)*b}function c(a){var b=a.getBoundingClientRect(),c=a.ownerDocument,d=c.defaultView||c.parentWindow,e=c.documentElement,f=d.pageXOffset;return/webkit.*Chrome.*Mobile/i.test(navigator.userAgent)&&(f=0),{top:b.top+d.pageYOffset-e.clientTop,left:b.left+f-e.clientLeft}}function d(a){return"number"==typeof a&&!isNaN(a)&&isFinite(a)}function e(a){var b=Math.pow(10,7);return Number((Math.round(a*b)/b).toFixed(7))}function f(a,b,c){j(a,b),setTimeout(function(){k(a,b)},c)}function g(a){return Math.max(Math.min(a,100),0)}function h(a){return Array.isArray(a)?a:[a]}function i(a){var b=a.split(".");return b.length>1?b[1].length:0}function j(a,b){a.classList?a.classList.add(b):a.className+=" "+b}function k(a,b){a.classList?a.classList.remove(b):a.className=a.className.replace(new RegExp("(^|\\b)"+b.split(" ").join("|")+"(\\b|$)","gi")," ")}function l(a,b){a.classList?a.classList.contains(b):new RegExp("(^| )"+b+"( |$)","gi").test(a.className)}function m(a,b){return 100/(b-a)}function n(a,b){return 100*b/(a[1]-a[0])}function o(a,b){return n(a,a[0]<0?b+Math.abs(a[0]):b-a[0])}function p(a,b){return b*(a[1]-a[0])/100+a[0]}function q(a,b){for(var c=1;a>=b[c];)c+=1;return c}function r(a,b,c){if(c>=a.slice(-1)[0])return 100;var d,e,f,g,h=q(c,a);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],f+o([d,e],c)/m(f,g)}function s(a,b,c){if(c>=100)return a.slice(-1)[0];var d,e,f,g,h=q(c,b);return d=a[h-1],e=a[h],f=b[h-1],g=b[h],p([d,e],(c-f)*m(f,g))}function t(a,c,d,e){if(100===e)return e;var f,g,h=q(e,a);return d?(f=a[h-1],g=a[h],e-f>(g-f)/2?g:f):c[h-1]?a[h-1]+b(e-a[h-1],c[h-1]):e}function u(a,b,c){var e;if("number"==typeof b&&(b=[b]),"[object Array]"!==Object.prototype.toString.call(b))throw new Error("noUiSlider: 'range' contains invalid value.");if(e="min"===a?0:"max"===a?100:parseFloat(a),!d(e)||!d(b[0]))throw new Error("noUiSlider: 'range' value isn't numeric.");c.xPct.push(e),c.xVal.push(b[0]),e?c.xSteps.push(isNaN(b[1])?!1:b[1]):isNaN(b[1])||(c.xSteps[0]=b[1])}function v(a,b,c){return b?void(c.xSteps[a]=n([c.xVal[a],c.xVal[a+1]],b)/m(c.xPct[a],c.xPct[a+1])):!0}function w(a,b,c,d){this.xPct=[],this.xVal=[],this.xSteps=[d||!1],this.xNumSteps=[!1],this.snap=b,this.direction=c;var e,f=[];for(e in a)a.hasOwnProperty(e)&&f.push([a[e],e]);for(f.sort(function(a,b){return a[0]-b[0]}),e=0;e<f.length;e++)u(f[e][1],f[e][0],this);for(this.xNumSteps=this.xSteps.slice(0),e=0;e<this.xNumSteps.length;e++)v(e,this.xNumSteps[e],this)}function x(a,b){if(!d(b))throw new Error("noUiSlider: 'step' is not numeric.");a.singleStep=b}function y(a,b){if("object"!=typeof b||Array.isArray(b))throw new Error("noUiSlider: 'range' is not an object.");if(void 0===b.min||void 0===b.max)throw new Error("noUiSlider: Missing 'min' or 'max' in 'range'.");a.spectrum=new w(b,a.snap,a.dir,a.singleStep)}function z(a,b){if(b=h(b),!Array.isArray(b)||!b.length||b.length>2)throw new Error("noUiSlider: 'start' option is incorrect.");a.handles=b.length,a.start=b}function A(a,b){if(a.snap=b,"boolean"!=typeof b)throw new Error("noUiSlider: 'snap' option must be a boolean.")}function B(a,b){if(a.animate=b,"boolean"!=typeof b)throw new Error("noUiSlider: 'animate' option must be a boolean.")}function C(a,b){if("lower"===b&&1===a.handles)a.connect=1;else if("upper"===b&&1===a.handles)a.connect=2;else if(b===!0&&2===a.handles)a.connect=3;else{if(b!==!1)throw new Error("noUiSlider: 'connect' option doesn't match handle count.");a.connect=0}}function D(a,b){switch(b){case"horizontal":a.ort=0;break;case"vertical":a.ort=1;break;default:throw new Error("noUiSlider: 'orientation' option is invalid.")}}function E(a,b){if(!d(b))throw new Error("noUiSlider: 'margin' option must be numeric.");if(a.margin=a.spectrum.getMargin(b),!a.margin)throw new Error("noUiSlider: 'margin' option is only supported on linear sliders.")}function F(a,b){if(!d(b))throw new Error("noUiSlider: 'limit' option must be numeric.");if(a.limit=a.spectrum.getMargin(b),!a.limit)throw new Error("noUiSlider: 'limit' option is only supported on linear sliders.")}function G(a,b){switch(b){case"ltr":a.dir=0;break;case"rtl":a.dir=1,a.connect=[0,2,1,3][a.connect];break;default:throw new Error("noUiSlider: 'direction' option was not recognized.")}}function H(a,b){if("string"!=typeof b)throw new Error("noUiSlider: 'behaviour' must be a string containing options.");var c=b.indexOf("tap")>=0,d=b.indexOf("drag")>=0,e=b.indexOf("fixed")>=0,f=b.indexOf("snap")>=0;a.events={tap:c||f,drag:d,fixed:e,snap:f}}function I(a,b){if(a.format=b,"function"==typeof b.to&&"function"==typeof b.from)return!0;throw new Error("noUiSlider: 'format' requires 'to' and 'from' methods.")}function J(a){var b,c={margin:0,limit:0,animate:!0,format:U};b={step:{r:!1,t:x},start:{r:!0,t:z},connect:{r:!0,t:C},direction:{r:!0,t:G},snap:{r:!1,t:A},animate:{r:!1,t:B},range:{r:!0,t:y},orientation:{r:!1,t:D},margin:{r:!1,t:E},limit:{r:!1,t:F},behaviour:{r:!0,t:H},format:{r:!1,t:I}};var d={connect:!1,direction:"ltr",behaviour:"tap",orientation:"horizontal"};return Object.keys(d).forEach(function(b){void 0===a[b]&&(a[b]=d[b])}),Object.keys(b).forEach(function(d){var e=b[d];if(void 0===a[d]){if(e.r)throw new Error("noUiSlider: '"+d+"' is required.");return!0}e.t(c,a[d])}),c.pips=a.pips,c.style=c.ort?"top":"left",c}function K(a,b,c){var d=a+b[0],e=a+b[1];return c?(0>d&&(e+=Math.abs(d)),e>100&&(d-=e-100),[g(d),g(e)]):[d,e]}function L(a){a.preventDefault();var b,c,d=0===a.type.indexOf("touch"),e=0===a.type.indexOf("mouse"),f=0===a.type.indexOf("pointer"),g=a;return 0===a.type.indexOf("MSPointer")&&(f=!0),d&&(b=a.changedTouches[0].pageX,c=a.changedTouches[0].pageY),(e||f)&&(b=a.clientX+window.pageXOffset,c=a.clientY+window.pageYOffset),g.points=[b,c],g.cursor=e||f,g}function M(a,b){var c=document.createElement("div"),d=document.createElement("div"),e=["-lower","-upper"];return a&&e.reverse(),j(d,T[3]),j(d,T[3]+e[b]),j(c,T[2]),c.appendChild(d),c}function N(a,b,c){switch(a){case 1:j(b,T[7]),j(c[0],T[6]);break;case 3:j(c[1],T[6]);case 2:j(c[0],T[7]);case 0:j(b,T[6])}}function O(a,b,c){var d,e=[];for(d=0;a>d;d+=1)e.push(c.appendChild(M(b,d)));return e}function P(a,b,c){j(c,T[0]),j(c,T[8+a]),j(c,T[4+b]);var d=document.createElement("div");return j(d,T[1]),c.appendChild(d),d}function Q(b,d){function e(a,b,c){if("range"===a||"steps"===a)return M.xVal;if("count"===a){var d,e=100/(b-1),f=0;for(b=[];(d=f++*e)<=100;)b.push(d);a="positions"}return"positions"===a?b.map(function(a){return M.fromStepping(c?M.getStep(a):a)}):"values"===a?c?b.map(function(a){return M.fromStepping(M.getStep(M.toStepping(a)))}):b:void 0}function m(b,c,d){var e=M.direction,f={},g=M.xVal[0],h=M.xVal[M.xVal.length-1],i=!1,j=!1,k=0;return M.direction=0,d=a(d.slice().sort(function(a,b){return a-b})),d[0]!==g&&(d.unshift(g),i=!0),d[d.length-1]!==h&&(d.push(h),j=!0),d.forEach(function(a,e){var g,h,l,m,n,o,p,q,r,s,t=a,u=d[e+1];if("steps"===c&&(g=M.xNumSteps[e]),g||(g=u-t),t!==!1&&void 0!==u)for(h=t;u>=h;h+=g){for(m=M.toStepping(h),n=m-k,q=n/b,r=Math.round(q),s=n/r,l=1;r>=l;l+=1)o=k+l*s,f[o.toFixed(5)]=["x",0];p=d.indexOf(h)>-1?1:"steps"===c?2:0,!e&&i&&(p=0),h===u&&j||(f[m.toFixed(5)]=[h,p]),k=m}}),M.direction=e,f}function n(a,b,c){function e(a){return["-normal","-large","-sub"][a]}function f(a,b,c){return'class="'+b+" "+b+"-"+h+" "+b+e(c[1])+'" style="'+d.style+": "+a+'%"'}function g(a,d){M.direction&&(a=100-a),d[1]=d[1]&&b?b(d[0],d[1]):d[1],i.innerHTML+="<div "+f(a,"noUi-marker",d)+"></div>",d[1]&&(i.innerHTML+="<div "+f(a,"noUi-value",d)+">"+c.to(d[0])+"</div>")}var h=["horizontal","vertical"][d.ort],i=document.createElement("div");return j(i,"noUi-pips"),j(i,"noUi-pips-"+h),Object.keys(a).forEach(function(b){g(b,a[b])}),i}function o(a){var b=a.mode,c=a.density||1,d=a.filter||!1,f=a.values||!1,g=a.stepped||!1,h=e(b,f,g),i=m(c,b,h),j=a.format||{to:Math.round};return I.appendChild(n(i,d,j))}function p(){return G["offset"+["Width","Height"][d.ort]]}function q(a,b){void 0!==b&&(b=Math.abs(b-d.dir)),Object.keys(R).forEach(function(c){var d=c.split(".")[0];a===d&&R[c].forEach(function(a){a(h(B()),b,r(Array.prototype.slice.call(Q)))})})}function r(a){return 1===a.length?a[0]:d.dir?a.reverse():a}function s(a,b,c,e){var f=function(b){return I.hasAttribute("disabled")?!1:l(I,T[14])?!1:(b=L(b),a===S.start&&void 0!==b.buttons&&b.buttons>1?!1:(b.calcPoint=b.points[d.ort],void c(b,e)))},g=[];return a.split(" ").forEach(function(a){b.addEventListener(a,f,!1),g.push([a,f])}),g}function t(a,b){var c,d,e=b.handles||H,f=!1,g=100*(a.calcPoint-b.start)/p(),h=e[0]===H[0]?0:1;if(c=K(g,b.positions,e.length>1),f=y(e[0],c[h],1===e.length),e.length>1){if(f=y(e[1],c[h?0:1],!1)||f)for(d=0;d<b.handles.length;d++)q("slide",d)}else f&&q("slide",h)}function u(a,b){var c=G.getElementsByClassName(T[15]),d=b.handles[0]===H[0]?0:1;c.length&&k(c[0],T[15]),a.cursor&&(document.body.style.cursor="",document.body.removeEventListener("selectstart",document.body.noUiListener));var e=document.documentElement;e.noUiListeners.forEach(function(a){e.removeEventListener(a[0],a[1])}),k(I,T[12]),q("set",d),q("change",d)}function v(a,b){var c=document.documentElement;if(1===b.handles.length&&(j(b.handles[0].children[0],T[15]),b.handles[0].hasAttribute("disabled")))return!1;a.stopPropagation();var d=s(S.move,c,t,{start:a.calcPoint,handles:b.handles,positions:[J[0],J[H.length-1]]}),e=s(S.end,c,u,{handles:b.handles});if(c.noUiListeners=d.concat(e),a.cursor){document.body.style.cursor=getComputedStyle(a.target).cursor,H.length>1&&j(I,T[12]);var f=function(){return!1};document.body.noUiListener=f,document.body.addEventListener("selectstart",f,!1)}}function w(a){var b,e,g=a.calcPoint,h=0;return a.stopPropagation(),H.forEach(function(a){h+=c(a)[d.style]}),b=h/2>g||1===H.length?0:1,g-=c(G)[d.style],e=100*g/p(),d.events.snap||f(I,T[14],300),H[b].hasAttribute("disabled")?!1:(y(H[b],e),q("slide",b),q("set",b),q("change",b),void(d.events.snap&&v(a,{handles:[H[h]]})))}function x(a){var b,c;if(!a.fixed)for(b=0;b<H.length;b+=1)s(S.start,H[b].children[0],v,{handles:[H[b]]});a.tap&&s(S.start,G,w,{handles:H}),a.drag&&(c=[G.getElementsByClassName(T[7])[0]],j(c[0],T[10]),a.fixed&&c.push(H[c[0]===H[0]?1:0].children[0]),c.forEach(function(a){s(S.start,a,v,{handles:H})}))}function y(a,b,c){var e=a!==H[0]?1:0,f=J[0]+d.margin,h=J[1]-d.margin,i=J[0]+d.limit,l=J[1]-d.limit;return H.length>1&&(b=e?Math.max(b,f):Math.min(b,h)),c!==!1&&d.limit&&H.length>1&&(b=e?Math.min(b,i):Math.max(b,l)),b=M.getStep(b),b=g(parseFloat(b.toFixed(7))),b===J[e]?!1:(a.style[d.style]=b+"%",a.previousSibling||(k(a,T[17]),b>50&&j(a,T[17])),J[e]=b,Q[e]=M.fromStepping(b),q("update",e),!0)}function z(a,b){var c,e,f;for(d.limit&&(a+=1),c=0;a>c;c+=1)e=c%2,f=b[e],null!==f&&f!==!1&&("number"==typeof f&&(f=String(f)),f=d.format.from(f),(f===!1||isNaN(f)||y(H[e],M.toStepping(f),c===3-d.dir)===!1)&&q("update",e))}function A(a){var b,c,e=h(a);for(d.dir&&d.handles>1&&e.reverse(),d.animate&&-1!==J[0]&&f(I,T[14],300),b=H.length>1?3:1,1===e.length&&(b=1),z(b,e),c=0;c<H.length;c++)q("set",c)}function B(){var a,b=[];for(a=0;a<d.handles;a+=1)b[a]=d.format.to(Q[a]);return r(b)}function C(){T.forEach(function(a){a&&k(I,a)}),I.innerHTML="",delete I.noUiSlider}function D(){var a=J.map(function(a,b){var c=M.getApplicableStep(a),d=i(String(c[2])),e=Q[b],f=100===a?null:c[2],g=Number((e-c[2]).toFixed(d)),h=0===a?null:g>=c[1]?c[2]:c[0]||!1;return[h,f]});return r(a)}function E(a,b){R[a]=R[a]||[],R[a].push(b),"update"===a.split(".")[0]&&H.forEach(function(a,b){q("update",b)})}function F(a){var b=a.split(".")[0],c=a.substring(b.length);Object.keys(R).forEach(function(a){var d=a.split(".")[0],e=a.substring(d.length);b&&b!==d||c&&c!==e||delete R[a]})}var G,H,I=b,J=[-1,-1],M=d.spectrum,Q=[],R={};if(I.noUiSlider)throw new Error("Slider was already initialized.");return G=P(d.dir,d.ort,I),H=O(d.handles,d.dir,G),N(d.connect,I,H),x(d.events),d.pips&&o(d.pips),{destroy:C,steps:D,on:E,off:F,get:B,set:A}}function R(a,b){if(!a.nodeName)throw new Error("noUiSlider.create requires a single element.");var c=J(b,a),d=Q(a,c);d.set(c.start),a.noUiSlider=d}var S=window.navigator.pointerEnabled?{start:"pointerdown",move:"pointermove",end:"pointerup"}:window.navigator.msPointerEnabled?{start:"MSPointerDown",move:"MSPointerMove",end:"MSPointerUp"}:{start:"mousedown touchstart",move:"mousemove touchmove",end:"mouseup touchend"},T=["noUi-target","noUi-base","noUi-origin","noUi-handle","noUi-horizontal","noUi-vertical","noUi-background","noUi-connect","noUi-ltr","noUi-rtl","noUi-dragable","","noUi-state-drag","","noUi-state-tap","noUi-active","","noUi-stacking"];w.prototype.getMargin=function(a){return 2===this.xPct.length?n(this.xVal,a):!1},w.prototype.toStepping=function(a){return a=r(this.xVal,this.xPct,a),this.direction&&(a=100-a),a},w.prototype.fromStepping=function(a){return this.direction&&(a=100-a),e(s(this.xVal,this.xPct,a))},w.prototype.getStep=function(a){return this.direction&&(a=100-a),a=t(this.xPct,this.xSteps,this.snap,a),this.direction&&(a=100-a),a},w.prototype.getApplicableStep=function(a){var b=q(a,this.xPct),c=100===a?2:1;return[this.xNumSteps[b-2],this.xVal[b-c],this.xNumSteps[b-c]]},w.prototype.convert=function(a){return this.getStep(this.toStepping(a))};var U={to:function(a){return a.toFixed(2)},from:Number};return{create:R}});
!function(e){if("object"==typeof exports)module.exports=e();else if("function"==typeof define&&define.amd)define(e);else{var t;"undefined"!=typeof window?t=window:"undefined"!=typeof global?t=global:"undefined"!=typeof self&&(t=self),t.objectHash=e()}}(function(){return function e(t,r,n){function o(u,a){if(!r[u]){if(!t[u]){var s="function"==typeof require&&require;if(!a&&s)return s(u,!0);if(i)return i(u,!0);throw new Error("Cannot find module '"+u+"'")}var f=r[u]={exports:{}};t[u][0].call(f.exports,function(e){var r=t[u][1][e];return o(r?r:e)},f,f.exports,e,t,r,n)}return r[u].exports}for(var i="function"==typeof require&&require,u=0;u<n.length;u++)o(n[u]);return o}({1:[function(e,t,r){(function(n,o,i,u,a,s,f,c,l){"use strict";function d(e,t){return t=t||{},t.algorithm=t.algorithm||"sha1",t.encoding=t.encoding||"hex",t.excludeValues=t.excludeValues?!0:!1,t.algorithm=t.algorithm.toLowerCase(),t.encoding=t.encoding.toLowerCase(),p(e,t),h(e,t)}function p(e,t){var r=y.getHashes?y.getHashes():["sha1","md5"],n=["buffer","hex","binary","base64"];if("undefined"==typeof e)throw new Error("Object argument required.");if(-1===r.indexOf(t.algorithm))throw new Error('Algorithm "'+t.algorithm+'"  not supported. supported values: '+r.join(", "));if(-1===n.indexOf(t.encoding))throw new Error('Encoding "'+t.encoding+'"  not supported. supported values: '+n.join(", "))}function h(e,t){var r=y.createHash(t.algorithm),n=[];return g(r,t,n).dispatch(e),"buffer"===t.encoding?r.digest():r.digest(t.encoding)}function g(e,t,r){return{dispatch:function(e){var t=typeof e,r=this["_"+t];return null===e?this._null():r(e)},_object:function(n){var o=/\[object (.*)\]/i,u=Object.prototype.toString.call(n),a=o.exec(u)[1]||"null",s=null;if(a=a.toLowerCase(),(s=r.indexOf(n))>=0)return void g(e,t,r).dispatch("[CIRCULAR]: "+s);if(r.push(n),"undefined"!=typeof i&&i.isBuffer&&i.isBuffer(n))return e.update("buffer:"),e.update(n);if("object"===a){e.update("object:");var f=Object.keys(n).sort();return f.forEach(function(o){e.update(o,"utf8"),t.excludeValues||g(e,t,r).dispatch(n[o])})}if(!g(e,t,r)["_"+a])throw new Error('Unknown object type "'+a+'"');g(e,t,r)["_"+a](n)},_array:function(n){return e.update("array:"+n.length+":"),n.forEach(function(n){g(e,t,r).dispatch(n)})},_date:function(t){return e.update("date:"+t.toJSON())},_error:function(t){return e.update("error:"+t.toString(),"utf8")},_boolean:function(t){return e.update("bool:"+t.toString())},_string:function(t){return e.update("string:"+t,"utf8")},_function:function(t){return e.update("fn:"+t.toString(),"utf8")},_number:function(t){return e.update("number:"+t.toString())},_xml:function(t){return e.update("xml:"+t.toString(),"utf8")},_null:function(){return e.update("Null")},_undefined:function(){return e.update("Undefined")},_regexp:function(t){return e.update("regex:"+t.toString(),"utf8")},_uint8array:function(n){return e.update("uint8array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint8clampedarray:function(n){return e.update("uint8clampedarray:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int8array:function(n){return e.update("uint8array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint16array:function(n){return e.update("uint16array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int16array:function(n){return e.update("uint16array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint32array:function(n){return e.update("uint32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int32array:function(n){return e.update("uint32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_float32array:function(n){return e.update("float32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_float64array:function(n){return e.update("float64array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_arraybuffer:function(n){return e.update("arraybuffer:"),g(e,t,r).dispatch(new Uint8Array(n))},_domwindow:function(){return e.update("domwindow")},_process:function(){return e.update("process")},_timer:function(){return e.update("timer")},_pipe:function(){return e.update("pipe")},_tcp:function(){return e.update("tcp")},_udp:function(){return e.update("udp")},_tty:function(){return e.update("tty")},_statwatcher:function(){return e.update("statwatcher")},_securecontext:function(){return e.update("securecontext")},_connection:function(){return e.update("connection")},_zlib:function(){return e.update("zlib")},_context:function(){return e.update("context")},_nodescript:function(){return e.update("nodescript")},_httpparser:function(){return e.update("httpparser")},_dataview:function(){return e.update("dataview")},_signal:function(){return e.update("signal")},_fsevent:function(){return e.update("fsevent")},_tlswrap:function(){return e.update("tlswrap")}}}var y=e("crypto");r=t.exports=d,r.sha1=function(e){return d(e)},r.keys=function(e){return d(e,{excludeValues:!0,algorithm:"sha1",encoding:"hex"})},r.MD5=function(e){return d(e,{algorithm:"md5",encoding:"hex"})},r.keysMD5=function(e){return d(e,{algorithm:"md5",encoding:"hex",excludeValues:!0})},r.HashTable=e("./lib/hashTable")}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/fake_2e2e9901.js","/")},{"./lib/hashTable":3,IrXUsu:13,buffer:4,crypto:8}],2:[function(e,t,r){(function(n,o,i,u,a,s,f,c,l){"use strict";function d(e,t){return t=t||{},t.algorithm=t.algorithm||"sha1",t.encoding=t.encoding||"hex",t.excludeValues=t.excludeValues?!0:!1,t.algorithm=t.algorithm.toLowerCase(),t.encoding=t.encoding.toLowerCase(),p(e,t),h(e,t)}function p(e,t){var r=y.getHashes?y.getHashes():["sha1","md5"],n=["buffer","hex","binary","base64"];if("undefined"==typeof e)throw new Error("Object argument required.");if(-1===r.indexOf(t.algorithm))throw new Error('Algorithm "'+t.algorithm+'"  not supported. supported values: '+r.join(", "));if(-1===n.indexOf(t.encoding))throw new Error('Encoding "'+t.encoding+'"  not supported. supported values: '+n.join(", "))}function h(e,t){var r=y.createHash(t.algorithm),n=[];return g(r,t,n).dispatch(e),"buffer"===t.encoding?r.digest():r.digest(t.encoding)}function g(e,t,r){return{dispatch:function(e){var t=typeof e,r=this["_"+t];return null===e?this._null():r(e)},_object:function(n){var o=/\[object (.*)\]/i,u=Object.prototype.toString.call(n),a=o.exec(u)[1]||"null",s=null;if(a=a.toLowerCase(),(s=r.indexOf(n))>=0)return void g(e,t,r).dispatch("[CIRCULAR]: "+s);if(r.push(n),"undefined"!=typeof i&&i.isBuffer&&i.isBuffer(n))return e.update("buffer:"),e.update(n);if("object"===a){e.update("object:");var f=Object.keys(n).sort();return f.forEach(function(o){e.update(o,"utf8"),t.excludeValues||g(e,t,r).dispatch(n[o])})}if(!g(e,t,r)["_"+a])throw new Error('Unknown object type "'+a+'"');g(e,t,r)["_"+a](n)},_array:function(n){return e.update("array:"+n.length+":"),n.forEach(function(n){g(e,t,r).dispatch(n)})},_date:function(t){return e.update("date:"+t.toJSON())},_error:function(t){return e.update("error:"+t.toString(),"utf8")},_boolean:function(t){return e.update("bool:"+t.toString())},_string:function(t){return e.update("string:"+t,"utf8")},_function:function(t){return e.update("fn:"+t.toString(),"utf8")},_number:function(t){return e.update("number:"+t.toString())},_xml:function(t){return e.update("xml:"+t.toString(),"utf8")},_null:function(){return e.update("Null")},_undefined:function(){return e.update("Undefined")},_regexp:function(t){return e.update("regex:"+t.toString(),"utf8")},_uint8array:function(n){return e.update("uint8array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint8clampedarray:function(n){return e.update("uint8clampedarray:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int8array:function(n){return e.update("uint8array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint16array:function(n){return e.update("uint16array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int16array:function(n){return e.update("uint16array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_uint32array:function(n){return e.update("uint32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_int32array:function(n){return e.update("uint32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_float32array:function(n){return e.update("float32array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_float64array:function(n){return e.update("float64array:"),g(e,t,r).dispatch(Array.prototype.slice.call(n))},_arraybuffer:function(n){return e.update("arraybuffer:"),g(e,t,r).dispatch(new Uint8Array(n))},_domwindow:function(){return e.update("domwindow")},_process:function(){return e.update("process")},_timer:function(){return e.update("timer")},_pipe:function(){return e.update("pipe")},_tcp:function(){return e.update("tcp")},_udp:function(){return e.update("udp")},_tty:function(){return e.update("tty")},_statwatcher:function(){return e.update("statwatcher")},_securecontext:function(){return e.update("securecontext")},_connection:function(){return e.update("connection")},_zlib:function(){return e.update("zlib")},_context:function(){return e.update("context")},_nodescript:function(){return e.update("nodescript")},_httpparser:function(){return e.update("httpparser")},_dataview:function(){return e.update("dataview")},_signal:function(){return e.update("signal")},_fsevent:function(){return e.update("fsevent")},_tlswrap:function(){return e.update("tlswrap")}}}var y=e("crypto");r=t.exports=d,r.sha1=function(e){return d(e)},r.keys=function(e){return d(e,{excludeValues:!0,algorithm:"sha1",encoding:"hex"})},r.MD5=function(e){return d(e,{algorithm:"md5",encoding:"hex"})},r.keysMD5=function(e){return d(e,{algorithm:"md5",encoding:"hex",excludeValues:!0})},r.HashTable=e("./lib/hashTable")}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/index.js","/")},{"./lib/hashTable":3,IrXUsu:13,buffer:4,crypto:8}],3:[function(e,t,r){(function(n,o,i,u,a,s,f,c,l){"use strict";function d(e){e=e||{},this.options=e,this._table={}}var p=e("../index");r=t.exports=d,d.prototype.add=function(){var e=this,t=Array.prototype.slice.call(arguments,0);return t.forEach(function(t){"[object Array]"===Object.prototype.toString.call(t)?t.forEach(function(t){e._addObject(t)}):e._addObject(t)}),this},d.prototype.remove=function(){var e=this,t=Array.prototype.slice.call(arguments,0);return t.forEach(function(t){"[object Array]"===Object.prototype.toString.call(t)?t.forEach(function(t){e._removeObject(t)}):e._removeObject(t)}),this},d.prototype._removeObject=function(e){var t=p(e,this.options),r=this.getCount(t);1>=r?delete this._table[t]:this._table[t].count=r-1},d.prototype._addObject=function(e){var t=p(e,this.options);this._table[t]?(this._table[t].count++,this.options.excludeValues&&this._table[t].value.push(e)):this._table[t]={value:this.options.excludeValues?[e]:e,count:1}},d.prototype.hasKey=function(e){return!!this._table[e]},d.prototype.getValue=function(e){return this._table[e]?this._table[e].value:void 0},d.prototype.getCount=function(e){return this._table[e]?this._table[e].count:0},d.prototype.table=function(){return this._table},d.prototype.toArray=function(){for(var e=Object.keys(this._table),t=[],r=0;r<e.length;r++)t.push({value:this._table[e[r]].value,count:this._table[e[r]].count,hash:e[r]});return t},d.prototype.reset=function(){return this._table={},this}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/lib/hashTable.js","/lib")},{"../index":2,IrXUsu:13,buffer:4}],4:[function(e,t,r){(function(t,n,o,i,u,a,s,f,c){function o(e,t,r){if(!(this instanceof o))return new o(e,t,r);var n=typeof e;if("base64"===t&&"string"===n)for(e=X(e);e.length%4!==0;)e+="=";var i;if("number"===n)i=N(e);else if("string"===n)i=o.byteLength(e,t);else{if("object"!==n)throw new Error("First argument needs to be a number, array or string.");i=N(e.length)}var u;o._useTypedArrays?u=o._augment(new Uint8Array(i)):(u=this,u.length=i,u._isBuffer=!0);var a;if(o._useTypedArrays&&"number"==typeof e.byteLength)u._set(e);else if(F(e))for(a=0;i>a;a++)o.isBuffer(e)?u[a]=e.readUInt8(a):u[a]=e[a];else if("string"===n)u.write(e,0,t);else if("number"===n&&!o._useTypedArrays&&!r)for(a=0;i>a;a++)u[a]=0;return u}function l(e,t,r,n){r=Number(r)||0;var i=e.length-r;n?(n=Number(n),n>i&&(n=i)):n=i;var u=t.length;G(u%2===0,"Invalid hex string"),n>u/2&&(n=u/2);for(var a=0;n>a;a++){var s=parseInt(t.substr(2*a,2),16);G(!isNaN(s),"Invalid hex string"),e[r+a]=s}return o._charsWritten=2*a,a}function d(e,t,r,n){var i=o._charsWritten=J(H(t),e,r,n);return i}function p(e,t,r,n){var i=o._charsWritten=J(R(t),e,r,n);return i}function h(e,t,r,n){return p(e,t,r,n)}function g(e,t,r,n){var i=o._charsWritten=J(z(t),e,r,n);return i}function y(e,t,r,n){var i=o._charsWritten=J(q(t),e,r,n);return i}function b(e,t,r){return Q.fromByteArray(0===t&&r===e.length?e:e.slice(t,r))}function w(e,t,r){var n="",o="";r=Math.min(e.length,r);for(var i=t;r>i;i++)e[i]<=127?(n+=W(o)+String.fromCharCode(e[i]),o=""):o+="%"+e[i].toString(16);return n+W(o)}function m(e,t,r){var n="";r=Math.min(e.length,r);for(var o=t;r>o;o++)n+=String.fromCharCode(e[o]);return n}function v(e,t,r){return m(e,t,r)}function _(e,t,r){var n=e.length;(!t||0>t)&&(t=0),(!r||0>r||r>n)&&(r=n);for(var o="",i=t;r>i;i++)o+=V(e[i]);return o}function E(e,t,r){for(var n=e.slice(t,r),o="",i=0;i<n.length;i+=2)o+=String.fromCharCode(n[i]+256*n[i+1]);return o}function I(e,t,r,n){n||(G("boolean"==typeof r,"missing or invalid endian"),G(void 0!==t&&null!==t,"missing offset"),G(t+1<e.length,"Trying to read beyond buffer length"));var o=e.length;if(!(t>=o)){var i;return r?(i=e[t],o>t+1&&(i|=e[t+1]<<8)):(i=e[t]<<8,o>t+1&&(i|=e[t+1])),i}}function A(e,t,r,n){n||(G("boolean"==typeof r,"missing or invalid endian"),G(void 0!==t&&null!==t,"missing offset"),G(t+3<e.length,"Trying to read beyond buffer length"));var o=e.length;if(!(t>=o)){var i;return r?(o>t+2&&(i=e[t+2]<<16),o>t+1&&(i|=e[t+1]<<8),i|=e[t],o>t+3&&(i+=e[t+3]<<24>>>0)):(o>t+1&&(i=e[t+1]<<16),o>t+2&&(i|=e[t+2]<<8),o>t+3&&(i|=e[t+3]),i+=e[t]<<24>>>0),i}}function B(e,t,r,n){n||(G("boolean"==typeof r,"missing or invalid endian"),G(void 0!==t&&null!==t,"missing offset"),G(t+1<e.length,"Trying to read beyond buffer length"));var o=e.length;if(!(t>=o)){var i=I(e,t,r,!0),u=32768&i;return u?-1*(65535-i+1):i}}function U(e,t,r,n){n||(G("boolean"==typeof r,"missing or invalid endian"),G(void 0!==t&&null!==t,"missing offset"),G(t+3<e.length,"Trying to read beyond buffer length"));var o=e.length;if(!(t>=o)){var i=A(e,t,r,!0),u=2147483648&i;return u?-1*(4294967295-i+1):i}}function x(e,t,r,n){return n||(G("boolean"==typeof r,"missing or invalid endian"),G(t+3<e.length,"Trying to read beyond buffer length")),Z.read(e,t,r,23,4)}function L(e,t,r,n){return n||(G("boolean"==typeof r,"missing or invalid endian"),G(t+7<e.length,"Trying to read beyond buffer length")),Z.read(e,t,r,52,8)}function j(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+1<e.length,"trying to write beyond buffer length"),P(t,65535));var i=e.length;if(!(r>=i))for(var u=0,a=Math.min(i-r,2);a>u;u++)e[r+u]=(t&255<<8*(n?u:1-u))>>>8*(n?u:1-u)}function S(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+3<e.length,"trying to write beyond buffer length"),P(t,4294967295));var i=e.length;if(!(r>=i))for(var u=0,a=Math.min(i-r,4);a>u;u++)e[r+u]=t>>>8*(n?u:3-u)&255}function C(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+1<e.length,"Trying to write beyond buffer length"),Y(t,32767,-32768));var i=e.length;r>=i||(t>=0?j(e,t,r,n,o):j(e,65535+t+1,r,n,o))}function k(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+3<e.length,"Trying to write beyond buffer length"),Y(t,2147483647,-2147483648));var i=e.length;r>=i||(t>=0?S(e,t,r,n,o):S(e,4294967295+t+1,r,n,o))}function T(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+3<e.length,"Trying to write beyond buffer length"),K(t,3.4028234663852886e38,-3.4028234663852886e38));var i=e.length;r>=i||Z.write(e,t,r,n,23,4)}function M(e,t,r,n,o){o||(G(void 0!==t&&null!==t,"missing value"),G("boolean"==typeof n,"missing or invalid endian"),G(void 0!==r&&null!==r,"missing offset"),G(r+7<e.length,"Trying to write beyond buffer length"),K(t,1.7976931348623157e308,-1.7976931348623157e308));var i=e.length;r>=i||Z.write(e,t,r,n,52,8)}function X(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}function O(e,t,r){return"number"!=typeof e?r:(e=~~e,e>=t?t:e>=0?e:(e+=t,e>=0?e:0))}function N(e){return e=~~Math.ceil(+e),0>e?0:e}function D(e){return(Array.isArray||function(e){return"[object Array]"===Object.prototype.toString.call(e)})(e)}function F(e){return D(e)||o.isBuffer(e)||e&&"object"==typeof e&&"number"==typeof e.length}function V(e){return 16>e?"0"+e.toString(16):e.toString(16)}function H(e){for(var t=[],r=0;r<e.length;r++){var n=e.charCodeAt(r);if(127>=n)t.push(e.charCodeAt(r));else{var o=r;n>=55296&&57343>=n&&r++;for(var i=encodeURIComponent(e.slice(o,r+1)).substr(1).split("%"),u=0;u<i.length;u++)t.push(parseInt(i[u],16))}}return t}function R(e){for(var t=[],r=0;r<e.length;r++)t.push(255&e.charCodeAt(r));return t}function q(e){for(var t,r,n,o=[],i=0;i<e.length;i++)t=e.charCodeAt(i),r=t>>8,n=t%256,o.push(n),o.push(r);return o}function z(e){return Q.toByteArray(e)}function J(e,t,r,n){for(var o=0;n>o&&!(o+r>=t.length||o>=e.length);o++)t[o+r]=e[o];return o}function W(e){try{return decodeURIComponent(e)}catch(t){return String.fromCharCode(65533)}}function P(e,t){G("number"==typeof e,"cannot write a non-number as a number"),G(e>=0,"specified a negative value for writing an unsigned value"),G(t>=e,"value is larger than maximum value for type"),G(Math.floor(e)===e,"value has a fractional component")}function Y(e,t,r){G("number"==typeof e,"cannot write a non-number as a number"),G(t>=e,"value larger than maximum allowed value"),G(e>=r,"value smaller than minimum allowed value"),G(Math.floor(e)===e,"value has a fractional component")}function K(e,t,r){G("number"==typeof e,"cannot write a non-number as a number"),G(t>=e,"value larger than maximum allowed value"),G(e>=r,"value smaller than minimum allowed value")}function G(e,t){if(!e)throw new Error(t||"Failed assertion")}var Q=e("base64-js"),Z=e("ieee754");r.Buffer=o,r.SlowBuffer=o,r.INSPECT_MAX_BYTES=50,o.poolSize=8192,o._useTypedArrays=function(){try{var e=new ArrayBuffer(0),t=new Uint8Array(e);return t.foo=function(){return 42},42===t.foo()&&"function"==typeof t.subarray}catch(r){return!1}}(),o.isEncoding=function(e){switch(String(e).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"binary":case"base64":case"raw":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},o.isBuffer=function(e){return!(null===e||void 0===e||!e._isBuffer)},o.byteLength=function(e,t){var r;switch(e+="",t||"utf8"){case"hex":r=e.length/2;break;case"utf8":case"utf-8":r=H(e).length;break;case"ascii":case"binary":case"raw":r=e.length;break;case"base64":r=z(e).length;break;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":r=2*e.length;break;default:throw new Error("Unknown encoding")}return r},o.concat=function(e,t){if(G(D(e),"Usage: Buffer.concat(list, [totalLength])\nlist should be an Array."),0===e.length)return new o(0);if(1===e.length)return e[0];var r;if("number"!=typeof t)for(t=0,r=0;r<e.length;r++)t+=e[r].length;var n=new o(t),i=0;for(r=0;r<e.length;r++){var u=e[r];u.copy(n,i),i+=u.length}return n},o.prototype.write=function(e,t,r,n){if(isFinite(t))isFinite(r)||(n=r,r=void 0);else{var o=n;n=t,t=r,r=o}t=Number(t)||0;var i=this.length-t;r?(r=Number(r),r>i&&(r=i)):r=i,n=String(n||"utf8").toLowerCase();var u;switch(n){case"hex":u=l(this,e,t,r);break;case"utf8":case"utf-8":u=d(this,e,t,r);break;case"ascii":u=p(this,e,t,r);break;case"binary":u=h(this,e,t,r);break;case"base64":u=g(this,e,t,r);break;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":u=y(this,e,t,r);break;default:throw new Error("Unknown encoding")}return u},o.prototype.toString=function(e,t,r){var n=this;if(e=String(e||"utf8").toLowerCase(),t=Number(t)||0,r=void 0!==r?Number(r):r=n.length,r===t)return"";var o;switch(e){case"hex":o=_(n,t,r);break;case"utf8":case"utf-8":o=w(n,t,r);break;case"ascii":o=m(n,t,r);break;case"binary":o=v(n,t,r);break;case"base64":o=b(n,t,r);break;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":o=E(n,t,r);break;default:throw new Error("Unknown encoding")}return o},o.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}},o.prototype.copy=function(e,t,r,n){var i=this;if(r||(r=0),n||0===n||(n=this.length),t||(t=0),n!==r&&0!==e.length&&0!==i.length){G(n>=r,"sourceEnd < sourceStart"),G(t>=0&&t<e.length,"targetStart out of bounds"),G(r>=0&&r<i.length,"sourceStart out of bounds"),G(n>=0&&n<=i.length,"sourceEnd out of bounds"),n>this.length&&(n=this.length),e.length-t<n-r&&(n=e.length-t+r);var u=n-r;if(100>u||!o._useTypedArrays)for(var a=0;u>a;a++)e[a+t]=this[a+r];else e._set(this.subarray(r,r+u),t)}},o.prototype.slice=function(e,t){var r=this.length;if(e=O(e,r,0),t=O(t,r,r),o._useTypedArrays)return o._augment(this.subarray(e,t));for(var n=t-e,i=new o(n,void 0,!0),u=0;n>u;u++)i[u]=this[u+e];return i},o.prototype.get=function(e){return console.log(".get() is deprecated. Access using array indexes instead."),this.readUInt8(e)},o.prototype.set=function(e,t){return console.log(".set() is deprecated. Access using array indexes instead."),this.writeUInt8(e,t)},o.prototype.readUInt8=function(e,t){return t||(G(void 0!==e&&null!==e,"missing offset"),G(e<this.length,"Trying to read beyond buffer length")),e>=this.length?void 0:this[e]},o.prototype.readUInt16LE=function(e,t){return I(this,e,!0,t)},o.prototype.readUInt16BE=function(e,t){return I(this,e,!1,t)},o.prototype.readUInt32LE=function(e,t){return A(this,e,!0,t)},o.prototype.readUInt32BE=function(e,t){return A(this,e,!1,t)},o.prototype.readInt8=function(e,t){if(t||(G(void 0!==e&&null!==e,"missing offset"),G(e<this.length,"Trying to read beyond buffer length")),!(e>=this.length)){var r=128&this[e];return r?-1*(255-this[e]+1):this[e]}},o.prototype.readInt16LE=function(e,t){return B(this,e,!0,t)},o.prototype.readInt16BE=function(e,t){return B(this,e,!1,t)},o.prototype.readInt32LE=function(e,t){return U(this,e,!0,t)},o.prototype.readInt32BE=function(e,t){return U(this,e,!1,t)},o.prototype.readFloatLE=function(e,t){return x(this,e,!0,t)},o.prototype.readFloatBE=function(e,t){return x(this,e,!1,t)},o.prototype.readDoubleLE=function(e,t){return L(this,e,!0,t)},o.prototype.readDoubleBE=function(e,t){return L(this,e,!1,t)},o.prototype.writeUInt8=function(e,t,r){r||(G(void 0!==e&&null!==e,"missing value"),G(void 0!==t&&null!==t,"missing offset"),G(t<this.length,"trying to write beyond buffer length"),P(e,255)),t>=this.length||(this[t]=e)},o.prototype.writeUInt16LE=function(e,t,r){j(this,e,t,!0,r)},o.prototype.writeUInt16BE=function(e,t,r){j(this,e,t,!1,r)},o.prototype.writeUInt32LE=function(e,t,r){S(this,e,t,!0,r)},o.prototype.writeUInt32BE=function(e,t,r){S(this,e,t,!1,r)},o.prototype.writeInt8=function(e,t,r){r||(G(void 0!==e&&null!==e,"missing value"),G(void 0!==t&&null!==t,"missing offset"),G(t<this.length,"Trying to write beyond buffer length"),Y(e,127,-128)),t>=this.length||(e>=0?this.writeUInt8(e,t,r):this.writeUInt8(255+e+1,t,r))},o.prototype.writeInt16LE=function(e,t,r){C(this,e,t,!0,r)},o.prototype.writeInt16BE=function(e,t,r){C(this,e,t,!1,r)},o.prototype.writeInt32LE=function(e,t,r){k(this,e,t,!0,r)},o.prototype.writeInt32BE=function(e,t,r){k(this,e,t,!1,r)},o.prototype.writeFloatLE=function(e,t,r){T(this,e,t,!0,r)},o.prototype.writeFloatBE=function(e,t,r){T(this,e,t,!1,r)},o.prototype.writeDoubleLE=function(e,t,r){M(this,e,t,!0,r)},o.prototype.writeDoubleBE=function(e,t,r){M(this,e,t,!1,r)},o.prototype.fill=function(e,t,r){if(e||(e=0),t||(t=0),r||(r=this.length),"string"==typeof e&&(e=e.charCodeAt(0)),G("number"==typeof e&&!isNaN(e),"value is not a number"),G(r>=t,"end < start"),r!==t&&0!==this.length){G(t>=0&&t<this.length,"start out of bounds"),G(r>=0&&r<=this.length,"end out of bounds");for(var n=t;r>n;n++)this[n]=e}},o.prototype.inspect=function(){for(var e=[],t=this.length,n=0;t>n;n++)if(e[n]=V(this[n]),n===r.INSPECT_MAX_BYTES){e[n+1]="...";break}return"<Buffer "+e.join(" ")+">"},o.prototype.toArrayBuffer=function(){if("undefined"!=typeof Uint8Array){if(o._useTypedArrays)return new o(this).buffer;for(var e=new Uint8Array(this.length),t=0,r=e.length;r>t;t+=1)e[t]=this[t];return e.buffer}throw new Error("Buffer.toArrayBuffer not supported in this browser")};var $=o.prototype;o._augment=function(e){return e._isBuffer=!0,e._get=e.get,e._set=e.set,e.get=$.get,e.set=$.set,e.write=$.write,e.toString=$.toString,e.toLocaleString=$.toString,e.toJSON=$.toJSON,e.copy=$.copy,e.slice=$.slice,e.readUInt8=$.readUInt8,e.readUInt16LE=$.readUInt16LE,e.readUInt16BE=$.readUInt16BE,e.readUInt32LE=$.readUInt32LE,e.readUInt32BE=$.readUInt32BE,e.readInt8=$.readInt8,e.readInt16LE=$.readInt16LE,e.readInt16BE=$.readInt16BE,e.readInt32LE=$.readInt32LE,e.readInt32BE=$.readInt32BE,e.readFloatLE=$.readFloatLE,e.readFloatBE=$.readFloatBE,e.readDoubleLE=$.readDoubleLE,e.readDoubleBE=$.readDoubleBE,e.writeUInt8=$.writeUInt8,e.writeUInt16LE=$.writeUInt16LE,e.writeUInt16BE=$.writeUInt16BE,e.writeUInt32LE=$.writeUInt32LE,e.writeUInt32BE=$.writeUInt32BE,e.writeInt8=$.writeInt8,e.writeInt16LE=$.writeInt16LE,e.writeInt16BE=$.writeInt16BE,e.writeInt32LE=$.writeInt32LE,e.writeInt32BE=$.writeInt32BE,e.writeFloatLE=$.writeFloatLE,e.writeFloatBE=$.writeFloatBE,e.writeDoubleLE=$.writeDoubleLE,e.writeDoubleBE=$.writeDoubleBE,e.fill=$.fill,e.inspect=$.inspect,e.toArrayBuffer=$.toArrayBuffer,e}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer/index.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer")},{IrXUsu:13,"base64-js":5,buffer:4,ieee754:6}],5:[function(e,t,r){(function(e,t,n,o,i,u,a,s,f){var c="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";!function(e){"use strict";function t(e){var t=e.charCodeAt(0);return t===i||t===l?62:t===u||t===d?63:a>t?-1:a+10>t?t-a+26+26:f+26>t?t-f:s+26>t?t-s+26:void 0}function r(e){function r(e){f[l++]=e}var n,i,u,a,s,f;if(e.length%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var c=e.length;s="="===e.charAt(c-2)?2:"="===e.charAt(c-1)?1:0,f=new o(3*e.length/4-s),u=s>0?e.length-4:e.length;var l=0;for(n=0,i=0;u>n;n+=4,i+=3)a=t(e.charAt(n))<<18|t(e.charAt(n+1))<<12|t(e.charAt(n+2))<<6|t(e.charAt(n+3)),r((16711680&a)>>16),r((65280&a)>>8),r(255&a);return 2===s?(a=t(e.charAt(n))<<2|t(e.charAt(n+1))>>4,r(255&a)):1===s&&(a=t(e.charAt(n))<<10|t(e.charAt(n+1))<<4|t(e.charAt(n+2))>>2,r(a>>8&255),r(255&a)),f}function n(e){function t(e){return c.charAt(e)}function r(e){return t(e>>18&63)+t(e>>12&63)+t(e>>6&63)+t(63&e)}var n,o,i,u=e.length%3,a="";for(n=0,i=e.length-u;i>n;n+=3)o=(e[n]<<16)+(e[n+1]<<8)+e[n+2],a+=r(o);switch(u){case 1:o=e[e.length-1],a+=t(o>>2),a+=t(o<<4&63),a+="==";break;case 2:o=(e[e.length-2]<<8)+e[e.length-1],a+=t(o>>10),a+=t(o>>4&63),a+=t(o<<2&63),a+="="}return a}var o="undefined"!=typeof Uint8Array?Uint8Array:Array,i="+".charCodeAt(0),u="/".charCodeAt(0),a="0".charCodeAt(0),s="a".charCodeAt(0),f="A".charCodeAt(0),l="-".charCodeAt(0),d="_".charCodeAt(0);e.toByteArray=r,e.fromByteArray=n}("undefined"==typeof r?this.base64js={}:r)}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib/b64.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer/node_modules/base64-js/lib")},{IrXUsu:13,buffer:4}],6:[function(e,t,r){(function(e,t,n,o,i,u,a,s,f){r.read=function(e,t,r,n,o){var i,u,a=8*o-n-1,s=(1<<a)-1,f=s>>1,c=-7,l=r?o-1:0,d=r?-1:1,p=e[t+l];for(l+=d,i=p&(1<<-c)-1,p>>=-c,c+=a;c>0;i=256*i+e[t+l],l+=d,c-=8);for(u=i&(1<<-c)-1,i>>=-c,c+=n;c>0;u=256*u+e[t+l],l+=d,c-=8);if(0===i)i=1-f;else{if(i===s)return u?NaN:(p?-1:1)*(1/0);u+=Math.pow(2,n),i-=f}return(p?-1:1)*u*Math.pow(2,i-n)},r.write=function(e,t,r,n,o,i){var u,a,s,f=8*i-o-1,c=(1<<f)-1,l=c>>1,d=23===o?Math.pow(2,-24)-Math.pow(2,-77):0,p=n?0:i-1,h=n?1:-1,g=0>t||0===t&&0>1/t?1:0;for(t=Math.abs(t),isNaN(t)||t===1/0?(a=isNaN(t)?1:0,u=c):(u=Math.floor(Math.log(t)/Math.LN2),t*(s=Math.pow(2,-u))<1&&(u--,s*=2),t+=u+l>=1?d/s:d*Math.pow(2,1-l),t*s>=2&&(u++,s/=2),u+l>=c?(a=0,u=c):u+l>=1?(a=(t*s-1)*Math.pow(2,o),u+=l):(a=t*Math.pow(2,l-1)*Math.pow(2,o),u=0));o>=8;e[r+p]=255&a,p+=h,a/=256,o-=8);for(u=u<<o|a,f+=o;f>0;e[r+p]=255&u,p+=h,u/=256,f-=8);e[r+p-h]|=128*g}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754/index.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/buffer/node_modules/ieee754")},{IrXUsu:13,buffer:4}],7:[function(e,t,r){(function(r,n,o,i,u,a,s,f,c){function l(e,t){if(e.length%h!==0){var r=e.length+(h-e.length%h);e=o.concat([e,g],r)}for(var n=[],i=t?e.readInt32BE:e.readInt32LE,u=0;u<e.length;u+=h)n.push(i.call(e,u));return n}function d(e,t,r){for(var n=new o(t),i=r?n.writeInt32BE:n.writeInt32LE,u=0;u<e.length;u++)i.call(n,e[u],4*u,!0);return n}function p(e,t,r,n){o.isBuffer(e)||(e=new o(e));var i=t(l(e,n),e.length*y);return d(i,r,n)}var o=e("buffer").Buffer,h=4,g=new o(h);g.fill(0);var y=8;t.exports={hash:p}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/helpers.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{IrXUsu:13,buffer:4}],8:[function(e,t,r){(function(t,n,o,i,u,a,s,f,c){function l(e,t,r){o.isBuffer(t)||(t=new o(t)),o.isBuffer(r)||(r=new o(r)),t.length>v?t=e(t):t.length<v&&(t=o.concat([t,_],v));for(var n=new o(v),i=new o(v),u=0;v>u;u++)n[u]=54^t[u],i[u]=92^t[u];var a=e(o.concat([n,r]));return e(o.concat([i,a]))}function d(e,t){e=e||"sha1";var r=m[e],n=[],i=0;return r||p("algorithm:",e,"is not yet supported"),{update:function(e){return o.isBuffer(e)||(e=new o(e)),n.push(e),i+=e.length,this},digest:function(e){var i=o.concat(n),u=t?l(r,t,i):r(i);return n=null,e?u.toString(e):u}}}function p(){var e=[].slice.call(arguments).join(" ");throw new Error([e,"we accept pull requests","http://github.com/dominictarr/crypto-browserify"].join("\n"))}function h(e,t){for(var r in e)t(e[r],r)}var o=e("buffer").Buffer,g=e("./sha"),y=e("./sha256"),b=e("./rng"),w=e("./md5"),m={sha1:g,sha256:y,md5:w},v=64,_=new o(v);_.fill(0),r.createHash=function(e){return d(e)},r.createHmac=function(e,t){return d(e,t)},r.randomBytes=function(e,t){if(!t||!t.call)return new o(b(e));try{t.call(this,void 0,new o(b(e)))}catch(r){t(r)}},h(["createCredentials","createCipher","createCipheriv","createDecipher","createDecipheriv","createSign","createVerify","createDiffieHellman","pbkdf2"],function(e){
r[e]=function(){p("sorry,",e,"is not implemented yet")}})}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/index.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{"./md5":9,"./rng":10,"./sha":11,"./sha256":12,IrXUsu:13,buffer:4}],9:[function(e,t,r){(function(r,n,o,i,u,a,s,f,c){function l(e,t){e[t>>5]|=128<<t%32,e[(t+64>>>9<<4)+14]=t;for(var r=1732584193,n=-271733879,o=-1732584194,i=271733878,u=0;u<e.length;u+=16){var a=r,s=n,f=o,c=i;r=p(r,n,o,i,e[u+0],7,-680876936),i=p(i,r,n,o,e[u+1],12,-389564586),o=p(o,i,r,n,e[u+2],17,606105819),n=p(n,o,i,r,e[u+3],22,-1044525330),r=p(r,n,o,i,e[u+4],7,-176418897),i=p(i,r,n,o,e[u+5],12,1200080426),o=p(o,i,r,n,e[u+6],17,-1473231341),n=p(n,o,i,r,e[u+7],22,-45705983),r=p(r,n,o,i,e[u+8],7,1770035416),i=p(i,r,n,o,e[u+9],12,-1958414417),o=p(o,i,r,n,e[u+10],17,-42063),n=p(n,o,i,r,e[u+11],22,-1990404162),r=p(r,n,o,i,e[u+12],7,1804603682),i=p(i,r,n,o,e[u+13],12,-40341101),o=p(o,i,r,n,e[u+14],17,-1502002290),n=p(n,o,i,r,e[u+15],22,1236535329),r=h(r,n,o,i,e[u+1],5,-165796510),i=h(i,r,n,o,e[u+6],9,-1069501632),o=h(o,i,r,n,e[u+11],14,643717713),n=h(n,o,i,r,e[u+0],20,-373897302),r=h(r,n,o,i,e[u+5],5,-701558691),i=h(i,r,n,o,e[u+10],9,38016083),o=h(o,i,r,n,e[u+15],14,-660478335),n=h(n,o,i,r,e[u+4],20,-405537848),r=h(r,n,o,i,e[u+9],5,568446438),i=h(i,r,n,o,e[u+14],9,-1019803690),o=h(o,i,r,n,e[u+3],14,-187363961),n=h(n,o,i,r,e[u+8],20,1163531501),r=h(r,n,o,i,e[u+13],5,-1444681467),i=h(i,r,n,o,e[u+2],9,-51403784),o=h(o,i,r,n,e[u+7],14,1735328473),n=h(n,o,i,r,e[u+12],20,-1926607734),r=g(r,n,o,i,e[u+5],4,-378558),i=g(i,r,n,o,e[u+8],11,-2022574463),o=g(o,i,r,n,e[u+11],16,1839030562),n=g(n,o,i,r,e[u+14],23,-35309556),r=g(r,n,o,i,e[u+1],4,-1530992060),i=g(i,r,n,o,e[u+4],11,1272893353),o=g(o,i,r,n,e[u+7],16,-155497632),n=g(n,o,i,r,e[u+10],23,-1094730640),r=g(r,n,o,i,e[u+13],4,681279174),i=g(i,r,n,o,e[u+0],11,-358537222),o=g(o,i,r,n,e[u+3],16,-722521979),n=g(n,o,i,r,e[u+6],23,76029189),r=g(r,n,o,i,e[u+9],4,-640364487),i=g(i,r,n,o,e[u+12],11,-421815835),o=g(o,i,r,n,e[u+15],16,530742520),n=g(n,o,i,r,e[u+2],23,-995338651),r=y(r,n,o,i,e[u+0],6,-198630844),i=y(i,r,n,o,e[u+7],10,1126891415),o=y(o,i,r,n,e[u+14],15,-1416354905),n=y(n,o,i,r,e[u+5],21,-57434055),r=y(r,n,o,i,e[u+12],6,1700485571),i=y(i,r,n,o,e[u+3],10,-1894986606),o=y(o,i,r,n,e[u+10],15,-1051523),n=y(n,o,i,r,e[u+1],21,-2054922799),r=y(r,n,o,i,e[u+8],6,1873313359),i=y(i,r,n,o,e[u+15],10,-30611744),o=y(o,i,r,n,e[u+6],15,-1560198380),n=y(n,o,i,r,e[u+13],21,1309151649),r=y(r,n,o,i,e[u+4],6,-145523070),i=y(i,r,n,o,e[u+11],10,-1120210379),o=y(o,i,r,n,e[u+2],15,718787259),n=y(n,o,i,r,e[u+9],21,-343485551),r=b(r,a),n=b(n,s),o=b(o,f),i=b(i,c)}return Array(r,n,o,i)}function d(e,t,r,n,o,i){return b(w(b(b(t,e),b(n,i)),o),r)}function p(e,t,r,n,o,i,u){return d(t&r|~t&n,e,t,o,i,u)}function h(e,t,r,n,o,i,u){return d(t&n|r&~n,e,t,o,i,u)}function g(e,t,r,n,o,i,u){return d(t^r^n,e,t,o,i,u)}function y(e,t,r,n,o,i,u){return d(r^(t|~n),e,t,o,i,u)}function b(e,t){var r=(65535&e)+(65535&t),n=(e>>16)+(t>>16)+(r>>16);return n<<16|65535&r}function w(e,t){return e<<t|e>>>32-t}var m=e("./helpers");t.exports=function(e){return m.hash(e,l,16)}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/md5.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{"./helpers":7,IrXUsu:13,buffer:4}],10:[function(e,t,r){(function(e,r,n,o,i,u,a,s,f){!function(){var e,r,n=this;e=function(e){for(var t,t,r=new Array(e),n=0;e>n;n++)0==(3&n)&&(t=4294967296*Math.random()),r[n]=t>>>((3&n)<<3)&255;return r},n.crypto&&crypto.getRandomValues&&(r=function(e){var t=new Uint8Array(e);return crypto.getRandomValues(t),t}),t.exports=r||e}()}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/rng.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{IrXUsu:13,buffer:4}],11:[function(e,t,r){(function(r,n,o,i,u,a,s,f,c){function l(e,t){e[t>>5]|=128<<24-t%32,e[(t+64>>9<<4)+15]=t;for(var r=Array(80),n=1732584193,o=-271733879,i=-1732584194,u=271733878,a=-1009589776,s=0;s<e.length;s+=16){for(var f=n,c=o,l=i,y=u,b=a,w=0;80>w;w++){16>w?r[w]=e[s+w]:r[w]=g(r[w-3]^r[w-8]^r[w-14]^r[w-16],1);var m=h(h(g(n,5),d(w,o,i,u)),h(h(a,r[w]),p(w)));a=u,u=i,i=g(o,30),o=n,n=m}n=h(n,f),o=h(o,c),i=h(i,l),u=h(u,y),a=h(a,b)}return Array(n,o,i,u,a)}function d(e,t,r,n){return 20>e?t&r|~t&n:40>e?t^r^n:60>e?t&r|t&n|r&n:t^r^n}function p(e){return 20>e?1518500249:40>e?1859775393:60>e?-1894007588:-899497514}function h(e,t){var r=(65535&e)+(65535&t),n=(e>>16)+(t>>16)+(r>>16);return n<<16|65535&r}function g(e,t){return e<<t|e>>>32-t}var y=e("./helpers");t.exports=function(e){return y.hash(e,l,20,!0)}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/sha.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{"./helpers":7,IrXUsu:13,buffer:4}],12:[function(e,t,r){(function(r,n,o,i,u,a,s,f,c){var l=e("./helpers"),d=function(e,t){var r=(65535&e)+(65535&t),n=(e>>16)+(t>>16)+(r>>16);return n<<16|65535&r},p=function(e,t){return e>>>t|e<<32-t},h=function(e,t){return e>>>t},g=function(e,t,r){return e&t^~e&r},y=function(e,t,r){return e&t^e&r^t&r},b=function(e){return p(e,2)^p(e,13)^p(e,22)},w=function(e){return p(e,6)^p(e,11)^p(e,25)},m=function(e){return p(e,7)^p(e,18)^h(e,3)},v=function(e){return p(e,17)^p(e,19)^h(e,10)},_=function(e,t){var r,n,o,i,u,a,s,f,c,l,p,h,_=new Array(1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298),E=new Array(1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225),I=new Array(64);e[t>>5]|=128<<24-t%32,e[(t+64>>9<<4)+15]=t;for(var c=0;c<e.length;c+=16){r=E[0],n=E[1],o=E[2],i=E[3],u=E[4],a=E[5],s=E[6],f=E[7];for(var l=0;64>l;l++)16>l?I[l]=e[l+c]:I[l]=d(d(d(v(I[l-2]),I[l-7]),m(I[l-15])),I[l-16]),p=d(d(d(d(f,w(u)),g(u,a,s)),_[l]),I[l]),h=d(b(r),y(r,n,o)),f=s,s=a,a=u,u=d(i,p),i=o,o=n,n=r,r=d(p,h);E[0]=d(r,E[0]),E[1]=d(n,E[1]),E[2]=d(o,E[2]),E[3]=d(i,E[3]),E[4]=d(u,E[4]),E[5]=d(a,E[5]),E[6]=d(s,E[6]),E[7]=d(f,E[7])}return E};t.exports=function(e){return l.hash(e,_,32,!0)}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify/sha256.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/crypto-browserify")},{"./helpers":7,IrXUsu:13,buffer:4}],13:[function(e,t,r){(function(e,r,n,o,i,u,a,s,f){function c(){}var e=t.exports={};e.nextTick=function(){var e="undefined"!=typeof window&&window.setImmediate,t="undefined"!=typeof window&&window.postMessage&&window.addEventListener;if(e)return function(e){return window.setImmediate(e)};if(t){var r=[];return window.addEventListener("message",function(e){var t=e.source;if((t===window||null===t)&&"process-tick"===e.data&&(e.stopPropagation(),r.length>0)){var n=r.shift();n()}},!0),function(e){r.push(e),window.postMessage("process-tick","*")}}return function(e){setTimeout(e,0)}}(),e.title="browser",e.browser=!0,e.env={},e.argv=[],e.on=c,e.addListener=c,e.once=c,e.off=c,e.removeListener=c,e.removeAllListeners=c,e.emit=c,e.binding=function(e){throw new Error("process.binding is not supported")},e.cwd=function(){return"/"},e.chdir=function(e){throw new Error("process.chdir is not supported")}}).call(this,e("IrXUsu"),"undefined"!=typeof self?self:"undefined"!=typeof window?window:{},e("buffer").Buffer,arguments[3],arguments[4],arguments[5],arguments[6],"/node_modules/gulp-browserify/node_modules/browserify/node_modules/process/browser.js","/node_modules/gulp-browserify/node_modules/browserify/node_modules/process")},{IrXUsu:13,buffer:4}]},{},[1])(1)});
//# sourceMappingURL=object_hash.js.map
/* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */
// Inspired by base2 and Prototype
(function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
 
  // The base Class implementation (does nothing)
  this.Class = function(){};
 
  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;
   
    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;
   
    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;
           
            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];
           
            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);        
            this._super = tmp;
           
            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }
   
    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }
   
    // Populate our constructed prototype object
    Class.prototype = prototype;
   
    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;
 
    // And make this class extendable
    Class.extend = arguments.callee;
   
    return Class;
  };
})();
/* @preserve
 * Leaflet 1.6.0+Detached: 0c81bdf904d864fd12a286e3d1979f47aba17991.0c81bdf, a JS library for interactive maps. http://leafletjs.com
 * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade
 */
!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?i(exports):"function"==typeof define&&define.amd?define(["exports"],i):i(t.L={})}(this,function(t){"use strict";var i=Object.freeze;function h(t){var i,e,n,o;for(e=1,n=arguments.length;e<n;e++)for(i in o=arguments[e])t[i]=o[i];return t}Object.freeze=function(t){return t};var s=Object.create||function(t){return e.prototype=t,new e};function e(){}function a(t,i){var e=Array.prototype.slice;if(t.bind)return t.bind.apply(t,e.call(arguments,1));var n=e.call(arguments,2);return function(){return t.apply(i,n.length?n.concat(e.call(arguments)):arguments)}}var n=0;function u(t){return t._leaflet_id=t._leaflet_id||++n,t._leaflet_id}function o(t,i,e){var n,o,s,r;return r=function(){n=!1,o&&(s.apply(e,o),o=!1)},s=function(){n?o=arguments:(t.apply(e,arguments),setTimeout(r,i),n=!0)}}function r(t,i,e){var n=i[1],o=i[0],s=n-o;return t===n&&e?t:((t-o)%s+s)%s+o}function l(){return!1}function c(t,i){var e=Math.pow(10,void 0===i?6:i);return Math.round(t*e)/e}function _(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}function d(t){return _(t).split(/\s+/)}function p(t,i){for(var e in t.hasOwnProperty("options")||(t.options=t.options?s(t.options):{}),i)t.options[e]=i[e];return t.options}function m(t,i,e){var n=[];for(var o in t)n.push(encodeURIComponent(e?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(i&&-1!==i.indexOf("?")?"&":"?")+n.join("&")}var f=/\{ *([\w_-]+) *\}/g;function g(t,n){return t.replace(f,function(t,i){var e=n[i];if(void 0===e)throw new Error("No value provided for variable "+t);return"function"==typeof e&&(e=e(n)),e})}var v=Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)};function y(t,i){for(var e=0;e<t.length;e++)if(t[e]===i)return e;return-1}var x="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=";function w(t){return window["webkit"+t]||window["moz"+t]||window["ms"+t]}var P=0;function b(t){var i=+new Date,e=Math.max(0,16-(i-P));return P=i+e,window.setTimeout(t,e)}var T=window.requestAnimationFrame||w("RequestAnimationFrame")||b,z=window.cancelAnimationFrame||w("CancelAnimationFrame")||w("CancelRequestAnimationFrame")||function(t){window.clearTimeout(t)};function M(t,i,e){if(!e||T!==b)return T.call(window,a(t,i));t.call(i)}function C(t){t&&z.call(window,t)}var E=(Object.freeze||Object)({freeze:i,extend:h,create:s,bind:a,lastId:n,stamp:u,throttle:o,wrapNum:r,falseFn:l,formatNum:c,trim:_,splitWords:d,setOptions:p,getParamString:m,template:g,isArray:v,indexOf:y,emptyImageUrl:x,requestFn:T,cancelFn:z,requestAnimFrame:M,cancelAnimFrame:C});function S(){}S.extend=function(t){function i(){this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()}var e=i.__super__=this.prototype,n=s(e);for(var o in(n.constructor=i).prototype=n,this)this.hasOwnProperty(o)&&"prototype"!==o&&"__super__"!==o&&(i[o]=this[o]);return t.statics&&(h(i,t.statics),delete t.statics),t.includes&&(function(t){if("undefined"==typeof L||!L||!L.Mixin)return;t=v(t)?t:[t];for(var i=0;i<t.length;i++)t[i]===L.Mixin.Events&&console.warn("Deprecated include of L.Mixin.Events: this property will be removed in future releases, please inherit from L.Evented instead.",(new Error).stack)}(t.includes),h.apply(null,[n].concat(t.includes)),delete t.includes),n.options&&(t.options=h(s(n.options),t.options)),h(n,t),n._initHooks=[],n.callInitHooks=function(){if(!this._initHooksCalled){e.callInitHooks&&e.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,i=n._initHooks.length;t<i;t++)n._initHooks[t].call(this)}},i},S.include=function(t){return h(this.prototype,t),this},S.mergeOptions=function(t){return h(this.prototype.options,t),this},S.addInitHook=function(t){var i=Array.prototype.slice.call(arguments,1),e="function"==typeof t?t:function(){this[t].apply(this,i)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(e),this};var Z={on:function(t,i,e){if("object"==typeof t)for(var n in t)this._on(n,t[n],i);else for(var o=0,s=(t=d(t)).length;o<s;o++)this._on(t[o],i,e);return this},off:function(t,i,e){if(t)if("object"==typeof t)for(var n in t)this._off(n,t[n],i);else for(var o=0,s=(t=d(t)).length;o<s;o++)this._off(t[o],i,e);else delete this._events;return this},_on:function(t,i,e){this._events=this._events||{};var n=this._events[t];n||(n=[],this._events[t]=n),e===this&&(e=void 0);for(var o={fn:i,ctx:e},s=n,r=0,a=s.length;r<a;r++)if(s[r].fn===i&&s[r].ctx===e)return;s.push(o)},_off:function(t,i,e){var n,o,s;if(this._events&&(n=this._events[t]))if(i){if(e===this&&(e=void 0),n)for(o=0,s=n.length;o<s;o++){var r=n[o];if(r.ctx===e&&r.fn===i)return r.fn=l,this._firingCount&&(this._events[t]=n=n.slice()),void n.splice(o,1)}}else{for(o=0,s=n.length;o<s;o++)n[o].fn=l;delete this._events[t]}},fire:function(t,i,e){if(!this.listens(t,e))return this;var n=h({},i,{type:t,target:this,sourceTarget:i&&i.sourceTarget||this});if(this._events){var o=this._events[t];if(o){this._firingCount=this._firingCount+1||1;for(var s=0,r=o.length;s<r;s++){var a=o[s];a.fn.call(a.ctx||this,n)}this._firingCount--}}return e&&this._propagateEvent(n),this},listens:function(t,i){var e=this._events&&this._events[t];if(e&&e.length)return!0;if(i)for(var n in this._eventParents)if(this._eventParents[n].listens(t,i))return!0;return!1},once:function(t,i,e){if("object"==typeof t){for(var n in t)this.once(n,t[n],i);return this}var o=a(function(){this.off(t,i,e).off(t,o,e)},this);return this.on(t,i,e).on(t,o,e)},addEventParent:function(t){return this._eventParents=this._eventParents||{},this._eventParents[u(t)]=t,this},removeEventParent:function(t){return this._eventParents&&delete this._eventParents[u(t)],this},_propagateEvent:function(t){for(var i in this._eventParents)this._eventParents[i].fire(t.type,h({layer:t.target,propagatedFrom:t.target},t),!0)}};Z.addEventListener=Z.on,Z.removeEventListener=Z.clearAllEventListeners=Z.off,Z.addOneTimeEventListener=Z.once,Z.fireEvent=Z.fire,Z.hasEventListeners=Z.listens;var k=S.extend(Z);function B(t,i,e){this.x=e?Math.round(t):t,this.y=e?Math.round(i):i}var A=Math.trunc||function(t){return 0<t?Math.floor(t):Math.ceil(t)};function I(t,i,e){return t instanceof B?t:v(t)?new B(t[0],t[1]):null==t?t:"object"==typeof t&&"x"in t&&"y"in t?new B(t.x,t.y):new B(t,i,e)}function O(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function R(t,i){return!t||t instanceof O?t:new O(t,i)}function N(t,i){if(t)for(var e=i?[t,i]:t,n=0,o=e.length;n<o;n++)this.extend(e[n])}function D(t,i){return t instanceof N?t:new N(t,i)}function j(t,i,e){if(isNaN(t)||isNaN(i))throw new Error("Invalid LatLng object: ("+t+", "+i+")");this.lat=+t,this.lng=+i,void 0!==e&&(this.alt=+e)}function W(t,i,e){return t instanceof j?t:v(t)&&"object"!=typeof t[0]?3===t.length?new j(t[0],t[1],t[2]):2===t.length?new j(t[0],t[1]):null:null==t?t:"object"==typeof t&&"lat"in t?new j(t.lat,"lng"in t?t.lng:t.lon,t.alt):void 0===i?null:new j(t,i,e)}B.prototype={clone:function(){return new B(this.x,this.y)},add:function(t){return this.clone()._add(I(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(I(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new B(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new B(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},trunc:function(){return this.clone()._trunc()},_trunc:function(){return this.x=A(this.x),this.y=A(this.y),this},distanceTo:function(t){var i=(t=I(t)).x-this.x,e=t.y-this.y;return Math.sqrt(i*i+e*e)},equals:function(t){return(t=I(t)).x===this.x&&t.y===this.y},contains:function(t){return t=I(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+c(this.x)+", "+c(this.y)+")"}},O.prototype={extend:function(t){return t=I(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new B((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new B(this.min.x,this.max.y)},getTopRight:function(){return new B(this.max.x,this.min.y)},getTopLeft:function(){return this.min},getBottomRight:function(){return this.max},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var i,e;return(t="number"==typeof t[0]||t instanceof B?I(t):R(t))instanceof O?(i=t.min,e=t.max):i=e=t,i.x>=this.min.x&&e.x<=this.max.x&&i.y>=this.min.y&&e.y<=this.max.y},intersects:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>=i.x&&n.x<=e.x,r=o.y>=i.y&&n.y<=e.y;return s&&r},overlaps:function(t){t=R(t);var i=this.min,e=this.max,n=t.min,o=t.max,s=o.x>i.x&&n.x<e.x,r=o.y>i.y&&n.y<e.y;return s&&r},isValid:function(){return!(!this.min||!this.max)}},N.prototype={extend:function(t){var i,e,n=this._southWest,o=this._northEast;if(t instanceof j)e=i=t;else{if(!(t instanceof N))return t?this.extend(W(t)||D(t)):this;if(i=t._southWest,e=t._northEast,!i||!e)return this}return n||o?(n.lat=Math.min(i.lat,n.lat),n.lng=Math.min(i.lng,n.lng),o.lat=Math.max(e.lat,o.lat),o.lng=Math.max(e.lng,o.lng)):(this._southWest=new j(i.lat,i.lng),this._northEast=new j(e.lat,e.lng)),this},pad:function(t){var i=this._southWest,e=this._northEast,n=Math.abs(i.lat-e.lat)*t,o=Math.abs(i.lng-e.lng)*t;return new N(new j(i.lat-n,i.lng-o),new j(e.lat+n,e.lng+o))},getCenter:function(){return new j((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new j(this.getNorth(),this.getWest())},getSouthEast:function(){return new j(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t="number"==typeof t[0]||t instanceof j||"lat"in t?W(t):D(t);var i,e,n=this._southWest,o=this._northEast;return t instanceof N?(i=t.getSouthWest(),e=t.getNorthEast()):i=e=t,i.lat>=n.lat&&e.lat<=o.lat&&i.lng>=n.lng&&e.lng<=o.lng},intersects:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>=i.lat&&n.lat<=e.lat,r=o.lng>=i.lng&&n.lng<=e.lng;return s&&r},overlaps:function(t){t=D(t);var i=this._southWest,e=this._northEast,n=t.getSouthWest(),o=t.getNorthEast(),s=o.lat>i.lat&&n.lat<e.lat,r=o.lng>i.lng&&n.lng<e.lng;return s&&r},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t,i){return!!t&&(t=D(t),this._southWest.equals(t.getSouthWest(),i)&&this._northEast.equals(t.getNorthEast(),i))},isValid:function(){return!(!this._southWest||!this._northEast)}};var H,F={latLngToPoint:function(t,i){var e=this.projection.project(t),n=this.scale(i);return this.transformation._transform(e,n)},pointToLatLng:function(t,i){var e=this.scale(i),n=this.transformation.untransform(t,e);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},unproject:function(t){return this.projection.unproject(t)},scale:function(t){return 256*Math.pow(2,t)},zoom:function(t){return Math.log(t/256)/Math.LN2},getProjectedBounds:function(t){if(this.infinite)return null;var i=this.projection.bounds,e=this.scale(t);return new O(this.transformation.transform(i.min,e),this.transformation.transform(i.max,e))},infinite:!(j.prototype={equals:function(t,i){return!!t&&(t=W(t),Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng))<=(void 0===i?1e-9:i))},toString:function(t){return"LatLng("+c(this.lat,t)+", "+c(this.lng,t)+")"},distanceTo:function(t){return U.distance(this,W(t))},wrap:function(){return U.wrapLatLng(this)},toBounds:function(t){var i=180*t/40075017,e=i/Math.cos(Math.PI/180*this.lat);return D([this.lat-i,this.lng-e],[this.lat+i,this.lng+e])},clone:function(){return new j(this.lat,this.lng,this.alt)}}),wrapLatLng:function(t){var i=this.wrapLng?r(t.lng,this.wrapLng,!0):t.lng;return new j(this.wrapLat?r(t.lat,this.wrapLat,!0):t.lat,i,t.alt)},wrapLatLngBounds:function(t){var i=t.getCenter(),e=this.wrapLatLng(i),n=i.lat-e.lat,o=i.lng-e.lng;if(0==n&&0==o)return t;var s=t.getSouthWest(),r=t.getNorthEast();return new N(new j(s.lat-n,s.lng-o),new j(r.lat-n,r.lng-o))}},U=h({},F,{wrapLng:[-180,180],R:6371e3,distance:function(t,i){var e=Math.PI/180,n=t.lat*e,o=i.lat*e,s=Math.sin((i.lat-t.lat)*e/2),r=Math.sin((i.lng-t.lng)*e/2),a=s*s+Math.cos(n)*Math.cos(o)*r*r,h=2*Math.atan2(Math.sqrt(a),Math.sqrt(1-a));return this.R*h}}),V=6378137,q={R:V,MAX_LATITUDE:85.0511287798,project:function(t){var i=Math.PI/180,e=this.MAX_LATITUDE,n=Math.max(Math.min(e,t.lat),-e),o=Math.sin(n*i);return new B(this.R*t.lng*i,this.R*Math.log((1+o)/(1-o))/2)},unproject:function(t){var i=180/Math.PI;return new j((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*i,t.x*i/this.R)},bounds:(H=V*Math.PI,new O([-H,-H],[H,H]))};function G(t,i,e,n){if(v(t))return this._a=t[0],this._b=t[1],this._c=t[2],void(this._d=t[3]);this._a=t,this._b=i,this._c=e,this._d=n}function K(t,i,e,n){return new G(t,i,e,n)}G.prototype={transform:function(t,i){return this._transform(t.clone(),i)},_transform:function(t,i){return i=i||1,t.x=i*(this._a*t.x+this._b),t.y=i*(this._c*t.y+this._d),t},untransform:function(t,i){return i=i||1,new B((t.x/i-this._b)/this._a,(t.y/i-this._d)/this._c)}};var Y,X=h({},U,{code:"EPSG:3857",projection:q,transformation:(Y=.5/(Math.PI*q.R),K(Y,.5,-Y,.5))}),J=h({},X,{code:"EPSG:900913"});function $(t){return document.createElementNS("http://www.w3.org/2000/svg",t)}function Q(t,i){var e,n,o,s,r,a,h="";for(e=0,o=t.length;e<o;e++){for(n=0,s=(r=t[e]).length;n<s;n++)h+=(n?"L":"M")+(a=r[n]).x+" "+a.y;h+=i?Zt?"z":"x":""}return h||"M0 0"}var tt=document.documentElement.style,it="ActiveXObject"in window,et=it&&!document.addEventListener,nt="msLaunchUri"in navigator&&!("documentMode"in document),ot=Bt("webkit"),st=Bt("android"),rt=Bt("android 2")||Bt("android 3"),at=parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1],10),ht=st&&Bt("Google")&&at<537&&!("AudioNode"in window),ut=!!window.opera,lt=Bt("chrome"),ct=Bt("gecko")&&!ot&&!ut&&!it,_t=!lt&&Bt("safari"),dt=Bt("phantom"),pt="OTransition"in tt,mt=0===navigator.platform.indexOf("Win"),ft=it&&"transition"in tt,gt="WebKitCSSMatrix"in window&&"m11"in new window.WebKitCSSMatrix&&!rt,vt="MozPerspective"in tt,yt=!window.L_DISABLE_3D&&(ft||gt||vt)&&!pt&&!dt,xt="undefined"!=typeof orientation||Bt("mobile"),wt=xt&&ot,Pt=xt&&gt,Lt=!window.PointerEvent&&window.MSPointerEvent,bt=!(ot||!window.PointerEvent&&!Lt),Tt=!window.L_NO_TOUCH&&(bt||"ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch),zt=xt&&ut,Mt=xt&&ct,Ct=1<(window.devicePixelRatio||window.screen.deviceXDPI/window.screen.logicalXDPI),Et=function(){var t=!1;try{var i=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("testPassiveEventSupport",l,i),window.removeEventListener("testPassiveEventSupport",l,i)}catch(t){}return t},St=!!document.createElement("canvas").getContext,Zt=!(!document.createElementNS||!$("svg").createSVGRect),kt=!Zt&&function(){try{var t=document.createElement("div");t.innerHTML='<v:shape adj="1"/>';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}();function Bt(t){return 0<=navigator.userAgent.toLowerCase().indexOf(t)}var At=(Object.freeze||Object)({ie:it,ielt9:et,edge:nt,webkit:ot,android:st,android23:rt,androidStock:ht,opera:ut,chrome:lt,gecko:ct,safari:_t,phantom:dt,opera12:pt,win:mt,ie3d:ft,webkit3d:gt,gecko3d:vt,any3d:yt,mobile:xt,mobileWebkit:wt,mobileWebkit3d:Pt,msPointer:Lt,pointer:bt,touch:Tt,mobileOpera:zt,mobileGecko:Mt,retina:Ct,passiveEvents:Et,canvas:St,svg:Zt,vml:kt}),It=Lt?"MSPointerDown":"pointerdown",Ot=Lt?"MSPointerMove":"pointermove",Rt=Lt?"MSPointerUp":"pointerup",Nt=Lt?"MSPointerCancel":"pointercancel",Dt=["INPUT","SELECT","OPTION"],jt={},Wt=!1,Ht=0;function Ft(t,i,e,n){return"touchstart"===i?function(t,i,e){var n=a(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(Dt.indexOf(t.target.tagName)<0))return;ji(t)}Gt(t,i)});t["_leaflet_touchstart"+e]=n,t.addEventListener(It,n,!1),Wt||(document.documentElement.addEventListener(It,Ut,!0),document.documentElement.addEventListener(Ot,Vt,!0),document.documentElement.addEventListener(Rt,qt,!0),document.documentElement.addEventListener(Nt,qt,!0),Wt=!0)}(t,e,n):"touchmove"===i?function(t,i,e){function n(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&Gt(t,i)}t["_leaflet_touchmove"+e]=n,t.addEventListener(Ot,n,!1)}(t,e,n):"touchend"===i&&function(t,i,e){function n(t){Gt(t,i)}t["_leaflet_touchend"+e]=n,t.addEventListener(Rt,n,!1),t.addEventListener(Nt,n,!1)}(t,e,n),this}function Ut(t){jt[t.pointerId]=t,Ht++}function Vt(t){jt[t.pointerId]&&(jt[t.pointerId]=t)}function qt(t){delete jt[t.pointerId],Ht--}function Gt(t,i){for(var e in t.touches=[],jt)t.touches.push(jt[e]);t.changedTouches=[t],i(t)}var Kt=Lt?"MSPointerDown":bt?"pointerdown":"touchstart",Yt=Lt?"MSPointerUp":bt?"pointerup":"touchend",Xt="_leaflet_";function Jt(t,o,i){var s,r,a=!1;function e(t){var i;if(bt){if(!nt||"mouse"===t.pointerType)return;i=Ht}else i=t.touches.length;if(!(1<i)){var e=Date.now(),n=e-(s||e);r=t.touches?t.touches[0]:t,a=0<n&&n<=250,s=e}}function n(t){if(a&&!r.cancelBubble){if(bt){if(!nt||"mouse"===t.pointerType)return;var i,e,n={};for(e in r)i=r[e],n[e]=i&&i.bind?i.bind(r):i;r=n}r.type="dblclick",r.button=0,o(r),s=null}}return t[Xt+Kt+i]=e,t[Xt+Yt+i]=n,t[Xt+"dblclick"+i]=o,t.addEventListener(Kt,e,!!Et&&{passive:!1}),t.addEventListener(Yt,n,!!Et&&{passive:!1}),t.addEventListener("dblclick",o,!1),this}function $t(t,i){var e=t[Xt+Kt+i],n=t[Xt+Yt+i],o=t[Xt+"dblclick"+i];return t.removeEventListener(Kt,e,!!Et&&{passive:!1}),t.removeEventListener(Yt,n,!!Et&&{passive:!1}),nt||t.removeEventListener("dblclick",o,!1),this}var Qt,ti,ii,ei,ni,oi=xi(["transform","webkitTransform","OTransform","MozTransform","msTransform"]),si=xi(["webkitTransition","transition","OTransition","MozTransition","msTransition"]),ri="webkitTransition"===si||"OTransition"===si?si+"End":"transitionend";function ai(t){return"string"==typeof t?document.getElementById(t):t}function hi(t,i){var e=t.style[i]||t.currentStyle&&t.currentStyle[i];if((!e||"auto"===e)&&document.defaultView){var n=document.defaultView.getComputedStyle(t,null);e=n?n[i]:null}return"auto"===e?null:e}function ui(t,i,e){var n=document.createElement(t);return n.className=i||"",e&&e.appendChild(n),n}function li(t){var i=t.parentNode;i&&i.removeChild(t)}function ci(t){for(;t.firstChild;)t.removeChild(t.firstChild)}function _i(t){var i=t.parentNode;i&&i.lastChild!==t&&i.appendChild(t)}function di(t){var i=t.parentNode;i&&i.firstChild!==t&&i.insertBefore(t,i.firstChild)}function pi(t,i){if(void 0!==t.classList)return t.classList.contains(i);var e=vi(t);return 0<e.length&&new RegExp("(^|\\s)"+i+"(\\s|$)").test(e)}function mi(t,i){if(void 0!==t.classList)for(var e=d(i),n=0,o=e.length;n<o;n++)t.classList.add(e[n]);else if(!pi(t,i)){var s=vi(t);gi(t,(s?s+" ":"")+i)}}function fi(t,i){void 0!==t.classList?t.classList.remove(i):gi(t,_((" "+vi(t)+" ").replace(" "+i+" "," ")))}function gi(t,i){void 0===t.className.baseVal?t.className=i:t.className.baseVal=i}function vi(t){return t.correspondingElement&&(t=t.correspondingElement),void 0===t.className.baseVal?t.className:t.className.baseVal}function yi(t,i){"opacity"in t.style?t.style.opacity=i:"filter"in t.style&&function(t,i){var e=!1,n="DXImageTransform.Microsoft.Alpha";try{e=t.filters.item(n)}catch(t){if(1===i)return}i=Math.round(100*i),e?(e.Enabled=100!==i,e.Opacity=i):t.style.filter+=" progid:"+n+"(opacity="+i+")"}(t,i)}function xi(t){for(var i=document.documentElement.style,e=0;e<t.length;e++)if(t[e]in i)return t[e];return!1}function wi(t,i,e){var n=i||new B(0,0);t.style[oi]=(ft?"translate("+n.x+"px,"+n.y+"px)":"translate3d("+n.x+"px,"+n.y+"px,0)")+(e?" scale("+e+")":"")}function Pi(t,i){t._leaflet_pos=i,yt?wi(t,i):(t.style.left=i.x+"px",t.style.top=i.y+"px")}function Li(t){return t._leaflet_pos||new B(0,0)}if("onselectstart"in document)Qt=function(){ki(window,"selectstart",ji)},ti=function(){Ai(window,"selectstart",ji)};else{var bi=xi(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]);Qt=function(){if(bi){var t=document.documentElement.style;ii=t[bi],t[bi]="none"}},ti=function(){bi&&(document.documentElement.style[bi]=ii,ii=void 0)}}function Ti(){ki(window,"dragstart",ji)}function zi(){Ai(window,"dragstart",ji)}function Mi(t){for(;-1===t.tabIndex;)t=t.parentNode;t.style&&(Ci(),ni=(ei=t).style.outline,t.style.outline="none",ki(window,"keydown",Ci))}function Ci(){ei&&(ei.style.outline=ni,ni=ei=void 0,Ai(window,"keydown",Ci))}function Ei(t){for(;!((t=t.parentNode).offsetWidth&&t.offsetHeight||t===document.body););return t}function Si(t){var i=t.getBoundingClientRect();return{x:i.width/t.offsetWidth||1,y:i.height/t.offsetHeight||1,boundingClientRect:i}}var Zi=(Object.freeze||Object)({TRANSFORM:oi,TRANSITION:si,TRANSITION_END:ri,get:ai,getStyle:hi,create:ui,remove:li,empty:ci,toFront:_i,toBack:di,hasClass:pi,addClass:mi,removeClass:fi,setClass:gi,getClass:vi,setOpacity:yi,testProp:xi,setTransform:wi,setPosition:Pi,getPosition:Li,disableTextSelection:Qt,enableTextSelection:ti,disableImageDrag:Ti,enableImageDrag:zi,preventOutline:Mi,restoreOutline:Ci,getSizedParentNode:Ei,getScale:Si});function ki(t,i,e,n){if("object"==typeof i)for(var o in i)Ii(t,o,i[o],e);else for(var s=0,r=(i=d(i)).length;s<r;s++)Ii(t,i[s],e,n);return this}var Bi="_leaflet_events";function Ai(t,i,e,n){if("object"==typeof i)for(var o in i)Oi(t,o,i[o],e);else if(i)for(var s=0,r=(i=d(i)).length;s<r;s++)Oi(t,i[s],e,n);else{for(var a in t[Bi])Oi(t,a,t[Bi][a]);delete t[Bi]}return this}function Ii(i,t,e,n){var o=t+u(e)+(n?"_"+u(n):"");if(i[Bi]&&i[Bi][o])return this;var s=function(t){return e.call(n||i,t||window.event)},r=s;bt&&0===t.indexOf("touch")?Ft(i,t,s,o):!Tt||"dblclick"!==t||bt&&lt?"addEventListener"in i?"mousewheel"===t?i.addEventListener("onwheel"in i?"wheel":"mousewheel",s,!!Et&&{passive:!1}):"mouseenter"===t||"mouseleave"===t?(s=function(t){t=t||window.event,Yi(i,t)&&r(t)},i.addEventListener("mouseenter"===t?"mouseover":"mouseout",s,!1)):("click"===t&&st&&(s=function(t){!function(t,i){var e=t.timeStamp||t.originalEvent&&t.originalEvent.timeStamp,n=Vi&&e-Vi;if(n&&100<n&&n<500||t.target._simulatedClick&&!t._simulated)return Wi(t);Vi=e,i(t)}(t,r)}),i.addEventListener(t,s,!1)):"attachEvent"in i&&i.attachEvent("on"+t,s):Jt(i,s,o),i[Bi]=i[Bi]||{},i[Bi][o]=s}function Oi(t,i,e,n){var o=i+u(e)+(n?"_"+u(n):""),s=t[Bi]&&t[Bi][o];if(!s)return this;bt&&0===i.indexOf("touch")?function(t,i,e){var n=t["_leaflet_"+i+e];"touchstart"===i?t.removeEventListener(It,n,!1):"touchmove"===i?t.removeEventListener(Ot,n,!1):"touchend"===i&&(t.removeEventListener(Rt,n,!1),t.removeEventListener(Nt,n,!1))}(t,i,o):!Tt||"dblclick"!==i||bt&&lt?"removeEventListener"in t?"mousewheel"===i?t.removeEventListener("onwheel"in t?"wheel":"mousewheel",s,!!Et&&{passive:!1}):t.removeEventListener("mouseenter"===i?"mouseover":"mouseleave"===i?"mouseout":i,s,!1):"detachEvent"in t&&t.detachEvent("on"+i,s):$t(t,o),t[Bi][o]=null}function Ri(t){return t.stopPropagation?t.stopPropagation():t.originalEvent?t.originalEvent._stopped=!0:t.cancelBubble=!0,Ki(t),this}function Ni(t){return Ii(t,"mousewheel",Ri),this}function Di(t){return ki(t,"mousedown touchstart dblclick",Ri),Ii(t,"click",Gi),this}function ji(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this}function Wi(t){return ji(t),Ri(t),this}function Hi(t,i){if(!i)return new B(t.clientX,t.clientY);var e=Si(i),n=e.boundingClientRect;return new B((t.clientX-n.left)/e.x-i.clientLeft,(t.clientY-n.top)/e.y-i.clientTop)}var Fi=mt&&lt?2*window.devicePixelRatio:ct?window.devicePixelRatio:1;function Ui(t){return nt?t.wheelDeltaY/2:t.deltaY&&0===t.deltaMode?-t.deltaY/Fi:t.deltaY&&1===t.deltaMode?20*-t.deltaY:t.deltaY&&2===t.deltaMode?60*-t.deltaY:t.deltaX||t.deltaZ?0:t.wheelDelta?(t.wheelDeltaY||t.wheelDelta)/2:t.detail&&Math.abs(t.detail)<32765?20*-t.detail:t.detail?t.detail/-32765*60:0}var Vi,qi={};function Gi(t){qi[t.type]=!0}function Ki(t){var i=qi[t.type];return qi[t.type]=!1,i}function Yi(t,i){var e=i.relatedTarget;if(!e)return!0;try{for(;e&&e!==t;)e=e.parentNode}catch(t){return!1}return e!==t}var Xi=(Object.freeze||Object)({on:ki,off:Ai,stopPropagation:Ri,disableScrollPropagation:Ni,disableClickPropagation:Di,preventDefault:ji,stop:Wi,getMousePosition:Hi,getWheelDelta:Ui,fakeStop:Gi,skipped:Ki,isExternalTarget:Yi,addListener:ki,removeListener:Ai}),Ji=k.extend({run:function(t,i,e,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=e||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=Li(t),this._offset=i.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=M(this._animate,this),this._step()},_step:function(t){var i=+new Date-this._startTime,e=1e3*this._duration;i<e?this._runFrame(this._easeOut(i/e),t):(this._runFrame(1),this._complete())},_runFrame:function(t,i){var e=this._startPos.add(this._offset.multiplyBy(t));i&&e._round(),Pi(this._el,e),this.fire("step")},_complete:function(){C(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),$i=k.extend({options:{crs:X,center:void 0,zoom:void 0,minZoom:void 0,maxZoom:void 0,layers:[],maxBounds:void 0,renderer:void 0,zoomAnimation:!0,zoomAnimationThreshold:4,fadeAnimation:!0,markerZoomAnimation:!0,transform3DLimit:8388608,zoomSnap:1,zoomDelta:1,trackResize:!0},initialize:function(t,i){i=p(this,i),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this._initContainer(t),this._initLayout(),this._onResize=a(this._onResize,this),this._initEvents(),i.maxBounds&&this.setMaxBounds(i.maxBounds),void 0!==i.zoom&&(this._zoom=this._limitZoom(i.zoom)),i.center&&void 0!==i.zoom&&this.setView(W(i.center),i.zoom,{reset:!0}),this.callInitHooks(),this._zoomAnimated=si&&yt&&!zt&&this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),ki(this._proxy,ri,this._catchTransitionEnd,this)),this._addLayers(this.options.layers)},setView:function(t,i,e){if((i=void 0===i?this._zoom:this._limitZoom(i),t=this._limitCenter(W(t),i,this.options.maxBounds),e=e||{},this._stop(),this._loaded&&!e.reset&&!0!==e)&&(void 0!==e.animate&&(e.zoom=h({animate:e.animate},e.zoom),e.pan=h({animate:e.animate,duration:e.duration},e.pan)),this._zoom!==i?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,i,e.zoom):this._tryAnimatedPan(t,e.pan)))return clearTimeout(this._sizeTimer),this;return this._resetView(t,i),this},setZoom:function(t,i){return this._loaded?this.setView(this.getCenter(),t,{zoom:i}):(this._zoom=t,this)},zoomIn:function(t,i){return t=t||(yt?this.options.zoomDelta:1),this.setZoom(this._zoom+t,i)},zoomOut:function(t,i){return t=t||(yt?this.options.zoomDelta:1),this.setZoom(this._zoom-t,i)},setZoomAround:function(t,i,e){var n=this.getZoomScale(i),o=this.getSize().divideBy(2),s=(t instanceof B?t:this.latLngToContainerPoint(t)).subtract(o).multiplyBy(1-1/n),r=this.containerPointToLatLng(o.add(s));return this.setView(r,i,{zoom:e})},_getBoundsCenterZoom:function(t,i){i=i||{},t=t.getBounds?t.getBounds():D(t);var e=I(i.paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getBoundsZoom(t,!1,e.add(n));if((o="number"==typeof i.maxZoom?Math.min(i.maxZoom,o):o)===1/0)return{center:t.getCenter(),zoom:o};var s=n.subtract(e).divideBy(2),r=this.project(t.getSouthWest(),o),a=this.project(t.getNorthEast(),o);return{center:this.unproject(r.add(a).divideBy(2).add(s),o),zoom:o}},fitBounds:function(t,i){if(!(t=D(t)).isValid())throw new Error("Bounds are not valid.");var e=this._getBoundsCenterZoom(t,i);return this.setView(e.center,e.zoom,i)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,i){return this.setView(t,this._zoom,{pan:i})},panBy:function(t,i){if(i=i||{},!(t=I(t).round()).x&&!t.y)return this.fire("moveend");if(!0!==i.animate&&!this.getSize().contains(t))return this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom()),this;if(this._panAnim||(this._panAnim=new Ji,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),i.noMoveStart||this.fire("movestart"),!1!==i.animate){mi(this._mapPane,"leaflet-pan-anim");var e=this._getMapPanePos().subtract(t).round();this._panAnim.run(this._mapPane,e,i.duration||.25,i.easeLinearity)}else this._rawPanBy(t),this.fire("move").fire("moveend");return this},flyTo:function(n,o,t){if(!1===(t=t||{}).animate||!yt)return this.setView(n,o,t);this._stop();var s=this.project(this.getCenter()),r=this.project(n),i=this.getSize(),a=this._zoom;n=W(n),o=void 0===o?a:o;var h=Math.max(i.x,i.y),u=h*this.getZoomScale(a,o),l=r.distanceTo(s)||1,c=1.42,_=c*c;function e(t){var i=(u*u-h*h+(t?-1:1)*_*_*l*l)/(2*(t?u:h)*_*l),e=Math.sqrt(i*i+1)-i;return e<1e-9?-18:Math.log(e)}function d(t){return(Math.exp(t)-Math.exp(-t))/2}function p(t){return(Math.exp(t)+Math.exp(-t))/2}var m=e(0);function f(t){return h*(p(m)*function(t){return d(t)/p(t)}(m+c*t)-d(m))/_}var g=Date.now(),v=(e(1)-m)/c,y=t.duration?1e3*t.duration:1e3*v*.8;return this._moveStart(!0,t.noMoveStart),function t(){var i=(Date.now()-g)/y,e=function(t){return 1-Math.pow(1-t,1.5)}(i)*v;i<=1?(this._flyToFrame=M(t,this),this._move(this.unproject(s.add(r.subtract(s).multiplyBy(f(e)/l)),a),this.getScaleZoom(h/function(t){return h*(p(m)/p(m+c*t))}(e),a),{flyTo:!0})):this._move(n,o)._moveEnd(!0)}.call(this),this},flyToBounds:function(t,i){var e=this._getBoundsCenterZoom(t,i);return this.flyTo(e.center,e.zoom,i)},setMaxBounds:function(t){return(t=D(t)).isValid()?(this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this.options.maxBounds=t,this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds)):(this.options.maxBounds=null,this.off("moveend",this._panInsideMaxBounds))},setMinZoom:function(t){var i=this.options.minZoom;return this.options.minZoom=t,this._loaded&&i!==t&&(this.fire("zoomlevelschange"),this.getZoom()<this.options.minZoom)?this.setZoom(t):this},setMaxZoom:function(t){var i=this.options.maxZoom;return this.options.maxZoom=t,this._loaded&&i!==t&&(this.fire("zoomlevelschange"),this.getZoom()>this.options.maxZoom)?this.setZoom(t):this},panInsideBounds:function(t,i){this._enforcingBounds=!0;var e=this.getCenter(),n=this._limitCenter(e,this._zoom,D(t));return e.equals(n)||this.panTo(n,i),this._enforcingBounds=!1,this},panInside:function(t,i){var e=I((i=i||{}).paddingTopLeft||i.padding||[0,0]),n=I(i.paddingBottomRight||i.padding||[0,0]),o=this.getCenter(),s=this.project(o),r=this.project(t),a=this.getPixelBounds(),h=a.getSize().divideBy(2),u=R([a.min.add(e),a.max.subtract(n)]);if(!u.contains(r)){this._enforcingBounds=!0;var l=s.subtract(r),c=I(r.x+l.x,r.y+l.y);(r.x<u.min.x||r.x>u.max.x)&&(c.x=s.x-l.x,0<l.x?c.x+=h.x-e.x:c.x-=h.x-n.x),(r.y<u.min.y||r.y>u.max.y)&&(c.y=s.y-l.y,0<l.y?c.y+=h.y-e.y:c.y-=h.y-n.y),this.panTo(this.unproject(c),i),this._enforcingBounds=!1}return this},invalidateSize:function(t){if(!this._loaded)return this;t=h({animate:!1,pan:!0},!0===t?{animate:!0}:t);var i=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var e=this.getSize(),n=i.divideBy(2).round(),o=e.divideBy(2).round(),s=n.subtract(o);return s.x||s.y?(t.animate&&t.pan?this.panBy(s):(t.pan&&this._rawPanBy(s),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(a(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:i,newSize:e})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=h({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var i=a(this._handleGeolocationResponse,this),e=a(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(i,e,t):navigator.geolocation.getCurrentPosition(i,e,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var i=t.code,e=t.message||(1===i?"permission denied":2===i?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:i,message:"Geolocation error: "+e+"."})},_handleGeolocationResponse:function(t){var i=new j(t.coords.latitude,t.coords.longitude),e=i.toBounds(2*t.coords.accuracy),n=this._locateOptions;if(n.setView){var o=this.getBoundsZoom(e);this.setView(i,n.maxZoom?Math.min(o,n.maxZoom):o)}var s={latlng:i,bounds:e,timestamp:t.timestamp};for(var r in t.coords)"number"==typeof t.coords[r]&&(s[r]=t.coords[r]);this.fire("locationfound",s)},addHandler:function(t,i){if(!i)return this;var e=this[t]=new i(this);return this._handlers.push(e),this.options[t]&&e.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=void 0,this._containerId=void 0}var t;for(t in void 0!==this._locationWatchId&&this.stopLocate(),this._stop(),li(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._resizeRequest&&(C(this._resizeRequest),this._resizeRequest=null),this._clearHandlers(),this._loaded&&this.fire("unload"),this._layers)this._layers[t].remove();for(t in this._panes)li(this._panes[t]);return this._layers=[],this._panes=[],delete this._mapPane,delete this._renderer,this},createPane:function(t,i){var e=ui("div","leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),i||this._mapPane);return t&&(this._panes[t]=e),e},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds();return new N(this.unproject(t.getBottomLeft()),this.unproject(t.getTopRight()))},getMinZoom:function(){return void 0===this.options.minZoom?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return void 0===this.options.maxZoom?void 0===this._layersMaxZoom?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,i,e){t=D(t),e=I(e||[0,0]);var n=this.getZoom()||0,o=this.getMinZoom(),s=this.getMaxZoom(),r=t.getNorthWest(),a=t.getSouthEast(),h=this.getSize().subtract(e),u=R(this.project(a,n),this.project(r,n)).getSize(),l=yt?this.options.zoomSnap:1,c=h.x/u.x,_=h.y/u.y,d=i?Math.max(c,_):Math.min(c,_);return n=this.getScaleZoom(d,n),l&&(n=Math.round(n/(l/100))*(l/100),n=i?Math.ceil(n/l)*l:Math.floor(n/l)*l),Math.max(o,Math.min(s,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new B(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,i){var e=this._getTopLeftPoint(t,i);return new O(e,e.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(void 0===t?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,i){var e=this.options.crs;return i=void 0===i?this._zoom:i,e.scale(t)/e.scale(i)},getScaleZoom:function(t,i){var e=this.options.crs;i=void 0===i?this._zoom:i;var n=e.zoom(t*e.scale(i));return isNaN(n)?1/0:n},project:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.latLngToPoint(W(t),i)},unproject:function(t,i){return i=void 0===i?this._zoom:i,this.options.crs.pointToLatLng(I(t),i)},layerPointToLatLng:function(t){var i=I(t).add(this.getPixelOrigin());return this.unproject(i)},latLngToLayerPoint:function(t){return this.project(W(t))._round()._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(W(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(D(t))},distance:function(t,i){return this.options.crs.distance(W(t),W(i))},containerPointToLayerPoint:function(t){return I(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return I(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var i=this.containerPointToLayerPoint(I(t));return this.layerPointToLatLng(i)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(W(t)))},mouseEventToContainerPoint:function(t){return Hi(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var i=this._container=ai(t);if(!i)throw new Error("Map container not found.");if(i._leaflet_id)throw new Error("Map container is already initialized.");ki(i,"scroll",this._onScroll,this),this._containerId=u(i)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&yt,mi(t,"leaflet-container"+(Tt?" leaflet-touch":"")+(Ct?" leaflet-retina":"")+(et?" leaflet-oldie":"")+(_t?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var i=hi(t,"position");"absolute"!==i&&"relative"!==i&&"fixed"!==i&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),Pi(this._mapPane,new B(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(mi(t.markerPane,"leaflet-zoom-hide"),mi(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,i){Pi(this._mapPane,new B(0,0));var e=!this._loaded;this._loaded=!0,i=this._limitZoom(i),this.fire("viewprereset");var n=this._zoom!==i;this._moveStart(n,!1)._move(t,i)._moveEnd(n),this.fire("viewreset"),e&&this.fire("load")},_moveStart:function(t,i){return t&&this.fire("zoomstart"),i||this.fire("movestart"),this},_move:function(t,i,e){void 0===i&&(i=this._zoom);var n=this._zoom!==i;return this._zoom=i,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(n||e&&e.pinch)&&this.fire("zoom",e),this.fire("move",e)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return C(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){Pi(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(t){this._targets={};var i=t?Ai:ki;i((this._targets[u(this._container)]=this)._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress keydown keyup",this._handleDOMEvent,this),this.options.trackResize&&i(window,"resize",this._onResize,this),yt&&this.options.transform3DLimit&&(t?this.off:this.on).call(this,"moveend",this._onMoveEnd)},_onResize:function(){C(this._resizeRequest),this._resizeRequest=M(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,i){for(var e,n=[],o="mouseout"===i||"mouseover"===i,s=t.target||t.srcElement,r=!1;s;){if((e=this._targets[u(s)])&&("click"===i||"preclick"===i)&&!t._simulated&&this._draggableMoved(e)){r=!0;break}if(e&&e.listens(i,!0)){if(o&&!Yi(s,t))break;if(n.push(e),o)break}if(s===this._container)break;s=s.parentNode}return n.length||r||o||!Yi(s,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!Ki(t)){var i=t.type;"mousedown"!==i&&"keypress"!==i&&"keyup"!==i&&"keydown"!==i||Mi(t.target||t.srcElement),this._fireDOMEvent(t,i)}},_mouseEvents:["click","dblclick","mouseover","mouseout","contextmenu"],_fireDOMEvent:function(t,i,e){if("click"===t.type){var n=h({},t);n.type="preclick",this._fireDOMEvent(n,n.type,e)}if(!t._stopped&&(e=(e||[]).concat(this._findEventTargets(t,i))).length){var o=e[0];"contextmenu"===i&&o.listens(i,!0)&&ji(t);var s={originalEvent:t};if("keypress"!==t.type&&"keydown"!==t.type&&"keyup"!==t.type){var r=o.getLatLng&&(!o._radius||o._radius<=10);s.containerPoint=r?this.latLngToContainerPoint(o.getLatLng()):this.mouseEventToContainerPoint(t),s.layerPoint=this.containerPointToLayerPoint(s.containerPoint),s.latlng=r?o.getLatLng():this.layerPointToLatLng(s.layerPoint)}for(var a=0;a<e.length;a++)if(e[a].fire(i,s,!0),s.originalEvent._stopped||!1===e[a].options.bubblingMouseEvents&&-1!==y(this._mouseEvents,i))return}},_draggableMoved:function(t){return(t=t.dragging&&t.dragging.enabled()?t:this).dragging&&t.dragging.moved()||this.boxZoom&&this.boxZoom.moved()},_clearHandlers:function(){for(var t=0,i=this._handlers.length;t<i;t++)this._handlers[t].disable()},whenReady:function(t,i){return this._loaded?t.call(i||this,{target:this}):this.on("load",t,i),this},_getMapPanePos:function(){return Li(this._mapPane)||new B(0,0)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(t,i){return(t&&void 0!==i?this._getNewPixelOrigin(t,i):this.getPixelOrigin()).subtract(this._getMapPanePos())},_getNewPixelOrigin:function(t,i){var e=this.getSize()._divideBy(2);return this.project(t,i)._subtract(e)._add(this._getMapPanePos())._round()},_latLngToNewLayerPoint:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return this.project(t,i)._subtract(n)},_latLngBoundsToNewLayerBounds:function(t,i,e){var n=this._getNewPixelOrigin(e,i);return R([this.project(t.getSouthWest(),i)._subtract(n),this.project(t.getNorthWest(),i)._subtract(n),this.project(t.getSouthEast(),i)._subtract(n),this.project(t.getNorthEast(),i)._subtract(n)])},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,i,e){if(!e)return t;var n=this.project(t,i),o=this.getSize().divideBy(2),s=new O(n.subtract(o),n.add(o)),r=this._getBoundsOffset(s,e,i);return r.round().equals([0,0])?t:this.unproject(n.add(r),i)},_limitOffset:function(t,i){if(!i)return t;var e=this.getPixelBounds(),n=new O(e.min.add(t),e.max.add(t));return t.add(this._getBoundsOffset(n,i))},_getBoundsOffset:function(t,i,e){var n=R(this.project(i.getNorthEast(),e),this.project(i.getSouthWest(),e)),o=n.min.subtract(t.min),s=n.max.subtract(t.max);return new B(this._rebound(o.x,-s.x),this._rebound(o.y,-s.y))},_rebound:function(t,i){return 0<t+i?Math.round(t-i)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(i))},_limitZoom:function(t){var i=this.getMinZoom(),e=this.getMaxZoom(),n=yt?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(i,Math.min(e,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){fi(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,i){var e=this._getCenterOffset(t)._trunc();return!(!0!==(i&&i.animate)&&!this.getSize().contains(e))&&(this.panBy(e,i),!0)},_createAnimProxy:function(){var t=this._proxy=ui("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(t){var i=oi,e=this._proxy.style[i];wi(this._proxy,this.project(t.center,t.zoom),this.getZoomScale(t.zoom,1)),e===this._proxy.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",this._animMoveEnd,this),this._on("unload",this._destroyAnimProxy,this)},_destroyAnimProxy:function(){li(this._proxy),this.off("load moveend",this._animMoveEnd,this),delete this._proxy},_animMoveEnd:function(){var t=this.getCenter(),i=this.getZoom();wi(this._proxy,this.project(t,i),this.getZoomScale(i,1))},_catchTransitionEnd:function(t){this._animatingZoom&&0<=t.propertyName.indexOf("transform")&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,i,e){if(this._animatingZoom)return!0;if(e=e||{},!this._zoomAnimated||!1===e.animate||this._nothingToAnimate()||Math.abs(i-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(i),o=this._getCenterOffset(t)._divideBy(1-1/n);return!(!0!==e.animate&&!this.getSize().contains(o))&&(M(function(){this._moveStart(!0,!1)._animateZoom(t,i,!0)},this),!0)},_animateZoom:function(t,i,e,n){this._mapPane&&(e&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=i,mi(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:i,noUpdate:n}),setTimeout(a(this._onZoomTransitionEnd,this),250))},_onZoomTransitionEnd:function(){this._animatingZoom&&(this._mapPane&&fi(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),M(function(){this._moveEnd(!0)},this))}});function Qi(t){return new te(t)}var te=S.extend({options:{position:"topright"},initialize:function(t){p(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var i=this._map;return i&&i.removeControl(this),this.options.position=t,i&&i.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var i=this._container=this.onAdd(t),e=this.getPosition(),n=t._controlCorners[e];return mi(i,"leaflet-control"),-1!==e.indexOf("bottom")?n.insertBefore(i,n.firstChild):n.appendChild(i),this._map.on("unload",this.remove,this),this},remove:function(){return this._map&&(li(this._container),this.onRemove&&this.onRemove(this._map),this._map.off("unload",this.remove,this),this._map=null),this},_refocusOnMap:function(t){this._map&&t&&0<t.screenX&&0<t.screenY&&this._map.getContainer().focus()}});$i.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){var n=this._controlCorners={},o="leaflet-",s=this._controlContainer=ui("div",o+"control-container",this._container);function t(t,i){var e=o+t+" "+o+i;n[t+i]=ui("div",e,s)}t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){for(var t in this._controlCorners)li(this._controlCorners[t]);li(this._controlContainer),delete this._controlCorners,delete this._controlContainer}});var ie=te.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,i,e,n){return e<n?-1:n<e?1:0}},initialize:function(t,i,e){for(var n in p(this,e),this._layerControlInputs=[],this._layers=[],this._lastZIndex=0,this._handlingClick=!1,t)this._addLayer(t[n],n);for(n in i)this._addLayer(i[n],n,!0)},onAdd:function(t){this._initLayout(),this._update(),(this._map=t).on("zoomend",this._checkDisabledLayers,this);for(var i=0;i<this._layers.length;i++)this._layers[i].layer.on("add remove",this._onLayerChange,this);return this._container},addTo:function(t){return te.prototype.addTo.call(this,t),this._expandIfNotCollapsed()},onRemove:function(){this._map.off("zoomend",this._checkDisabledLayers,this);for(var t=0;t<this._layers.length;t++)this._layers[t].layer.off("add remove",this._onLayerChange,this)},addBaseLayer:function(t,i){return this._addLayer(t,i),this._map?this._update():this},addOverlay:function(t,i){return this._addLayer(t,i,!0),this._map?this._update():this},removeLayer:function(t){t.off("add remove",this._onLayerChange,this);var i=this._getLayer(u(t));return i&&this._layers.splice(this._layers.indexOf(i),1),this._map?this._update():this},expand:function(){mi(this._container,"leaflet-control-layers-expanded"),this._section.style.height=null;var t=this._map.getSize().y-(this._container.offsetTop+50);return t<this._section.clientHeight?(mi(this._section,"leaflet-control-layers-scrollbar"),this._section.style.height=t+"px"):fi(this._section,"leaflet-control-layers-scrollbar"),this._checkDisabledLayers(),this},collapse:function(){return fi(this._container,"leaflet-control-layers-expanded"),this},_initLayout:function(){var t="leaflet-control-layers",i=this._container=ui("div",t),e=this.options.collapsed;i.setAttribute("aria-haspopup",!0),Di(i),Ni(i);var n=this._section=ui("section",t+"-list");e&&(this._map.on("click",this.collapse,this),st||ki(i,{mouseenter:this.expand,mouseleave:this.collapse},this));var o=this._layersLink=ui("a",t+"-toggle",i);o.href="#",o.title="Layers",Tt?(ki(o,"click",Wi),ki(o,"click",this.expand,this)):ki(o,"focus",this.expand,this),e||this.expand(),this._baseLayersList=ui("div",t+"-base",n),this._separator=ui("div",t+"-separator",n),this._overlaysList=ui("div",t+"-overlays",n),i.appendChild(n)},_getLayer:function(t){for(var i=0;i<this._layers.length;i++)if(this._layers[i]&&u(this._layers[i].layer)===t)return this._layers[i]},_addLayer:function(t,i,e){this._map&&t.on("add remove",this._onLayerChange,this),this._layers.push({layer:t,name:i,overlay:e}),this.options.sortLayers&&this._layers.sort(a(function(t,i){return this.options.sortFunction(t.layer,i.layer,t.name,i.name)},this)),this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex)),this._expandIfNotCollapsed()},_update:function(){if(!this._container)return this;ci(this._baseLayersList),ci(this._overlaysList),this._layerControlInputs=[];var t,i,e,n,o=0;for(e=0;e<this._layers.length;e++)n=this._layers[e],this._addItem(n),i=i||n.overlay,t=t||!n.overlay,o+=n.overlay?0:1;return this.options.hideSingleBase&&(t=t&&1<o,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=i&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var i=this._getLayer(u(t.target)),e=i.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;e&&this._map.fire(e,i)},_createRadioElement:function(t,i){var e='<input type="radio" class="leaflet-control-layers-selector" name="'+t+'"'+(i?' checked="checked"':"")+"/>",n=document.createElement("div");return n.innerHTML=e,n.firstChild},_addItem:function(t){var i,e=document.createElement("label"),n=this._map.hasLayer(t.layer);t.overlay?((i=document.createElement("input")).type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=n):i=this._createRadioElement("leaflet-base-layers_"+u(this),n),this._layerControlInputs.push(i),i.layerId=u(t.layer),ki(i,"click",this._onInputClick,this);var o=document.createElement("span");o.innerHTML=" "+t.name;var s=document.createElement("div");return e.appendChild(s),s.appendChild(i),s.appendChild(o),(t.overlay?this._overlaysList:this._baseLayersList).appendChild(e),this._checkDisabledLayers(),e},_onInputClick:function(){var t,i,e=this._layerControlInputs,n=[],o=[];this._handlingClick=!0;for(var s=e.length-1;0<=s;s--)t=e[s],i=this._getLayer(t.layerId).layer,t.checked?n.push(i):t.checked||o.push(i);for(s=0;s<o.length;s++)this._map.hasLayer(o[s])&&this._map.removeLayer(o[s]);for(s=0;s<n.length;s++)this._map.hasLayer(n[s])||this._map.addLayer(n[s]);this._handlingClick=!1,this._refocusOnMap()},_checkDisabledLayers:function(){for(var t,i,e=this._layerControlInputs,n=this._map.getZoom(),o=e.length-1;0<=o;o--)t=e[o],i=this._getLayer(t.layerId).layer,t.disabled=void 0!==i.options.minZoom&&n<i.options.minZoom||void 0!==i.options.maxZoom&&n>i.options.maxZoom},_expandIfNotCollapsed:function(){return this._map&&!this.options.collapsed&&this.expand(),this},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),ee=te.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"&#x2212;",zoomOutTitle:"Zoom out"},onAdd:function(t){var i="leaflet-control-zoom",e=ui("div",i+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,i+"-in",e,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,i+"-out",e,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),e},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoom<this._map.getMaxZoom()&&this._map.zoomIn(this._map.options.zoomDelta*(t.shiftKey?3:1))},_zoomOut:function(t){!this._disabled&&this._map._zoom>this._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,i,e,n,o){var s=ui("a",e,n);return s.innerHTML=t,s.href="#",s.title=i,s.setAttribute("role","button"),s.setAttribute("aria-label",i),Di(s),ki(s,"click",Wi),ki(s,"click",o,this),ki(s,"click",this._refocusOnMap,this),s},_updateDisabled:function(){var t=this._map,i="leaflet-disabled";fi(this._zoomInButton,i),fi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMinZoom()||mi(this._zoomOutButton,i),!this._disabled&&t._zoom!==t.getMaxZoom()||mi(this._zoomInButton,i)}});$i.mergeOptions({zoomControl:!0}),$i.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new ee,this.addControl(this.zoomControl))});var ne=te.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var i="leaflet-control-scale",e=ui("div",i),n=this.options;return this._addScales(n,i+"-line",e),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),e},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,i,e){t.metric&&(this._mScale=ui("div",i,e)),t.imperial&&(this._iScale=ui("div",i,e))},_update:function(){var t=this._map,i=t.getSize().y/2,e=t.distance(t.containerPointToLatLng([0,i]),t.containerPointToLatLng([this.options.maxWidth,i]));this._updateScales(e)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var i=this._getRoundNum(t),e=i<1e3?i+" m":i/1e3+" km";this._updateScale(this._mScale,e,i/t)},_updateImperial:function(t){var i,e,n,o=3.2808399*t;5280<o?(i=o/5280,e=this._getRoundNum(i),this._updateScale(this._iScale,e+" mi",e/i)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,i,e){t.style.width=Math.round(this.options.maxWidth*e)+"px",t.innerHTML=i},_getRoundNum:function(t){var i=Math.pow(10,(Math.floor(t)+"").length-1),e=t/i;return i*(e=10<=e?10:5<=e?5:3<=e?3:2<=e?2:1)}}),oe=te.extend({options:{position:"bottomright",prefix:'<a href="https://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'},initialize:function(t){p(this,t),this._attributions={}},onAdd:function(t){for(var i in(t.attributionControl=this)._container=ui("div","leaflet-control-attribution"),Di(this._container),t._layers)t._layers[i].getAttribution&&this.addAttribution(t._layers[i].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t&&(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update()),this},removeAttribution:function(t){return t&&this._attributions[t]&&(this._attributions[t]--,this._update()),this},_update:function(){if(this._map){var t=[];for(var i in this._attributions)this._attributions[i]&&t.push(i);var e=[];this.options.prefix&&e.push(this.options.prefix),t.length&&e.push(t.join(", ")),this._container.innerHTML=e.join(" | ")}}});$i.mergeOptions({attributionControl:!0}),$i.addInitHook(function(){this.options.attributionControl&&(new oe).addTo(this)});te.Layers=ie,te.Zoom=ee,te.Scale=ne,te.Attribution=oe,Qi.layers=function(t,i,e){return new ie(t,i,e)},Qi.zoom=function(t){return new ee(t)},Qi.scale=function(t){return new ne(t)},Qi.attribution=function(t){return new oe(t)};var se=S.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled||(this._enabled=!0,this.addHooks()),this},disable:function(){return this._enabled&&(this._enabled=!1,this.removeHooks()),this},enabled:function(){return!!this._enabled}});se.addTo=function(t,i){return t.addHandler(i,this),this};var re,ae={Events:Z},he=Tt?"touchstart mousedown":"mousedown",ue={mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},le={mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"},ce=k.extend({options:{clickTolerance:3},initialize:function(t,i,e,n){p(this,n),this._element=t,this._dragStartTarget=i||t,this._preventOutline=e},enable:function(){this._enabled||(ki(this._dragStartTarget,he,this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(ce._dragging===this&&this.finishDrag(),Ai(this._dragStartTarget,he,this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!pi(this._element,"leaflet-zoom-anim")&&!(ce._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||((ce._dragging=this)._preventOutline&&Mi(this._element),Ti(),Qt(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t,e=Ei(this._element);this._startPoint=new B(i.clientX,i.clientY),this._parentScale=Si(e),ki(document,le[t.type],this._onMove,this),ki(document,ue[t.type],this._onUp,this)}},_onMove:function(t){if(!t._simulated&&this._enabled)if(t.touches&&1<t.touches.length)this._moved=!0;else{var i=t.touches&&1===t.touches.length?t.touches[0]:t,e=new B(i.clientX,i.clientY)._subtract(this._startPoint);(e.x||e.y)&&(Math.abs(e.x)+Math.abs(e.y)<this.options.clickTolerance||(e.x/=this._parentScale.x,e.y/=this._parentScale.y,ji(t),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=Li(this._element).subtract(e),mi(document.body,"leaflet-dragging"),this._lastTarget=t.target||t.srcElement,window.SVGElementInstance&&this._lastTarget instanceof SVGElementInstance&&(this._lastTarget=this._lastTarget.correspondingUseElement),mi(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(e),this._moving=!0,C(this._animRequest),this._lastEvent=t,this._animRequest=M(this._updatePosition,this,!0)))}},_updatePosition:function(){var t={originalEvent:this._lastEvent};this.fire("predrag",t),Pi(this._element,this._newPos),this.fire("drag",t)},_onUp:function(t){!t._simulated&&this._enabled&&this.finishDrag()},finishDrag:function(){for(var t in fi(document.body,"leaflet-dragging"),this._lastTarget&&(fi(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null),le)Ai(document,le[t],this._onMove,this),Ai(document,ue[t],this._onUp,this);zi(),ti(),this._moved&&this._moving&&(C(this._animRequest),this.fire("dragend",{distance:this._newPos.distanceTo(this._startPos)})),this._moving=!1,ce._dragging=!1}});function _e(t,i){if(!i||!t.length)return t.slice();var e=i*i;return t=function(t,i){var e=t.length,n=new(typeof Uint8Array!=void 0+""?Uint8Array:Array)(e);n[0]=n[e-1]=1,function t(i,e,n,o,s){var r,a,h,u=0;for(a=o+1;a<=s-1;a++)h=ge(i[a],i[o],i[s],!0),u<h&&(r=a,u=h);n<u&&(e[r]=1,t(i,e,n,o,r),t(i,e,n,r,s))}(t,n,i,0,e-1);var o,s=[];for(o=0;o<e;o++)n[o]&&s.push(t[o]);return s}(t=function(t,i){for(var e=[t[0]],n=1,o=0,s=t.length;n<s;n++)r=t[n],a=t[o],void 0,h=a.x-r.x,u=a.y-r.y,i<h*h+u*u&&(e.push(t[n]),o=n);var r,a,h,u;o<s-1&&e.push(t[s-1]);return e}(t,e),e)}function de(t,i,e){return Math.sqrt(ge(t,i,e,!0))}function pe(t,i,e,n,o){var s,r,a,h=n?re:fe(t,e),u=fe(i,e);for(re=u;;){if(!(h|u))return[t,i];if(h&u)return!1;a=fe(r=me(t,i,s=h||u,e,o),e),s===h?(t=r,h=a):(i=r,u=a)}}function me(t,i,e,n,o){var s,r,a=i.x-t.x,h=i.y-t.y,u=n.min,l=n.max;return 8&e?(s=t.x+a*(l.y-t.y)/h,r=l.y):4&e?(s=t.x+a*(u.y-t.y)/h,r=u.y):2&e?(s=l.x,r=t.y+h*(l.x-t.x)/a):1&e&&(s=u.x,r=t.y+h*(u.x-t.x)/a),new B(s,r,o)}function fe(t,i){var e=0;return t.x<i.min.x?e|=1:t.x>i.max.x&&(e|=2),t.y<i.min.y?e|=4:t.y>i.max.y&&(e|=8),e}function ge(t,i,e,n){var o,s=i.x,r=i.y,a=e.x-s,h=e.y-r,u=a*a+h*h;return 0<u&&(1<(o=((t.x-s)*a+(t.y-r)*h)/u)?(s=e.x,r=e.y):0<o&&(s+=a*o,r+=h*o)),a=t.x-s,h=t.y-r,n?a*a+h*h:new B(s,r)}function ve(t){return!v(t[0])||"object"!=typeof t[0][0]&&void 0!==t[0][0]}function ye(t){return console.warn("Deprecated use of _flat, please use L.LineUtil.isFlat instead."),ve(t)}var xe=(Object.freeze||Object)({simplify:_e,pointToSegmentDistance:de,closestPointOnSegment:function(t,i,e){return ge(t,i,e)},clipSegment:pe,_getEdgeIntersection:me,_getBitCode:fe,_sqClosestPointOnSegment:ge,isFlat:ve,_flat:ye});function we(t,i,e){var n,o,s,r,a,h,u,l,c,_=[1,4,2,8];for(o=0,u=t.length;o<u;o++)t[o]._code=fe(t[o],i);for(r=0;r<4;r++){for(l=_[r],n=[],o=0,s=(u=t.length)-1;o<u;s=o++)a=t[o],h=t[s],a._code&l?h._code&l||((c=me(h,a,l,i,e))._code=fe(c,i),n.push(c)):(h._code&l&&((c=me(h,a,l,i,e))._code=fe(c,i),n.push(c)),n.push(a));t=n}return t}var Pe,Le=(Object.freeze||Object)({clipPolygon:we}),be={project:function(t){return new B(t.lng,t.lat)},unproject:function(t){return new j(t.y,t.x)},bounds:new O([-180,-90],[180,90])},Te={R:6378137,R_MINOR:6356752.314245179,bounds:new O([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(t){var i=Math.PI/180,e=this.R,n=t.lat*i,o=this.R_MINOR/e,s=Math.sqrt(1-o*o),r=s*Math.sin(n),a=Math.tan(Math.PI/4-n/2)/Math.pow((1-r)/(1+r),s/2);return n=-e*Math.log(Math.max(a,1e-10)),new B(t.lng*i*e,n)},unproject:function(t){for(var i,e=180/Math.PI,n=this.R,o=this.R_MINOR/n,s=Math.sqrt(1-o*o),r=Math.exp(-t.y/n),a=Math.PI/2-2*Math.atan(r),h=0,u=.1;h<15&&1e-7<Math.abs(u);h++)i=s*Math.sin(a),i=Math.pow((1-i)/(1+i),s/2),a+=u=Math.PI/2-2*Math.atan(r*i)-a;return new j(a*e,t.x*e/n)}},ze=(Object.freeze||Object)({LonLat:be,Mercator:Te,SphericalMercator:q}),Me=h({},U,{code:"EPSG:3395",projection:Te,transformation:(Pe=.5/(Math.PI*Te.R),K(Pe,.5,-Pe,.5))}),Ce=h({},U,{code:"EPSG:4326",projection:be,transformation:K(1/180,1,-1/180,.5)}),Ee=h({},F,{projection:be,transformation:K(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,i){var e=i.lng-t.lng,n=i.lat-t.lat;return Math.sqrt(e*e+n*n)},infinite:!0});F.Earth=U,F.EPSG3395=Me,F.EPSG3857=X,F.EPSG900913=J,F.EPSG4326=Ce,F.Simple=Ee;var Se=k.extend({options:{pane:"overlayPane",attribution:null,bubblingMouseEvents:!0},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[u(t)]=this},removeInteractiveTarget:function(t){return delete this._map._targets[u(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var i=t.target;if(i.hasLayer(this)){if(this._map=i,this._zoomAnimated=i._zoomAnimated,this.getEvents){var e=this.getEvents();i.on(e,this),this.once("remove",function(){i.off(e,this)},this)}this.onAdd(i),this.getAttribution&&i.attributionControl&&i.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),i.fire("layeradd",{layer:this})}}});$i.include({addLayer:function(t){if(!t._layerAdd)throw new Error("The provided object is not a Layer.");var i=u(t);return this._layers[i]||((this._layers[i]=t)._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t)),this},removeLayer:function(t){var i=u(t);return this._layers[i]&&(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[i],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null),this},hasLayer:function(t){return!!t&&u(t)in this._layers},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},_addLayers:function(t){for(var i=0,e=(t=t?v(t)?t:[t]:[]).length;i<e;i++)this.addLayer(t[i])},_addZoomLimit:function(t){!isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[u(t)]=t,this._updateZoomLevels())},_removeZoomLimit:function(t){var i=u(t);this._zoomBoundLayers[i]&&(delete this._zoomBoundLayers[i],this._updateZoomLevels())},_updateZoomLevels:function(){var t=1/0,i=-1/0,e=this._getZoomSpan();for(var n in this._zoomBoundLayers){var o=this._zoomBoundLayers[n].options;t=void 0===o.minZoom?t:Math.min(t,o.minZoom),i=void 0===o.maxZoom?i:Math.max(i,o.maxZoom)}this._layersMaxZoom=i===-1/0?void 0:i,this._layersMinZoom=t===1/0?void 0:t,e!==this._getZoomSpan()&&this.fire("zoomlevelschange"),void 0===this.options.maxZoom&&this._layersMaxZoom&&this.getZoom()>this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),void 0===this.options.minZoom&&this._layersMinZoom&&this.getZoom()<this._layersMinZoom&&this.setZoom(this._layersMinZoom)}});var Ze=Se.extend({initialize:function(t,i){var e,n;if(p(this,i),this._layers={},t)for(e=0,n=t.length;e<n;e++)this.addLayer(t[e])},addLayer:function(t){var i=this.getLayerId(t);return this._layers[i]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var i=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[i]&&this._map.removeLayer(this._layers[i]),delete this._layers[i],this},hasLayer:function(t){return!!t&&(t in this._layers||this.getLayerId(t)in this._layers)},clearLayers:function(){return this.eachLayer(this.removeLayer,this)},invoke:function(t){var i,e,n=Array.prototype.slice.call(arguments,1);for(i in this._layers)(e=this._layers[i])[t]&&e[t].apply(e,n);return this},onAdd:function(t){this.eachLayer(t.addLayer,t)},onRemove:function(t){this.eachLayer(t.removeLayer,t)},eachLayer:function(t,i){for(var e in this._layers)t.call(i,this._layers[e]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];return this.eachLayer(t.push,t),t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:function(t){return u(t)}}),ke=Ze.extend({addLayer:function(t){return this.hasLayer(t)?this:(t.addEventParent(this),Ze.prototype.addLayer.call(this,t),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.removeEventParent(this),Ze.prototype.removeLayer.call(this,t),this.fire("layerremove",{layer:t})):this},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t=new N;for(var i in this._layers){var e=this._layers[i];t.extend(e.getBounds?e.getBounds():e.getLatLng())}return t}}),Be=S.extend({options:{popupAnchor:[0,0],tooltipAnchor:[0,0]},initialize:function(t){p(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,i){var e=this._getIconUrl(t);if(!e){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(e,i&&"IMG"===i.tagName?i:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,i){var e=this.options,n=e[i+"Size"];"number"==typeof n&&(n=[n,n]);var o=I(n),s=I("shadow"===i&&e.shadowAnchor||e.iconAnchor||o&&o.divideBy(2,!0));t.className="leaflet-marker-"+i+" "+(e.className||""),s&&(t.style.marginLeft=-s.x+"px",t.style.marginTop=-s.y+"px"),o&&(t.style.width=o.x+"px",t.style.height=o.y+"px")},_createImg:function(t,i){return(i=i||document.createElement("img")).src=t,i},_getIconUrl:function(t){return Ct&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}});var Ae=Be.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return Ae.imagePath||(Ae.imagePath=this._detectIconPath()),(this.options.imagePath||Ae.imagePath)+Be.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=ui("div","leaflet-default-icon-path",document.body),i=hi(t,"background-image")||hi(t,"backgroundImage");return document.body.removeChild(t),i=null===i||0!==i.indexOf("url")?"":i.replace(/^url\(["']?/,"").replace(/marker-icon\.png["']?\)$/,"")}}),Ie=se.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new ce(t,t,!0)),this._draggable.on({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).enable(),mi(t,"leaflet-marker-draggable")},removeHooks:function(){this._draggable.off({dragstart:this._onDragStart,predrag:this._onPreDrag,drag:this._onDrag,dragend:this._onDragEnd},this).disable(),this._marker._icon&&fi(this._marker._icon,"leaflet-marker-draggable")},moved:function(){return this._draggable&&this._draggable._moved},_adjustPan:function(t){var i=this._marker,e=i._map,n=this._marker.options.autoPanSpeed,o=this._marker.options.autoPanPadding,s=Li(i._icon),r=e.getPixelBounds(),a=e.getPixelOrigin(),h=R(r.min._subtract(a).add(o),r.max._subtract(a).subtract(o));if(!h.contains(s)){var u=I((Math.max(h.max.x,s.x)-h.max.x)/(r.max.x-h.max.x)-(Math.min(h.min.x,s.x)-h.min.x)/(r.min.x-h.min.x),(Math.max(h.max.y,s.y)-h.max.y)/(r.max.y-h.max.y)-(Math.min(h.min.y,s.y)-h.min.y)/(r.min.y-h.min.y)).multiplyBy(n);e.panBy(u,{animate:!1}),this._draggable._newPos._add(u),this._draggable._startPos._add(u),Pi(i._icon,this._draggable._newPos),this._onDrag(t),this._panRequest=M(this._adjustPan.bind(this,t))}},_onDragStart:function(){this._oldLatLng=this._marker.getLatLng(),this._marker.closePopup().fire("movestart").fire("dragstart")},_onPreDrag:function(t){this._marker.options.autoPan&&(C(this._panRequest),this._panRequest=M(this._adjustPan.bind(this,t)))},_onDrag:function(t){var i=this._marker,e=i._shadow,n=Li(i._icon),o=i._map.layerPointToLatLng(n);e&&Pi(e,n),i._latlng=o,t.latlng=o,t.oldLatLng=this._oldLatLng,i.fire("move",t).fire("drag",t)},_onDragEnd:function(t){C(this._panRequest),delete this._oldLatLng,this._marker.fire("moveend").fire("dragend",t)}}),Oe=Se.extend({options:{icon:new Ae,interactive:!0,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",shadowPane:"shadowPane",bubblingMouseEvents:!1,draggable:!1,autoPan:!1,autoPanPadding:[50,50],autoPanSpeed:10},initialize:function(t,i){p(this,i),this._latlng=W(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),delete this.dragging,this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var i=this._latlng;return this._latlng=W(t),this.update(),this.fire("move",{oldLatLng:i,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},getIcon:function(){return this.options.icon},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon&&this._map){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,i="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),e=t.icon.createIcon(this._icon),n=!1;e!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(e.title=t.title),"IMG"===e.tagName&&(e.alt=t.alt||"")),mi(e,i),t.keyboard&&(e.tabIndex="0"),this._icon=e,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var o=t.icon.createShadow(this._shadow),s=!1;o!==this._shadow&&(this._removeShadow(),s=!0),o&&(mi(o,i),o.alt=""),this._shadow=o,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),o&&s&&this.getPane(t.shadowPane).appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),li(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&li(this._shadow),this._shadow=null},_setPos:function(t){this._icon&&Pi(this._icon,t),this._shadow&&Pi(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon&&(this._icon.style.zIndex=this._zIndex+t)},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(i)},_initInteraction:function(){if(this.options.interactive&&(mi(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),Ie)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new Ie(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;this._icon&&yi(this._icon,t),this._shadow&&yi(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor}});var Re=Se.extend({options:{stroke:!0,color:"#3388ff",weight:3,opacity:1,lineCap:"round",lineJoin:"round",dashArray:null,dashOffset:null,fill:!1,fillColor:null,fillOpacity:.2,fillRule:"evenodd",interactive:!0,bubblingMouseEvents:!0},beforeAdd:function(t){this._renderer=t.getRenderer(this)},onAdd:function(){this._renderer._initPath(this),this._reset(),this._renderer._addPath(this)},onRemove:function(){this._renderer._removePath(this)},redraw:function(){return this._map&&this._renderer._updatePath(this),this},setStyle:function(t){return p(this,t),this._renderer&&(this._renderer._updateStyle(this),this.options.stroke&&t&&t.hasOwnProperty("weight")&&this._updateBounds()),this},bringToFront:function(){return this._renderer&&this._renderer._bringToFront(this),this},bringToBack:function(){return this._renderer&&this._renderer._bringToBack(this),this},getElement:function(){return this._path},_reset:function(){this._project(),this._update()},_clickTolerance:function(){return(this.options.stroke?this.options.weight/2:0)+this._renderer.options.tolerance}}),Ne=Re.extend({options:{fill:!0,radius:10},initialize:function(t,i){p(this,i),this._latlng=W(t),this._radius=this.options.radius},setLatLng:function(t){var i=this._latlng;return this._latlng=W(t),this.redraw(),this.fire("move",{oldLatLng:i,latlng:this._latlng})},getLatLng:function(){return this._latlng},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius},setStyle:function(t){var i=t&&t.radius||this._radius;return Re.prototype.setStyle.call(this,t),this.setRadius(i),this},_project:function(){this._point=this._map.latLngToLayerPoint(this._latlng),this._updateBounds()},_updateBounds:function(){var t=this._radius,i=this._radiusY||t,e=this._clickTolerance(),n=[t+e,i+e];this._pxBounds=new O(this._point.subtract(n),this._point.add(n))},_update:function(){this._map&&this._updatePath()},_updatePath:function(){this._renderer._updateCircle(this)},_empty:function(){return this._radius&&!this._renderer._bounds.intersects(this._pxBounds)},_containsPoint:function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()}});var De=Ne.extend({initialize:function(t,i,e){if("number"==typeof i&&(i=h({},e,{radius:i})),p(this,i),this._latlng=W(t),isNaN(this.options.radius))throw new Error("Circle radius cannot be NaN");this._mRadius=this.options.radius},setRadius:function(t){return this._mRadius=t,this.redraw()},getRadius:function(){return this._mRadius},getBounds:function(){var t=[this._radius,this._radiusY||this._radius];return new N(this._map.layerPointToLatLng(this._point.subtract(t)),this._map.layerPointToLatLng(this._point.add(t)))},setStyle:Re.prototype.setStyle,_project:function(){var t=this._latlng.lng,i=this._latlng.lat,e=this._map,n=e.options.crs;if(n.distance===U.distance){var o=Math.PI/180,s=this._mRadius/U.R/o,r=e.project([i+s,t]),a=e.project([i-s,t]),h=r.add(a).divideBy(2),u=e.unproject(h).lat,l=Math.acos((Math.cos(s*o)-Math.sin(i*o)*Math.sin(u*o))/(Math.cos(i*o)*Math.cos(u*o)))/o;!isNaN(l)&&0!==l||(l=s/Math.cos(Math.PI/180*i)),this._point=h.subtract(e.getPixelOrigin()),this._radius=isNaN(l)?0:h.x-e.project([u,t-l]).x,this._radiusY=h.y-r.y}else{var c=n.unproject(n.project(this._latlng).subtract([this._mRadius,0]));this._point=e.latLngToLayerPoint(this._latlng),this._radius=this._point.x-e.latLngToLayerPoint(c).x}this._updateBounds()}});var je=Re.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,i){p(this,i),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var i,e,n=1/0,o=null,s=ge,r=0,a=this._parts.length;r<a;r++)for(var h=this._parts[r],u=1,l=h.length;u<l;u++){var c=s(t,i=h[u-1],e=h[u],!0);c<n&&(n=c,o=s(t,i,e))}return o&&(o.distance=Math.sqrt(n)),o},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,i,e,n,o,s,r,a=this._rings[0],h=a.length;if(!h)return null;for(i=t=0;t<h-1;t++)i+=a[t].distanceTo(a[t+1])/2;if(0===i)return this._map.layerPointToLatLng(a[0]);for(n=t=0;t<h-1;t++)if(o=a[t],s=a[t+1],i<(n+=e=o.distanceTo(s)))return r=(n-i)/e,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,i){return i=i||this._defaultShape(),t=W(t),i.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new N,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return ve(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var i=[],e=ve(t),n=0,o=t.length;n<o;n++)e?(i[n]=W(t[n]),this._bounds.extend(i[n])):i[n]=this._convertLatLngs(t[n]);return i},_project:function(){var t=new O;this._rings=[],this._projectLatlngs(this._latlngs,this._rings,t),this._bounds.isValid()&&t.isValid()&&(this._rawPxBounds=t,this._updateBounds())},_updateBounds:function(){var t=this._clickTolerance(),i=new B(t,t);this._pxBounds=new O([this._rawPxBounds.min.subtract(i),this._rawPxBounds.max.add(i)])},_projectLatlngs:function(t,i,e){var n,o,s=t[0]instanceof j,r=t.length;if(s){for(o=[],n=0;n<r;n++)o[n]=this._map.latLngToLayerPoint(t[n]),e.extend(o[n]);i.push(o)}else for(n=0;n<r;n++)this._projectLatlngs(t[n],i,e)},_clipPoints:function(){var t=this._renderer._bounds;if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else{var i,e,n,o,s,r,a,h=this._parts;for(n=i=0,o=this._rings.length;i<o;i++)for(e=0,s=(a=this._rings[i]).length;e<s-1;e++)(r=pe(a[e],a[e+1],t,e,!0))&&(h[n]=h[n]||[],h[n].push(r[0]),r[1]===a[e+1]&&e!==s-2||(h[n].push(r[1]),n++))}},_simplifyPoints:function(){for(var t=this._parts,i=this.options.smoothFactor,e=0,n=t.length;e<n;e++)t[e]=_e(t[e],i)},_update:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),this._updatePath())},_updatePath:function(){this._renderer._updatePoly(this)},_containsPoint:function(t,i){var e,n,o,s,r,a,h=this._clickTolerance();if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(e=0,s=this._parts.length;e<s;e++)for(n=0,o=(r=(a=this._parts[e]).length)-1;n<r;o=n++)if((i||0!==n)&&de(t,a[o],a[n])<=h)return!0;return!1}});je._flat=ye;var We=je.extend({options:{fill:!0},isEmpty:function(){return!this._latlngs.length||!this._latlngs[0].length},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,i,e,n,o,s,r,a,h,u=this._rings[0],l=u.length;if(!l)return null;for(s=r=a=0,t=0,i=l-1;t<l;i=t++)e=u[t],n=u[i],o=e.y*n.x-n.y*e.x,r+=(e.x+n.x)*o,a+=(e.y+n.y)*o,s+=3*o;return h=0===s?u[0]:[r/s,a/s],this._map.layerPointToLatLng(h)},_convertLatLngs:function(t){var i=je.prototype._convertLatLngs.call(this,t),e=i.length;return 2<=e&&i[0]instanceof j&&i[0].equals(i[e-1])&&i.pop(),i},_setLatLngs:function(t){je.prototype._setLatLngs.call(this,t),ve(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return ve(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,i=this.options.weight,e=new B(i,i);if(t=new O(t.min.subtract(e),t.max.add(e)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t))if(this.options.noClip)this._parts=this._rings;else for(var n,o=0,s=this._rings.length;o<s;o++)(n=we(this._rings[o],t,!0)).length&&this._parts.push(n)},_updatePath:function(){this._renderer._updatePoly(this,!0)},_containsPoint:function(t){var i,e,n,o,s,r,a,h,u=!1;if(!this._pxBounds||!this._pxBounds.contains(t))return!1;for(o=0,a=this._parts.length;o<a;o++)for(s=0,r=(h=(i=this._parts[o]).length)-1;s<h;r=s++)e=i[s],n=i[r],e.y>t.y!=n.y>t.y&&t.x<(n.x-e.x)*(t.y-e.y)/(n.y-e.y)+e.x&&(u=!u);return u||je.prototype._containsPoint.call(this,t,!0)}});var He=ke.extend({initialize:function(t,i){p(this,i),this._layers={},t&&this.addData(t)},addData:function(t){var i,e,n,o=v(t)?t:t.features;if(o){for(i=0,e=o.length;i<e;i++)((n=o[i]).geometries||n.geometry||n.features||n.coordinates)&&this.addData(n);return this}var s=this.options;if(s.filter&&!s.filter(t))return this;var r=Fe(t,s);return r?(r.feature=Xe(t),r.defaultOptions=r.options,this.resetStyle(r),s.onEachFeature&&s.onEachFeature(t,r),this.addLayer(r)):this},resetStyle:function(t){return void 0===t?this.eachLayer(this.resetStyle,this):(t.options=h({},t.defaultOptions),this._setLayerStyle(t,this.options.style),this)},setStyle:function(i){return this.eachLayer(function(t){this._setLayerStyle(t,i)},this)},_setLayerStyle:function(t,i){t.setStyle&&("function"==typeof i&&(i=i(t.feature)),t.setStyle(i))}});function Fe(t,i){var e,n,o,s,r="Feature"===t.type?t.geometry:t,a=r?r.coordinates:null,h=[],u=i&&i.pointToLayer,l=i&&i.coordsToLatLng||Ve;if(!a&&!r)return null;switch(r.type){case"Point":return Ue(u,t,e=l(a),i);case"MultiPoint":for(o=0,s=a.length;o<s;o++)e=l(a[o]),h.push(Ue(u,t,e,i));return new ke(h);case"LineString":case"MultiLineString":return n=qe(a,"LineString"===r.type?0:1,l),new je(n,i);case"Polygon":case"MultiPolygon":return n=qe(a,"Polygon"===r.type?1:2,l),new We(n,i);case"GeometryCollection":for(o=0,s=r.geometries.length;o<s;o++){var c=Fe({geometry:r.geometries[o],type:"Feature",properties:t.properties},i);c&&h.push(c)}return new ke(h);default:throw new Error("Invalid GeoJSON object.")}}function Ue(t,i,e,n){return t?t(i,e):new Oe(e,n&&n.markersInheritOptions&&n)}function Ve(t){return new j(t[1],t[0],t[2])}function qe(t,i,e){for(var n,o=[],s=0,r=t.length;s<r;s++)n=i?qe(t[s],i-1,e):(e||Ve)(t[s]),o.push(n);return o}function Ge(t,i){return i="number"==typeof i?i:6,void 0!==t.alt?[c(t.lng,i),c(t.lat,i),c(t.alt,i)]:[c(t.lng,i),c(t.lat,i)]}function Ke(t,i,e,n){for(var o=[],s=0,r=t.length;s<r;s++)o.push(i?Ke(t[s],i-1,e,n):Ge(t[s],n));return!i&&e&&o.push(o[0]),o}function Ye(t,i){return t.feature?h({},t.feature,{geometry:i}):Xe(i)}function Xe(t){return"Feature"===t.type||"FeatureCollection"===t.type?t:{type:"Feature",properties:{},geometry:t}}var Je={toGeoJSON:function(t){return Ye(this,{type:"Point",coordinates:Ge(this.getLatLng(),t)})}};function $e(t,i){return new He(t,i)}Oe.include(Je),De.include(Je),Ne.include(Je),je.include({toGeoJSON:function(t){var i=!ve(this._latlngs);return Ye(this,{type:(i?"Multi":"")+"LineString",coordinates:Ke(this._latlngs,i?1:0,!1,t)})}}),We.include({toGeoJSON:function(t){var i=!ve(this._latlngs),e=i&&!ve(this._latlngs[0]),n=Ke(this._latlngs,e?2:i?1:0,!0,t);return i||(n=[n]),Ye(this,{type:(e?"Multi":"")+"Polygon",coordinates:n})}}),Ze.include({toMultiPoint:function(i){var e=[];return this.eachLayer(function(t){e.push(t.toGeoJSON(i).geometry.coordinates)}),Ye(this,{type:"MultiPoint",coordinates:e})},toGeoJSON:function(n){var t=this.feature&&this.feature.geometry&&this.feature.geometry.type;if("MultiPoint"===t)return this.toMultiPoint(n);var o="GeometryCollection"===t,s=[];return this.eachLayer(function(t){if(t.toGeoJSON){var i=t.toGeoJSON(n);if(o)s.push(i.geometry);else{var e=Xe(i);"FeatureCollection"===e.type?s.push.apply(s,e.features):s.push(e)}}}),o?Ye(this,{geometries:s,type:"GeometryCollection"}):{type:"FeatureCollection",features:s}}});var Qe=$e,tn=Se.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1,errorOverlayUrl:"",zIndex:1,className:""},initialize:function(t,i,e){this._url=t,this._bounds=D(i),p(this,e)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(mi(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){li(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&_i(this._image),this},bringToBack:function(){return this._map&&di(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=D(t),this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t="IMG"===this._url.tagName,i=this._image=t?this._url:ui("img");mi(i,"leaflet-image-layer"),this._zoomAnimated&&mi(i,"leaflet-zoom-animated"),this.options.className&&mi(i,this.options.className),i.onselectstart=l,i.onmousemove=l,i.onload=a(this.fire,this,"load"),i.onerror=a(this._overlayOnError,this,"error"),!this.options.crossOrigin&&""!==this.options.crossOrigin||(i.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),this.options.zIndex&&this._updateZIndex(),t?this._url=i.src:(i.src=this._url,i.alt=this.options.alt)},_animateZoom:function(t){var i=this._map.getZoomScale(t.zoom),e=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;wi(this._image,e,i)},_reset:function(){var t=this._image,i=new O(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),e=i.getSize();Pi(t,i.min),t.style.width=e.x+"px",t.style.height=e.y+"px"},_updateOpacity:function(){yi(this._image,this.options.opacity)},_updateZIndex:function(){this._image&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._image.style.zIndex=this.options.zIndex)},_overlayOnError:function(){this.fire("error");var t=this.options.errorOverlayUrl;t&&this._url!==t&&(this._url=t,this._image.src=t)}}),en=tn.extend({options:{autoplay:!0,loop:!0,keepAspectRatio:!0},_initImage:function(){var t="VIDEO"===this._url.tagName,i=this._image=t?this._url:ui("video");if(mi(i,"leaflet-image-layer"),this._zoomAnimated&&mi(i,"leaflet-zoom-animated"),this.options.className&&mi(i,this.options.className),i.onselectstart=l,i.onmousemove=l,i.onloadeddata=a(this.fire,this,"load"),t){for(var e=i.getElementsByTagName("source"),n=[],o=0;o<e.length;o++)n.push(e[o].src);this._url=0<e.length?n:[i.src]}else{v(this._url)||(this._url=[this._url]),!this.options.keepAspectRatio&&i.style.hasOwnProperty("objectFit")&&(i.style.objectFit="fill"),i.autoplay=!!this.options.autoplay,i.loop=!!this.options.loop;for(var s=0;s<this._url.length;s++){var r=ui("source");r.src=this._url[s],i.appendChild(r)}}}});var nn=tn.extend({_initImage:function(){var t=this._image=this._url;mi(t,"leaflet-image-layer"),this._zoomAnimated&&mi(t,"leaflet-zoom-animated"),this.options.className&&mi(t,this.options.className),t.onselectstart=l,t.onmousemove=l}});var on=Se.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,i){p(this,t),this._source=i},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&yi(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&yi(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(yi(this._container,0),this._removeTimeout=setTimeout(a(li,void 0,this._container),200)):li(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=W(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&_i(this._container),this},bringToBack:function(){return this._map&&di(this._container),this},_prepareOpen:function(t,i,e){if(i instanceof Se||(e=i,i=t),i instanceof ke)for(var n in t._layers){i=t._layers[n];break}if(!e)if(i.getCenter)e=i.getCenter();else{if(!i.getLatLng)throw new Error("Unable to get source layer LatLng.");e=i.getLatLng()}return this._source=i,this.update(),e},_updateContent:function(){if(this._content){var t=this._contentNode,i="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof i)t.innerHTML=i;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(i)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),i=I(this.options.offset),e=this._getAnchor();this._zoomAnimated?Pi(this._container,t.add(e)):i=i.add(t).add(e);var n=this._containerBottom=-i.y,o=this._containerLeft=-Math.round(this._containerWidth/2)+i.x;this._container.style.bottom=n+"px",this._container.style.left=o+"px"}},_getAnchor:function(){return[0,0]}}),sn=on.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,closeOnEscapeKey:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){on.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof Re||this._source.on("preclick",Ri))},onRemove:function(t){on.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof Re||this._source.off("preclick",Ri))},getEvents:function(){var t=on.prototype.getEvents.call(this);return(void 0!==this.options.closeOnClick?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",i=this._container=ui("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated"),e=this._wrapper=ui("div",t+"-content-wrapper",i);if(this._contentNode=ui("div",t+"-content",e),Di(e),Ni(this._contentNode),ki(e,"contextmenu",Ri),this._tipContainer=ui("div",t+"-tip-container",i),this._tip=ui("div",t+"-tip",this._tipContainer),this.options.closeButton){var n=this._closeButton=ui("a",t+"-close-button",i);n.href="#close",n.innerHTML="&#215;",ki(n,"click",this._onCloseButtonClick,this)}},_updateLayout:function(){var t=this._contentNode,i=t.style;i.width="",i.whiteSpace="nowrap";var e=t.offsetWidth;e=Math.min(e,this.options.maxWidth),e=Math.max(e,this.options.minWidth),i.width=e+1+"px",i.whiteSpace="",i.height="";var n=t.offsetHeight,o=this.options.maxHeight,s="leaflet-popup-scrolled";o&&o<n?(i.height=o+"px",mi(t,s)):fi(t,s),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),e=this._getAnchor();Pi(this._container,i.add(e))},_adjustPan:function(){if(this.options.autoPan){this._map._panAnim&&this._map._panAnim.stop();var t=this._map,i=parseInt(hi(this._container,"marginBottom"),10)||0,e=this._container.offsetHeight+i,n=this._containerWidth,o=new B(this._containerLeft,-e-this._containerBottom);o._add(Li(this._container));var s=t.layerPointToContainerPoint(o),r=I(this.options.autoPanPadding),a=I(this.options.autoPanPaddingTopLeft||r),h=I(this.options.autoPanPaddingBottomRight||r),u=t.getSize(),l=0,c=0;s.x+n+h.x>u.x&&(l=s.x+n-u.x+h.x),s.x-l-a.x<0&&(l=s.x-a.x),s.y+e+h.y>u.y&&(c=s.y+e-u.y+h.y),s.y-c-a.y<0&&(c=s.y-a.y),(l||c)&&t.fire("autopanstart").panBy([l,c])}},_onCloseButtonClick:function(t){this._close(),Wi(t)},_getAnchor:function(){return I(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}});$i.mergeOptions({closePopupOnClick:!0}),$i.include({openPopup:function(t,i,e){return t instanceof sn||(t=new sn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),Se.include({bindPopup:function(t,i){return t instanceof sn?(p(t,i),(this._popup=t)._source=this):(this._popup&&!i||(this._popup=new sn(i,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,keypress:this._onKeyPress,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,i){return this._popup&&this._map&&(i=this._popup._prepareOpen(this,t,i),this._map.openPopup(this._popup,i)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var i=t.layer||t.target;this._popup&&this._map&&(Wi(t),i instanceof Re?this.openPopup(t.layer||t.target,t.latlng):this._map.hasLayer(this._popup)&&this._popup._source===i?this.closePopup():this.openPopup(i,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)},_onKeyPress:function(t){13===t.originalEvent.keyCode&&this._openPopup(t)}});var rn=on.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){on.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){on.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=on.prototype.getEvents.call(this);return Tt&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=ui("div",t)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var i=this._map,e=this._container,n=i.latLngToContainerPoint(i.getCenter()),o=i.layerPointToContainerPoint(t),s=this.options.direction,r=e.offsetWidth,a=e.offsetHeight,h=I(this.options.offset),u=this._getAnchor();t="top"===s?t.add(I(-r/2+h.x,-a+h.y+u.y,!0)):"bottom"===s?t.subtract(I(r/2-h.x,-h.y,!0)):"center"===s?t.subtract(I(r/2+h.x,a/2-u.y+h.y,!0)):"right"===s||"auto"===s&&o.x<n.x?(s="right",t.add(I(h.x+u.x,u.y-a/2+h.y,!0))):(s="left",t.subtract(I(r+u.x-h.x,a/2-u.y-h.y,!0))),fi(e,"leaflet-tooltip-right"),fi(e,"leaflet-tooltip-left"),fi(e,"leaflet-tooltip-top"),fi(e,"leaflet-tooltip-bottom"),mi(e,"leaflet-tooltip-"+s),Pi(e,t)},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},setOpacity:function(t){this.options.opacity=t,this._container&&yi(this._container,t)},_animateZoom:function(t){var i=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(i)},_getAnchor:function(){return I(this._source&&this._source._getTooltipAnchor&&!this.options.sticky?this._source._getTooltipAnchor():[0,0])}});$i.include({openTooltip:function(t,i,e){return t instanceof rn||(t=new rn(e).setContent(t)),i&&t.setLatLng(i),this.hasLayer(t)?this:this.addLayer(t)},closeTooltip:function(t){return t&&this.removeLayer(t),this}}),Se.include({bindTooltip:function(t,i){return t instanceof rn?(p(t,i),(this._tooltip=t)._source=this):(this._tooltip&&!i||(this._tooltip=new rn(i,this)),this._tooltip.setContent(t)),this._initTooltipInteractions(),this._tooltip.options.permanent&&this._map&&this._map.hasLayer(this)&&this.openTooltip(),this},unbindTooltip:function(){return this._tooltip&&(this._initTooltipInteractions(!0),this.closeTooltip(),this._tooltip=null),this},_initTooltipInteractions:function(t){if(t||!this._tooltipHandlersAdded){var i=t?"off":"on",e={remove:this.closeTooltip,move:this._moveTooltip};this._tooltip.options.permanent?e.add=this._openTooltip:(e.mouseover=this._openTooltip,e.mouseout=this.closeTooltip,this._tooltip.options.sticky&&(e.mousemove=this._moveTooltip),Tt&&(e.click=this._openTooltip)),this[i](e),this._tooltipHandlersAdded=!t}},openTooltip:function(t,i){return this._tooltip&&this._map&&(i=this._tooltip._prepareOpen(this,t,i),this._map.openTooltip(this._tooltip,i),this._tooltip.options.interactive&&this._tooltip._container&&(mi(this._tooltip._container,"leaflet-clickable"),this.addInteractiveTarget(this._tooltip._container))),this},closeTooltip:function(){return this._tooltip&&(this._tooltip._close(),this._tooltip.options.interactive&&this._tooltip._container&&(fi(this._tooltip._container,"leaflet-clickable"),this.removeInteractiveTarget(this._tooltip._container))),this},toggleTooltip:function(t){return this._tooltip&&(this._tooltip._map?this.closeTooltip():this.openTooltip(t)),this},isTooltipOpen:function(){return this._tooltip.isOpen()},setTooltipContent:function(t){return this._tooltip&&this._tooltip.setContent(t),this},getTooltip:function(){return this._tooltip},_openTooltip:function(t){var i=t.layer||t.target;this._tooltip&&this._map&&this.openTooltip(i,this._tooltip.options.sticky?t.latlng:void 0)},_moveTooltip:function(t){var i,e,n=t.latlng;this._tooltip.options.sticky&&t.originalEvent&&(i=this._map.mouseEventToContainerPoint(t.originalEvent),e=this._map.containerPointToLayerPoint(i),n=this._map.layerPointToLatLng(e)),this._tooltip.setLatLng(n)}});var an=Be.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:document.createElement("div"),e=this.options;if(e.html instanceof Element?(ci(i),i.appendChild(e.html)):i.innerHTML=!1!==e.html?e.html:"",e.bgPos){var n=I(e.bgPos);i.style.backgroundPosition=-n.x+"px "+-n.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}});Be.Default=Ae;var hn=Se.extend({options:{tileSize:256,opacity:1,updateWhenIdle:xt,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:void 0,maxNativeZoom:void 0,minNativeZoom:void 0,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){p(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),li(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=void 0},bringToFront:function(){return this._map&&(_i(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(di(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return document.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof B?t:new B(t,t)},_updateZIndex:function(){this._container&&void 0!==this.options.zIndex&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var i,e=this.getPane().children,n=-t(-1/0,1/0),o=0,s=e.length;o<s;o++)i=e[o].style.zIndex,e[o]!==this._container&&i&&(n=t(n,+i));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex())},_updateOpacity:function(){if(this._map&&!et){yi(this._container,this.options.opacity);var t=+new Date,i=!1,e=!1;for(var n in this._tiles){var o=this._tiles[n];if(o.current&&o.loaded){var s=Math.min(1,(t-o.loaded)/200);yi(o.el,s),s<1?i=!0:(o.active?e=!0:this._onOpaqueTile(o),o.active=!0)}}e&&!this._noPrune&&this._pruneTiles(),i&&(C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this))}},_onOpaqueTile:l,_initContainer:function(){this._container||(this._container=ui("div","leaflet-layer "+(this.options.className||"")),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container))},_updateLevels:function(){var t=this._tileZoom,i=this.options.maxZoom;if(void 0!==t){for(var e in this._levels)this._levels[e].el.children.length||e===t?(this._levels[e].el.style.zIndex=i-Math.abs(t-e),this._onUpdateLevel(e)):(li(this._levels[e].el),this._removeTilesAtZoom(e),this._onRemoveLevel(e),delete this._levels[e]);var n=this._levels[t],o=this._map;return n||((n=this._levels[t]={}).el=ui("div","leaflet-tile-container leaflet-zoom-animated",this._container),n.el.style.zIndex=i,n.origin=o.project(o.unproject(o.getPixelOrigin()),t).round(),n.zoom=t,this._setZoomTransform(n,o.getCenter(),o.getZoom()),n.el.offsetWidth,this._onCreateLevel(n)),this._level=n}},_onUpdateLevel:l,_onRemoveLevel:l,_onCreateLevel:l,_pruneTiles:function(){if(this._map){var t,i,e=this._map.getZoom();if(e>this.options.maxZoom||e<this.options.minZoom)this._removeAllTiles();else{for(t in this._tiles)(i=this._tiles[t]).retain=i.current;for(t in this._tiles)if((i=this._tiles[t]).current&&!i.active){var n=i.coords;this._retainParent(n.x,n.y,n.z,n.z-5)||this._retainChildren(n.x,n.y,n.z,n.z+2)}for(t in this._tiles)this._tiles[t].retain||this._removeTile(t)}}},_removeTilesAtZoom:function(t){for(var i in this._tiles)this._tiles[i].coords.z===t&&this._removeTile(i)},_removeAllTiles:function(){for(var t in this._tiles)this._removeTile(t)},_invalidateAll:function(){for(var t in this._levels)li(this._levels[t].el),this._onRemoveLevel(t),delete this._levels[t];this._removeAllTiles(),this._tileZoom=void 0},_retainParent:function(t,i,e,n){var o=Math.floor(t/2),s=Math.floor(i/2),r=e-1,a=new B(+o,+s);a.z=+r;var h=this._tileCoordsToKey(a),u=this._tiles[h];return u&&u.active?u.retain=!0:(u&&u.loaded&&(u.retain=!0),n<r&&this._retainParent(o,s,r,n))},_retainChildren:function(t,i,e,n){for(var o=2*t;o<2*t+2;o++)for(var s=2*i;s<2*i+2;s++){var r=new B(o,s);r.z=e+1;var a=this._tileCoordsToKey(r),h=this._tiles[a];h&&h.active?h.retain=!0:(h&&h.loaded&&(h.retain=!0),e+1<n&&this._retainChildren(o,s,e+1,n))}},_resetView:function(t){var i=t&&(t.pinch||t.flyTo);this._setView(this._map.getCenter(),this._map.getZoom(),i,i)},_animateZoom:function(t){this._setView(t.center,t.zoom,!0,t.noUpdate)},_clampZoom:function(t){var i=this.options;return void 0!==i.minNativeZoom&&t<i.minNativeZoom?i.minNativeZoom:void 0!==i.maxNativeZoom&&i.maxNativeZoom<t?i.maxNativeZoom:t},_setView:function(t,i,e,n){var o=this._clampZoom(Math.round(i));(void 0!==this.options.maxZoom&&o>this.options.maxZoom||void 0!==this.options.minZoom&&o<this.options.minZoom)&&(o=void 0);var s=this.options.updateWhenZooming&&o!==this._tileZoom;n&&!s||(this._tileZoom=o,this._abortLoading&&this._abortLoading(),this._updateLevels(),this._resetGrid(),void 0!==o&&this._update(t),e||this._pruneTiles(),this._noPrune=!!e),this._setZoomTransforms(t,i)},_setZoomTransforms:function(t,i){for(var e in this._levels)this._setZoomTransform(this._levels[e],t,i)},_setZoomTransform:function(t,i,e){var n=this._map.getZoomScale(e,t.zoom),o=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(i,e)).round();yt?wi(t.el,o,n):Pi(t.el,o)},_resetGrid:function(){var t=this._map,i=t.options.crs,e=this._tileSize=this.getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=i.wrapLng&&!this.options.noWrap&&[Math.floor(t.project([0,i.wrapLng[0]],n).x/e.x),Math.ceil(t.project([0,i.wrapLng[1]],n).x/e.y)],this._wrapY=i.wrapLat&&!this.options.noWrap&&[Math.floor(t.project([i.wrapLat[0],0],n).y/e.x),Math.ceil(t.project([i.wrapLat[1],0],n).y/e.y)]},_onMoveEnd:function(){this._map&&!this._map._animatingZoom&&this._update()},_getTiledPixelBounds:function(t){var i=this._map,e=i._animatingZoom?Math.max(i._animateToZoom,i.getZoom()):i.getZoom(),n=i.getZoomScale(e,this._tileZoom),o=i.project(t,this._tileZoom).floor(),s=i.getSize().divideBy(2*n);return new O(o.subtract(s),o.add(s))},_update:function(t){var i=this._map;if(i){var e=this._clampZoom(i.getZoom());if(void 0===t&&(t=i.getCenter()),void 0!==this._tileZoom){var n=this._getTiledPixelBounds(t),o=this._pxBoundsToTileRange(n),s=o.getCenter(),r=[],a=this.options.keepBuffer,h=new O(o.getBottomLeft().subtract([a,-a]),o.getTopRight().add([a,-a]));if(!(isFinite(o.min.x)&&isFinite(o.min.y)&&isFinite(o.max.x)&&isFinite(o.max.y)))throw new Error("Attempted to load an infinite number of tiles");for(var u in this._tiles){var l=this._tiles[u].coords;l.z===this._tileZoom&&h.contains(new B(l.x,l.y))||(this._tiles[u].current=!1)}if(1<Math.abs(e-this._tileZoom))this._setView(t,e);else{for(var c=o.min.y;c<=o.max.y;c++)for(var _=o.min.x;_<=o.max.x;_++){var d=new B(_,c);if(d.z=this._tileZoom,this._isValidTile(d)){var p=this._tiles[this._tileCoordsToKey(d)];p?p.current=!0:r.push(d)}}if(r.sort(function(t,i){return t.distanceTo(s)-i.distanceTo(s)}),0!==r.length){this._loading||(this._loading=!0,this.fire("loading"));var m=document.createDocumentFragment();for(_=0;_<r.length;_++)this._addTile(r[_],m);this._level.el.appendChild(m)}}}}},_isValidTile:function(t){var i=this._map.options.crs;if(!i.infinite){var e=this._globalTileRange;if(!i.wrapLng&&(t.x<e.min.x||t.x>e.max.x)||!i.wrapLat&&(t.y<e.min.y||t.y>e.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return D(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToNwSe:function(t){var i=this._map,e=this.getTileSize(),n=t.scaleBy(e),o=n.add(e);return[i.unproject(n,t.z),i.unproject(o,t.z)]},_tileCoordsToBounds:function(t){var i=this._tileCoordsToNwSe(t),e=new N(i[0],i[1]);return this.options.noWrap||(e=this._map.wrapLatLngBounds(e)),e},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var i=t.split(":"),e=new B(+i[0],+i[1]);return e.z=+i[2],e},_removeTile:function(t){var i=this._tiles[t];i&&(li(i.el),delete this._tiles[t],this.fire("tileunload",{tile:i.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){mi(t,"leaflet-tile");var i=this.getTileSize();t.style.width=i.x+"px",t.style.height=i.y+"px",t.onselectstart=l,t.onmousemove=l,et&&this.options.opacity<1&&yi(t,this.options.opacity),st&&!rt&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,i){var e=this._getTilePos(t),n=this._tileCoordsToKey(t),o=this.createTile(this._wrapCoords(t),a(this._tileReady,this,t));this._initTile(o),this.createTile.length<2&&M(a(this._tileReady,this,t,null,o)),Pi(o,e),this._tiles[n]={el:o,coords:t,current:!0},i.appendChild(o),this.fire("tileloadstart",{tile:o,coords:t})},_tileReady:function(t,i,e){i&&this.fire("tileerror",{error:i,tile:e,coords:t});var n=this._tileCoordsToKey(t);(e=this._tiles[n])&&(e.loaded=+new Date,this._map._fadeAnimated?(yi(e.el,0),C(this._fadeFrame),this._fadeFrame=M(this._updateOpacity,this)):(e.active=!0,this._pruneTiles()),i||(mi(e.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:e.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),et||!this._map._fadeAnimated?M(this._pruneTiles,this):setTimeout(a(this._pruneTiles,this),250)))},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var i=new B(this._wrapX?r(t.x,this._wrapX):t.x,this._wrapY?r(t.y,this._wrapY):t.y);return i.z=t.z,i},_pxBoundsToTileRange:function(t){var i=this.getTileSize();return new O(t.min.unscaleBy(i).floor(),t.max.unscaleBy(i).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}});var un=hn.extend({options:{minZoom:0,maxZoom:18,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,i){this._url=t,(i=p(this,i)).detectRetina&&Ct&&0<i.maxZoom&&(i.tileSize=Math.floor(i.tileSize/2),i.zoomReverse?(i.zoomOffset--,i.minZoom++):(i.zoomOffset++,i.maxZoom--),i.minZoom=Math.max(0,i.minZoom)),"string"==typeof i.subdomains&&(i.subdomains=i.subdomains.split("")),st||this.on("tileunload",this._onTileRemove)},setUrl:function(t,i){return this._url===t&&void 0===i&&(i=!0),this._url=t,i||this.redraw(),this},createTile:function(t,i){var e=document.createElement("img");return ki(e,"load",a(this._tileOnLoad,this,i,e)),ki(e,"error",a(this._tileOnError,this,i,e)),!this.options.crossOrigin&&""!==this.options.crossOrigin||(e.crossOrigin=!0===this.options.crossOrigin?"":this.options.crossOrigin),e.alt="",e.setAttribute("role","presentation"),e.src=this.getTileUrl(t),e},getTileUrl:function(t){var i={r:Ct?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var e=this._globalTileRange.max.y-t.y;this.options.tms&&(i.y=e),i["-y"]=e}return g(this._url,h(i,this.options))},_tileOnLoad:function(t,i){et?setTimeout(a(t,this,null,i),0):t(null,i)},_tileOnError:function(t,i,e){var n=this.options.errorTileUrl;n&&i.getAttribute("src")!==n&&(i.src=n),t(e,i)},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,i=this.options.maxZoom;return this.options.zoomReverse&&(t=i-t),t+this.options.zoomOffset},_getSubdomain:function(t){var i=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[i]},_abortLoading:function(){var t,i;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&((i=this._tiles[t].el).onload=l,i.onerror=l,i.complete||(i.src=x,li(i),delete this._tiles[t]))},_removeTile:function(t){var i=this._tiles[t];if(i)return ht||i.el.setAttribute("src",x),hn.prototype._removeTile.call(this,t)},_tileReady:function(t,i,e){if(this._map&&(!e||e.getAttribute("src")!==x))return hn.prototype._tileReady.call(this,t,i,e)}});function ln(t,i){return new un(t,i)}var cn=un.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,i){this._url=t;var e=h({},this.defaultWmsParams);for(var n in i)n in this.options||(e[n]=i[n]);var o=(i=p(this,i)).detectRetina&&Ct?2:1,s=this.getTileSize();e.width=s.x*o,e.height=s.y*o,this.wmsParams=e},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var i=1.3<=this._wmsVersion?"crs":"srs";this.wmsParams[i]=this._crs.code,un.prototype.onAdd.call(this,t)},getTileUrl:function(t){var i=this._tileCoordsToNwSe(t),e=this._crs,n=R(e.project(i[0]),e.project(i[1])),o=n.min,s=n.max,r=(1.3<=this._wmsVersion&&this._crs===Ce?[o.y,o.x,s.y,s.x]:[o.x,o.y,s.x,s.y]).join(","),a=un.prototype.getTileUrl.call(this,t);return a+m(this.wmsParams,a,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+r},setParams:function(t,i){return h(this.wmsParams,t),i||this.redraw(),this}});un.WMS=cn,ln.wms=function(t,i){return new cn(t,i)};var _n=Se.extend({options:{padding:.1,tolerance:0},initialize:function(t){p(this,t),u(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&mi(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){this.off("update",this._updatePaths,this),this._destroyContainer()},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,i){var e=this._map.getZoomScale(i,this._zoom),n=Li(this._container),o=this._map.getSize().multiplyBy(.5+this.options.padding),s=this._map.project(this._center,i),r=this._map.project(t,i).subtract(s),a=o.multiplyBy(-e).add(n).add(o).subtract(r);yt?wi(this._container,a,e):Pi(this._container,a)},_reset:function(){for(var t in this._update(),this._updateTransform(this._center,this._zoom),this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,i=this._map.getSize(),e=this._map.containerPointToLayerPoint(i.multiplyBy(-t)).round();this._bounds=new O(e,e.add(i.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),dn=_n.extend({getEvents:function(){var t=_n.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){_n.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=document.createElement("canvas");ki(t,"mousemove",this._onMouseMove,this),ki(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this),ki(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_destroyContainer:function(){C(this._redrawRequest),delete this._ctx,li(this._container),Ai(this._container),delete this._container},_updatePaths:function(){if(!this._postponeUpdatePaths){for(var t in this._redrawBounds=null,this._layers)this._layers[t]._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){_n.prototype._update.call(this);var t=this._bounds,i=this._container,e=t.getSize(),n=Ct?2:1;Pi(i,t.min),i.width=n*e.x,i.height=n*e.y,i.style.width=e.x+"px",i.style.height=e.y+"px",Ct&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){_n.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t);var i=(this._layers[u(t)]=t)._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=i),this._drawLast=i,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var i=t._order,e=i.next,n=i.prev;e?e.prev=n:this._drawLast=n,n?n.next=e:this._drawFirst=e,delete t._order,delete this._layers[u(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if("string"==typeof t.options.dashArray){var i,e,n=t.options.dashArray.split(/[, ]+/),o=[];for(e=0;e<n.length;e++){if(i=Number(n[e]),isNaN(i))return;o.push(i)}t.options._dashArray=o}else t.options._dashArray=t.options.dashArray},_requestRedraw:function(t){this._map&&(this._extendRedrawBounds(t),this._redrawRequest=this._redrawRequest||M(this._redraw,this))},_extendRedrawBounds:function(t){if(t._pxBounds){var i=(t.options.weight||0)+1;this._redrawBounds=this._redrawBounds||new O,this._redrawBounds.extend(t._pxBounds.min.subtract([i,i])),this._redrawBounds.extend(t._pxBounds.max.add([i,i]))}},_redraw:function(){this._redrawRequest=null,this._redrawBounds&&(this._redrawBounds.min._floor(),this._redrawBounds.max._ceil()),this._clear(),this._draw(),this._redrawBounds=null},_clear:function(){var t=this._redrawBounds;if(t){var i=t.getSize();this._ctx.clearRect(t.min.x,t.min.y,i.x,i.y)}else this._ctx.clearRect(0,0,this._container.width,this._container.height)},_draw:function(){var t,i=this._redrawBounds;if(this._ctx.save(),i){var e=i.getSize();this._ctx.beginPath(),this._ctx.rect(i.min.x,i.min.y,e.x,e.y),this._ctx.clip()}this._drawing=!0;for(var n=this._drawFirst;n;n=n.next)t=n.layer,(!i||t._pxBounds&&t._pxBounds.intersects(i))&&t._updatePath();this._drawing=!1,this._ctx.restore()},_updatePoly:function(t,i){if(this._drawing){var e,n,o,s,r=t._parts,a=r.length,h=this._ctx;if(a){for(h.beginPath(),e=0;e<a;e++){for(n=0,o=r[e].length;n<o;n++)s=r[e][n],h[n?"lineTo":"moveTo"](s.x,s.y);i&&h.closePath()}this._fillStroke(h,t)}}},_updateCircle:function(t){if(this._drawing&&!t._empty()){var i=t._point,e=this._ctx,n=Math.max(Math.round(t._radius),1),o=(Math.max(Math.round(t._radiusY),1)||n)/n;1!=o&&(e.save(),e.scale(1,o)),e.beginPath(),e.arc(i.x,i.y/o,n,0,2*Math.PI,!1),1!=o&&e.restore(),this._fillStroke(e,t)}},_fillStroke:function(t,i){var e=i.options;e.fill&&(t.globalAlpha=e.fillOpacity,t.fillStyle=e.fillColor||e.color,t.fill(e.fillRule||"evenodd")),e.stroke&&0!==e.weight&&(t.setLineDash&&t.setLineDash(i.options&&i.options._dashArray||[]),t.globalAlpha=e.opacity,t.lineWidth=e.weight,t.strokeStyle=e.color,t.lineCap=e.lineCap,t.lineJoin=e.lineJoin,t.stroke())},_onClick:function(t){for(var i,e,n=this._map.mouseEventToLayerPoint(t),o=this._drawFirst;o;o=o.next)(i=o.layer).options.interactive&&i._containsPoint(n)&&!this._map._draggableMoved(i)&&(e=i);e&&(Gi(t),this._fireEvent([e],t))},_onMouseMove:function(t){if(this._map&&!this._map.dragging.moving()&&!this._map._animatingZoom){var i=this._map.mouseEventToLayerPoint(t);this._handleMouseHover(t,i)}},_handleMouseOut:function(t){var i=this._hoveredLayer;i&&(fi(this._container,"leaflet-interactive"),this._fireEvent([i],t,"mouseout"),this._hoveredLayer=null,this._mouseHoverThrottled=!1)},_handleMouseHover:function(t,i){if(!this._mouseHoverThrottled){for(var e,n,o=this._drawFirst;o;o=o.next)(e=o.layer).options.interactive&&e._containsPoint(i)&&(n=e);n!==this._hoveredLayer&&(this._handleMouseOut(t),n&&(mi(this._container,"leaflet-interactive"),this._fireEvent([n],t,"mouseover"),this._hoveredLayer=n)),this._hoveredLayer&&this._fireEvent([this._hoveredLayer],t),this._mouseHoverThrottled=!0,setTimeout(L.bind(function(){this._mouseHoverThrottled=!1},this),32)}},_fireEvent:function(t,i,e){this._map._fireDOMEvent(i,e||i.type,t)},_bringToFront:function(t){var i=t._order;if(i){var e=i.next,n=i.prev;e&&((e.prev=n)?n.next=e:e&&(this._drawFirst=e),i.prev=this._drawLast,(this._drawLast.next=i).next=null,this._drawLast=i,this._requestRedraw(t))}},_bringToBack:function(t){var i=t._order;if(i){var e=i.next,n=i.prev;n&&((n.next=e)?e.prev=n:n&&(this._drawLast=n),i.prev=null,i.next=this._drawFirst,this._drawFirst.prev=i,this._drawFirst=i,this._requestRedraw(t))}}});function pn(t){return St?new dn(t):null}var mn=function(){try{return document.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return document.createElement("<lvml:"+t+' class="lvml">')}}catch(t){return function(t){return document.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}(),fn={_initContainer:function(){this._container=ui("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(_n.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var i=t._container=mn("shape");mi(i,"leaflet-vml-shape "+(this.options.className||"")),i.coordsize="1 1",t._path=mn("path"),i.appendChild(t._path),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){var i=t._container;this._container.appendChild(i),t.options.interactive&&t.addInteractiveTarget(i)},_removePath:function(t){var i=t._container;li(i),t.removeInteractiveTarget(i),delete this._layers[u(t)]},_updateStyle:function(t){var i=t._stroke,e=t._fill,n=t.options,o=t._container;o.stroked=!!n.stroke,o.filled=!!n.fill,n.stroke?(i||(i=t._stroke=mn("stroke")),o.appendChild(i),i.weight=n.weight+"px",i.color=n.color,i.opacity=n.opacity,n.dashArray?i.dashStyle=v(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):i.dashStyle="",i.endcap=n.lineCap.replace("butt","flat"),i.joinstyle=n.lineJoin):i&&(o.removeChild(i),t._stroke=null),n.fill?(e||(e=t._fill=mn("fill")),o.appendChild(e),e.color=n.fillColor||n.color,e.opacity=n.fillOpacity):e&&(o.removeChild(e),t._fill=null)},_updateCircle:function(t){var i=t._point.round(),e=Math.round(t._radius),n=Math.round(t._radiusY||e);this._setPath(t,t._empty()?"M0 0":"AL "+i.x+","+i.y+" "+e+","+n+" 0,23592600")},_setPath:function(t,i){t._path.v=i},_bringToFront:function(t){_i(t._container)},_bringToBack:function(t){di(t._container)}},gn=kt?mn:$,vn=_n.extend({getEvents:function(){var t=_n.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=gn("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=gn("g"),this._container.appendChild(this._rootGroup)},_destroyContainer:function(){li(this._container),Ai(this._container),delete this._container,delete this._rootGroup,delete this._svgSize},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){_n.prototype._update.call(this);var t=this._bounds,i=t.getSize(),e=this._container;this._svgSize&&this._svgSize.equals(i)||(this._svgSize=i,e.setAttribute("width",i.x),e.setAttribute("height",i.y)),Pi(e,t.min),e.setAttribute("viewBox",[t.min.x,t.min.y,i.x,i.y].join(" ")),this.fire("update")}},_initPath:function(t){var i=t._path=gn("path");t.options.className&&mi(i,t.options.className),t.options.interactive&&mi(i,"leaflet-interactive"),this._updateStyle(t),this._layers[u(t)]=t},_addPath:function(t){this._rootGroup||this._initContainer(),this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){li(t._path),t.removeInteractiveTarget(t._path),delete this._layers[u(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var i=t._path,e=t.options;i&&(e.stroke?(i.setAttribute("stroke",e.color),i.setAttribute("stroke-opacity",e.opacity),i.setAttribute("stroke-width",e.weight),i.setAttribute("stroke-linecap",e.lineCap),i.setAttribute("stroke-linejoin",e.lineJoin),e.dashArray?i.setAttribute("stroke-dasharray",e.dashArray):i.removeAttribute("stroke-dasharray"),e.dashOffset?i.setAttribute("stroke-dashoffset",e.dashOffset):i.removeAttribute("stroke-dashoffset")):i.setAttribute("stroke","none"),e.fill?(i.setAttribute("fill",e.fillColor||e.color),i.setAttribute("fill-opacity",e.fillOpacity),i.setAttribute("fill-rule",e.fillRule||"evenodd")):i.setAttribute("fill","none"))},_updatePoly:function(t,i){this._setPath(t,Q(t._parts,i))},_updateCircle:function(t){var i=t._point,e=Math.max(Math.round(t._radius),1),n="a"+e+","+(Math.max(Math.round(t._radiusY),1)||e)+" 0 1,0 ",o=t._empty()?"M0 0":"M"+(i.x-e)+","+i.y+n+2*e+",0 "+n+2*-e+",0 ";this._setPath(t,o)},_setPath:function(t,i){t._path.setAttribute("d",i)},_bringToFront:function(t){_i(t._path)},_bringToBack:function(t){di(t._path)}});function yn(t){return Zt||kt?new vn(t):null}kt&&vn.include(fn),$i.include({getRenderer:function(t){var i=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return i||(i=this._renderer=this._createRenderer()),this.hasLayer(i)||this.addLayer(i),i},_getPaneRenderer:function(t){if("overlayPane"===t||void 0===t)return!1;var i=this._paneRenderers[t];return void 0===i&&(i=this._createRenderer({pane:t}),this._paneRenderers[t]=i),i},_createRenderer:function(t){return this.options.preferCanvas&&pn(t)||yn(t)}});var xn=We.extend({initialize:function(t,i){We.prototype.initialize.call(this,this._boundsToLatLngs(t),i)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return[(t=D(t)).getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}});vn.create=gn,vn.pointsToPath=Q,He.geometryToLayer=Fe,He.coordsToLatLng=Ve,He.coordsToLatLngs=qe,He.latLngToCoords=Ge,He.latLngsToCoords=Ke,He.getFeature=Ye,He.asFeature=Xe,$i.mergeOptions({boxZoom:!0});var wn=se.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane,this._resetStateTimeout=0,t.on("unload",this._destroy,this)},addHooks:function(){ki(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){Ai(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_destroy:function(){li(this._pane),delete this._pane},_resetState:function(){this._resetStateTimeout=0,this._moved=!1},_clearDeferredResetState:function(){0!==this._resetStateTimeout&&(clearTimeout(this._resetStateTimeout),this._resetStateTimeout=0)},_onMouseDown:function(t){if(!t.shiftKey||1!==t.which&&1!==t.button)return!1;this._clearDeferredResetState(),this._resetState(),Qt(),Ti(),this._startPoint=this._map.mouseEventToContainerPoint(t),ki(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=ui("div","leaflet-zoom-box",this._container),mi(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var i=new O(this._point,this._startPoint),e=i.getSize();Pi(this._box,i.min),this._box.style.width=e.x+"px",this._box.style.height=e.y+"px"},_finish:function(){this._moved&&(li(this._box),fi(this._container,"leaflet-crosshair")),ti(),zi(),Ai(document,{contextmenu:Wi,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){this._clearDeferredResetState(),this._resetStateTimeout=setTimeout(a(this._resetState,this),0);var i=new N(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(i).fire("boxzoomend",{boxZoomBounds:i})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}});$i.addInitHook("addHandler","boxZoom",wn),$i.mergeOptions({doubleClickZoom:!0});var Pn=se.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var i=this._map,e=i.getZoom(),n=i.options.zoomDelta,o=t.originalEvent.shiftKey?e-n:e+n;"center"===i.options.doubleClickZoom?i.setZoom(o):i.setZoomAround(t.containerPoint,o)}});$i.addInitHook("addHandler","doubleClickZoom",Pn),$i.mergeOptions({dragging:!0,inertia:!rt,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0});var Ln=se.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new ce(t._mapPane,t._container),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}mi(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){fi(this._map._container,"leaflet-grab"),fi(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDragStart:function(){var t=this._map;if(t._stop(),this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var i=D(this._map.options.maxBounds);this._offsetLimit=R(this._map.latLngToContainerPoint(i.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(i.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var i=this._lastTime=+new Date,e=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(e),this._times.push(i),this._prunePositions(i)}this._map.fire("move",t).fire("drag",t)},_prunePositions:function(t){for(;1<this._positions.length&&50<t-this._times[0];)this._positions.shift(),this._times.shift()},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),i=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=i.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,i){return t-(t-i)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),i=this._offsetLimit;t.x<i.min.x&&(t.x=this._viscousLimit(t.x,i.min.x)),t.y<i.min.y&&(t.y=this._viscousLimit(t.y,i.min.y)),t.x>i.max.x&&(t.x=this._viscousLimit(t.x,i.max.x)),t.y>i.max.y&&(t.y=this._viscousLimit(t.y,i.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,i=Math.round(t/2),e=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-i+e)%t+i-e,s=(n+i+e)%t-i-e,r=Math.abs(o+e)<Math.abs(s+e)?o:s;this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=r},_onDragEnd:function(t){var i=this._map,e=i.options,n=!e.inertia||this._times.length<2;if(i.fire("dragend",t),n)i.fire("moveend");else{this._prunePositions(+new Date);var o=this._lastPos.subtract(this._positions[0]),s=(this._lastTime-this._times[0])/1e3,r=e.easeLinearity,a=o.multiplyBy(r/s),h=a.distanceTo([0,0]),u=Math.min(e.inertiaMaxSpeed,h),l=a.multiplyBy(u/h),c=u/(e.inertiaDeceleration*r),_=l.multiplyBy(-c/2).round();_.x||_.y?(_=i._limitOffset(_,i.options.maxBounds),M(function(){i.panBy(_,{duration:c,easeLinearity:r,noMoveStart:!0,animate:!0})})):i.fire("moveend")}}});$i.addInitHook("addHandler","dragging",Ln),$i.mergeOptions({keyboard:!0,keyboardPanDelta:80});var bn=se.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),ki(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),Ai(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var t=document.body,i=document.documentElement,e=t.scrollTop||i.scrollTop,n=t.scrollLeft||i.scrollLeft;this._map._container.focus(),window.scrollTo(n,e)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var i,e,n=this._panKeys={},o=this.keyCodes;for(i=0,e=o.left.length;i<e;i++)n[o.left[i]]=[-1*t,0];for(i=0,e=o.right.length;i<e;i++)n[o.right[i]]=[t,0];for(i=0,e=o.down.length;i<e;i++)n[o.down[i]]=[0,t];for(i=0,e=o.up.length;i<e;i++)n[o.up[i]]=[0,-1*t]},_setZoomDelta:function(t){var i,e,n=this._zoomKeys={},o=this.keyCodes;for(i=0,e=o.zoomIn.length;i<e;i++)n[o.zoomIn[i]]=t;for(i=0,e=o.zoomOut.length;i<e;i++)n[o.zoomOut[i]]=-t},_addHooks:function(){ki(document,"keydown",this._onKeyDown,this)},_removeHooks:function(){Ai(document,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){if(!(t.altKey||t.ctrlKey||t.metaKey)){var i,e=t.keyCode,n=this._map;if(e in this._panKeys)n._panAnim&&n._panAnim._inProgress||(i=this._panKeys[e],t.shiftKey&&(i=I(i).multiplyBy(3)),n.panBy(i),n.options.maxBounds&&n.panInsideBounds(n.options.maxBounds));else if(e in this._zoomKeys)n.setZoom(n.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[e]);else{if(27!==e||!n._popup||!n._popup.options.closeOnEscapeKey)return;n.closePopup()}Wi(t)}}});$i.addInitHook("addHandler","keyboard",bn),$i.mergeOptions({scrollWheelZoom:!0,wheelDebounceTime:40,wheelPxPerZoomLevel:60});var Tn=se.extend({addHooks:function(){ki(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){Ai(this._map._container,"mousewheel",this._onWheelScroll,this)},_onWheelScroll:function(t){var i=Ui(t),e=this._map.options.wheelDebounceTime;this._delta+=i,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var n=Math.max(e-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(a(this._performZoom,this),n),Wi(t)},_performZoom:function(){var t=this._map,i=t.getZoom(),e=this._map.options.zoomSnap||0;t._stop();var n=this._delta/(4*this._map.options.wheelPxPerZoomLevel),o=4*Math.log(2/(1+Math.exp(-Math.abs(n))))/Math.LN2,s=e?Math.ceil(o/e)*e:o,r=t._limitZoom(i+(0<this._delta?s:-s))-i;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(i+r):t.setZoomAround(this._lastMousePos,i+r))}});$i.addInitHook("addHandler","scrollWheelZoom",Tn),$i.mergeOptions({tap:!0,tapTolerance:15});var zn=se.extend({addHooks:function(){ki(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){Ai(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(ji(t),this._fireClick=!0,1<t.touches.length)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],e=i.target;this._startPos=this._newPos=new B(i.clientX,i.clientY),e.tagName&&"a"===e.tagName.toLowerCase()&&mi(e,"leaflet-active"),this._holdTimeout=setTimeout(a(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),ki(document,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),Ai(document,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],e=i.target;e&&e.tagName&&"a"===e.tagName.toLowerCase()&&fi(e,"leaflet-active"),this._simulateEvent("mouseup",i),this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var i=t.touches[0];this._newPos=new B(i.clientX,i.clientY),this._simulateEvent("mousemove",i)},_simulateEvent:function(t,i){var e=document.createEvent("MouseEvents");e._simulated=!0,i.target._simulatedClick=!0,e.initMouseEvent(t,!0,!0,window,1,i.screenX,i.screenY,i.clientX,i.clientY,!1,!1,!1,!1,0,null),i.target.dispatchEvent(e)}});Tt&&!bt&&$i.addInitHook("addHandler","tap",zn),$i.mergeOptions({touchZoom:Tt&&!rt,bounceAtZoomLimits:!0});var Mn=se.extend({addHooks:function(){mi(this._map._container,"leaflet-touch-zoom"),ki(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){fi(this._map._container,"leaflet-touch-zoom"),Ai(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(e.add(n)._divideBy(2))),this._startDist=e.distanceTo(n),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),ki(document,"touchmove",this._onTouchMove,this),ki(document,"touchend",this._onTouchEnd,this),ji(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var i=this._map,e=i.mouseEventToContainerPoint(t.touches[0]),n=i.mouseEventToContainerPoint(t.touches[1]),o=e.distanceTo(n)/this._startDist;if(this._zoom=i.getScaleZoom(o,this._startZoom),!i.options.bounceAtZoomLimits&&(this._zoom<i.getMinZoom()&&o<1||this._zoom>i.getMaxZoom()&&1<o)&&(this._zoom=i._limitZoom(this._zoom)),"center"===i.options.touchZoom){if(this._center=this._startLatLng,1==o)return}else{var s=e._add(n)._divideBy(2)._subtract(this._centerPoint);if(1==o&&0===s.x&&0===s.y)return;this._center=i.unproject(i.project(this._pinchStartLatLng,this._zoom).subtract(s),this._zoom)}this._moved||(i._moveStart(!0,!1),this._moved=!0),C(this._animRequest);var r=a(i._move,i,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=M(r,this,!0),ji(t)}},_onTouchEnd:function(){this._moved&&this._zooming?(this._zooming=!1,C(this._animRequest),Ai(document,"touchmove",this._onTouchMove),Ai(document,"touchend",this._onTouchEnd),this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom))):this._zooming=!1}});$i.addInitHook("addHandler","touchZoom",Mn),$i.BoxZoom=wn,$i.DoubleClickZoom=Pn,$i.Drag=Ln,$i.Keyboard=bn,$i.ScrollWheelZoom=Tn,$i.Tap=zn,$i.TouchZoom=Mn,Object.freeze=i,t.version="1.6.0+HEAD.0c81bdf",t.Control=te,t.control=Qi,t.Browser=At,t.Evented=k,t.Mixin=ae,t.Util=E,t.Class=S,t.Handler=se,t.extend=h,t.bind=a,t.stamp=u,t.setOptions=p,t.DomEvent=Xi,t.DomUtil=Zi,t.PosAnimation=Ji,t.Draggable=ce,t.LineUtil=xe,t.PolyUtil=Le,t.Point=B,t.point=I,t.Bounds=O,t.bounds=R,t.Transformation=G,t.transformation=K,t.Projection=ze,t.LatLng=j,t.latLng=W,t.LatLngBounds=N,t.latLngBounds=D,t.CRS=F,t.GeoJSON=He,t.geoJSON=$e,t.geoJson=Qe,t.Layer=Se,t.LayerGroup=Ze,t.layerGroup=function(t,i){return new Ze(t,i)},t.FeatureGroup=ke,t.featureGroup=function(t){return new ke(t)},t.ImageOverlay=tn,t.imageOverlay=function(t,i,e){return new tn(t,i,e)},t.VideoOverlay=en,t.videoOverlay=function(t,i,e){return new en(t,i,e)},t.SVGOverlay=nn,t.svgOverlay=function(t,i,e){return new nn(t,i,e)},t.DivOverlay=on,t.Popup=sn,t.popup=function(t,i){return new sn(t,i)},t.Tooltip=rn,t.tooltip=function(t,i){return new rn(t,i)},t.Icon=Be,t.icon=function(t){return new Be(t)},t.DivIcon=an,t.divIcon=function(t){return new an(t)},t.Marker=Oe,t.marker=function(t,i){return new Oe(t,i)},t.TileLayer=un,t.tileLayer=ln,t.GridLayer=hn,t.gridLayer=function(t){return new hn(t)},t.SVG=vn,t.svg=yn,t.Renderer=_n,t.Canvas=dn,t.canvas=pn,t.Path=Re,t.CircleMarker=Ne,t.circleMarker=function(t,i){return new Ne(t,i)},t.Circle=De,t.circle=function(t,i,e){return new De(t,i,e)},t.Polyline=je,t.polyline=function(t,i){return new je(t,i)},t.Polygon=We,t.polygon=function(t,i){return new We(t,i)},t.Rectangle=xn,t.rectangle=function(t,i){return new xn(t,i)},t.Map=$i,t.map=function(t,i){return new $i(t,i)};var Cn=window.L;t.noConflict=function(){return window.L=Cn,this},window.L=t});
imx = {
  version:'0.1.3',
  /**
   * @param {mixed} expression
   * @return fluent interface
   * @type imx
   */
  log: function(expression) {
    if(typeof(console) == 'object' && typeof(console.log) == 'function') {
      console.log(expression);
    }
    return this;
  },
  /**
   * @param {mixed} expression
   * @return fluent interface
   * @type imx
   */
  warn: function(expression) {
    if(typeof(console) == 'object' && typeof(console.warn) == 'function') {
      console.warn(expression);
    } else {
      imx.log(expression);
    }
    return this;
  },
  /**
   * @param {mixed} expression
   * @return fluent interface
   * @type imx
   */
  error: function(expression) {
    if(typeof(console) == 'object' && typeof(console.error) == 'function') {
      console.error(expression);
    } else {
      imx.warn(expression);
    }
    return this;
  },
  /**
   * @param {String} expected the expected type as string
   * @param {Object} subject the object to test
   * @param {bool} showLog switch wether to show log messages or not
   * @return True if the type matches the expected
   * @type bool
   */
  isTypeOf: function(expected, subject, showLog) {
    if(showLog) imx.log('isTypeOf: type of subject: ' + typeof(subject) + ' expected: ' + expected);
    return (typeof(subject) == expected);
  },
  includedScripts: [],
  /**
   * Includes a javascript by appending a script tag with the given source to the body
   * @param {string} source the path of the including script
   * @return fluent interface
   * @type imx
   */
  include: function(source) {
    imx.log('include: including script ' + source);
    var script = jQuery(document.createElement('script'));
    script.attr('type', 'text/javascript');
    script.attr('language', 'javascript');
    script.attr('src', source);
    jQuery('body').append(script);
    return this;
  },
  /**
   * Includes a javascript by appending a script tag with the given source to the body only if is not yet included
   * @param {string} source the path of the including script
   * @return fluent interface
   * @type imx
   */
  include_once: function(source) {
    imx.log('include_once: checking for included script ' + source);
    if (!this.in_array(source, this.includedScripts)) {
      imx.log('include_once: script not yet included');
      this.includedScripts[this.includedScripts.length] = source;
      this.include(source);
    }else {
      imx.log('include_once: script already included');
    }

  },
  /**
   * aquvivalent to php's in_array, searches an array for the given needle
   * @return the search result
   * @type bool
   */
  in_array: function (needle, haystack) {
    for (var i = 0; i < haystack.length; i++) {
      if (haystack[i] == needle) {
        return true;
      }
    }
    return false;
  },

  /**
  * Simple thread-safe implementation. If checkFunction returns true, the callback is executed. If not, a recursion is executed after the given timeout
  * @param {function} checkFunction
  * @param {function} callback
  * @param {int} timeout Timeout in milliseconds, defaults to 500
  * @todo handle callback arguments
  */
  waitUntil: function (checkFunction,callback,timeout) {
    if (checkFunction()) {
      return callback();
    }
    var args = imx.collectionToArray(imx.waitUntil.arguments).join();
    setTimeout("imx.waitUntil("+args+")",timeout || 500);
    return null;
  },

  /**
 * turns a collection into a proper array
 * @param {idk?} collection
 * @return Array
 */
  collectionToArray: function (collection) {
    var entries = collection.length;
    var result = new Array(entries);
    for (var entry= 0; entry < entries; entry++) result[entry] = collection[entry];
    return result;
  }

};

/**
 * Check for dependend jQuery
 */
if(!imx.isTypeOf('function',jQuery)) alert('GNAAAAAAH! MISSING jQuery!!!');

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2015 infomax websolutions GmbH
 * @link       http://www.infomax-it.de
 * @author     Christian Heindl <christian.heindl@cebesoft.com>
 * @since      28.06.2014
 * @version    $$Id$$
 */

/**
 *
 * @class imx.Autocomplete
 * @constructor
 * @param {jQuery} input the input field
 * @param {jQuery} container container for autocomplete
 * @param {Object} options the settings of this autocomplete
 */
imx.Autocomplete = function(input, container, options) {
  this.keyCodes = {
    UP: 38,
    DOWN: 40,
    RETURN: 13,
    TAB: 9,
    ESC: 27,
    DEL: 46
  };

  var defaults = {
    adapter: null,
    inputClass: 'autocomplete',
    resultsClass: 'results',
    loadingClass: 'loading',
    minChars: 1,
    delay: 400,
    listElement: jQuery('<ul />'),
    itemElement: jQuery('<li />'),
    columnsReverse: false,
    numColumns: 2,
    mustSelect: false,
    wrap: {
      start: function() {
        return false;
      },
      end: function() {
        return false;
      },
      element: jQuery('<div />')
    },
    templates: {},
    events: {
      select: function() {
        return this;
      },
      change: function() {
        return this;
      },
      create: function() {
        return this;
      },
      destroy: function() {
        return this;
      },
      show: function() {
        return this;
      },
      hide: function() {
        return this;
      },
      beforeRequest: function() {
        return this;
      },
      afterRequest: function() {
        return this;
      }
    }
  };

  this.setSettings(jQuery.extend(true, defaults, options));
  this.setInput(input);
  this.setContainer(container);
  this.setList(this.buildAutocompleteList_());
  this.setSelection(false);
};

/**
 *
 * @return the input field
 * @type jQuery
 */
imx.Autocomplete.prototype.getInput = function() {
  return this.input;
};

/**
 *
 * @param {jQuery} input the input field
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.setInput = function(input) {
  this.input = input;
  return this;
};

/**
 * @return the container
 * @type jQuery
 */
imx.Autocomplete.prototype.getContainer = function() {
 return this.container;
};

/**
 * @param {jQuery} container the container
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.setContainer = function(container) {
 this.container = container;
 return this;
};


/**
 *
 * @return The list containing all the suggestion items.
 * @type jQuery
 */
imx.Autocomplete.prototype.getList = function() {
  return this.list;
};

/**
 *
 * @param {jQuery} list The list containing all the suggestion items.
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.setList = function(list) {
  this.list = list;
  return this;
};

/**
 *
 * @return the settings of this autocomplete
 * @type Object
 */
imx.Autocomplete.prototype.getSettings = function() {
  return this.settings;
};

/**
 *
 * @param {Object} settings the settings of this autocomplete
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.setSettings = function(settings) {
  this.settings = settings;
  return this;
};

/**
 *
 * @returns {Boolean}
 */
imx.Autocomplete.prototype.getSelection = function() {
  return this.selection;
};

/**
 * @param {boolean} selection flag
 * @returns {imx.Autocomplete}
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.setSelection = function(selection) {
  this.selection = selection;
  return this;
};

/**
 * This starts the autocomplete, builds it and binds all the needed events.
 *
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.create = function() {
  var that = this;
  var input = this.getInput();
  var list = this.getList();
  var settings = this.getSettings();
  var timeout = null;
  var term = '';
  var ignoreBlur = false;

  input.attr('autocomplete', 'off');
  input.addClass(settings.inputClass);

  input.bind('keydown.autocomplete', function(event) {
    switch(event.keyCode) {
      case that.keyCodes.UP:
        if(list.is(':visible')) {
          that.select_('prev', term);
          event.preventDefault();
        }else {
          that.show();
        }
        break;

      case that.keyCodes.DOWN:
        if(list.is(':visible')) {
          that.select_('next', term);
          event.preventDefault();
        }else {
          that.show();
        }
        break;

      case that.keyCodes.RETURN:
      case that.keyCodes.TAB:
        if(list.is(':visible') && jQuery('.selectable.selected', list).length > 0) {
          that.change_();
          event.preventDefault();
        }
        break;

      case that.keyCodes.ESC:
        that.hide();
        break;

      default:
        clearTimeout(timeout);
        timeout = setTimeout(function() {
          term = input.val();
          that.handleChange_();
        }, settings.delay);
        break;
    }
  });

  list.bind('mouseenter', function() { ignoreBlur = true; });
  list.bind('mouseleave', function() { ignoreBlur = false; input.focus(); });

  input.bind('blur.autocomplete', function(event) {
    if(!ignoreBlur) {
      that.hide();
    }
  });

  settings.events.create.call(this);
  return this;
};

/**
 * This destroys the autocomplete and unbinds all registered events.
 *
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.destroy = function() {
  this.hide();

  var input = this.getInput();

  input.removeAttr('autocomplete');
  input.removeClass(settings.inputClass);
  input.unbind('.autocomplete');

  this.getContainer().empty();

  this.getSettings().events.destroy.call(this);
  return this;
};

/**
 * This shows the autocomplete.
 *
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.show = function() {
  var input = this.getInput();

  this.getContainer().addClass('visible');
  this.getSettings().events.show.call(this);
  return this;
};

/**
 * This hides the autocomplete.
 *
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.hide = function() {
  var list = this.getList();
  var current = jQuery('.selectable.selected', list);

  list.hide();
  current.removeClass('selected');

  this.getContainer().removeClass('visible');

  this.getSettings().events.hide.call(this);
  return this;
};

/**
 * This handles the select of a value and sets it into the input.
 *
 * @private
 * @param {String} direction
 * @param {String} term
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.select_ = function(direction, term) {
  var input = this.getInput();
  var list = this.getList();

  var current = jQuery('.selectable.selected', list);
  var selected = (direction === 'next') ? current.nextAll('.selectable:first') : current.prevAll('.selectable:first');

  if(current.length === 0) {
    selected = (direction === 'next') ? jQuery('.selectable:first', list) : jQuery('.selectable:last', list);
  }

  current.removeClass('selected');

  if(selected.length > 0) {
    var item = selected.data('item');

    selected.addClass('selected');
    input.val(item.label);
    this.getSettings().events.select.call(this, item);
  }else {
    input.val(term);
  }
  return this;
};

/**
 * This handles a change of the value, sets it into the input and closes the autocomplete.
 *
 * @private
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.change_ = function(ev) {
  var current = ev.currentTarget;
  var item = jQuery(current).data('item');

  if(item) {
    this.getInput().val(item.label);
    this.getSettings().events.change.call(this, item);
    this.hide();
  }
  return this;
};

/**
 * This builds the container of the autocomplete and appends it to the <body>.
 *
 * @private
 * @return The list containing all the suggestion items.
 * @type jQuery
 */
imx.Autocomplete.prototype.buildAutocompleteList_ = function() {
  var settings = this.getSettings();
  var input = this.getInput();
  var offset = input.offset();

  var list = settings.listElement.attr({
    'id': input.attr('id') + '_autocomplete',
    'class': 'autocomplete ' + settings.resultsClass
  }).css({
    'display': 'none',
    'width': input.outerWidth(),
    'position': 'absolute',
    'top': offset.top + input.outerHeight(),
    'left': offset.left
  });

  list.appendTo(this.getContainer());
  return list;
};

/**
 * This checks for the minimum text-length and handles the keydowns within the input, that are not caught.
 *
 * @private
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.handleChange_ = function() {
  var input = this.getInput();
  var settings = this.getSettings();
  var value = input.val();

  if(value.length >= settings.minChars) {
    input.addClass(settings.loadingClass);
    this.handleAdapter_();
  }else {
    input.removeClass(settings.loadingClass);
    this.hide();
  }
  return this;
};

/**
 * This method handles the adapter, requests the data and build the basic list of results.
 * The templates will be used for this and if there is no template for a given type no item will be rendered.
 *
 * @private
 * @return fluent interface
 * @type imx.Autocomplete
 */
imx.Autocomplete.prototype.handleAdapter_ = function() {
  var term = this.getInput().val();

  var callback = jQuery.proxy(function(data) {
    var items = data.autosuggest.suggests;

    if(items) {
      var groups = {};

      jQuery.each(items, function(idx, elem) {
        var type = elem.type;
        if(!groups[type]) {
          groups[type] = {
            type: type,
            items: [],
          };
        }
        groups[type].items.push(elem);
      });

      for(var i = 1; i <= this.getSettings().numColumns; i++) {
        jQuery('.column' + i, this.getContainer()).hide();
      }

      var countIdx = this.getSettings().columnsReverse ? this.getSettings().numColumns : 1;
      jQuery.each(groups, jQuery.proxy(function(groupIdx, group) {
        var type = group.type;
        if(group.items.length > 0) {
          var column = jQuery('.column' + countIdx, this.getContainer());
          jQuery('footer > span', column).text(portal.translations['autosuggest.' + type]);

          var list = jQuery('.-IMXEVNT-scrollerArea ul', column);

          list.empty();
          jQuery.each(group.items, jQuery.proxy(function(idx, item) {
            var listItem = jQuery('<li/>');
            var linkItem = jQuery('<a>');

            if(item.internal_type === 'address' || item.internal_type === 'addressGroup') {
              linkItem.append('<span class="icon-building"></span> '); /* icon-building */
            } else if(item.internal_type === 'location') {
              linkItem.append('<span class="icon-poiMarker"></span> '); /* icon-poiMarker */
            }

            linkItem.append(item.label);
            linkItem.data('item', item);
            linkItem.bind('mousedown', jQuery.proxy(this.change_, this));

            listItem.append(linkItem);

            list.append(listItem);
          }, this));

          column.show();

          if(this.getSettings().columnsReverse) {
            countIdx--;
          } else {
            countIdx++;
          }

        }
      }, this));

      if(items.length > 0) {
        this.show();
      } else {
        this.hide();
      }
    } else {
      this.hide();
    }
    this.getInput().removeClass(this.getSettings().loadingClass);
  }, this);

  this.getSettings().adapter.request(term, callback, this.getSettings().events.beforeRequest, this.getSettings().events.afterRequest);
  return this;
};

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2015 infomax websolutions GmbH
 * @link       http://www.infomax-it.de
 * @author     Christian Heindl <christian.heindl@cebesoft.com>
 * @since      28.07.2014
 * @version    $$Id$$
 */

/**
 * @class imx.Autocomplete.AjaxAdapter
 * @constructor
 * @param {Object} options the settings of this autocomplete
 */
imx.Autocomplete.AjaxAdapter = function(options) {
  var defaults = {
    url: '',
    extraParams: {}
  };

  this.setSettings(jQuery.extend(defaults, options));
};

/**
 * @return the settings of this autocomplete
 * @type Object
 */
imx.Autocomplete.AjaxAdapter.prototype.getSettings = function() {
  return this.settings;
};

/**
 * @param {Object} settings the settings of this autocomplete
 * @return fluent interface
 * @type imx.Autocomplete.AjaxAdapter
 */
imx.Autocomplete.AjaxAdapter.prototype.setSettings = function(settings) {
  this.settings = settings;
  return this;
};

/**
 * @param {String} value The text to search
 * @param {Function} callback The callback to call after the request was successful.
 * @param {Function} before The user-callback to call before the request gets sent.
 * @param {Function} after The user-callback to call after the request was sent.
 * @return fluent interface
 * @type imx.Autocomplete.AjaxAdapter
 */
imx.Autocomplete.AjaxAdapter.prototype.request = function(value, callback, before, after) {
  var settings = this.getSettings();

  var params = {
    q: value
  };

  if(this.request_) {
    this.request_.abort();
  }

  this.request_ = jQuery.ajax({
    url: settings.url,
    data: jQuery.extend(params, settings.extraParams),
    dataType: 'json',
    cache: false,
    beforeSend: function() {
      before();
    },
    success: function(items) {
      callback(items);
    },
    complete: function() {
      after();
    }
  });
  return this;
};

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2015 infomax websolutions GmbH
 * @link       http://www.infomax-it.de
 * @author     Christian Heindl <christian.heindl@cebesoft.com>
 * @since      28.07.2014
 * @version    $$Id: AjaxAdapter.js 40 2015-07-29 16:29:53Z cheindl $$
 */

/**
 * @class imx.Autocomplete.AjaxAdapter
 * @constructor
 * @param {Object} options the settings of this autocomplete
 */
imx.Autocomplete.DataAttributeAdapter = function(options) {
  var defaults = {
    url: '',
    extraParams: {}
  };

  this.setSettings(jQuery.extend(defaults, options));
};

/**
 * @return the settings of this autocomplete
 * @type Object
 */
imx.Autocomplete.DataAttributeAdapter.prototype.getSettings = function() {
  return this.settings;
};

/**
 * @param {Object} settings the settings of this autocomplete
 * @return fluent interface
 * @type imx.Autocomplete.AjaxAdapter
 */
imx.Autocomplete.DataAttributeAdapter.prototype.setSettings = function(settings) {
  this.settings = settings;
  return this;
};

/**
 * @param {String} value The text to search
 * @param {Function} callback The callback to call after the request was successful.
 * @param {Function} before The user-callback to call before the request gets sent.
 * @param {Function} after The user-callback to call after the request was sent.
 * @return fluent interface
 * @type imx.Autocomplete.AjaxAdapter
 */
imx.Autocomplete.DataAttributeAdapter.prototype.request = function(value, callback, before, after) {
  var settings = this.getSettings();

  var suggests = [];
  for(var key in settings.values) {
    if(settings.values.hasOwnProperty(key)) {
      var parts = key.split('_');
      suggests.push({
        "type": "where",
        "internal_type": parts[0],
        "label": settings.values[key],
        "value": parts[1]
      });
    }
  }

  // needed to be here since the order was lost because javaScript object does not know ordered properties.
  if (settings.sort === 'alphabetically'){
    suggests.sort(function(a, b) {
      var labelA = a.label;
      var labelB = b.label;
      return labelA < labelB ? -1 : 1;
    });
  }

  callback({
        autosuggest: {
          suggests: suggests
        }
      }
  );
  return this;
};

window.imx = window.imx || {};

imx.Mapwork = {
  /**
   * Constants defining the different maptypes, that can be shown
   *
   * @type object
   */
  mapTypeId: {
    ROADMAP: 1,
    SATELLITE: 2,
    HYBRID: 3,
    TERRAIN: 4
  },
  /**
   * These vendors are currently supported by the mapwork.
   *
   * @type object
   */
  vendorId: {
    GOOGLE: 1,
    ALPSTEIN: 2,
    TOURSPRUNG: 3,
    TOURSPRUNGSTATIC: 4,
    ECONTENTMAPS: 5,
    GOOGLESTATIC: 6,
    CONTWISEMAPS: 7,
    TOURSPRUNGLEAFLET: 8,
    LEAFLET: 9
  },
  /**
   * Creates and returns the map object for further implementation
   *
   * @param {String} id in which element this map should be rendered into
   * @param {imx.Mapwork.Configuration} configuration the configuration object for this map
   * @param {Boolean} [isMiniMap=false] if this map is very small, use this to hide all controls
   * @return the vendor specific map object
   * @type imx.Mapwork.Map
   */
  createMap: function(id, configuration, isMiniMap) {
    var map = null;
    isMiniMap = isMiniMap || false;

    switch(configuration.getVendorId()) {
      case imx.Mapwork.vendorId.GOOGLE:
        map = new imx.Mapwork.Map.Google(id, configuration);
        break;

      case imx.Mapwork.vendorId.GOOGLESTATIC:
        map = new imx.Mapwork.Map.GoogleStatic(id, configuration);
        break;

      case imx.Mapwork.vendorId.ALPSTEIN:
        map = new imx.Mapwork.Map.Alpstein(id, configuration);
        break;

      case imx.Mapwork.vendorId.TOURSPRUNG:
        map = new imx.Mapwork.Map.Toursprung(id, configuration);
        break;

      case imx.Mapwork.vendorId.TOURSPRUNGSTATIC:
        map = new imx.Mapwork.Map.ToursprungStatic(id, configuration);
        break;

      case imx.Mapwork.vendorId.ECONTENTMAPS:
        map = new imx.Mapwork.Map.EContentMaps(id, configuration);
        break;

      case imx.Mapwork.vendorId.CONTWISEMAPS:
        map = new imx.Mapwork.Map.ContwiseMaps(id, configuration);
        break;

      case imx.Mapwork.vendorId.TOURSPRUNGLEAFLET:
        map = new imx.Mapwork.Map.ToursprungLeaflet(id, configuration);
        break;

      case imx.Mapwork.vendorId.LEAFLET:
        map = new imx.Mapwork.Map.Leaflet(id, configuration);
        break;

      default:
        console.error('vendor not yet implemented: ' + configuration.getVendorId());
        break;
    }

    map.loadMap();
    map.isMiniMap(isMiniMap);

    return map;
  },
  /**
   * Easter-Egg for Axel.
   * You requested it, now you got it!
   *
   * @param {String} what type of the cupholder
   */
  cupholder: function(what) {
    var uri = 'https://www.google.com/images?q=cupholder';
    if('' !== what) {
      uri += '+' + what.replace(' ', '+');
    }
    window.open(uri, '_blank').focus();
  }
};

window.imx = window.imx || {};
window.imx.Mapwork = window.imx.Mapwork || {};

/**
 * Builds the configuration for using the mapwork.
 *
 * @class imx.Mapwork.Configuration
 * @constructor
 * @base imx.Mapwork
 */
imx.Mapwork.Configuration = function() {
  this._mapConfig = {
    center: new imx.Mapwork.LatLng(47.779325, 12.450438),
    mapTypeId: imx.Mapwork.mapTypeId.ROADMAP,
    zoom: 9,
    mapTypeControlOptions: {},
    navigationControlOptions: {},
    scrollwheel: true,
    draggable: true
  };
  this._clusterServerUri = null;
  this._vendorId = imx.Mapwork.vendorId.GOOGLE;
  this._vendorConfig = {};
  this._language = 'de';
  this._readyCallback = function(map) {
    // Work with the map.
  };
};

/**
 * Set the basic configuration for showing a map.
 *
 * @param {Object} mapConfig
 * @param {imx.Mapwork.LatLng} mapConfig.center Where should the map be centered.
 * @param {Number} mapConfig.mapTypeId Which maptype should be used.
 * @param {Number} mapConfig.zoom Which zoom level should be used.
 * @param {Object} mapConfig.mapTypeControlOptions Which type controls should be used.
 * @param {Object} mapConfig.navigationControlOptions Which navigation controls should be used.
 * @param {Boolean} mapConfig.scrollwheel Should the scrollwheel be usable to zoom?
 * @param {Boolean} mapConfig.draggable Should the map be draggable?
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setMapConfig = function(mapConfig) {
  for(var member in this._mapConfig) {
    var overwrite = mapConfig[member];

    if(typeof (overwrite) !== 'undefined') {
      this._mapConfig[member] = overwrite;
    }
  }

  return this;
};

/**
 * Get the basic configuration for showing a map.
 *
 * @returns {Object}
 */
imx.Mapwork.Configuration.prototype.getMapConfig = function() {
  return this._mapConfig;
};

/**
 * Set the URI to an implementation of a cluster server, if needed.
 *
 * @param {String} uri the URI
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setClusterServerUri = function(uri) {
  this._clusterServerUri = uri;
  return this;
};

/**
 * Get the path to an configured cluster server.
 *
 * @returns {String}
 */
imx.Mapwork.Configuration.prototype.getClusterServerUri = function() {
  return this._clusterServerUri;
};

/**
 * Set the ID of the vendor providing the map.
 *
 * @param {Number} vendorId the ID
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setVendorId = function(vendorId) {
  this._vendorId = vendorId;
  return this;
};

/**
 * Get the ID of the vnedor providing the map
 *
 * @returns {Number}
 */
imx.Mapwork.Configuration.prototype.getVendorId = function() {
  return this._vendorId;
};

/**
 * If the vendor specific maps need some configuration, this is the place for setting it.
 *
 * @param {object} vendorConfig the vendor specific configuration
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setVendorConfig = function(vendorConfig) {
  this._vendorConfig = vendorConfig;
  return this;
};

/**
 * Get the vendor specific configuration.
 *
 * @returns {Object}
 */
imx.Mapwork.Configuration.prototype.getVendorConfig = function() {
  return this._vendorConfig;
};

/**
 * Sets the language.
 *
 * @param {String} language the URI
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setLanguage = function(language) {
  this._language = language;
  return this;
};

/**
 * Get the language.
 * Default value is 'de' for compatibility with older versions where this configuration could not be made.
 *
 * @returns {String}
 */
imx.Mapwork.Configuration.prototype.getLanguage = function() {
  return this._language;
};

/**
 * Sets the callback being called after map finished loading.
 *
 * @param {Function} readyCallback
 * @returns {imx.Mapwork.Configuration}
 */
imx.Mapwork.Configuration.prototype.setReadyCallback = function(readyCallback) {
  this._readyCallback = readyCallback;
  return this;
};

/**
 * Get the callback being called after map finished loading.
 *
 * @returns {Function}
 */
imx.Mapwork.Configuration.prototype.getReadyCallback = function() {
  return this._readyCallback;
};

window.imx = window.imx || {};
window.imx.Mapwork = window.imx.Mapwork || {};

/**
 * Representing a coordinate.
 *
 * @class imx.Mapwork.LatLng
 * @constructor
 * @base imx.Mapwork
 * 
 * @param {Number} latitude The latitude of the desired coordinate.
 * @param {Number} longitude The longitude of the desired coordinate.
 */
imx.Mapwork.LatLng = function(latitude, longitude) {
  this.setLatitude(latitude);
  this.setLongitude(longitude);
};

/**
 * Set the latitude of this coordinate
 * 
 * @param {Number} latitude
 * @return fluent interface
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.LatLng.prototype.setLatitude = function(latitude) {
  if (latitude >= -90 || latitude <= 90) {
    this.latitude = latitude;
  } else {
    console.error('The latitude has to be a double between -90 and 90, given: ' + latitude);
  }
  return this;
};

/**
 * Get the latitude of this coordinate
 * 
 * @type Number
 */
imx.Mapwork.LatLng.prototype.getLatitude = function() {
  return this.latitude;
};

/**
 * Set the longitude of this coordinate
 * 
 * @param {Number} longitude
 * @return fluent interface
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.LatLng.prototype.setLongitude = function(longitude) {
  if (longitude >= -180 || longitude <= 180) {
    this.longitude = longitude;
  } else {
    console.error('The longitude has to be a double between -180 and 180, given: ' + longitude);
  }
  return this;
};

/**
 * Get the longitude of this coordinate
 * 
 * @type Number
 */
imx.Mapwork.LatLng.prototype.getLongitude = function() {
  return this.longitude;
};

window.imx = window.imx || {};
window.imx.Mapwork = window.imx.Mapwork || {};

/**
 * Representing an area between two coordinates.
 *
 * @class imx.Mapwork.LatLngBounds
 * @constructor
 * @base imx.Mapwork
 *
 * @param {imx.Mapwork.LatLng} southWest The southwest coordinate of the bounding box
 * @param {imx.Mapwork.LatLng} northEast The northeast coordinate of the bounding box
 */
imx.Mapwork.LatLngBounds = function(southWest, northEast) {
  this.setSouthWest(southWest);
  this.setNorthEast(northEast);
};

/**
 * Set the south-west coordinate of this area.
 *
 * @param {imx.Mapwork.LatLng} southWest
 * @return fluent interface
 * @type imx.Mapwork.LatLngBounds
 */
imx.Mapwork.LatLngBounds.prototype.setSouthWest = function(southWest) {
  this.southWest = southWest;
  return this;
};

/**
 * Get the south-west coordinate of this area.
 *
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.LatLngBounds.prototype.getSouthWest = function() {
  return this.southWest;
};

/**
 * Set the north-east coordinate of this area.
 *
 * @param {imx.Mapwork.LatLng} northEast
 * @return fluent interface
 * @type imx.Mapwork.LatLngBounds
 */
imx.Mapwork.LatLngBounds.prototype.setNorthEast = function(northEast) {
  this.northEast = northEast;
  return this;
};

/**
 * Get the north-east coordinate of this area.
 *
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.LatLngBounds.prototype.getNorthEast = function() {
  return this.northEast;
};

window.imx = window.imx || {};
window.imx.Mapwork = window.imx.Mapwork || {};

/**
 * With this the communication with a cluster server is made.
 *
 * @class imx.Mapwork.ClusterServer
 * @constructor
 * @base imx.Mapwork
 *
 * @param {String} method this method gets called at the server-side
 * @param {imx.Mapwork.LatLngBounds} bounds within these bounds are the returned objects
 * @param {imx.Mapwork.Configuration} configuration the map configuration
 * @param {object} params some additional params, that can be added to the request
 */
imx.Mapwork.ClusterServer = function(method, bounds, configuration, params) {
  this.setMethod(method);
  this.setBounds(bounds);
  this.setConfiguration(configuration);
  this.setParams(params);
};

/**
 * Set the method, that´s called at the server-side
 *
 * @param {String} method
 * @return fluent interface
 * @type imx.Mapwork.ClusterServer
 */
imx.Mapwork.ClusterServer.prototype.setMethod = function(method) {
  this.method = method;
  return this;
};

/**
 * Get the method, that´s called at the server-side
 *
 * @type String
 */
imx.Mapwork.ClusterServer.prototype.getMethod = function() {
  return this.method;
};

/**
 * Set the bounds, within returned objects should be
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @return fluent interface
 * @type imx.Mapwork.ClusterServer
 */
imx.Mapwork.ClusterServer.prototype.setBounds = function(bounds) {
  this.bounds = bounds;
  return this;
};

/**
 * Get the bounds, within returned objects should be
 *
 * @type imx.Mapwork.LatLngBounds
 */
imx.Mapwork.ClusterServer.prototype.getBounds = function() {
  return this.bounds;
};

/**
 * Set the map configuration.
 *
 * @param {imx.Mapwork.Configuration} configuration
 * @return fluent interface
 * @type imx.Mapwork.ClusterServer
 */
imx.Mapwork.ClusterServer.prototype.setConfiguration = function(configuration) {
  this.configuration = configuration;
  return this;
};

/**
 * Get the map configuration.
 *
 * @type imx.Mapwork.Configuration
 */
imx.Mapwork.ClusterServer.prototype.getConfiguration = function() {
  return this.configuration;
};

/**
 * Add some additional parameters, that can be added to the request
 *
 * @param {object} params
 * @return fluent interface
 * @type imx.Mapwork.ClusterServer
 */
imx.Mapwork.ClusterServer.prototype.setParams = function(params) {
  this.params = params;
  return this;
};

/**
 * Get some additional parameters, that are added to the request
 *
 * @type object
 */
imx.Mapwork.ClusterServer.prototype.getParams = function() {
  return this.params;
};

/**
 * Send the built request and call the given callback.
 *
 * @param {Function} callback Function receiving the JSON response from the sever.
 * @returns {Object} Will always be empty.
 */
imx.Mapwork.ClusterServer.prototype.request = function(callback) {
  if(typeof (this._lastRequest) !== 'object') {
    this._lastRequest = {};
  }

  if(typeof (this._lastRequest) === 'object' && typeof (this._lastRequest.data) === 'object' && typeof (this._lastRequest.data.method) === 'string' && this._lastRequest.data.method === this.getMethod()) {
    this._lastRequest.request.abort();
  }


  var bounds = this.getBounds();
  var southWest = bounds.getSouthWest();
  var northEast = bounds.getNorthEast();
  var response = {};

  var data = {
    method: this.getMethod(),
    language: this.getConfiguration().getLanguage(),
    north: northEast.getLatitude(),
    east: northEast.getLongitude(),
    south: southWest.getLatitude(),
    west: southWest.getLongitude(),
    params: this.getParams()
  };

  var request = new XMLHttpRequest();

  request.open('POST', this.getConfiguration().getClusterServerUri(), true);

  request.onreadystatechange = function() {
    if(this.readyState === XMLHttpRequest.DONE && this.status === 200) {
      callback(JSON.parse(request.responseText));
    }
  };

  request.send(this._serializeData(data));

  this._lastRequest = {
    data: data,
    request: request
  };

  return response;
};

/**
 * Takes any given data and tries to convert it into a FormData object, that can be used with XMLHttpRequest.
 *
 * @param object
 * @param {FormData} [data]
 * @param {String} [previous]
 * @returns {FormData}
 * @private
 */
imx.Mapwork.ClusterServer.prototype._serializeData = function(object, data, previous) {
  var self = this;

  data = data || new FormData();

  if(object === undefined) {
    return data;
  }else if(object === null) {
    data.append(previous, '');
  }else if(typeof object === 'boolean') {
    data.append(previous, object);
  }else if(Array.isArray(object)) {
    if(!object.length) {
      data.append(previous + '[]', '');
    }else {
      object.forEach(function(value) {
        self._serializeData(value, data, previous + '[]');
      });
    }
  }else if(object instanceof Date) {
    data.append(previous, object.toISOString());
  }else if(object === Object(object)) {
    Object.keys(object).forEach(function(prop) {
      var value = object[prop];

      if(Array.isArray(value)) {
        while(prop.length > 2 && prop.lastIndexOf('[]') === prop.length - 2) {
          prop = prop.substring(0, prop.length - 2);
        }
      }

      var key = previous ? previous + '[' + prop + ']' : prop;

      self._serializeData(value, data, key);
    });
  }else {
    data.append(previous, object);
  }

  return data;
};

/**
 * Abstract map object for convenience methods and basic things
 *
 * @class imx.Mapwork.Map
 * @constructor
 * @base imx.Mapwork
 *
 * @param {String} id in which element this map should be rendered into
 * @param {imx.Mapwork.Configuration} configuration the configuration object for this map
 */
imx.Mapwork.Map = function(id, configuration) {
  this.setId(id);
  this.setConfiguration(configuration);

  this._isMiniMap = false;
};

/**
 * Set the id, where the map should be rendered.
 *
 * @param {String} id
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setId = function(id) {
  this._id = id;
  return this;
};

/**
 * Get the id, where the map should be rendered.
 *
 * @type String
 */
imx.Mapwork.Map.prototype.getId = function() {
  return this._id;
};

/**
 * Set the configuration for this map
 *
 * @param {imx.Mapwork.Configuration} configuration
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setConfiguration = function(configuration) {
  this._configuration = configuration;
  return this;
};

/**
 * Get the configuration for this map
 *
 * @type imx.Mapwork.Configuration
 */
imx.Mapwork.Map.prototype.getConfiguration = function() {
  return this._configuration;
};

/**
 * Set the vendor specific map object
 *
 * @param {object} map
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setMap = function(map) {
  this._map = map;
  return this;
};

/**
 * Get the vendor specific map object
 *
 * @type object
 */
imx.Mapwork.Map.prototype.getMap = function() {
  return this._map;
};

/**
 * Set the bounds of the map.
 * If the bounds cannot be set exactly, the best zoom level will be used to show the whole area.
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setBounds = function(bounds) {
  console.error('setBounds not implemented!');
};

/**
 * Get the exact bounds of this map.
 *
 * @type imx.Mapwork.LatLngBounds
 */
imx.Mapwork.Map.prototype.getBounds = function() {
  console.error('getBounds not implemented!');
};

/**
 * Set the center coordinate of this map.
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setCenter = function(latLng) {
  console.error('setCenter not implemented!');
};

/**
 * Get the center coordinate of the current map view.
 *
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.Map.prototype.getCenter = function() {
  console.error('getCenter not implemented!');
};

/**
 * Set the maptype, that is getting shown
 *
 * @param {Number} mapTypeId
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setMapTypeId = function(mapTypeId) {
  console.error('setMapTypeId not implemented!');
};

/**
 * Get the currently shown maptype
 *
 * @type Number
 */
imx.Mapwork.Map.prototype.getMapTypeId = function() {
  console.error('getMapTypeId not implemented!');
};

/**
 * Set the zoom level for this map.
 *
 * @param {Number} zoom
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setZoom = function(zoom) {
  console.error('setZoom not implemented!');
};

/**
 * Get the current zoom level of this map
 *
 * @type Number
 */
imx.Mapwork.Map.prototype.getZoom = function() {
  console.error('getZoom not implemented!');
};

/**
 * Convert coordinates to the appropriate object of the vendor
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @type object
 */
imx.Mapwork.Map.prototype.convertLatLngToBase = function(latLng) {
  console.error('convertLatLngToBase not implemented!');
};

/**
 * Convert coordinates to the appropriate object of the mapwork
 *
 * @param {object} latLng
 * @type imx.Mapwork.LatLng
 */
imx.Mapwork.Map.prototype.convertLatLngToMapwork = function(latLng) {
  console.error('convertLatLngToMapwork not implemented!');
};

/**
 * Convert a bounds object to the appropriate object of the vendor
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @type object
 */
imx.Mapwork.Map.prototype.convertLatLngBoundsToBase = function(bounds) {
  console.error('convertLatLngBoundsToBase not implemented!');
};

/**
 * Convert a bounds object to the appropriate object of the mapwork
 *
 * @param {object} bounds
 * @type imx.Mapwork.LatLngBounds
 */
imx.Mapwork.Map.prototype.convertLatLngBoundsToMapwork = function(bounds) {
  console.error('convertLatLngBoundsToMapwork not implemented!');
};

/**
 * Convert the maptype to the appropriate type of the vendor
 *
 * @param {Number} mapTypeId
 * @type mixed
 */
imx.Mapwork.Map.prototype.convertMapTypeIdToBase = function(mapTypeId) {
  console.error('convertMapTypeIdToBase not implemented!');
};

/**
 * Convert the maptype to the appropriate type of the mapwork
 *
 * @param {mixed} mapTypeId
 * @type Number
 */
imx.Mapwork.Map.prototype.convertMapTypeIdToMapwork = function(mapTypeId) {
  console.error('convertMapTypeIdToMapwork not implemented!');
};

/**
 * This is the most important method, since it is neccessary for loading and finally showing the map.
 *
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.loadMap = function() {
  console.error('loadMap not implemented!');
};

/**
 * With this it is possible to show specific objects on the map.
 * Just pass some identfiers, that can be recognized by the underlying system of the vendor.
 * Usually this would be identifiers like this:
 * - imx.CMS: {00000000-0000-0000-0000-000000000000}
 * - imx.Tools: address_123 or offer_123
 * - imx.EventManager: event_123
 *
 * @param {Array} ids
 * @param {function} callback
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setPois = function(ids, callback) {
  console.error('setPois not implemented!');
};

/**
 * Show a specific object on the map by its ID.
 *
 * @param {String} id
 * @param {function} callback
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.showPoi = function(id, callback) {
  console.error('setPois not implemented!');
};

/**
 * Show any layer on the map, that can be activated by an unique identifier.
 *
 * @param {mixed} identifier
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.showLayer = function(identifier) {
  console.error('showLayer not implemented!');
};

/**
 * Hide any layer on the map, that´s currently shown.
 *
 * @param {mixed} identifier
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.hideLayer = function(identifier) {
  console.error('hideLayer not implemented!');
};

/**
 * If the size of the map is very small, this can be used for hiding all controls.
 *
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.hideControls = function() {
  console.error('hideControls not implemented!');
};

/**
 * If the size of the map is large enough, this can be used for showing all controls.
 *
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.showControls = function() {
  console.error('showControls not implemented!');
};

/**
 * Set, if this is a mini map or get the value, if the param is omitted.
 * If the params is given, the controls will be removed or added.
 *
 * @param {Boolean} [isMiniMap=undefined]
 * @return the current state
 * @type Boolean
 */
imx.Mapwork.Map.prototype.isMiniMap = function(isMiniMap) {
  if (typeof(isMiniMap) !== 'undefined') {
    if (isMiniMap === true) {
      this.hideControls();
    } else {
      this.showControls();
    }
    this._isMiniMap = isMiniMap;
  }
  return this._isMiniMap;
};

/**
 * Writes the current map state in the window.location.hash.
 *
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.trackMapState = function() {
  mapState = new imx.Mapwork.MapState(this);
  mapState.trackMapState();
  return this;
}

/**
 * Changes the current map state by the passed hash.
 *
 * @param {string} mapStateHash
 * @return fluent interface
 * @type imx.Mapwork.Map
 */
imx.Mapwork.Map.prototype.setMapState = function(mapStateHash) {
  mapState = new imx.Mapwork.MapState(this);
  mapState.setMapState(mapStateHash);
  return this;
}

/**
 * Concrete map object for wrapping the Google Maps-API
 *
 * @class imx.Mapwork.Map.Google
 * @constructor
 * @base imx.Mapwork.Map
 *
 * @param {String} id in which element this map should be rendered into
 * @param {imx.Mapwork.Configuration} configuration the configuration object for this map
 */
imx.Mapwork.Map.Google = function(id, configuration) {
  this.setId(id);
  this.setConfiguration(configuration);

  this._setLayerIds([]);
  this._setLayerMarkers([]);

  this._setPoiIds([]);
  this._setPoiMarkers({});

  this._setClusteredPoiIds([]);
  this._setClusteredPoiMarkers([]);

  this._setAdHocPois([]);
};

imx.Mapwork.Map.Google.prototype = new imx.Mapwork.Map();
imx.Mapwork.Map.Google.prototype.constructor = imx.Mapwork.Map.Google;

/**
 * Convert the given coordinates to the ones used by Google Maps
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @returns {google.maps.LatLng}
 */
imx.Mapwork.Map.Google.prototype.convertLatLngToBase = function(latLng) {
  var latitude = latLng.getLatitude();
  var longitude = latLng.getLongitude();

  return new google.maps.LatLng(latitude, longitude);
};

/**
 * Convert the given coordinates to the ones used by the mapwork
 *
 * @param {google.maps.LatLng} latLng
 * @returns {imx.Mapwork.LatLng}
 */
imx.Mapwork.Map.Google.prototype.convertLatLngToMapwork = function(latLng) {
  var latitude = latLng.lat();
  var longitude = latLng.lng();

  return new imx.Mapwork.LatLng(latitude, longitude);
};

/**
 * Convert a bounds object to the one used by Google Maps
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @returns {google.maps.LatLngBounds}
 */
imx.Mapwork.Map.Google.prototype.convertLatLngBoundsToBase = function(bounds) {
  var southWest = this.convertLatLngToBase(bounds.getSouthWest());
  var northEast = this.convertLatLngToBase(bounds.getNorthEast());

  return new google.maps.LatLngBounds(southWest, northEast);
};

/**
 * Convert the given bounds object to the one used by the mapwork
 *
 * @param {google.maps.LatLngBounds} bounds
 * @returns {imx.Mapwork.LatLngBounds}
 */
imx.Mapwork.Map.Google.prototype.convertLatLngBoundsToMapwork = function(bounds) {
  var southWest = this.convertLatLngToMapwork(bounds.getSouthWest());
  var northEast = this.convertLatLngToMapwork(bounds.getNorthEast());

  return new imx.Mapwork.LatLngBounds(southWest, northEast);
};

/**
 * Convert the given maptype to the appropriate ones of Google Maps
 *
 * @param {Number} mapTypeId
 * @returns {String}
 */
imx.Mapwork.Map.Google.prototype.convertMapTypeIdToBase = function(mapTypeId) {
  var googleMapTypeId = '';

  switch(mapTypeId) {
    case imx.Mapwork.mapTypeId.SATELLITE:
      googleMapTypeId = google.maps.MapTypeId.SATELLITE;
      break;

    case imx.Mapwork.mapTypeId.HYBRID:
      googleMapTypeId = google.maps.MapTypeId.HYBRID;
      break;

    case imx.Mapwork.mapTypeId.TERRAIN:
      googleMapTypeId = google.maps.MapTypeId.TERRAIN;
      break;

    case imx.Mapwork.mapTypeId.ROADMAP:
      googleMapTypeId = google.maps.MapTypeId.ROADMAP;
      break;
  }
  return googleMapTypeId;
};

/**
 * Convert the given maptype to the appropriate type of the mapwork
 *
 * @param {String} mapTypeId
 * @returns {Number}
 */
imx.Mapwork.Map.Google.prototype.convertMapTypeIdToMapwork = function(mapTypeId) {
  var mapworkMapTypeId = '';

  switch(mapTypeId) {
    case google.maps.MapTypeId.SATELLITE:
      mapworkMapTypeId = imx.Mapwork.mapTypeId.SATELLITE;
      break;

    case google.maps.MapTypeId.HYBRID:
      mapworkMapTypeId = imx.Mapwork.mapTypeId.HYBRID;
      break;

    case google.maps.MapTypeId.TERRAIN:
      mapworkMapTypeId = imx.Mapwork.mapTypeId.TERRAIN;
      break;

    case google.maps.MapTypeId.ROADMAP:
    default:
      mapworkMapTypeId = imx.Mapwork.mapTypeId.ROADMAP;
      break;
  }
  return mapworkMapTypeId;
};

/**
 * Set the bounds of the map.
 * If the bounds cannot be set exactly, the best zoom level will be used to show the whole area.
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setBounds = function(bounds) {
  var map = this.getMap();
  var baseBounds = this.convertLatLngBoundsToBase(bounds);
  var vendorConfig = this.getConfiguration().getVendorConfig();

  map.fitBounds(baseBounds, vendorConfig.fitBoundsPadding || 0);
  return this;
};

/**
 * Get the exact bounds of this map.
 *
 * @returns {imx.Mapwork.LatLngBounds}
 */
imx.Mapwork.Map.Google.prototype.getBounds = function() {
  return this.convertLatLngBoundsToMapwork(this.getMap().getBounds());
};

/**
 * Set the center coordinate of this map.
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setCenter = function(latLng) {
  this.getMap().setCenter(this.convertLatLngToBase(latLng));
  return this;
};

/**
 * Get the center coordinate of the current map view.
 *
 * @returns {imx.Mapwork.LatLng}
 */
imx.Mapwork.Map.Google.prototype.getCenter = function() {
  return this.convertLatLngToMapwork(this.getMap().getCenter());
};

/**
 * Set the maptype, that is getting shown
 *
 * @param {Number} mapTypeId
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setMapTypeId = function(mapTypeId) {
  this.getMap().setMapTypeId(this.convertMapTypeIdToBase(mapTypeId));
  return this;
};

/**
 * Get the currently shown maptype
 *
 * @returns {Number}
 */
imx.Mapwork.Map.Google.prototype.getMapTypeId = function() {
  return this.convertMapTypeIdToMapwork(this.getMap().getMapTypeId());
};

/**
 * Set the zoom level for this map.
 *
 * @param {Number} zoom
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setZoom = function(zoom) {
  this.getMap().setZoom(zoom);
  return this;
};

/**
 * Get the current zoom level of this map
 *
 * @returns {Number}
 */
imx.Mapwork.Map.Google.prototype.getZoom = function() {
  return this.getMap().getZoom();
};

/**
 * Set the IDs of POIs, that are currently shown
 *
 * @param {Array} ids
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setPoiIds = function(ids) {
  this._poiIds = ids;
  return this;
};

/**
 * Get the IDs of POIs, that are currently shown
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getPoiIds = function() {
  return this._poiIds;
};

/**
 * Set the markers of POIs, that are currently shown
 *
 * @param {Object} markers
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setPoiMarkers = function(markers) {
  this._poiMarkers = markers;
  return this;
};

/**
 * Get the markers of POIs, that are currently shown
 *
 * @returns {Object}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getPoiMarkers = function() {
  return this._poiMarkers;
};

/**
 * Remove all markers of POIs
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._removePoiMarkers = function() {
  var markers = this._getPoiMarkers();

  for(var i in markers) {
    if(markers[i].length > 0) {
      markers[i][0].setMap(null);
    }else {
      markers[i].setMap(null);
    }
  }

  return this;
};

/**
 * Set the IDs of layers, that are currently shown
 *
 * @param {Array} layerIds
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setLayerIds = function(layerIds) {
  this._layerIds = layerIds;
  return this;
};

/**
 * Get the IDs of layers, that are currently shown
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getLayerIds = function() {
  return this._layerIds;
};

/**
 * Set the markers of layers, that are currently shown
 *
 * @param {Array} layerMarkers
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setLayerMarkers = function(layerMarkers) {
  this._layerMarkers = layerMarkers;
  return this;
};

/**
 * Get the markers of layers, that are currently shown
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getLayerMarkers = function() {
  return this._layerMarkers;
};

/**
 * Remove all markers of shown layers
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._removeLayerMarkers = function() {
  var markers = this._getLayerMarkers();

  for(var i in markers) {
    if(markers[i].length > 0) {
      markers[i][0].setMap(null);
    }else {
      markers[i].setMap(null);
    }
  }

  return this;
};

/**
 *
 * @param {Array} clusteredPoiIds
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setClusteredPoiIds = function(clusteredPoiIds) {
  this._clusteredPoiIds = clusteredPoiIds;
  return this;
};

/**
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getClusteredPoiIds = function() {
  return this._clusteredPoiIds;
};

/**
 *
 * @param {Array} clusteredPoiMarkers
 * @returns {imx.Mapwork.Map}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setClusteredPoiMarkers = function(clusteredPoiMarkers) {
  this._clusteredPoiMarkers = clusteredPoiMarkers;
  return this;
};

/**
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getClusteredPoiMarkers = function() {
  return this._clusteredPoiMarkers;
};

/**
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._removeClusteredPoiMarkers = function() {
  var markers = this._getClusteredPoiMarkers();
  for(var i in markers) {
    markers[i].setMap(null);
  }
  return this;
};

/**
 *
 * @param {InfoBox} infoWindow
 * @returns {InfoBox}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setActiveInfoWindow = function(infoWindow) {
  if(this._infoWindow) {
    this._infoWindow.close();
  }

  this._infoWindow = infoWindow;

  return this._infoWindow;
};

/**
 *
 * @param {Array} adHocPois
 * @returns {imx.Mapwork.Map.Google}
 * @private
 */
imx.Mapwork.Map.Google.prototype._setAdHocPois = function(adHocPois) {
  this._adHocPois = adHocPois;
  return this;
};

/**
 *
 * @returns {Array}
 * @private
 */
imx.Mapwork.Map.Google.prototype._getAdHocPois = function() {
  return this._adHocPois;
};

/**
 * Go! Load the map!
 *
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.loadMap = function() {
  var id = this.getId();
  var options = this.getConfiguration().getMapConfig();
  var vendorConfig = this.getConfiguration().getVendorConfig();
  var readyCallback = this.getConfiguration().getReadyCallback();

  if(typeof vendorConfig.infoWindowEnabled === 'undefined') {
    vendorConfig.infoWindowEnabled = true;
  }
  if(typeof vendorConfig.toursEnabled === 'undefined') {
    vendorConfig.toursEnabled = true;
  }

  var mapOptions = {
    zoom: options.zoom,
    center: this.convertLatLngToBase(options.center),
    mapTypeId: this.convertMapTypeIdToBase(options.mapTypeId),
    scrollwheel: options.scrollwheel,
    draggable: options.draggable
  };

  /* handling for the the map controls */
  [
    'panControl',
    'zoomControl',
    'mapTypeControl',
    'scaleControl',
    'streetViewControl',
    'rotateControl',
    'fullscreenControl'
  ].forEach(function(control) {
    if(typeof vendorConfig[control] === 'boolean') {
      mapOptions[control] = vendorConfig[control];
    }
  });

  /* handling for the the map control options */
  [
    'panControlOptions',
    'zoomControlOptions',
    'mapTypeControlOptions',
    'scaleControlOptions',
    'streetViewControlOptions',
    'rotateControlOptions',
    'fullscreenControlOptions'
  ].forEach(function(control) {
    if(typeof vendorConfig[control] === 'object') {
      mapOptions[control] = vendorConfig[control];
    }
  });

  if(vendorConfig.gestureHandling) {
    mapOptions.gestureHandling = vendorConfig.gestureHandling;
  }

  if(typeof vendorConfig.clickableIcons === 'boolean') {
    mapOptions.clickableIcons = vendorConfig.clickableIcons;
  }

  var map = new google.maps.Map(document.getElementById(id), mapOptions);
  var self = this;
  var index;

  if(typeof vendorConfig.spiderfy === 'object' && typeof OverlappingMarkerSpiderfier === 'function') {
    this._oms = new OverlappingMarkerSpiderfier(map, vendorConfig.spiderfy);

    this._oms.addListener('spiderfy', function(markersToHighlight, markersToLowlight) {
      for(index = 0; index < markersToHighlight.length; index++) {
        markersToHighlight[index].setZIndex(1500 + index);
      }
      for(index = 0; index < markersToLowlight.length; index++) {
        markersToLowlight[index].content.style.opacity = 0.33;
      }
    });

    this._oms.addListener('unspiderfy', function(markersToHighlight, markersToLowlight) {
      for(index = 0; index < markersToHighlight.length; index++) {
        markersToHighlight[index].setZIndex(250);
      }
      for(index = 0; index < markersToLowlight.length; index++) {
        markersToLowlight[index].content.style.opacity = 1;
      }
    });
  }

  google.maps.event.addListenerOnce(map, 'idle', function() {
    readyCallback(self);

    google.maps.event.addListener(map, 'idle', function() {
      self.refresh();
    });
  });

  this.setMap(map);
  return this;
};

/**
 * This will refresh the map and reload all the layers and clustered POIs, so the changed bounds of the map get used in these requests.
 *
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.refresh = function() {
  this._loadLayerMarkers(this._getLayerIds());
  this._loadClusteredPois(this._getClusteredPoiIds());
  return this;
};

/**
 * With this it is possible to show specific objects on the map.
 * Just pass some identfiers, as used by the portal itself.
 *
 * @param {Array} ids
 * @param {Function} callback
 * @param {Function} [ajaxCallback]
 * @param {Boolean} [noAutoFitBounds]
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setPois = function(ids, callback, ajaxCallback, noAutoFitBounds) {
  var self = this;
  var config = this.getConfiguration().getVendorConfig();

  if(ids.length > 0) {
    this.requestClusterServer('GET_POIS', {
      ids: ids
    }, function(response) {
      if(response.counter > 0) {
        var pois = response.objects;
        var poiMarkers = {};
        var poiBoundingBox = new google.maps.LatLngBounds();

        for(var index in pois) {
          var marker = self._addMarker(pois[index], 'setPois', index);
          var id = pois[index].id;

          poiMarkers[id] = marker;
          poiBoundingBox.extend(marker.getPosition());
        }
        self._removePoiMarkers();
        self._setPoiMarkers(poiMarkers);

        if(noAutoFitBounds !== true) {
          self.getMap().fitBounds(poiBoundingBox, config.fitBoundsPadding || 0);
        }
      }

      if(config.maxZoomOnSetPois && self.getZoom() > config.maxZoomOnSetPois) {
        self.setZoom(config.maxZoomOnSetPois);
      }
      if(typeof (ajaxCallback) === 'function') {
        ajaxCallback();
      }
    });
  }else {
    this._removePoiMarkers();
    this._setPoiMarkers([]);

    if(typeof (ajaxCallback) === 'function') {
      ajaxCallback();
    }
  }

  this._setPoiIds(ids);

  if(typeof (callback) === 'function') {
    callback();
  }
  return this;
};

/**
 * Sets ad hoc pois to the map.
 *
 * @param {Array} pois
 * @param {function} callback
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.setAdHocPois = function(pois, callback) {
  var config = this.getConfiguration().getVendorConfig();
  var adHocPois = {};
  var poiBoundingBox = new google.maps.LatLngBounds();

  for(var index in pois) {
    var marker = this._addMarker(pois[index], 'setAdHocPois', index);
    var id = pois[index].id;

    adHocPois[id] = marker;
    poiBoundingBox.extend(marker.getPosition());
  }

  this._setAdHocPois(adHocPois);

  this.getMap().fitBounds(poiBoundingBox, config.fitBoundsPadding || 0);

  if(typeof (callback) === 'function')
    callback();
  if(config.maxZoomOnSetPois && this.getZoom() > config.maxZoomOnSetPois)
    this.setZoom(config.maxZoomOnSetPois);

  return this;
};

/**
 * Removes all adhoc pois.
 *
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.removeAdHocPois = function() {
  var adHocPois = this._getAdHocPois();
  for(var key in adHocPois) {
    adHocPois[key].setMap(null);
  }
  return this;
};

/**
 * Shows objects according to the passed ids on the map and clusters those objects.
 *
 * @param {Array} ids
 * @param {function} callback
 * @param {function} ajaxCallback
 * @param {Boolean} noAutoFitBounds
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.setClusteredPois = function(ids, callback, ajaxCallback, noAutoFitBounds) {
  var self = this;
  var config = this.getConfiguration().getVendorConfig();

  var buildBoundingBox = function(pois, bounds) {
    bounds = bounds || new google.maps.LatLngBounds();

    for(var index in pois) {
      if(pois[index].type === 'cluster') {
        bounds = buildBoundingBox(pois[index].pois, bounds);
      }else {
        bounds.extend(new google.maps.LatLng(pois[index].latLng.latitude, pois[index].latLng.longitude));
      }
    }

    return bounds;
  };

  var callbackToSetBounds = function(imxGoogleMap, pois) {
    if(pois[0] && noAutoFitBounds !== true) {
      self.getMap().fitBounds(buildBoundingBox(pois), config.fitBoundsPadding || 0);
    }

    if(config.maxZoomOnSetPois && self.getZoom() > config.maxZoomOnSetPois) {
      self.setZoom(config.maxZoomOnSetPois);
    }

    if(typeof (ajaxCallback) === 'function') {
      ajaxCallback();
    }
  };

  this._loadClusteredPois(ids, callbackToSetBounds);

  if(typeof (callback) === 'function') {
    callback();
  }
  return this;
};

/**
 * Loads clustered POIs by requesting the ClusterServer.
 *
 * @param {String[]} ids
 * @param {Function} [callback]
 * @private
 */
imx.Mapwork.Map.Google.prototype._loadClusteredPois = function(ids, callback) {
  var self = this;

  if(ids.length > 0) {
    this.requestClusterServer('GET_CLUSTERED_POIS', {
      ids: ids
    }, function(response) {
      var pois = response.objects;
      var clusteredPoiMarkers = [];

      for(var pIndex in pois) {
        var poi = pois[pIndex];
        var markers = self._addCluster(poi);

        for(var mIndex = 0; mIndex < markers.length; mIndex++) {
          clusteredPoiMarkers.push(markers[mIndex]);
        }
      }

      self._removeClusteredPoiMarkers();
      self._setClusteredPoiMarkers(clusteredPoiMarkers);
      if(typeof (callback) === 'function')
        callback(self, pois);
    });
    this._setClusteredPoiIds(ids);
  }
};

imx.Mapwork.Map.Google.prototype.hidePois = function() {
  this._removePoiMarkers();
};

/**
 * Removes all POIs, which were previously added clustered POIs, from the map
 *
 * @param {function} callback
 * @returns {imx.Mapwork.Map} description
 */
imx.Mapwork.Map.Google.prototype.hideClusteredPois = function(callback) {
  this._removeClusteredPoiMarkers();
  this._setClusteredPoiIds([]);

  if(typeof (callback) === 'function') {
    callback();
  }

  return this;
};

/**
 * Show a specific object on the map by its ID.
 *
 * @param {String} id
 * @param {function} callback
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.showPoi = function(id, callback) {
  var markers = this._getPoiMarkers();
  var vendorConfig = this.getConfiguration().getVendorConfig();
  var isMiniMap = this.isMiniMap();

  for(var identifier in markers) {
    if(!isMiniMap && id === identifier && typeof (callback) === 'function') {
      callback(markers[id].poi);
      return this;
    }
  }

  var self = this;
  this.requestClusterServer('GET_POIS', {
    ids: [id]
  }, function(response) {
    var pois = response.objects;

    for(var index in pois) {
      var marker = self._addMarker(pois[index], 'showPoi', index);

      if(isMiniMap && vendorConfig.toursEnabled && pois[index].isTour) {
        marker.kmlLayer = self._buildKmlLayer(pois[index].kml, false);
        marker.kmlLayer.setMap(self.getMap());

        google.maps.event.clearListeners(marker, 'mouseout');
      }

      self._poiMarkers[id] = marker;

      if(typeof (callback) === 'function') {
        callback(pois[index]);
      }
    }
  });
  return this;
};

/**
 * Shows a layer by its identifier.
 *
 * @param {String} identifier
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.showLayer = function(identifier, callback) {
  var layerIds = this._getLayerIds();
  var isAlreadyContained = false;

  for(var i in layerIds) {
    if(layerIds[i] === identifier) {
      isAlreadyContained = true;
    }
  }

  if(!isAlreadyContained) {
    layerIds.push(identifier);
  }

  this._loadLayerMarkers(layerIds, callback);
  return this;
};

/**
 * Shows layers by their identifiers.
 *
 * @param {String[]} identifiers
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.showLayers = function(identifiers, callback) {
  var layerIds = this._getLayerIds();

  for(var i = 0; i < identifiers.length; ++i) {
    layerIds.push(identifiers[i]);
  }

  this._loadLayerMarkers(layerIds, callback);
  return this;
};

/**
 * Loads layers by their identifiers.
 *
 * @param {String[]} layerIds
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Google}
 * @private
 */
imx.Mapwork.Map.Google.prototype._loadLayerMarkers = function(layerIds, callback) {
  var self = this;
  var vendorConfig = this.getConfiguration().getVendorConfig();

  if(layerIds.length > 0) {
    this.requestClusterServer('FIND_POIS', {
      Profiling: layerIds
    }, function(response) {
      var clusters = response.objects;
      var layerMarkers = [];

      for(var cIndex in clusters) {
        var markers = self._addCluster(clusters[cIndex]);

        for(var mIndex = 0; mIndex < markers.length; mIndex++) {
          layerMarkers.push(markers[mIndex]);
        }
      }
      self._removeLayerMarkers();
      self._setLayerMarkers(layerMarkers);

      if(typeof (callback) === 'function') {
        callback(clusters, layerIds);
      }
      if(typeof (vendorConfig.layerCallback) === 'function') {
        vendorConfig.layerCallback(clusters);
      }
    });
  }else {
    if(typeof (callback) === 'function') {
      callback({});
    }
    if(typeof (vendorConfig.layerCallback) === 'function') {
      vendorConfig.layerCallback({});
    }
  }

  this._setLayerIds(layerIds);
  return this;
};

/**
 * Hides a layer by its identifier.
 *
 * @param {String} identifier
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.hideLayer = function(identifier, callback) {
  var layerIds = this._getLayerIds();

  for(var index in layerIds) {
    if(layerIds[index] === identifier) {
      layerIds.splice(index, 1);
    }
  }

  this._removeLayerMarkers();
  this._loadLayerMarkers(layerIds, callback);
  return this;
};

/**
 * Hides layers by their identifiers.
 *
 * @param {String[]} identifiers
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.hideLayers = function(identifiers, callback) {
  var layerIds = this._getLayerIds();

  for(var i = 0; i < identifiers.length; ++i) {
    for(var index in layerIds) {
      if(layerIds[index] === identifiers[i]) {
        layerIds.splice(index, 1);
      }
    }
  }

  this._removeLayerMarkers();
  this._loadLayerMarkers(layerIds, callback);
  return this;
};

/**
 * Removes all currently active POI layers from the map
 *
 * @param {function} callback Optional callback function
 * @returns {imx.Mapwork.Map.Google}
 */
imx.Mapwork.Map.Google.prototype.hideAllLayers = function(callback) {
  var layerIds = this._getLayerIds();
  this.hideLayers(layerIds);

  if(typeof (callback) === 'function') {
    callback();
  }

  return this;
};

/**
 * Creates a marker for the map. If a custom icon is configured, this will be created.
 *
 * @param {object} poi
 * @param {string} originMethod
 * @param {int} index
 * @returns {google.maps.Marker}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildMarker = function(poi, originMethod, index) {
  var map = this.getMap();
  var latLng = new imx.Mapwork.LatLng(poi.latLng.latitude, poi.latLng.longitude);
  var marker = new RichMarker({
    position: this.convertLatLngToBase(latLng),
    map: map,
    flat: true,
    poi: poi,
    zIndex: 250
  });

  var config = this.getConfiguration().getVendorConfig();
  var content = null;

  if(typeof (config.mapIcon) === 'function') {
    content = config.mapIcon(poi, originMethod, index, marker);
  }else {
    var classes = ['imx-poi', originMethod];

    content = document.createElement('div');

    if(config.showPoiNumbers && index) {
      var counterSpan = document.createElement('span');
      counterSpan.innerHTML = (parseInt(index) + 1);
      content.appendChild(counterSpan);
    }

    if(typeof (config.mapIcon) === 'object') {
      content.style.width = config.mapIcon.size[0] + 'px';
      content.style.height = config.mapIcon.size[1] + 'px';
      content.style.background = 'transparent';
      content.style.backgroundImage = 'url(' + config.mapIcon.url(poi, originMethod, index) + ')';
      content.style.border = '0';

      if(typeof (config.mapIcon.id) === 'function') {
        content.setAttribute('id', config.mapIcon.id(poi, originMethod, index));
      }

      if(typeof (config.mapIcon.classes) === 'function') {
        classes = config.mapIcon.classes(poi, originMethod, index);
      }

      var anchor = new google.maps.Size(config.mapIcon.anchor[0], config.mapIcon.anchor[1]);
      marker.setAnchor(anchor);
    }else {
      content.style.width = '25px';
      content.style.height = '25px';
      content.style.background = '#fff';
      content.style.border = '1px solid #000';
    }

    content.setAttribute('title', poi.title);
    content.classList.add.apply(content.classList, classes);
    content.style.cursor = 'pointer';
  }

  if(typeof jQuery === 'function' && content instanceof jQuery) {
    marker.setContent(content.get(0));
  }else {
    marker.setContent(content);
  }

  return marker;
};

/**
 * Creates an infowindow for the map. If a custom content is configured, this will be used.
 *
 * @param {object} poi
 * @returns {InfoBox}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildInfoWindow = function(poi) {
  var latLng = new imx.Mapwork.LatLng(poi.latLng.latitude, poi.latLng.longitude);
  var infoWindowContent = poi.title;
  var config = this.getConfiguration().getVendorConfig();

  if(typeof (config.infoWindowContents) === 'function') {
    infoWindowContent = config.infoWindowContents(poi);
  }

  return new InfoBox({
    boxClass: 'imx-infowindow',
    content: infoWindowContent,
    position: this.convertLatLngToBase(latLng),
    closeBoxMargin: 0,
    closeBoxURL: (typeof config.closeIconUrl !== 'undefined') ? config.closeIconUrl : 'https://www.google.com/intl/en_us/mapfiles/close.gif',
    infoBoxClearance: config.infoBoxClearance || new google.maps.Size(0, 0),
    pixelOffset: config.infowindowOffset || new google.maps.Size(0, 0),
    alignBottom: config.infowindowAlignBottom || false,
    disableAutoPan: (poi.isTour) ? true : false
  });
};

/**
 * Creates a cluster
 *
 * @param {object} cluster
 * @returns {google.maps.Marker}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildClusterMarker = function(cluster) {
  var latLng = new imx.Mapwork.LatLng(cluster.latLng.latitude, cluster.latLng.longitude);
  var marker = new RichMarker({
    position: this.convertLatLngToBase(latLng),
    map: this.getMap(),
    flat: true,
    poi: cluster,
    zIndex: 250
  });

  var config = this.getConfiguration().getVendorConfig();
  var content = null;
  var count = 0;

  for(var i in cluster.pois) {
    count++;
  }

  if(typeof (config.clusterIcon) === 'function') {
    content = config.clusterIcon(cluster, marker, count);
  }else {
    content = document.createElement('div');

    content.classList.add('imx-cluster');

    content.style.cursor = 'pointer';
    content.style.width = '25px';
    content.style.height = '25px';
    content.style.background = '#fff';
    content.style.border = '1px solid #000';

    if(!config.hideClusterCounter) {
      var counterSpan = document.createElement('span');
      counterSpan.innerHTML = count;
      content.appendChild(counterSpan);
    }

    if(typeof (config.clusterIcon) === 'object') {
      content.style.width = config.clusterIcon.size[0] + 'px';
      content.style.height = config.clusterIcon.size[1] + 'px';
      content.style.background = 'transparent';
      content.style.backgroundImage = 'url(' + config.clusterIcon.url(cluster, count) + ')';
      content.style.border = '0';

      var anchor = new google.maps.Size(config.clusterIcon.anchor[0], config.clusterIcon.anchor[1]);
      marker.setAnchor(anchor);
    }
  }

  if(typeof jQuery === 'function' && content instanceof jQuery) {
    marker.setContent(content.get(0));
  }else {
    marker.setContent(content);
  }

  return marker;
};

/**
 * Creates an infowindow for the map. If a custom content is configured, this will be used.
 *
 * @param {object} cluster
 * @returns {InfoBox}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildClusterInfoWindow = function(cluster) {
  var boundingBox = cluster.boundingBox;
  var southWest = new google.maps.LatLng(boundingBox.south, boundingBox.west);
  var northEast = new google.maps.LatLng(boundingBox.north, boundingBox.east);

  var latLng = new google.maps.LatLngBounds(southWest, northEast).getCenter();
  var pois = cluster.pois;

  var infoWindowContent = '<ul>';
  for(var i in pois) {
    infoWindowContent += '<li><a href="' + pois[i].url + '">' + pois[i].title + '</a></li>';
  }
  infoWindowContent += '</ul>';

  var config = this.getConfiguration().getVendorConfig();
  if(typeof (config.clusterInfoWindowContents) === 'function')
    infoWindowContent = config.clusterInfoWindowContents(cluster);

  return new InfoBox({
    boxClass: 'imx-infowindow imx-clusterwindow',
    content: infoWindowContent,
    position: latLng,
    closeBoxMargin: 0,
    closeBoxURL: config.closeIconUrl || 'https://www.google.com/intl/en_us/mapfiles/close.gif',
    infoBoxClearance: config.infoBoxClearance || new google.maps.Size(0, 0),
    pixelOffset: config.infowindowOffset || new google.maps.Size(0, 0),
    alignBottom: config.infowindowAlignBottom || false
  });
};

/**
 * Creates the markerOptions needed for showing markers when displaying a route.
 *
 * @returns {object}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildRoutingMarkerOptions = function() {
  var markerOptions = {
    flat: true,
    zIndex: 250
  };
  var config = this.getConfiguration().getVendorConfig();

  if(typeof (config.routingMapIcon) === 'object') {
    markerOptions.icon = new google.maps.MarkerImage(
        config.routingMapIcon.url,
        new google.maps.Size(config.routingMapIcon.size[0], config.routingMapIcon.size[1]),
        new google.maps.Point(0, 0),
        new google.maps.Point(config.routingMapIcon.anchor[0], config.routingMapIcon.anchor[1])
    );
  }
  return markerOptions;
};

/**
 * Creates an infowindow when displaying a route.
 *
 * @returns {InfoBox}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildRoutingInfoWindow = function() {
  var config = this.getConfiguration().getVendorConfig();

  return new InfoBox({
    boxClass: 'imx-infowindow imx-routingwindow',
    closeBoxMargin: 0,
    closeBoxURL: config.closeIconUrl || 'https://www.google.com/intl/en_us/mapfiles/close.gif',
    infoBoxClearance: config.infoBoxClearance || new google.maps.Size(0, 0),
    pixelOffset: config.infowindowOffset || new google.maps.Size(0, 0),
    alignBottom: config.infowindowAlignBottom || false
  });
};

/**
 *
 * @param {String} kml
 * @param {Boolean} preserveViewport
 * @returns {google.maps.KmlLayer}
 * @private
 */
imx.Mapwork.Map.Google.prototype._buildKmlLayer = function(kml, preserveViewport) {
  return new google.maps.KmlLayer({
    url: kml,
    clickable: false,
    preserveViewport: preserveViewport,
    suppressInfoWindows: true
  });
};

/**
 *
 * @param {String} method
 * @param {object} params
 * @param {Function} callback
 * @returns {object}
 */
imx.Mapwork.Map.Google.prototype.requestClusterServer = function(method, params, callback) {
  if(typeof (this._clusterServer) !== 'object') {
    this._clusterServer = new imx.Mapwork.ClusterServer().setConfiguration(this.getConfiguration());
  }

  this._clusterServer.setMethod(method).setBounds(this.getBounds()).setParams(params);
  return this._clusterServer.request(callback);
};

/**
 * Adds the given pois to the map and registers the created markers with infowindows
 *
 * @param {Object} poi
 * @returns {google.maps.Marker}
 * @private
 */
imx.Mapwork.Map.Google.prototype._addMarker = function(poi, originMethod, index) {
  originMethod = originMethod || 'setPois';

  var self = this;
  var map = self.getMap();
  var marker = this._buildMarker(poi, originMethod, index);
  var config = this.getConfiguration().getVendorConfig();

  if(this._oms) {
    this._oms.addMarker(marker);
  }

  if(config.infoWindowEnabled === true) {
    var infoWindow = self._buildInfoWindow(poi);

    if(config.toursEnabled && poi.type === 'IMX_Mapwork_Poi_Tour') {
      infoWindow.kmlLayer = self._buildKmlLayer(poi.kml, false);

      google.maps.event.addListener(infoWindow, 'domready', function() {
        infoWindow.kmlLayer.setMap(map);
      });
      google.maps.event.addListener(infoWindow, 'closeclick', function() {
        infoWindow.kmlLayer.setMap(null);
      });
    }
  }

  var clickFunction = function() {
    if(!self._oms || (self._oms && !self._oms.spiderfied)) {
      if(config.infoWindowEnabled === true) {
        self._setActiveInfoWindow(infoWindow);
        infoWindow.open(map, this);
      }

      if(typeof (config.onInfoBoxContentChanged) === 'function') {
        google.maps.event.addListener(infoWindow, 'domready', config.onInfoBoxContentChanged);
      }
    }
  };

  if(!this.isMiniMap() && typeof (config.mapMarkerClick) === 'function') {
    clickFunction = function() {
      if(!self._oms || (self._oms && !self._oms.spiderfied)) {
        config.mapMarkerClick(poi, this);
      }
    };
  }
  if(this.isMiniMap() && typeof (config.miniMapMarkerClick) === 'function') {
    clickFunction = function() {
      if(!self._oms || (self._oms && !self._oms.spiderfied)) {
        config.miniMapMarkerClick(poi, this);
      }
    };
  }

  google.maps.event.addListener(marker, 'click', clickFunction);

  if(typeof (config.mapMarkerMouseover) === 'function') {
    google.maps.event.addListener(marker, 'mouseover', function() {
      config.mapMarkerMouseover(poi, this);
    });
  }
  if(typeof (config.mapMarkerMouseout) === 'function') {
    google.maps.event.addListener(marker, 'mouseout', function() {
      config.mapMarkerMouseout(poi, this);
    });
  }

  if(config.toursEnabled && poi.type === 'IMX_Mapwork_Poi_Tour') {
    marker.kmlLayer = this._buildKmlLayer(poi.kml, true);

    google.maps.event.addListener(marker, 'mouseover', function() {
      marker.kmlLayer.setMap(map);
    });

    google.maps.event.addListener(marker, 'mouseout', function() {
      marker.kmlLayer.setMap(null);
    });
  }
  return marker;
};

/**
 * Adds the given cluster to the map
 *
 * @param {Object} cluster
 * @returns {google.maps.Marker}
 * @private
 */
imx.Mapwork.Map.Google.prototype._addCluster = function(cluster) {
  var self = this;
  var pois = cluster.pois;
  var counter = Object.keys(pois).length;
  var bounds = new google.maps.LatLngBounds();
  var vendorConfig = this.getConfiguration().getVendorConfig();

  var fromLatLngToPoint = function(latLng) {
    var map = self.getMap();
    var topRight = map.getProjection().fromLatLngToPoint(map.getBounds().getNorthEast());
    var bottomLeft = map.getProjection().fromLatLngToPoint(map.getBounds().getSouthWest());
    var scale = Math.pow(2, map.getZoom());
    var worldPoint = map.getProjection().fromLatLngToPoint(latLng);
    return new google.maps.Point((worldPoint.x - bottomLeft.x) * scale, (worldPoint.y - topRight.y) * scale);
  };

  var hasVerySmallSpan = function(latLng) {
    var point = fromLatLngToPoint(latLng);
    var pointZero = fromLatLngToPoint(new google.maps.LatLng(0, 0));

    var zoom = (!vendorConfig.maxZoomOnSetPois || (vendorConfig.maxZoomOnSetPois && self.getZoom() >= vendorConfig.maxZoomOnSetPois));
    var smallSpan = (point.x - pointZero.x < vendorConfig.spiderfy.nearbyDistance || point.y - pointZero.y < vendorConfig.spiderfy.nearbyDistance);

    if(zoom && smallSpan) {
      return true;
    }
    return false;
  };

  for(var pIndex in pois) {
    var latLng = new google.maps.LatLng(pois[pIndex].latLng.latitude, pois[pIndex].latLng.longitude);
    bounds.extend(latLng);
  }

  if(counter === 1 || (this._oms && (counter <= 10 || hasVerySmallSpan(bounds.toSpan())))) {
    var markers = [];

    for(var i in cluster.pois) {
      markers.push(this._addMarker(cluster.pois[i], 'showLayer'));
    }
    return markers;
  }

  var marker = this._buildClusterMarker(cluster);

  google.maps.event.addListener(marker, 'click', function() {
    var mapTypeId = self.getMap().getMapTypeId();
    var mapType = self.getMap().mapTypes[mapTypeId];

    var openClusterInfowindow = false;
    if(typeof (mapType) === 'object') {
      openClusterInfowindow = (self.getZoom() === mapType.maxZoom);
    }

    if(bounds.getNorthEast().equals(bounds.getSouthWest()) || openClusterInfowindow) {
      if(typeof (vendorConfig.mapClusterMarkerClick) === 'function') {
        vendorConfig.mapClusterMarkerClick(marker.poi);
      }else {
        var infoWindow = self._buildClusterInfoWindow(marker.poi);
        self._setActiveInfoWindow(infoWindow);
        infoWindow.open(self.getMap(), marker);

        if(typeof (vendorConfig.onInfoBoxContentChanged) === 'function') {
          google.maps.event.addListener(infoWindow, 'domready', vendorConfig.onInfoBoxContentChanged)
        }
      }
    }else {
      self.getMap().fitBounds(bounds, vendorConfig.fitBoundsPadding || 0);
    }
  });
  return [marker];
};

/**
 * Hide the controls of this map.
 *
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.hideControls = function() {
  this.getMap().setOptions({
    disableDefaultUI: true
  });
  return this;
};

/**
 * Show the controls of this map.
 *
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.showControls = function() {
  this.getMap().setOptions({
    disableDefaultUI: false
  });
  return this;
};

/**
 * Calculate and show a route from start to end.
 * If a panelId is given the description will get rendered within a container having this ID.
 *
 * @param {String} start
 * @param {String} end
 * @param {String} panelId
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.showRoute = function(start, end, panelId) {
  this.hideRoute();

  if(!this._directionsRenderer && !this._directionsService) {
    this._directionsRenderer = new google.maps.DirectionsRenderer();
    this._directionsService = new google.maps.DirectionsService();
  }
  this._directionsPanelId = panelId || '';

  var request = {
    origin: start,
    destination: end,
    travelMode: google.maps.DirectionsTravelMode.DRIVING
  };

  var self = this;

  this._directionsService.route(request, function(response, status) {
    if(status !== google.maps.DirectionsStatus.OK) {
      return;
    }

    self._directionsRenderer.setOptions({
      directions: response,
      map: self.getMap(),
      infoWindow: self._buildRoutingInfoWindow(),
      markerOptions: self._buildRoutingMarkerOptions(),
      panel: (self._directionsPanelId !== '') ? document.getElementById(self._directionsPanelId) : null
    });
  });
  return this;
};

/**
 * Remove a route from the map.
 *
 * @returns {imx.Mapwork.Map}
 */
imx.Mapwork.Map.Google.prototype.hideRoute = function() {
  if(this._directionsRenderer && this._directionsService) {
    this._directionsRenderer.setMap(null);

    if(this._directionsPanelId !== '') {
      document.getElementById(this._directionsPanelId).textContent = '';
      this._directionsPanelId = '';
    }
  }
  return this;
};

window.imx = window.imx || {};
window.imx.Mapwork = window.imx.Mapwork || {};
window.imx.Mapwork.Map = window.imx.Mapwork.Map || {};

/**
 * Map object for wrapping the Leaflet API
 *
 * @class imx.Mapwork.Map.Leaflet
 * @constructor
 * @base imx.Mapwork.Map
 *
 * @param {String} id The HTML ID in which this map should be rendered into.
 * @param {imx.Mapwork.Configuration} configuration The configuration object for this map.
 */
imx.Mapwork.Map.Leaflet = function(id, configuration) {
  if(typeof (L) !== 'object') {
    throw new ReferenceError('Leaflet is not defined, but it\'s needed for the imx.Mapwork to work correctly.');
  }

  this.setId(id);
  this.setConfiguration(configuration);

  this._tileLayerId = null;
  this._tileLayerConfigs = [];

  this._layerIds = [];
  this._layerMarkers = [];

  this._poiIds = [];
  this._poiMarkers = [];

  this._clusteredPoiIds = [];
  this._clusteredPoiMarkers = [];
};

imx.Mapwork.Map.Leaflet.prototype = imx.Mapwork.Map.prototype;
imx.Mapwork.Map.Leaflet.prototype.constructor = imx.Mapwork.Map.Leaflet;

/**
 * Set the bounds of the map.
 * If the bounds cannot be set exactly, the best zoom level will be used to show the whole area.
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setBounds = function(bounds) {
  this.getMap().fitBounds(this.convertLatLngBoundsToBase(bounds), this.getConfiguration().getVendorConfig().fitBounds || {});
  return this;
};

/**
 * Get the exact bounds of this map.
 *
 * @returns {imx.Mapwork.LatLngBounds}
 */
imx.Mapwork.Map.Leaflet.prototype.getBounds = function() {
  return this.convertLatLngBoundsToMapwork(this.getMap().getBounds());
};

/**
 * Center the map to the given coordinate.
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setCenter = function(latLng) {
  this.getMap().panTo(this.convertLatLngToBase(latLng));
  return this;
};

/**
 * Get the center coordinate of the current map view.
 *
 * @returns {imx.Mapwork.LatLng}
 */
imx.Mapwork.Map.Leaflet.prototype.getCenter = function() {
  return this.convertLatLngToMapwork(this.getMap().getCenter());
};

/**
 * Set the maptype, that is getting shown.
 *
 * @see imx.Mapwork.mapTypeId
 * @param {Number|String} mapTypeId
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setMapTypeId = function(mapTypeId) {
  var self = this;
  var map = this.getMap();

  this._tileLayerConfigs.forEach(function(config) {
    if(config.id === mapTypeId) {
      self._tileLayerId = mapTypeId;
      config.layer.addTo(map);
    }else {
      config.layer.removeFrom(map);
    }
  });

  return this;
};

/**
 * Get the currently shown maptype.
 *
 * @see imx.Mapwork.mapTypeId
 * @returns {Number|String}
 */
imx.Mapwork.Map.Leaflet.prototype.getMapTypeId = function() {
  return this._tileLayerId;
};

/**
 * Set the zoom level for this map.
 *
 * @param {Number} zoom
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setZoom = function(zoom) {
  this.getMap().setZoom(zoom);
  return this;
};

/**
 * Get the current zoom level of this map.
 *
 * @returns {Number}
 */
imx.Mapwork.Map.Leaflet.prototype.getZoom = function() {
  return this.getMap().getZoom();
};

/**
 * Convert the given "imx.Mapwork.LatLng" object to "L.LatLng".
 *
 * @param {imx.Mapwork.LatLng} latLng
 * @returns {L.LatLng}
 */
imx.Mapwork.Map.Leaflet.prototype.convertLatLngToBase = function(latLng) {
  return new L.LatLng(latLng.getLatitude(), latLng.getLongitude());
};

/**
 * Convert the given "L.LatLng" object to "imx.Mapwork.LatLng".
 *
 * @param {L.LatLng} latLng
 * @returns {imx.Mapwork.LatLng}
 */
imx.Mapwork.Map.Leaflet.prototype.convertLatLngToMapwork = function(latLng) {
  return new imx.Mapwork.LatLng(latLng.lat, latLng.lng);
};

/**
 * Convert the given "imx.Mapwork.LatLngBounds" object to "L.LatLngBounds".
 *
 * @param {imx.Mapwork.LatLngBounds} bounds
 * @returns {L.LatLngBounds}
 */
imx.Mapwork.Map.Leaflet.prototype.convertLatLngBoundsToBase = function(bounds) {
  return new L.LatLngBounds(this.convertLatLngToBase(bounds.getSouthWest()), this.convertLatLngToBase(bounds.getNorthEast()));
};

/**
 * Convert the given "L.LatLngBounds" object to "imx.Mapwork.LatLngBounds".
 *
 * @param {L.LatLngBounds} bounds
 * @returns {imx.Mapwork.LatLngBounds}
 */
imx.Mapwork.Map.Leaflet.prototype.convertLatLngBoundsToMapwork = function(bounds) {
  return new imx.Mapwork.LatLngBounds(this.convertLatLngToMapwork(bounds.getSouthWest()), this.convertLatLngToMapwork(bounds.getNorthEast()));
};

/**
 * Hide the controls of this map.
 *
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.hideControls = function() {
  this.getMap().removeControl(this.getMap().zoomControl);
  return this;
};

/**
 * Show the controls of this map.
 *
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.showControls = function() {
  this.getMap().addControl(this.getMap().zoomControl);
  return this;
};

/**
 * Set, if this is a mini map or get the value, if the param is omitted.
 * If the params is given, the controls will be removed or added.
 *
 * @param {Boolean} [isMiniMap] If nothing is given the current state gets returned.
 * @returns {Boolean}
 */
imx.Mapwork.Map.Leaflet.prototype.isMiniMap = function(isMiniMap) {
  if(typeof (isMiniMap) !== 'undefined') {
    if(typeof (this.getMap()) === 'object') {
      isMiniMap ? this.hideControls() : this.showControls();
    }

    this._isMiniMap = isMiniMap;
  }

  return (this._isMiniMap === true);
};

/**
 * Go! Load the map!
 *
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.loadMap = function() {
  var self = this;
  var options = this.getConfiguration().getMapConfig();
  var config = this.getConfiguration().getVendorConfig();
  var readyCallback = this.getConfiguration().getReadyCallback();

  config.tileLayers.forEach(function(tileLayer) {
    var layer;

    if(tileLayer.type === 'wms') {
      layer = L.tileLayer.wms(tileLayer.url, tileLayer.options)
    }else {
      layer = L.tileLayer(tileLayer.url, tileLayer.options)
    }

    self._tileLayerConfigs.push({
      id: tileLayer.id,
      layer: layer
    });
  });

  var map = L.map(this.getId(), {
    zoom: options.zoom,
    center: this.convertLatLngToBase(options.center),
    scrollWheelZoom: options.scrollwheel,
    dragging: options.draggable
  });

  this.setMap(map);
  this.setMapTypeId(options.mapTypeId);

  map.whenReady(function() {
    readyCallback(self);
    map.on('resize zoomend moveend', self.refresh.bind(self));
  });

  return this;
};

/**
 * With this it is possible to show specific objects on the map.
 * Just pass some identfiers, that can be recognized by the underlying system of the vendor.
 *
 * @param {Array<String>} ids
 * @param {Function} [callback]
 * @param {Function} [ajaxCallback]
 * @param {Boolean} [noAutoFitBounds]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setPois = function(ids, callback, ajaxCallback, noAutoFitBounds) {
  var self = this;
  var config = this.getConfiguration().getVendorConfig();

  var callbackToSetBounds = function(pois) {
    if(pois[0] && noAutoFitBounds !== true) {
      var poiBoundingBox = new L.LatLngBounds();

      for(var index in pois) {
        poiBoundingBox.extend([pois[index].latLng.latitude, pois[index].latLng.longitude]);
      }

      self.getMap().fitBounds(poiBoundingBox, config.fitBounds || {});
    }

    if(config.maxZoomOnSetPois && self.getZoom() > config.maxZoomOnSetPois) {
      self.setZoom(config.maxZoomOnSetPois);
    }

    if(typeof (ajaxCallback) === 'function') {
      ajaxCallback();
    }
  };

  this._loadPois(ids, callbackToSetBounds);

  if(typeof (callback) === 'function') {
    callback();
  }

  return this;
};

/**
 * With this it is possible to show specific objects on the map, that get clustered.
 * Just pass some identfiers, that can be recognized by the underlying system of the vendor.
 *
 * @param {Array<String>} ids
 * @param {Function} [callback]
 * @param {Function} [ajaxCallback]
 * @param {Boolean} [noAutoFitBounds]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.setClusteredPois = function(ids, callback, ajaxCallback, noAutoFitBounds) {
  var self = this;
  var config = this.getConfiguration().getVendorConfig();

  var buildBoundingBox = function(pois, bounds) {
    bounds = bounds || new L.LatLngBounds();

    for(var index in pois) {
      if(pois[index].type === 'cluster') {
        bounds = buildBoundingBox(pois[index].pois, bounds);
      }else {
        bounds.extend([
          pois[index].latLng.latitude,
          pois[index].latLng.longitude
        ]);
      }
    }

    return bounds;
  };

  var callbackToSetBounds = function(pois) {
    if(pois[0] && noAutoFitBounds !== true) {
      self.getMap().fitBounds(buildBoundingBox(pois), config.fitBounds || {});
    }

    if(config.maxZoomOnSetPois && self.getZoom() > config.maxZoomOnSetPois) {
      self.setZoom(config.maxZoomOnSetPois);
    }

    if(typeof (ajaxCallback) === 'function') {
      ajaxCallback();
    }
  };

  this._loadClusteredPois(ids, callbackToSetBounds);

  if(typeof (callback) === 'function') {
    callback();
  }

  return this;
};

/**
 * Show a specific object on the map by its ID.
 *
 * @param {String} id
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.showPoi = function(id, callback) {
  var self = this;

  this.requestClusterServer('GET_POIS', {
    ids: [id]
  }, function(response) {
    var pois = response.objects;

    for(var index in pois) {
      self._poiMarkers.push(self._addMarker(pois[index], 'showPoi', index));

      if(typeof (callback) === 'function') {
        callback(pois[index]);
      }
    }
  });

  return this;
};

/**
 * Show any layer on the map, that can be activated by an identifier.
 *
 * @param {String} identifier
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.showLayer = function(identifier, callback) {
  var layerIds = this._layerIds;
  var isAlreadyContained = (layerIds.indexOf(identifier) > -1);

  if(!isAlreadyContained) {
    layerIds.push(identifier);
  }

  this._loadLayers(layerIds, callback);

  return this;
};

/**
 * Hide any layer on the map, that´s currently shown identified by the given identifier.
 *
 * @param {String} identifier
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.hideLayer = function(identifier, callback) {
  var layerIds = this._layerIds;
  var layerIndex = layerIds.indexOf(identifier);

  if(layerIndex > -1) {
    layerIds.splice(layerIndex, 1);
  }

  this._loadLayers(layerIds, callback);

  return this;
};

/**
 * Refreshes the map and repaints markers.
 *
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype.refresh = function() {
  this._loadLayers(this._layerIds);
  this._loadPois(this._poiIds);
  this._loadClusteredPois(this._clusteredPoiIds);
  return this;
};

/**
 * Requests the ClusterServer with the given method and params. Calls the given callback when the request was finished.
 *
 * @param {String} method
 * @param {Object} params
 * @param {Function} callback
 * @returns {Object}
 */
imx.Mapwork.Map.Leaflet.prototype.requestClusterServer = function(method, params, callback) {
  if(typeof (this._clusterServer) !== 'object') {
    this._clusterServer = new imx.Mapwork.ClusterServer().setConfiguration(this.getConfiguration());
  }

  this._clusterServer.setMethod(method).setBounds(this.getBounds()).setParams(params);
  return this._clusterServer.request(callback);
};

/**
 * Set the markers of layers, that are currently shown.
 * Also removes the previous markers.
 *
 * @private
 * @param {Array<L.Marker>} layerMarkers
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._setLayerMarkers = function(layerMarkers) {
  this._layerMarkers.forEach(function(marker) {
    marker.remove();
  });

  this._layerMarkers = layerMarkers;

  return this;
};

/**
 * Set the markers of POIs, that are currently shown.
 * Also removes the previous markers.
 *
 * @private
 * @param {Array<L.Marker>} markers
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._setPoiMarkers = function(markers) {
  this._poiMarkers.forEach(function(marker) {
    marker.remove();
  });

  this._poiMarkers = markers;

  return this;
};

/**
 * Set the markers of clustered POIs, that are currently shown.
 * Also removes the previous markers.
 *
 * @private
 * @param {Array<L.Marker>} clusteredPoiMarkers
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._setClusteredPoiMarkers = function(clusteredPoiMarkers) {
  this._clusteredPoiMarkers.forEach(function(marker) {
    marker.remove();
  });

  this._clusteredPoiMarkers = clusteredPoiMarkers;

  return this;
};

/**
 * Loads layer markers by using the given layer IDs and requesting the ClusterServer.
 *
 * @private
 * @param {Array<String>} layerIds
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._loadLayers = function(layerIds, callback) {
  var self = this;
  var config = this.getConfiguration().getVendorConfig();

  this._layerIds = layerIds;

  if(layerIds.length > 0) {
    this.requestClusterServer('FIND_POIS', {
      Profiling: layerIds
    }, function(response) {
      var clusters = response.objects;
      var layerMarkers = [];

      for(var clusterIndex in clusters) {
        var markers = self._addClusterMarker(clusters[clusterIndex]);

        for(var markerIndex = 0; markerIndex < markers.length; markerIndex++) {
          layerMarkers.push(markers[markerIndex]);
        }
      }

      self._setLayerMarkers(layerMarkers);

      if(typeof (callback) === 'function') {
        callback(clusters, layerIds);
      }

      if(typeof (config.layerCallback) === 'function') {
        config.layerCallback(clusters);
      }
    });
  }else {
    self._setLayerMarkers([]);

    if(typeof (callback) === 'function') {
      callback({}, []);
    }

    if(typeof (config.layerCallback) === 'function') {
      config.layerCallback({});
    }
  }

  return this;
};

/**
 * Loads cluster POI markers by using the given IDs and requesting the ClusterServer.
 *
 * @private
 * @param {Array<String>} ids
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._loadPois = function(ids, callback) {
  var self = this;

  this._poiIds = ids;

  if(ids.length > 0) {
    this.requestClusterServer('GET_POIS', {
      ids: ids
    }, function(response) {
      var pois = response.objects;
      var poiMarkers = [];

      for(var poiIndex in pois) {
        poiMarkers.push(self._addMarker(pois[poiIndex], 'setPois', poiIndex));
      }

      self._setPoiMarkers(poiMarkers);

      if(typeof (callback) === 'function') {
        callback(pois);
      }
    });
  }else {
    self._setPoiMarkers([]);

    if(typeof (callback) === 'function') {
      callback([]);
    }
  }

  return this;
};

/**
 * Loads cluster POI markers by using the given IDs and requesting the ClusterServer.
 *
 * @private
 * @param {Array<String>} ids
 * @param {Function} [callback]
 * @returns {imx.Mapwork.Map.Leaflet}
 */
imx.Mapwork.Map.Leaflet.prototype._loadClusteredPois = function(ids, callback) {
  var self = this;

  this._clusteredPoiIds = ids;

  if(ids.length > 0) {
    this.requestClusterServer('GET_CLUSTERED_POIS', {
      ids: ids
    }, function(response) {
      var pois = response.objects;
      var clusteredPoiMarkers = [];

      for(var poiIndex in pois) {
        var poi = pois[poiIndex];
        var markers = self._addClusterMarker(poi);

        for(var markerIndex = 0; markerIndex < markers.length; markerIndex++) {
          clusteredPoiMarkers.push(markers[markerIndex]);
        }
      }

      self._setClusteredPoiMarkers(clusteredPoiMarkers);

      if(typeof (callback) === 'function') {
        callback(pois);
      }
    });
  }else {
    self._setClusteredPoiMarkers([]);

    if(typeof (callback) === 'function') {
      callback([]);
    }
  }

  return this;
};

/**
 * Adds the given POI to the map by rendering a marker.
 *
 * @private
 * @param {Object} poi
 * @param {String} originMethod
 * @param {Number} index
 * @returns {L.Marker}
 */
imx.Mapwork.Map.Leaflet.prototype._addMarker = function(poi, originMethod, index) {
  originMethod = originMethod || 'setPois';

  var self = this;
  var map = self.getMap();
  var marker = this._buildMarker(poi, originMethod, index);
  var config = this.getConfiguration().getVendorConfig();

  var clickFunction = function() {
    if(config.infoWindowEnabled === true) {
      self._buildInfoWindow(poi).openOn(map);
    }
  };

  if(!this.isMiniMap() && typeof (config.mapMarkerClick) === 'function') {
    clickFunction = function() {
      config.mapMarkerClick(poi, this);
    };
  }

  if(this.isMiniMap() && typeof (config.miniMapMarkerClick) === 'function') {
    clickFunction = function() {
      config.miniMapMarkerClick(poi, this);
    };
  }

  marker.on('click', clickFunction);

  if(typeof (config.mapMarkerMouseover) === 'function') {
    marker.on('mouseover', function() {
      config.mapMarkerMouseover(poi, this);
    });
  }

  if(typeof (config.mapMarkerMouseout) === 'function') {
    marker.on('mouseout', function() {
      config.mapMarkerMouseout(poi, this);
    });
  }

  return marker;
};

/**
 * Adds the given cluster to the map by rendering a marker.
 *
 * @private
 * @param {Object} cluster
 * @returns {Array<L.Marker>}
 */
imx.Mapwork.Map.Leaflet.prototype._addClusterMarker = function(cluster) {
  var self = this;
  var counter = 0;
  var pois = cluster.pois;
  var bounds = new L.LatLngBounds();
  var markers = [];
  var config = this.getConfiguration().getVendorConfig();

  for(var poiIndex in pois) {
    counter++;
    bounds.extend(L.latLng(pois[poiIndex].latLng.latitude, pois[poiIndex].latLng.longitude));
  }

  if(counter === 1) {
    for(var singlePoiIndex in pois) {
      markers.push(this._addMarker(pois[singlePoiIndex], 'showLayer'));
    }
  }else {
    var marker = this._buildClusterMarker(cluster);

    markers.push(marker);

    marker.on('click', function() {
      var openClusterInfowindow = (self.getZoom() === self.getMap().getMaxZoom());

      if(openClusterInfowindow) {
        if(typeof (config.mapClusterMarkerClick) === 'function') {
          config.mapClusterMarkerClick(cluster);
        }else {
          self._buildClusterInfoWindow(cluster).openOn(self.getMap());
        }
      }else {
        self.getMap().fitBounds(bounds, config.fitBounds || {});
      }
    });
  }

  return markers;
};

/**
 * Creates a marker for the map. If a custom icon is configured, this will be created.
 *
 * @private
 * @param {Object} poi
 * @param {String} originMethod
 * @param {Number} index
 * @returns {L.Marker}
 */
imx.Mapwork.Map.Leaflet.prototype._buildMarker = function(poi, originMethod, index) {
  var config = this.getConfiguration().getVendorConfig();
  var icon = null;

  if(typeof (config.mapIcon) === 'function') {
    icon = config.mapIcon(poi, originMethod, index);
  }else {
    var size = null;
    var anchor = null;
    var content = document.createElement('div');
    var helper = document.createElement('div');

    content.classList.add('imx-poi', originMethod);

    if(typeof (config.mapIcon) === 'object') {
      size = L.point(config.mapIcon.size[0], config.mapIcon.size[1]);
      anchor = L.point(config.mapIcon.anchor[0], config.mapIcon.anchor[1]);

      content.style.width = config.mapIcon.size[0] + 'px';
      content.style.height = config.mapIcon.size[1] + 'px';
      content.style.backgroundImage = 'url(' + config.mapIcon.url(poi, originMethod, index) + ')';
    }else {
      size = L.point(27,27);
      anchor = L.point(13, 13);

      content.style.width = '25px';
      content.style.height = '25px';
      content.style.background = '#fff';
      content.style.border = '1px solid #000';
    }

    if(config.showPoiNumbers && index) {
      var counterSpan = document.createElement('span');

      counterSpan.innerHTML = (parseInt(index) + 1);

      content.appendChild(counterSpan);
    }

    helper.appendChild(content);

    icon = L.divIcon({
      html: helper.innerHTML,
      className: 'imx-poi-marker',
      iconSize: size,
      iconAnchor: anchor
    });
  }

  var marker = L.marker([poi.latLng.latitude, poi.latLng.longitude], {
    riseOnHover: true,
    title: poi.title,
    icon: icon
  });

  marker.addTo(this.getMap());

  return marker;
};

/**
 * Creates a cluster marker for the map. If a custom icon is configured, this will be created.
 *
 * @private
 * @param {Object} cluster
 * @returns {L.Marker}
 */
imx.Mapwork.Map.Leaflet.prototype._buildClusterMarker = function(cluster) {
  var config = this.getConfiguration().getVendorConfig();
  var icon = null;

  if(typeof (config.clusterIcon) === 'function') {
    icon = config.clusterIcon(cluster);
  }else {
    var size = null;
    var anchor = null;
    var content = document.createElement('div');
    var helper = document.createElement('div');

    content.classList.add('imx-cluster');

    if(typeof (config.clusterIcon) === 'object') {
      size = L.point(config.clusterIcon.size[0], config.clusterIcon.size[1]);
      anchor = L.point(config.clusterIcon.anchor[0], config.clusterIcon.anchor[1]);

      content.style.width = config.clusterIcon.size[0] + 'px';
      content.style.height = config.clusterIcon.size[1] + 'px';
      content.style.backgroundImage = 'url(' + config.clusterIcon.url(cluster) + ')';
    }else {
      size = L.point(27,27);
      anchor = L.point(13, 13);

      content.style.width = '25px';
      content.style.height = '25px';
      content.style.background = '#fff';
      content.style.border = '1px solid #000';
    }

    if(!config.hideClusterCounter) {
      var counterSpan = document.createElement('span');
      var counter = 0;

      for(var i in cluster.pois) {
        counter++;
      }

      counterSpan.innerHTML = '' + counter;

      content.appendChild(counterSpan);
    }

    helper.appendChild(content);

    icon = L.divIcon({
      html: helper.innerHTML,
      className: 'imx-cluster-marker',
      iconSize: size,
      iconAnchor: anchor
    });
  }

  var marker = L.marker([cluster.latLng.latitude, cluster.latLng.longitude], {
    riseOnHover: true,
    icon: icon
  });

  marker.addTo(this.getMap());

  return marker;
};

/**
 * Creates an infowindow for the map. If a custom content is configured, this will be used.
 *
 * @private
 * @param {Object} poi
 * @returns {L.Popup}
 */
imx.Mapwork.Map.Leaflet.prototype._buildInfoWindow = function(poi) {
  var config = this.getConfiguration().getVendorConfig();
  var content = poi.title;

  if(typeof (config.infoWindowContents) === 'function') {
    content = config.infoWindowContents(poi);
  }

  var infoWindow = L.popup({
    className: 'imx-infowindow',
    offset: config.infowindowOffset || L.point(0, 7)
  });

  infoWindow.setLatLng([poi.latLng.latitude, poi.latLng.longitude]);
  infoWindow.setContent(content);

  return infoWindow;
};

/**
 * Creates a cluster infowindow for the map. If a custom content is configured, this will be used.
 *
 * @private
 * @param {Object} cluster
 * @returns {L.Popup}
 */
imx.Mapwork.Map.Leaflet.prototype._buildClusterInfoWindow = function(cluster) {
  var boundingBox = cluster.boundingBox;
  var southWest = L.latLng(boundingBox.south, boundingBox.west);
  var northEast = L.latLng(boundingBox.north, boundingBox.east);

  var latLng = L.latLngBounds(southWest, northEast).getCenter();
  var pois = cluster.pois;

  var config = this.getConfiguration().getVendorConfig();

  if(typeof (config.clusterInfoWindowContents) === 'function') {
    infoWindowContent = config.clusterInfoWindowContents(cluster);
  }else {
    var infoWindowContent = '<ul>';

    for(var i in pois) {
      infoWindowContent += '<li><a href="' + pois[i].url + '">' + pois[i].title + '</a></li>';
    }

    infoWindowContent += '</ul>';
  }

  var infoWindow = L.popup({
    className: 'imx-infowindow imx-clusterwindow',
    offset: config.infowindowOffset || L.point(0, 7)
  });

  infoWindow.setLatLng(latLng);
  infoWindow.setContent(infoWindowContent);

  return infoWindow;
};

if(window.google && window.google.maps) {
  /**
   * @name InfoBox
   * @version 1.1.5 [March 1, 2011]
   * @author Gary Little (inspired by proof-of-concept code from Pamela Fox of Google)
   * @copyright Copyright 2010 Gary Little [gary at luxcentral.com]
   * @fileoverview InfoBox extends the Google Maps JavaScript API V3 <tt>OverlayView</tt> class.
   *  <p>
   *  An InfoBox behaves like a <tt>google.maps.InfoWindow</tt>, but it supports several
   *  additional properties for advanced styling. An InfoBox can also be used as a map label.
   *  <p>
   *  An InfoBox also fires the same events as a <tt>google.maps.InfoWindow</tt>.
   *  <p>
   *  Browsers tested:
   *  <p>
   *  Mac -- Safari (4.0.4), Firefox (3.6), Opera (10.10), Chrome (4.0.249.43), OmniWeb (5.10.1)
   *  <br>
   *  Win -- Safari, Firefox, Opera, Chrome (3.0.195.38), Internet Explorer (8.0.6001.18702)
   *  <br>
   *  iPod Touch/iPhone -- Safari (3.1.2)
   */

  /*!
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *       http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */

  /*jslint browser:true */
  /*global google */

  /**
   * @name InfoBoxOptions
   * @class This class represents the optional parameter passed to the {@link InfoBox} constructor.
   * @property {string|Node} content The content of the InfoBox (plain text or an HTML DOM node).
   * @property {boolean} disableAutoPan Disable auto-pan on <tt>open</tt> (default is <tt>false</tt>).
   * @property {number} maxWidth The maximum width (in pixels) of the InfoBox. Set to 0 if no maximum.
   * @property {Size} pixelOffset The offset (in pixels) from the top left corner of the InfoBox
   *  (or the bottom left corner if the <code>alignBottom</code> property is <code>true</code>)
   *  to the map pixel corresponding to <tt>position</tt>.
   * @property {LatLng} position The geographic location at which to display the InfoBox.
   * @property {number} zIndex The CSS z-index style value for the InfoBox.
   *  Note: This value overrides a zIndex setting specified in the <tt>boxStyle</tt> property.
   * @property {string} boxClass The name of the CSS class defining the styles for the InfoBox container.
   *  The default name is <code>infoBox</code>.
   * @property {Object} [boxStyle] An object literal whose properties define specific CSS
   *  style values to be applied to the InfoBox. Style values defined here override those that may
   *  be defined in the <code>boxClass</code> style sheet. If this property is changed after the
   *  InfoBox has been created, all previously set styles (except those defined in the style sheet)
   *  are removed from the InfoBox before the new style values are applied.
   * @property {string} closeBoxMargin The CSS margin style value for the close box.
   *  The default is "2px" (a 2-pixel margin on all sides).
   * @property {string} closeBoxURL The URL of the image representing the close box.
   *  Note: The default is the URL for Google's standard close box.
   *  Set this property to "" if no close box is required.
   * @property {Size} infoBoxClearance Minimum offset (in pixels) from the InfoBox to the
   *  map edge after an auto-pan.
   * @property {boolean} isHidden Hide the InfoBox on <tt>open</tt> (default is <tt>false</tt>).
   * @property {boolean} alignBottom Align the bottom left corner of the InfoBox to the <code>position</code>
   *  location (default is <tt>false</tt> which means that the top left corner of the InfoBox is aligned).
   * @property {string} pane The pane where the InfoBox is to appear (default is "floatPane").
   *  Set the pane to "mapPane" if the InfoBox is being used as a map label.
   *  Valid pane names are the property names for the <tt>google.maps.MapPanes</tt> object.
   * @property {boolean} enableEventPropagation Propagate mousedown, click, dblclick,
   *  and contextmenu events in the InfoBox (default is <tt>false</tt> to mimic the behavior
   *  of a <tt>google.maps.InfoWindow</tt>). Set this property to <tt>true</tt> if the InfoBox
   *  is being used as a map label. iPhone note: This property setting has no effect; events are
   *  always propagated.
   */

  /**
   * Creates an InfoBox with the options specified in {@link InfoBoxOptions}.
   *  Call <tt>InfoBox.open</tt> to add the box to the map.
   * @constructor
   * @param {InfoBoxOptions} [opt_opts]
   */
  function InfoBox(opt_opts) {

    opt_opts = opt_opts || {};

    google.maps.OverlayView.apply(this, arguments);

    // Standard options (in common with google.maps.InfoWindow):
    //
    this.content_ = opt_opts.content || "";
    this.disableAutoPan_ = opt_opts.disableAutoPan || false;
    this.maxWidth_ = opt_opts.maxWidth || 0;
    this.pixelOffset_ = opt_opts.pixelOffset || new google.maps.Size(0, 0);
    this.position_ = opt_opts.position || new google.maps.LatLng(0, 0);
    this.zIndex_ = opt_opts.zIndex || null;

    // Additional options (unique to InfoBox):
    //
    this.boxClass_ = opt_opts.boxClass || "infoBox";
    this.boxStyle_ = opt_opts.boxStyle || {};
    this.closeBoxMargin_ = opt_opts.closeBoxMargin || "2px";
    this.closeBoxURL_ = opt_opts.closeBoxURL || "https://www.google.com/intl/en_us/mapfiles/close.gif";
    if (opt_opts.closeBoxURL === "") {
      this.closeBoxURL_ = "";
    }
    this.infoBoxClearance_ = opt_opts.infoBoxClearance || new google.maps.Size(1, 1);
    this.isHidden_ = opt_opts.isHidden || false;
    this.alignBottom_ = opt_opts.alignBottom || false;
    this.pane_ = opt_opts.pane || "floatPane";
    this.enableEventPropagation_ = opt_opts.enableEventPropagation || false;

    this.div_ = null;
    this.closeListener_ = null;
    this.eventListener1_ = null;
    this.eventListener2_ = null;
    this.eventListener3_ = null;
    this.moveListener_ = null;
    this.contextListener_ = null;
    this.fixedWidthSet_ = null;
  }

  /* InfoBox extends OverlayView in the Google Maps API v3.
   */
  InfoBox.prototype = new google.maps.OverlayView();

  /**
   * Creates the DIV representing the InfoBox.
   * @private
   */
  InfoBox.prototype.createInfoBoxDiv_ = function () {

    var bw;
    var me = this;

    // This handler prevents an event in the InfoBox from being passed on to the map.
    //
    var cancelHandler = function (e) {
      e.cancelBubble = true;

      if (e.stopPropagation) {

        e.stopPropagation();
      }
    };

    // This handler ignores the current event in the InfoBox and conditionally prevents
    // the event from being passed on to the map. It is used for the contextmenu event.
    //
    var ignoreHandler = function (e) {

      e.returnValue = false;

      if (e.preventDefault) {

        e.preventDefault();
      }

      if (!me.enableEventPropagation_) {

        cancelHandler(e);
      }
    };

    if (!this.div_) {

      this.div_ = document.createElement("div");

      this.setBoxStyle_();

      if (typeof this.content_.nodeType === "undefined") {
        this.div_.innerHTML = this.getCloseBoxImg_() + this.content_;
      } else {
        this.div_.innerHTML = this.getCloseBoxImg_();
        this.div_.appendChild(this.content_);
      }

      // Add the InfoBox DIV to the DOM
      this.getPanes()[this.pane_].appendChild(this.div_);

      this.addClickHandler_();

      if (this.div_.style.width) {

        this.fixedWidthSet_ = true;

      } else {

        if (this.maxWidth_ !== 0 && this.div_.offsetWidth > this.maxWidth_) {

          this.div_.style.width = this.maxWidth_;
          this.div_.style.overflow = "auto";
          this.fixedWidthSet_ = true;

        } else { // The following code is needed to overcome problems with MSIE

          bw = this.getBoxWidths_();

          this.div_.style.width = (this.div_.offsetWidth - bw.left - bw.right) + "px";
          this.fixedWidthSet_ = false;
        }
      }

      this.panBox_(this.disableAutoPan_);

      if (!this.enableEventPropagation_) {

        // Cancel event propagation.
        //
        this.eventListener1_ = google.maps.event.addDomListener(this.div_, "mousedown", cancelHandler);
        this.eventListener2_ = google.maps.event.addDomListener(this.div_, "click", cancelHandler);
        this.eventListener3_ = google.maps.event.addDomListener(this.div_, "dblclick", cancelHandler);
      }

      this.contextListener_ = google.maps.event.addDomListener(this.div_, "contextmenu", ignoreHandler);

      /**
       * This event is fired when the DIV containing the InfoBox's content is attached to the DOM.
       * @name InfoBox#domready
       * @event
       */
      google.maps.event.trigger(this, "domready");
    }
  };

  /**
   * Returns the HTML <IMG> tag for the close box.
   * @private
   */
  InfoBox.prototype.getCloseBoxImg_ = function () {

    var img = "";

    if (this.closeBoxURL_ !== "") {

      img  = "<img";
      img += " src='" + this.closeBoxURL_ + "'";
      img += " align=right"; // Do this because Opera chokes on style='float: right;'
      img += " style='";
      img += " position: relative;"; // Required by MSIE
      img += " cursor: pointer;";
      img += " margin: " + this.closeBoxMargin_ + ";";
      img += "'>";
    }

    return img;
  };

  /**
   * Adds the click handler to the InfoBox close box.
   * @private
   */
  InfoBox.prototype.addClickHandler_ = function () {

    var closeBox;

    if (this.closeBoxURL_ !== "") {

      closeBox = this.div_.firstChild;
      this.closeListener_ = google.maps.event.addDomListener(closeBox, 'click', this.getCloseClickHandler_());

    } else {

      this.closeListener_ = null;
    }
  };

  /**
   * Returns the function to call when the user clicks the close box of an InfoBox.
   * @private
   */
  InfoBox.prototype.getCloseClickHandler_ = function () {

    var me = this;

    return function (e) {

      // 1.0.3 fix: Always prevent propagation of a close box click to the map:
      e.cancelBubble = true;

      if (e.stopPropagation) {

        e.stopPropagation();
      }

      me.close();

      /**
       * This event is fired when the InfoBox's close box is clicked.
       * @name InfoBox#closeclick
       * @event
       */
      google.maps.event.trigger(me, "closeclick");
    };
  };

  /**
   * Pans the map so that the InfoBox appears entirely within the map's visible area.
   * @private
   */
  InfoBox.prototype.panBox_ = function (disablePan) {

    var map;
    var bounds;
    var xOffset = 0, yOffset = 0;

    if (!disablePan) {

      map = this.getMap();

      if (map instanceof google.maps.Map) { // Only pan if attached to map, not panorama

        if (!map.getBounds().contains(this.position_)) {
        // Marker not in visible area of map, so set center
        // of map to the marker position first.
          map.setCenter(this.position_);
        }

        bounds = map.getBounds();

        var mapDiv = map.getDiv();
        var mapWidth = mapDiv.offsetWidth;
        var mapHeight = mapDiv.offsetHeight;
        var iwOffsetX = this.pixelOffset_.width;
        var iwOffsetY = this.pixelOffset_.height;
        var iwWidth = this.div_.offsetWidth;
        var iwHeight = this.div_.offsetHeight;
        var padX = this.infoBoxClearance_.width;
        var padY = this.infoBoxClearance_.height;
        var pixPosition = this.getProjection().fromLatLngToContainerPixel(this.position_);

        if (pixPosition.x < (-iwOffsetX + padX)) {
          xOffset = pixPosition.x + iwOffsetX - padX;
        } else if ((pixPosition.x + iwWidth + iwOffsetX + padX) > mapWidth) {
          xOffset = pixPosition.x + iwWidth + iwOffsetX + padX - mapWidth;
        }
        if (this.alignBottom_) {
          if (pixPosition.y < (-iwOffsetY + padY + iwHeight)) {
            yOffset = pixPosition.y + iwOffsetY - padY - iwHeight;
          } else if ((pixPosition.y + iwOffsetY + padY) > mapHeight) {
            yOffset = pixPosition.y + iwOffsetY + padY - mapHeight;
          }
        } else {
          if (pixPosition.y < (-iwOffsetY + padY)) {
            yOffset = pixPosition.y + iwOffsetY - padY;
          } else if ((pixPosition.y + iwHeight + iwOffsetY + padY) > mapHeight) {
            yOffset = pixPosition.y + iwHeight + iwOffsetY + padY - mapHeight;
          }
        }

        if (!(xOffset === 0 && yOffset === 0)) {

          // Move the map to the shifted center.
          //
          var c = map.getCenter();
          map.panBy(xOffset, yOffset);
        }
      }
    }
  };

  /**
   * Sets the style of the InfoBox by setting the style sheet and applying
   * other specific styles requested.
   * @private
   */
  InfoBox.prototype.setBoxStyle_ = function () {

    var i, boxStyle;

    if (this.div_) {

      // Apply style values from the style sheet defined in the boxClass parameter:
      this.div_.className = this.boxClass_;

      // Clear existing inline style values:
      this.div_.style.cssText = "";

      // Apply style values defined in the boxStyle parameter:
      boxStyle = this.boxStyle_;
      for (i in boxStyle) {

        if (boxStyle.hasOwnProperty(i)) {

          this.div_.style[i] = boxStyle[i];
        }
      }

      // Fix up opacity style for benefit of MSIE:
      //
      if (typeof this.div_.style.opacity !== "undefined" && this.div_.style.opacity !== "") {

        this.div_.style.filter = "alpha(opacity=" + (this.div_.style.opacity * 100) + ")";
      }

      // Apply required styles:
      //
      this.div_.style.position = "absolute";
      this.div_.style.visibility = 'hidden';
      if (this.zIndex_ !== null) {

        this.div_.style.zIndex = this.zIndex_;
      }
    }
  };

  /**
   * Get the widths of the borders of the InfoBox.
   * @private
   * @return {Object} widths object (top, bottom left, right)
   */
  InfoBox.prototype.getBoxWidths_ = function () {

    var computedStyle;
    var bw = {top: 0, bottom: 0, left: 0, right: 0};
    var box = this.div_;

    if (document.defaultView && document.defaultView.getComputedStyle) {

      computedStyle = box.ownerDocument.defaultView.getComputedStyle(box, "");

      if (computedStyle) {

        // The computed styles are always in pixel units (good!)
        bw.top = parseInt(computedStyle.borderTopWidth, 10) || 0;
        bw.bottom = parseInt(computedStyle.borderBottomWidth, 10) || 0;
        bw.left = parseInt(computedStyle.borderLeftWidth, 10) || 0;
        bw.right = parseInt(computedStyle.borderRightWidth, 10) || 0;
      }

    } else if (document.documentElement.currentStyle) { // MSIE

      if (box.currentStyle) {

        // The current styles may not be in pixel units, but assume they are (bad!)
        bw.top = parseInt(box.currentStyle.borderTopWidth, 10) || 0;
        bw.bottom = parseInt(box.currentStyle.borderBottomWidth, 10) || 0;
        bw.left = parseInt(box.currentStyle.borderLeftWidth, 10) || 0;
        bw.right = parseInt(box.currentStyle.borderRightWidth, 10) || 0;
      }
    }

    return bw;
  };

  /**
   * Invoked when <tt>close</tt> is called. Do not call it directly.
   */
  InfoBox.prototype.onRemove = function () {

    if (this.div_) {

      this.div_.parentNode.removeChild(this.div_);
      this.div_ = null;
    }
  };

  /**
   * Draws the InfoBox based on the current map projection and zoom level.
   */
  InfoBox.prototype.draw = function () {

    this.createInfoBoxDiv_();

    var pixPosition = this.getProjection().fromLatLngToDivPixel(this.position_);

    this.div_.style.left = (pixPosition.x + this.pixelOffset_.width) + "px";

    if (this.alignBottom_) {
      this.div_.style.bottom = -(pixPosition.y + this.pixelOffset_.height) + "px";
    } else {
      this.div_.style.top = (pixPosition.y + this.pixelOffset_.height) + "px";
    }

    if (this.isHidden_) {

      this.div_.style.visibility = 'hidden';

    } else {

      this.div_.style.visibility = "visible";
    }
  };

  /**
   * Sets the options for the InfoBox. Note that changes to the <tt>maxWidth</tt>,
   *  <tt>closeBoxMargin</tt>, <tt>closeBoxURL</tt>, and <tt>enableEventPropagation</tt>
   *  properties have no affect until the current InfoBox is <tt>close</tt>d and a new one
   *  is <tt>open</tt>ed.
   * @param {InfoBoxOptions} opt_opts
   */
  InfoBox.prototype.setOptions = function (opt_opts) {
    if (typeof opt_opts.boxClass !== "undefined") { // Must be first

      this.boxClass_ = opt_opts.boxClass;
      this.setBoxStyle_();
    }
    if (typeof opt_opts.boxStyle !== "undefined") { // Must be second

      this.boxStyle_ = opt_opts.boxStyle;
      this.setBoxStyle_();
    }
    if (typeof opt_opts.content !== "undefined") {

      this.setContent(opt_opts.content);
    }
    if (typeof opt_opts.disableAutoPan !== "undefined") {

      this.disableAutoPan_ = opt_opts.disableAutoPan;
    }
    if (typeof opt_opts.maxWidth !== "undefined") {

      this.maxWidth_ = opt_opts.maxWidth;
    }
    if (typeof opt_opts.pixelOffset !== "undefined") {

      this.pixelOffset_ = opt_opts.pixelOffset;
    }
    if (typeof opt_opts.position !== "undefined") {

      this.setPosition(opt_opts.position);
    }
    if (typeof opt_opts.zIndex !== "undefined") {

      this.setZIndex(opt_opts.zIndex);
    }
    if (typeof opt_opts.closeBoxMargin !== "undefined") {

      this.closeBoxMargin_ = opt_opts.closeBoxMargin;
    }
    if (typeof opt_opts.closeBoxURL !== "undefined") {

      this.closeBoxURL_ = opt_opts.closeBoxURL;
    }
    if (typeof opt_opts.infoBoxClearance !== "undefined") {

      this.infoBoxClearance_ = opt_opts.infoBoxClearance;
    }
    if (typeof opt_opts.isHidden !== "undefined") {

      this.isHidden_ = opt_opts.isHidden;
    }
    if (typeof opt_opts.enableEventPropagation !== "undefined") {

      this.enableEventPropagation_ = opt_opts.enableEventPropagation;
    }

    if (this.div_) {

      this.draw();
    }
  };

  /**
   * Sets the content of the InfoBox.
   *  The content can be plain text or an HTML DOM node.
   * @param {string|Node} content
   */
  InfoBox.prototype.setContent = function (content) {
    this.content_ = content;

    if (this.div_) {

      if (this.closeListener_) {

        google.maps.event.removeListener(this.closeListener_);
        this.closeListener_ = null;
      }

      // Odd code required to make things work with MSIE.
      //
      if (!this.fixedWidthSet_) {

        this.div_.style.width = "";
      }

      if (typeof content.nodeType === "undefined") {
        this.div_.innerHTML = this.getCloseBoxImg_() + content;
      } else {
        this.div_.innerHTML = this.getCloseBoxImg_();
        this.div_.appendChild(content);
      }

      // Perverse code required to make things work with MSIE.
      // (Ensures the close box does, in fact, float to the right.)
      //
      if (!this.fixedWidthSet_) {

        this.div_.style.width = this.div_.offsetWidth + "px";
        this.div_.innerHTML = this.getCloseBoxImg_() + content;
      }

      this.addClickHandler_();
    }

    /**
     * This event is fired when the content of the InfoBox changes.
     * @name InfoBox#content_changed
     * @event
     */
    google.maps.event.trigger(this, "content_changed");
  };

  /**
   * Sets the geographic location of the InfoBox.
   * @param {LatLng} latlng
   */
  InfoBox.prototype.setPosition = function (latlng) {

    this.position_ = latlng;

    if (this.div_) {

      this.draw();
    }

    /**
     * This event is fired when the position of the InfoBox changes.
     * @name InfoBox#position_changed
     * @event
     */
    google.maps.event.trigger(this, "position_changed");
  };

  /**
   * Sets the zIndex style for the InfoBox.
   * @param {number} index
   */
  InfoBox.prototype.setZIndex = function (index) {

    this.zIndex_ = index;

    if (this.div_) {

      this.div_.style.zIndex = index;
    }

    /**
     * This event is fired when the zIndex of the InfoBox changes.
     * @name InfoBox#zindex_changed
     * @event
     */
    google.maps.event.trigger(this, "zindex_changed");
  };

  /**
   * Returns the content of the InfoBox.
   * @returns {string}
   */
  InfoBox.prototype.getContent = function () {

    return this.content_;
  };

  /**
   * Returns the geographic location of the InfoBox.
   * @returns {LatLng}
   */
  InfoBox.prototype.getPosition = function () {

    return this.position_;
  };

  /**
   * Returns the zIndex for the InfoBox.
   * @returns {number}
   */
  InfoBox.prototype.getZIndex = function () {

    return this.zIndex_;
  };

  /**
   * Shows the InfoBox.
   */
  InfoBox.prototype.show = function () {

    this.isHidden_ = false;
    if (this.div_) {
      this.div_.style.visibility = "visible";
    }
  };

  /**
   * Hides the InfoBox.
   */
  InfoBox.prototype.hide = function () {

    this.isHidden_ = true;
    if (this.div_) {
      this.div_.style.visibility = "hidden";
    }
  };

  /**
   * Adds the InfoBox to the specified map or Street View panorama. If <tt>anchor</tt>
   *  (usually a <tt>google.maps.Marker</tt>) is specified, the position
   *  of the InfoBox is set to the position of the <tt>anchor</tt>. If the
   *  anchor is dragged to a new location, the InfoBox moves as well.
   * @param {Map|StreetViewPanorama} map
   * @param {MVCObject} [anchor]
   */
  InfoBox.prototype.open = function (map, anchor) {

    var me = this;

    if (anchor) {

      this.position_ = anchor.getPosition();
      this.moveListener_ = google.maps.event.addListener(anchor, "position_changed", function () {
        me.setPosition(this.getPosition());
      });
    }

    this.setMap(map);

    if (this.div_) {

      this.panBox_();
    }
  };

  /**
   * Removes the InfoBox from the map.
   */
  InfoBox.prototype.close = function () {

    if (this.closeListener_) {

      google.maps.event.removeListener(this.closeListener_);
      this.closeListener_ = null;
    }

    if (this.eventListener1_) {

      google.maps.event.removeListener(this.eventListener1_);
      google.maps.event.removeListener(this.eventListener2_);
      google.maps.event.removeListener(this.eventListener3_);
      this.eventListener1_ = null;
      this.eventListener2_ = null;
      this.eventListener3_ = null;
    }

    if (this.moveListener_) {

      google.maps.event.removeListener(this.moveListener_);
      this.moveListener_ = null;
    }

    if (this.contextListener_) {

      google.maps.event.removeListener(this.contextListener_);
      this.contextListener_ = null;
    }

    this.setMap(null);
  };
}

if(window.google && window.google.maps) {
  // ==ClosureCompiler==

  // @compilation_level ADVANCED_OPTIMIZATIONS
  // @externs_url http://closure-compiler.googlecode.com/svn/trunk/contrib/externs/maps/google_maps_api_v3.js
  // @output_wrapper (function() {%output%})();
  // ==/ClosureCompiler==

  /**
   * A RichMarker that allows any HTML/DOM to be added to a map and be draggable.
   *
   * @param {Object.<string, *>=} opt_options Optional properties to set.
   * @extends {google.maps.OverlayView}
   * @constructor
   */
  function RichMarker(opt_options) {
    var options = opt_options || {};

    /**
     * @type {boolean}
     * @private
     */
    this.ready_ = false;

    /**
     * @type {boolean}
     * @private
     */
    this.dragging_ = false;

    if (opt_options['visible'] == undefined) {
      opt_options['visible'] = true;
    }

    if (opt_options['shadow'] == undefined) {
      opt_options['shadow'] = '7px -3px 5px rgba(88,88,88,0.7)';
    }

    if (opt_options['anchor'] == undefined) {
      opt_options['anchor'] = RichMarkerPosition['BOTTOM'];
    }

    this.setValues(options);
  }
  RichMarker.prototype = new google.maps.OverlayView();
  window['RichMarker'] = RichMarker;


  /**
   * Returns the current visibility state of the marker.
   *
   * @return {boolean} The visiblity of the marker.
   */
  RichMarker.prototype.getVisible = function() {
    return /** @type {boolean} */ (this.get('visible'));
  };
  RichMarker.prototype['getVisible'] = RichMarker.prototype.getVisible;


  /**
   * Sets the visiblility state of the marker.
   *
   * @param {boolean} visible The visiblilty of the marker.
   */
  RichMarker.prototype.setVisible = function(visible) {
    this.set('visible', visible);
  };
  RichMarker.prototype['setVisible'] = RichMarker.prototype.setVisible;


  /**
   *  The visible changed event.
   */
  RichMarker.prototype.visible_changed = function() {
    if (this.ready_) {
      this.markerWrapper_.style['display'] = this.getVisible() ? '' : 'none';
      this.draw();
    }
  };
  RichMarker.prototype['visible_changed'] = RichMarker.prototype.visible_changed;


  /**
   * Sets the marker to be flat.
   *
   * @param {boolean} flat If the marker is to be flat or not.
   */
  RichMarker.prototype.setFlat = function(flat) {
    this.set('flat', !!flat);
  };
  RichMarker.prototype['setFlat'] = RichMarker.prototype.setFlat;


  /**
   * If the makrer is flat or not.
   *
   * @return {boolean} True the marker is flat.
   */
  RichMarker.prototype.getFlat = function() {
    return /** @type {boolean} */ (this.get('flat'));
  };
  RichMarker.prototype['getFlat'] = RichMarker.prototype.getFlat;


  /**
   * Get the width of the marker.
   *
   * @return {Number} The width of the marker.
   */
  RichMarker.prototype.getWidth = function() {
    return /** @type {Number} */ (this.get('width'));
  };
  RichMarker.prototype['getWidth'] = RichMarker.prototype.getWidth;


  /**
   * Get the height of the marker.
   *
   * @return {Number} The height of the marker.
   */
  RichMarker.prototype.getHeight = function() {
    return /** @type {Number} */ (this.get('height'));
  };
  RichMarker.prototype['getHeight'] = RichMarker.prototype.getHeight;


  /**
   * Sets the marker's box shadow.
   *
   * @param {string} shadow The box shadow to set.
   */
  RichMarker.prototype.setShadow = function(shadow) {
    this.set('shadow', shadow);
    this.flat_changed();
  };
  RichMarker.prototype['setShadow'] = RichMarker.prototype.setShadow;


  /**
   * Gets the marker's box shadow.
   *
   * @return {string} The box shadow.
   */
  RichMarker.prototype.getShadow = function() {
    return /** @type {string} */ (this.get('shadow'));
  };
  RichMarker.prototype['getShadow'] = RichMarker.prototype.getShadow;


  /**
   * Flat changed event.
   */
  RichMarker.prototype.flat_changed = function() {
    if (!this.ready_) {
      return;
    }

    this.markerWrapper_.style['boxShadow'] =
        this.markerWrapper_.style['webkitBoxShadow'] =
        this.markerWrapper_.style['MozBoxShadow'] =
        this.getFlat() ? '' : this.getShadow();
  };
  RichMarker.prototype['flat_changed'] = RichMarker.prototype.flat_changed;


  /**
   * Sets the zIndex of the marker.
   *
   * @param {Number} index The index to set.
   */
  RichMarker.prototype.setZIndex = function(index) {
    this.set('zIndex', index);
  };
  RichMarker.prototype['setZIndex'] = RichMarker.prototype.setZIndex;


  /**
   * Gets the zIndex of the marker.
   *
   * @return {Number} The zIndex of the marker.
   */
  RichMarker.prototype.getZIndex = function() {
    return /** @type {Number} */ (this.get('zIndex'));
  };
  RichMarker.prototype['getZIndex'] = RichMarker.prototype.getZIndex;


  /**
   * zIndex changed event.
   */
  RichMarker.prototype.zIndex_changed = function() {
    if (this.getZIndex() && this.ready_) {
      this.markerWrapper_.style.zIndex = this.getZIndex();
    }
  };
  RichMarker.prototype['zIndex_changed'] = RichMarker.prototype.zIndex_changed;

  /**
   * Whether the marker is draggable or not.
   *
   * @return {boolean} True if the marker is draggable.
   */
  RichMarker.prototype.getDraggable = function() {
    return /** @type {boolean} */ (this.get('draggable'));
  };
  RichMarker.prototype['getDraggable'] = RichMarker.prototype.getDraggable;


  /**
   * Sets the marker to be draggable or not.
   *
   * @param {boolean} draggable If the marker is draggable or not.
   */
  RichMarker.prototype.setDraggable = function(draggable) {
    this.set('draggable', !!draggable);
  };
  RichMarker.prototype['setDraggable'] = RichMarker.prototype.setDraggable;


  /**
   * Draggable property changed callback.
   */
  RichMarker.prototype.draggable_changed = function() {
    if (this.ready_) {
      if (this.getDraggable()) {
        this.addDragging_(this.markerWrapper_);
      } else {
        this.removeDragListeners_();
      }
    }
  };
  RichMarker.prototype['draggable_changed'] =
      RichMarker.prototype.draggable_changed;


  /**
   * Gets the postiton of the marker.
   *
   * @return {google.maps.LatLng} The position of the marker.
   */
  RichMarker.prototype.getPosition = function() {
    return /** @type {google.maps.LatLng} */ (this.get('position'));
  };
  RichMarker.prototype['getPosition'] = RichMarker.prototype.getPosition;


  /**
   * Sets the position of the marker.
   *
   * @param {google.maps.LatLng} position The position to set.
   */
  RichMarker.prototype.setPosition = function(position) {
    this.set('position', position);
  };
  RichMarker.prototype['setPosition'] = RichMarker.prototype.setPosition;


  /**
   * Position changed event.
   */
  RichMarker.prototype.position_changed = function() {
    this.draw();
  };
  RichMarker.prototype['position_changed'] =
      RichMarker.prototype.position_changed;


  /**
   * Gets the anchor.
   *
   * @return {google.maps.Size} The position of the anchor.
   */
  RichMarker.prototype.getAnchor = function() {
    return /** @type {google.maps.Size} */ (this.get('anchor'));
  };
  RichMarker.prototype['getAnchor'] = RichMarker.prototype.getAnchor;


  /**
   * Sets the anchor.
   *
   * @param {RichMarkerPosition|google.maps.Size} anchor The anchor to set.
   */
  RichMarker.prototype.setAnchor = function(anchor) {
    this.set('anchor', anchor);
  };
  RichMarker.prototype['setAnchor'] = RichMarker.prototype.setAnchor;


  /**
   * Anchor changed event.
   */
  RichMarker.prototype.anchor_changed = function() {
    this.draw();
  };
  RichMarker.prototype['anchor_changed'] = RichMarker.prototype.anchor_changed;


  /**
   * Converts a HTML string to a document fragment.
   *
   * @param {string} htmlString The HTML string to convert.
   * @return {Node} A HTML document fragment.
   * @private
   */
  RichMarker.prototype.htmlToDocumentFragment_ = function(htmlString) {
    var tempDiv = document.createElement('DIV');
    tempDiv.innerHTML = htmlString;
    if (tempDiv.childNodes.length == 1) {
      return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild));
    } else {
      var fragment = document.createDocumentFragment();
      while (tempDiv.firstChild) {
        fragment.appendChild(tempDiv.firstChild);
      }
      return fragment;
    }
  };


  /**
   * Removes all children from the node.
   *
   * @param {Node} node The node to remove all children from.
   * @private
   */
  RichMarker.prototype.removeChildren_ = function(node) {
    if (!node) {
      return;
    }

    var child;
    while (child = node.firstChild) {
      node.removeChild(child);
    }
  };


  /**
   * Sets the content of the marker.
   *
   * @param {string|Node} content The content to set.
   */
  RichMarker.prototype.setContent = function(content) {
    this.set('content', content);
  };
  RichMarker.prototype['setContent'] = RichMarker.prototype.setContent;


  /**
   * Get the content of the marker.
   *
   * @return {string|Node} The marker content.
   */
  RichMarker.prototype.getContent = function() {
    return /** @type {Node|string} */ (this.get('content'));
  };
  RichMarker.prototype['getContent'] = RichMarker.prototype.getContent;


  /**
   * Sets the marker content and adds loading events to images
   */
  RichMarker.prototype.content_changed = function() {
    if (!this.markerContent_) {
      // Marker content area doesnt exist.
      return;
    }

    this.removeChildren_(this.markerContent_);
    var content = this.getContent();
    if (content) {
      if (typeof content == 'string') {
        content = content.replace(/^\s*([\S\s]*)\b\s*$/, '$1');
        content = this.htmlToDocumentFragment_(content);
      }
      this.markerContent_.appendChild(content);

      var that = this;
      var images = this.markerContent_.getElementsByTagName('IMG');
      for (var i = 0, image; image = images[i]; i++) {
        // By default, a browser lets a image be dragged outside of the browser,
        // so by calling preventDefault we stop this behaviour and allow the image
        // to be dragged around the map and now out of the browser and onto the
        // desktop.
        google.maps.event.addDomListener(image, 'mousedown', function(e) {
          if (that.getDraggable()) {
            if (e.preventDefault) {
              e.preventDefault();
            }
            e.returnValue = false;
          }
        });

        // Because we don't know the size of an image till it loads, add a
        // listener to the image load so the marker can resize and reposition
        // itself to be the correct height.
        google.maps.event.addDomListener(image, 'load', function() {
          that.draw();
        });
      }

      google.maps.event.trigger(this, 'domready');
    }

    if (this.ready_) {
      this.draw();
    }
  };
  RichMarker.prototype['content_changed'] = RichMarker.prototype.content_changed;

  /**
   * Sets the cursor.
   *
   * @param {string} whichCursor What cursor to show.
   * @private
   */
  RichMarker.prototype.setCursor_ = function(whichCursor) {
    if (!this.ready_) {
      return;
    }

    var cursor = '';
    if (navigator.userAgent.indexOf('Gecko/') !== -1) {
      // Moz has some nice cursors :)
      if (whichCursor == 'dragging') {
        cursor = '-moz-grabbing';
      }

      if (whichCursor == 'dragready') {
        cursor = '-moz-grab';
      }

      if (whichCursor == 'draggable') {
        cursor = 'pointer';
      }
    } else {
      if (whichCursor == 'dragging' || whichCursor == 'dragready') {
        cursor = 'move';
      }

      if (whichCursor == 'draggable') {
        cursor = 'pointer';
      }
    }

    if (this.markerWrapper_.style.cursor != cursor) {
      this.markerWrapper_.style.cursor = cursor;
    }
  };

  /**
   * Start dragging.
   *
   * @param {Event} e The event.
   */
  RichMarker.prototype.startDrag = function(e) {
    if (!this.getDraggable()) {
      return;
    }

    if (!this.dragging_) {
      this.dragging_ = true;
      var map = this.getMap();
      this.mapDraggable_ = map.get('draggable');
      map.set('draggable', false);

      // Store the current mouse position
      this.mouseX_ = e.clientX;
      this.mouseY_ = e.clientY;

      this.setCursor_('dragready');

      // Stop the text from being selectable while being dragged
      this.markerWrapper_.style['MozUserSelect'] = 'none';
      this.markerWrapper_.style['KhtmlUserSelect'] = 'none';
      this.markerWrapper_.style['WebkitUserSelect'] = 'none';

      this.markerWrapper_['unselectable'] = 'on';
      this.markerWrapper_['onselectstart'] = function() {
        return false;
      };

      this.addDraggingListeners_();

      google.maps.event.trigger(this, 'dragstart');
    }
  };


  /**
   * Stop dragging.
   */
  RichMarker.prototype.stopDrag = function() {
    if (!this.getDraggable()) {
      return;
    }

    if (this.dragging_) {
      this.dragging_ = false;
      this.getMap().set('draggable', this.mapDraggable_);
      this.mouseX_ = this.mouseY_ = this.mapDraggable_ = null;

      // Allow the text to be selectable again
      this.markerWrapper_.style['MozUserSelect'] = '';
      this.markerWrapper_.style['KhtmlUserSelect'] = '';
      this.markerWrapper_.style['WebkitUserSelect'] = '';
      this.markerWrapper_['unselectable'] = 'off';
      this.markerWrapper_['onselectstart'] = function() {};

      this.removeDraggingListeners_();

      this.setCursor_('draggable');
      google.maps.event.trigger(this, 'dragend');

      this.draw();
    }
  };


  /**
   * Handles the drag event.
   *
   * @param {Event} e The event.
   */
  RichMarker.prototype.drag = function(e) {
    if (!this.getDraggable() || !this.dragging_) {
      // This object isn't draggable or we have stopped dragging
      this.stopDrag();
      return;
    }

    var dx = this.mouseX_ - e.clientX;
    var dy = this.mouseY_ - e.clientY;

    this.mouseX_ = e.clientX;
    this.mouseY_ = e.clientY;

    var left = parseInt(this.markerWrapper_.style['left'], 10) - dx;
    var top = parseInt(this.markerWrapper_.style['top'], 10) - dy;

    this.markerWrapper_.style['left'] = left + 'px';
    this.markerWrapper_.style['top'] = top + 'px';

    var offset = this.getOffset_();

    // Set the position property and adjust for the anchor offset
    var point = new google.maps.Point(left - offset.width, top - offset.height);
    var projection = this.getProjection();
    this.setPosition(projection.fromDivPixelToLatLng(point));

    this.setCursor_('dragging');
    google.maps.event.trigger(this, 'drag');
  };


  /**
   * Removes the drag listeners associated with the marker.
   *
   * @private
   */
  RichMarker.prototype.removeDragListeners_ = function() {
    if (this.draggableListener_) {
      google.maps.event.removeListener(this.draggableListener_);
      delete this.draggableListener_;
    }
    this.setCursor_('');
  };


  /**
   * Add dragability events to the marker.
   *
   * @param {Node} node The node to apply dragging to.
   * @private
   */
  RichMarker.prototype.addDragging_ = function(node) {
    if (!node) {
      return;
    }

    var that = this;
    this.draggableListener_ =
      google.maps.event.addDomListener(node, 'mousedown', function(e) {
        that.startDrag(e);
      });

    this.setCursor_('draggable');
  };


  /**
   * Add dragging listeners.
   *
   * @private
   */
  RichMarker.prototype.addDraggingListeners_ = function() {
    var that = this;
    if (this.markerWrapper_.setCapture) {
      this.markerWrapper_.setCapture(true);
      this.draggingListeners_ = [
        google.maps.event.addDomListener(this.markerWrapper_, 'mousemove', function(e) {
          that.drag(e);
        }, true),
        google.maps.event.addDomListener(this.markerWrapper_, 'mouseup', function() {
          that.stopDrag();
          that.markerWrapper_.releaseCapture();
        }, true)
      ];
    } else {
      this.draggingListeners_ = [
        google.maps.event.addDomListener(window, 'mousemove', function(e) {
          that.drag(e);
        }, true),
        google.maps.event.addDomListener(window, 'mouseup', function() {
          that.stopDrag();
        }, true)
      ];
    }
  };


  /**
   * Remove dragging listeners.
   *
   * @private
   */
  RichMarker.prototype.removeDraggingListeners_ = function() {
    if (this.draggingListeners_) {
      for (var i = 0, listener; listener = this.draggingListeners_[i]; i++) {
        google.maps.event.removeListener(listener);
      }
      this.draggingListeners_.length = 0;
    }
  };


  /**
   * Get the anchor offset.
   *
   * @return {google.maps.Size} The size offset.
   * @private
   */
  RichMarker.prototype.getOffset_ = function() {
    var anchor = this.getAnchor();
    if (typeof anchor == 'object') {
      return /** @type {google.maps.Size} */ (anchor);
    }

    var offset = new google.maps.Size(0, 0);
    if (!this.markerContent_) {
      return offset;
    }

    var width = this.markerContent_.offsetWidth;
    var height = this.markerContent_.offsetHeight;

    switch (anchor) {
     case RichMarkerPosition['TOP_LEFT']:
       break;
     case RichMarkerPosition['TOP']:
       offset.width = -width / 2;
       break;
     case RichMarkerPosition['TOP_RIGHT']:
       offset.width = -width;
       break;
     case RichMarkerPosition['LEFT']:
       offset.height = -height / 2;
       break;
     case RichMarkerPosition['MIDDLE']:
       offset.width = -width / 2;
       offset.height = -height / 2;
       break;
     case RichMarkerPosition['RIGHT']:
       offset.width = -width;
       offset.height = -height / 2;
       break;
     case RichMarkerPosition['BOTTOM_LEFT']:
       offset.height = -height;
       break;
     case RichMarkerPosition['BOTTOM']:
       offset.width = -width / 2;
       offset.height = -height;
       break;
     case RichMarkerPosition['BOTTOM_RIGHT']:
       offset.width = -width;
       offset.height = -height;
       break;
    }

    return offset;
  };


  /**
   * Adding the marker to a map.
   * Implementing the interface.
   */
  RichMarker.prototype.onAdd = function() {
    if (!this.markerWrapper_) {
      this.markerWrapper_ = document.createElement('DIV');
      this.markerWrapper_.style['position'] = 'absolute';
    }

    if (this.getZIndex()) {
      this.markerWrapper_.style['zIndex'] = this.getZIndex();
    }

    this.markerWrapper_.style['display'] = this.getVisible() ? '' : 'none';

    if (!this.markerContent_) {
      this.markerContent_ = document.createElement('DIV');
      this.markerWrapper_.appendChild(this.markerContent_);

      var that = this;
      google.maps.event.addDomListener(this.markerContent_, 'click', function(e) {
        e.cancelBubble = true;
        google.maps.event.trigger(that, 'click');
      });
      google.maps.event.addDomListener(this.markerContent_, 'mouseover', function(e) {
        google.maps.event.trigger(that, 'mouseover');
      });
      google.maps.event.addDomListener(this.markerContent_, 'mouseout', function(e) {
        google.maps.event.trigger(that, 'mouseout');
      });
    }

    this.ready_ = true;
    this.content_changed();
    this.flat_changed();
    this.draggable_changed();

    var panes = this.getPanes();
    if (panes) {
      panes.overlayMouseTarget.appendChild(this.markerWrapper_);
    }

    google.maps.event.trigger(this, 'ready');
  };
  RichMarker.prototype['onAdd'] = RichMarker.prototype.onAdd;


  /**
   * Impelementing the interface.
   */
  RichMarker.prototype.draw = function() {
    if (!this.ready_ || this.dragging_) {
      return;
    }

    var projection = this.getProjection();

    if (!projection) {
      // The map projection is not ready yet so do nothing
      return;
    }

    var latLng = /** @type {google.maps.LatLng} */ (this.get('position'));
    var pos = projection.fromLatLngToDivPixel(latLng);

    var offset = this.getOffset_();
    this.markerWrapper_.style['top'] = (pos.y + offset.height) + 'px';
    this.markerWrapper_.style['left'] = (pos.x + offset.width) + 'px';

    var height = this.markerContent_.offsetHeight;
    var width = this.markerContent_.offsetWidth;

    if (width != this.get('width')) {
      this.set('width', width);
    }

    if (height != this.get('height')) {
      this.set('height', height);
    }
  };
  RichMarker.prototype['draw'] = RichMarker.prototype.draw;


  /**
   * Removing a marker from the map.
   * Implementing the interface.
   */
  RichMarker.prototype.onRemove = function() {
    if (this.markerWrapper_ && this.markerWrapper_.parentNode) {
      this.markerWrapper_.parentNode.removeChild(this.markerWrapper_);
    }
    this.removeDragListeners_();
  };
  RichMarker.prototype['onRemove'] = RichMarker.prototype.onRemove;


  /**
   * RichMarker Anchor positions
   * @enum {number}
   */
  var RichMarkerPosition = {
    'TOP_LEFT': 1,
    'TOP': 2,
    'TOP_RIGHT': 3,
    'LEFT': 4,
    'MIDDLE': 5,
    'RIGHT': 6,
    'BOTTOM_LEFT': 7,
    'BOTTOM': 8,
    'BOTTOM_RIGHT': 9
  };
  window['RichMarkerPosition'] = RichMarkerPosition;
}

/**
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2021 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Steven Schöning <schoening@infomax-it.de>
 * @since      2021-03-11
 */
(function() {
  document.addEventListener("DOMContentLoaded", function() {
    var configObject = {};
    var heroImageNodeCollection = document.getElementsByClassName('-IMXEVNT-heroimageContainerSlider');

    for(var i = 0; i < heroImageNodeCollection.length; i++) {
      var currentHeroImageNode = heroImageNodeCollection[i];
      var sliderHammer = new Hammer(currentHeroImageNode);
      var heroImageSlider = new CSS3Slider(currentHeroImageNode, configObject);
      var heroImageControls = document.querySelector('.-IMXEVNT-heroimage--controls');

      if(heroImageControls) {
        var slideRight = heroImageControls.querySelector('.-IMXEVNT-heroimage--slideRight');
        var slideLeft = heroImageControls.querySelector('.-IMXEVNT-heroimage--slideLeft');

        if(sliderHammer) {
          sliderHammer.on('swipeleft', triggerSlideRight);
          sliderHammer.on('swiperight', triggerSlideLeft);
        }

        if(slideRight) {
          slideRight.addEventListener('click', triggerSlideRight);
        }

        if(slideLeft) {
          slideLeft.addEventListener('click', triggerSlideLeft);
        }
      }
    }

    function triggerSlideRight() {
      heroImageSlider.slideRight();
      updateSlideControls();
    }

    function triggerSlideLeft() {
      heroImageSlider.slideLeft();
      updateSlideControls();
    }

    function updateSlideControls() {
      var heroImageSliderRuntimeConfig = heroImageSlider.getRuntimeConfig();
      var currentPosition = heroImageSliderRuntimeConfig.slidePosition;
      var slideRight = heroImageControls.querySelector('.-IMXEVNT-heroimage--slideRight');
      var slideLeft = heroImageControls.querySelector('.-IMXEVNT-heroimage--slideLeft');
      var maxChildrens = heroImageSliderRuntimeConfig.slideChildrenCount - 1;
      var hiddenContentClass = '-IMXEVNT-heroimage__hidden';

      if(currentPosition === 0) {
        slideLeft.classList.toggle(hiddenContentClass);
      } else if(currentPosition === maxChildrens) {
        slideRight.classList.toggle(hiddenContentClass);
      } else {
        if(slideRight.classList.contains(hiddenContentClass)) {
          slideRight.classList.remove(hiddenContentClass);
        }
        if(slideLeft.classList.contains(hiddenContentClass)) {
          slideLeft.classList.remove(hiddenContentClass);
        }
      }
    }
  });
})();

/**
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2021 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Steven Schöning <schoening@infomax-it.de>
 * @since      2021-03-11
 */
(function() {
  document.addEventListener("DOMContentLoaded", function() {
    var videoContents = document.querySelectorAll('.-IMXEVNT-heroimageContainer--videoContent');
    var slideLeftButton = document.querySelector('.-IMXEVNT-heroimage--slideLeft');
    var slideRightButton = document.querySelector('.-IMXEVNT-heroimage--slideRight');

    for(var i = 0; i < videoContents.length; i++) {
      videoContents[i].addEventListener('click', videoContainerTrigger);
    }

    if(slideLeftButton) {
      slideLeftButton.addEventListener('click', resetVideoIframe);
    }
    if(slideRightButton) {
      slideRightButton.addEventListener('click', resetVideoIframe);
    }

  });

  function videoContainerTrigger(event) {
    var playButton = this.querySelector('.-IMXEVNT-videoPlay');

    if(event.target === playButton) {
      var videoIframe = this.querySelector('.-IMXEVNT-heroimageContainer--videoIframe');

      this.querySelector('.-IMXEVNT-videoPreviewImage').classList.toggle('-IMXEVNT-heroimage__hidden');
      playButton.classList.toggle('-IMXEVNT-heroimage__hidden');
      videoIframe.src = videoIframe.getAttribute('data-src');
      this.classList.add('-IMXEVNT-heroimage__ActiveVideo');
    }
  }

  function resetVideoIframe() {
    var activeVideo = document.querySelector('.-IMXEVNT-heroimage__ActiveVideo');

    if(activeVideo) {
      activeVideo.querySelector('.-IMXEVNT-videoPreviewImage').classList.remove('-IMXEVNT-heroimage__hidden');
      activeVideo.querySelector('.-IMXEVNT-videoPlay').classList.remove('-IMXEVNT-heroimage__hidden');
      activeVideo.classList.remove('-IMXEVNT-heroimage__ActiveVideo');
      activeVideo.querySelector('.-IMXEVNT-heroimageContainer--videoIframe').src = '';
    }
  }
})();

function IMXEVNT_StickyElement(configObject) {
  this.isSticky = false;
  this._clone = null;
  this._stickyContainer = document.getElementById('-IMXEVNT-sticky');

  this._configObject = configObject;
  this._mainNode = this._configObject.mainNode;

  this._createClone = function () {
    this._clone = this._configObject.node.cloneNode(true);
    this._stickyContainer.appendChild(this._clone);
    jQuery(document).trigger('-IMXEVNT-stickyElementAdded');
  };

  this._destroyClone = function () {
    this._stickyContainer.removeChild(this._clone);
    this._clone = null;
    jQuery(document).trigger('-IMXEVNT-stickyElementRemoved');
  };

  this.checkVerticalPosition = function (currentScrollPosition) {
    var self = this;

    window.requestAnimationFrame(function() {
      var verticalPosition = imxQuery.offsetTop(self._configObject.node, self._mainNode);
      var nodeHeight = self._configObject.node.offsetHeight;
      var parentHeight = self._configObject.node.parentNode.offsetHeight;

      //check if vertical position to create clone is reached - but only if targetNode is visible
      if (currentScrollPosition >= verticalPosition && nodeHeight > 0) {
        if (!self.isSticky) {
          self.isSticky = true;
          self._createClone();
        }

        if (currentScrollPosition >= verticalPosition - nodeHeight + parentHeight) {
          var newTopPosition = verticalPosition - nodeHeight + parentHeight - currentScrollPosition;
          self._clone.style.top = newTopPosition + 'px';
        } else {
          self._clone.style.top = '0px';
        }

      } else {
        if (self.isSticky) {
          self.isSticky = false;
          self._destroyClone();
        }
      }
    });
  };
  this.getVerticalOffset = function () {
    return imxQuery.offsetTop(this._configObject.firstNode, this._mainNode);
  };

  this.getAssociatedCheckbox = function () {
    return this._configObject.checkbox;
  };
}

//function IMXEVNT_Sticky() {
//
//  this._createStickyElements = function() {
//    var collection = [];
//
//    [].forEach.call(document.querySelectorAll('[data-tabtarget]'), function(tab) {
//      var tabId = tab.dataset.tabtarget.replace('-IMXEVNT-switchArea__tabCheckbox--', '');
//      var checkbox = document.getElementById('-IMXEVNT-switchArea__tabCheckbox--' + tabId);
//      var stickyElementCollection = tab.getElementsByClassName('-IMXEVNT-stickyElement');
//
//      for(var i = 0; i < stickyElementCollection.length; i++) {
//        collection.push(new IMXEVNT_StickyElement({
//          mainNode: that._mainNode,
//          firstNode: stickyElementCollection[0],
//          node: stickyElementCollection[i],
//          checkbox: checkbox
//        }));
//      }
//    });
//    return collection;
//  };
//
//  this._checkStickyElements = function() {
//    window.requestAnimationFrame(function() {
//      var stickyCollection = that._stickyElementsCollection;
//      var currentScrollPosition = window.pageYOffset;
//
//      jQuery('#-IMXEVNT-sticky > ul').show();
//
//      for(var i = 0; i < stickyCollection.length; i++) {
//        var currentIndex = i;
//        stickyCollection[currentIndex].checkVerticalPosition(currentScrollPosition);
//        if(stickyCollection[currentIndex].getAssociatedCheckbox() && stickyCollection[currentIndex].getAssociatedCheckbox().checked) {
//          var newTop = stickyCollection[currentIndex].getVerticalOffset() - currentScrollPosition;
//          var $sticky = jQuery('#-IMXEVNT-sticky.-IMXEVNT-sticky--isSticky');
//          if(newTop > 0) {
////            jQuery('#-IMXEVNT-sticky').css('top', newTop);
//            $sticky.css('top', stickyCollection[currentIndex].getVerticalOffset());
//            $sticky.css('position', 'absolute');
//            $sticky.addClass('-IMXEVNT-floatingSticky');
//          }else {
//            $sticky.css('top', 0);
//            $sticky.css('position', 'fixed');
//            $sticky.removeClass('-IMXEVNT-floatingSticky');
//          }
//        }
//      }
//    });
//  };
//
//  this.checStickyElement = function() {
//    this._checkStickyElements();
//  };
//
//  this._registerEventListener = function() {
//    if(this._mainNode === document.body) {
//      window.addEventListener('scroll', this.checStickyElement.bind(that));
//    }else {
//      this._mainNode.addEventListener('scroll', this.checStickyElement.bind(that));
//    }
//
//    window.addEventListener('resize', this.checStickyElement.bind(that));
//    for(var i = 1; i <= 3; i++) {
//      var fieldset = document.querySelector('#-IMXEVNT-heroimage__form__fieldset' + i);
//      if(fieldset) {
//        document.querySelector('#-IMXEVNT-heroimage__form__fieldset' + i).addEventListener('change', this.checStickyElement.bind(that));
//      }
//    }
//    window.addEventListener('DOMContentLoaded', this.checStickyElement.bind(that));
//
//
//    this._checkStickyElements();
//  };
//
//  this._mainNode = document.body;
////  this._mainNode = document.getElementById('-IMXEVNT-main-wrapper');
////  if(document.getElementsByTagName('html')[0].classList.contains('touch')) {
////    this._mainNode = document.body;
////  }
//
//  var that = this;
//
//  if(this._mainNode) {
//    this._stickyElementsCollection = this._createStickyElements();
//    this._registerEventListener();
//
//    var numberOfStickyClones = 0;
//    var stickyElements = this._stickyElementsCollection;
//
//    var checkStickyButtons = function() {
//      if(numberOfStickyClones > 0) {
//        jQuery('#-IMXEVNT-sticky > ul').show();
//      }
//    };
//    jQuery(document).on('-IMXEVNT-stickyElementAdded', function() {
//      numberOfStickyClones++;
//      checkStickyButtons();
//    });
//    jQuery(document).on('-IMXEVNT-stickyElementRemoved', function() {
//      numberOfStickyClones--;
//      checkStickyButtons();
//    });
//  }
//}

var Geocoder = Class.extend({
  geocode: function(coordinates, callback) {
    var url = portal.uri + '/action/googleGeocoder?lat=' + coordinates[0] + '&long=' + coordinates[1];

    jQuery.getJSON(url, function(json) {
      callback(json.results, json.status);
    });
  }
});

var UrlHelper = Class.extend({
  applyCurrentSearchConfigurationToUri: function(targetUri) {
    var currentUri = new URI();
    var data = currentUri.search(true);
    var contentForm = document.querySelector('.-IMXEVNT-contentForm');
    var hasFormAddressIds = false;
    // from date
    if(currentUri.hasQuery('dateFrom')) {
      targetUri.setSearch('dateFrom', data.dateFrom);
    }else {
      targetUri.setSearch('dateFrom', portal.defaults.search.dateFrom);
    }

    // from to
    if(currentUri.hasQuery('dateTo')) {
      targetUri.setSearch('dateTo', data.dateTo);
    }else {
      targetUri.setSearch('dateTo', portal.defaults.search.dateTo);
    }

    // longitude
    if(currentUri.hasQuery('longitude')) {
      targetUri.setSearch('longitude', data.longitude);
    }else if(!isNaN(portal.defaults.search.longitude)) {
      targetUri.setSearch('longitude', portal.defaults.search.longitude);
    }

    // latitude
    if(currentUri.hasQuery('latitude')) {
      targetUri.setSearch('latitude', data.latitude);
    }else if(!isNaN(portal.defaults.search.latitude)) {
      targetUri.setSearch('latitude', portal.defaults.search.latitude);
    }

    // distance
    if(currentUri.hasQuery('distance')) {
      targetUri.setSearch('distance', data.distance);
    }else if(!isNaN(portal.defaults.search.distance) && portal.defaults.search.distance > 0) {
      targetUri.setSearch('distance', portal.defaults.search.distance);
    }

    // addressId
    if(currentUri.hasQuery('addressId')) {
      targetUri.setSearch('addressId', data.addressId);
    }else if(contentForm && contentForm.querySelectorAll('input[name="addressIds[]"]').length > 0) {
      [].forEach.call(contentForm.querySelectorAll('input[name="addressIds[]"]'), function(input) {
        targetUri.addSearch('addressIds[]', input.value);
      });
      hasFormAddressIds = true;
    }else if(!isNaN(portal.defaults.search.addressId) && portal.defaults.search.addressId > 0 && !currentUri.hasQuery('locationId')) {
      targetUri.setSearch('addressId', portal.defaults.search.addressId);
    }

    // addressGroupId
    if(currentUri.hasQuery('addressGroupId')) {
      targetUri.setSearch('addressGroupId', data.addressGroupId);
    }else if(contentForm && contentForm.querySelectorAll('input[name="addressGroupIds[]"]').length > 0) {
      [].forEach.call(contentForm.querySelectorAll('input[name="addressGroupIds[]"]'), function(input) {
        targetUri.addSearch('addressGroupIds[]', input.value);
      });
      hasFormAddressIds = true;
    }else if(!isNaN(portal.defaults.search.addressGroupId) && portal.defaults.search.addressGroupId > 0 && !currentUri.hasQuery('locationId')) {
      targetUri.setSearch('addressGroupId', portal.defaults.search.addressGroupId);
    }

    // locationId
    if(currentUri.hasQuery('locationId')) {
      targetUri.setSearch('locationId', data.locationId);
    }else if(!isNaN(portal.defaults.search.locationId) && portal.defaults.search.locationId > 0) {
      targetUri.setSearch('locationId', portal.defaults.search.locationId);
    }

    // location
    if(currentUri.hasQuery('location')) {
      targetUri.setSearch('location', data.location);
    }

    // zipcodes
    if(currentUri.hasQuery('zipcodes[]')) {
      if(typeof data['zipcodes[]'] === 'array') {  /* jshint ignore:line */
        data['zipcodes[]'].forEach(function(zipcode) {
          targetUri.addSearch('zipcodes[]', zipcode);
        });
      }else {
        targetUri.addSearch('zipcodes[]', data['zipcodes[]']);
      }
    }else if(contentForm && contentForm.querySelectorAll('input[name="zipcodes[]"]').length > 0) {
      [].forEach.call(contentForm.querySelectorAll('input[name="zipcodes[]"]'), function(input) {
        targetUri.addSearch('zipcodes[]', input.value);
      });
    }else if(portal.defaults.search.zipcodes.length > 0
        && !currentUri.hasQuery('addressGroupId') && !currentUri.hasQuery('addressId') /* jshint ignore:line */
        && !currentUri.hasQuery('locationId') && !hasFormAddressIds) { /* jshint ignore:line */
      portal.defaults.search.zipcodes.forEach(function(zipcode) {
        targetUri.addSearch('zipcodes[]', zipcode);
      });
    }

    // wysiwyg
    if(currentUri.hasQuery('wysiwyg')) {
      targetUri.setSearch('wysiwyg', data.wysiwyg);
    }
  },
  applyCurrentQueryParamToUri: function(paramName, targetUri) {
    var currentUri = new URI();
    if(currentUri.hasSearch(paramName)) {
      targetUri.setSearch(paramName, currentUri.getSearch(paramName));
    }
  }
});

var RoutingForm = Class.extend({
  container: null,
  init: function(container) {
    this.container = container;
    this.initEventHandlers();
    this.initGeocodedAddress();
  },
  initEventHandlers: function() {
    jQuery(this.container).submit(jQuery.proxy(this.handleSubmit, this));
    jQuery('input[name="type"]', this.container).change(jQuery.proxy(this.handleTypeChange, this));
  },
  initGeocodedAddress: function() {
    // init geolocation only on touch devices, which have geolocation
    if(jQuery('html').hasClass('geolocation') && jQuery('html').hasClass('touch')) {
      if(navigator.geolocation) {
        navigator.geolocation.getCurrentPosition(jQuery.proxy(this.handleGeoLocation, this));
      }
    }
  },
  handleGeoLocation: function(position) {
    var lat = position.coords.latitude;
    var lng = position.coords.longitude;
    geocoder = new Geocoder();
    geocoder.geocode([lat, lng], jQuery.proxy(function(results, status) {
      if(status === 'OK') {
        if(results.length > 0) {
          var location = this.buildLocationFromGeocodingResult(results[0]);
          jQuery('input[name="street"]', this.container).val(location.street);
          jQuery('input[name="city"]', this.container).val(location.city);
        }
      }
    }, this));
  },
  buildLocationFromGeocodingResult: function(geoResult) {
    var location = {street: '', city: ''};
    var streetNo = null;
    var street = null;
    jQuery.each(geoResult.address_components, function(idx, element) {
      if(element.types.indexOf('street_number') >= 0) {
        streetNo = element.long_name;
      } else if(element.types.indexOf('route') >= 0) {
        street = element.long_name;
      } else if(element.types.indexOf('locality') >= 0) {
        location.city = element.long_name;
      }
    });
    if(street != null) {
      location.street = street;
      if(streetNo != null) {
        location.street += ' ' + streetNo;
      }
    }

    return location;
  },
  handleSubmit: function(ev) {
    var type = jQuery('input[name="type"]:checked', this.container).val();
    var mapping = {
      'car': 'd',
      'bike': 'b',
      'walk': 'w',
      'publicTransportation': 'r'
    };
    this.openGoogleNavigation(mapping[type]);
    ev.preventDefault();
  },
  openGoogleNavigation: function(type) {
    var url = 'http://maps.google.com';
    var params = {
      daddr: jQuery('input[name="destination"]', this.container).val(),
      hl: portal.language,
      saddr: jQuery('input[name="city"]', this.container).val() + ', ' + jQuery('input[name="street"]', this.container).val(),
      dirflg: type,
      date: jQuery('input[name="date"]', this.container).val()
    };
    window.open(url + '?' + $.param(params));
  }
});

var StandaloneFilterForm = Class.extend({
  offCanvasContainer: null,
  filterForm: null,
  init: function(offCanvasContainer) {
    this.offCanvasContainer = offCanvasContainer;
    this.filterForm = jQuery('form', this.offCanvasContainer);
    
    this.setupFilterHandlers();
  },
  setupFilterHandlers: function() {
    this.filterForm.on('reset', jQuery.proxy(this.handleFilterFormReset, this));
    this.filterForm.submit(jQuery.proxy(this.handleFilterFormSubmit, this));
  },
  handleFilterFormSubmit: function(ev) {
    // do nothing
  },
  handleFilterFormReset: function(ev) {
    ev.preventDefault();
    jQuery('input[type="checkbox"]', this.offCanvasContainer).prop('checked', false);
    jQuery(this.filterForm).trigger('submit');
  },
});
var SearchForm = StandaloneFilterForm.extend({
  container: null,
  form: null,
  datepicker: null,
  timeSlider: null,
  checkboxWithoutDate: null,
  dateRangePresets: null,
  dateRangePicker: null,
  inputDateRange: null,
  inputDateFrom: null,
  inputDateTo: null,
  inputTimeFrom: null,
  checkboxUseGeoLocation: null,
  checkboxFreeEntry: null,
  checkboxBookable: null,
  inputLocation: null,
  inputLocationError: null,
  inputAddressId: null,
  inputAddressIds: null,
  inputAdressGroupId: null,
  inputAdressGroupIds: null,
  inputLocationId: null,
  inputLocationDisplayName: null,
  inputLatitude: null,
  inputLongitude: null,
  labelDistance: null,
  inputDistance: null,
  inputZipcodes: null,
  distanceSlider: null,
  inputQuery: null,
  inputEventSerieId: null,
  inputCriterionId: null,
  whereAutosuggest: null,
  whatAutosuggest: null,
  mobileDatePickerMediaMatch: null,
  init: function(container, offCanvasContainer) {
    this._super(offCanvasContainer);

    // save current search state
    new SearchHistory().saveState(new URI().removeSearch('pageNotFound').toString());

    this.container = container;

    this.form = jQuery('form', this.container);

    // assign form inputs (when)
    this.checkboxWithoutDate = jQuery('input[name="dateWithout[]"]', this.container);
    this.dateRangePresets = jQuery('.-IMXEVNT-contentForm__inputDate__item--preset', this.container);
    this.dateRangePicker = jQuery('.-IMXEVNT-contentForm__inputDate__item--date', this.container);
    this.inputDateRange = jQuery('input[name="date"]', this.container);
    this.inputDateFrom = jQuery('input[name="dateFrom"]', this.container);
    this.inputDateTo = jQuery('input[name="dateTo"]', this.container);
    this.inputTimeFrom = jQuery('input[name="timeFrom"]', this.container);
    this.timeSlider = document.getElementById('-IMXEVNT-contentForm__sliderTime');

    // assign form inputs (where)
    this.inputAddressId = jQuery('input[name="addressId"]', this.container);
    this.inputAddressGroupId = jQuery('input[name="addressGroupId"]', this.container);
    this.inputLocationDisplayName = jQuery('input[name="locationDisplayName"]', this.container);
    this.inputDistance = jQuery('input[name="distance"]', this.container);
    this.inputZipcodes = jQuery('input[name="zipcodes[]"]', this.container);
    this.distanceSlider = document.getElementById('-IMXEVNT-contentForm__sliderDistance');
    this.labelDistance = jQuery('.-IMXEVNT-contentForm__sliderWrapper_distance .-IMXEVNT-contentForm__sliderValue', this.container);

    // assign form inputs (what)
    this.inputQuery = jQuery('input[name="query"]', this.container);
    this.inputEventSerieId = jQuery('input[name="eventSerieId"]', this.container);
    this.inputCriterionId = jQuery('input[name="criterionId"]', this.container);
    this.checkboxBookable = jQuery('input[name="bookable[]"]', this.container);
    this.checkboxFreeEntry = jQuery('input[name="freeEntry[]"]', this.container);

    this.mobileDatePickerMediaMatch =  window.matchMedia("(max-width: 600px)");
    this.setupTimeSlider();
    this.setupDatepicker();

    this.setupDistanceSlider();

    this.setupWhatAutosuggest();

    this.setupEventHandlers();

    this.handleWindowResize();
  },
  setupDatepicker: function() {
    this.datepicker = jQuery("#-IMXEVNT-heroimage__form__date", this.container);

    if(this.datepicker) {
      var datepicker = this.datepicker;

      datepicker.daterangepicker({
        dateFormat: 'dd.mm.yy',
        presetRanges: [],
        onChange: jQuery.proxy(this.handleDatepickerRangeChange, this),
        onClose: jQuery.proxy(this.handleDatePickerClose, this),
        initialText: portal.translations['v3.form.search.dateRange.label'],
        applyButtonText: portal.translations['datepicker.apply'],
        clearButtonText: portal.translations['datepicker.clear'],
        datepickerOptions: {
          minDate: 0,
          maxDate: null,
          numberOfMonths: 1,
          applyOnMenuSelect: false,
          mirrorOnCollision: false,
          autoFitCalendars: false
        }
      });

      // initialize date range from form fields
      if(!this.checkboxWithoutDate.prop('checked')) {
        var dateFrom = moment(this.inputDateFrom.val());
        var dateTo = moment(this.inputDateTo.val());
        if(dateFrom.isValid() && dateTo.isValid()) {
          datepicker.daterangepicker('setRange', {start: dateFrom.toDate(), end: dateTo.toDate()});
          this.enableTimeSlider(true);
        } else {
          this.disableTimeSlider(true);
        }
      } else {
        this.disableTimeSlider(true);
      }

      this.dateRangePresets.each(function() {
        var button = this.querySelector('button');

        button.addEventListener('click', function() {
          var dateFrom = moment(button.dataset.start);
          var dateTo = moment(button.dataset.end);

          if(dateFrom.isValid() && dateTo.isValid()) {
            datepicker.daterangepicker('setRange', {
              start: dateFrom.toDate(),
              end: dateTo.toDate()
            });
          }
        });
      });
    }
  },
  setupTimeSlider: function() {
    if(this.timeSlider) {
      // create slider
      noUiSlider.create(this.timeSlider, {
        start: [this.inputTimeFrom.val()],
        connect: false,
        range: {
          'min': [0, 10],
          '20%': [10, 4],
          '60%': [18, 2],
          'max': [22]
        },
        format: {
          to: function(value) {
            return parseInt(value);
          },
          from: function(value) {
            return parseInt(value);
          }
        }
      });

      this.timeSlider.noUiSlider.on('update', jQuery.proxy(this.handleTimeSliderChange, this));
    }
  },
  setupDistanceSlider: function() {
    if(this.distanceSlider) {
      noUiSlider.create(this.distanceSlider, {
        start: [this.inputDistance.val()],
        connect: false,
        step: 1,
        range: {
          'min': [1],
          'max': [50]
        },
        format: {
          to: function(value) {
            return parseInt(value);
          },
          from: function(value) {
            return parseInt(value);
          }
        }
      });


      this.distanceSlider.noUiSlider.on('update', jQuery.proxy(this.handleDistanceSliderChange, this));
    }
  },
  setupWhereAutosuggest: function() {
    var autocompleteOptions = null;
    if(this.inputLocation.length > 0) {

    }else if (this.inputLocationDisplayName.length > 0 && this.inputAddressId.data('autocompleteValues') != ""){

    }
  },
  handleWhereSuggestInputChange: function() {
    // Check if input is active to avoid automatic triggers in IE 11: https://stackoverflow.com/a/26341709/1756304
    if(jQuery(document.activeElement) !== this.inputLocation) {
      return;
    }

    this.resetLocationSelection(true);
    this.checkboxUseGeoLocation.prop('checked', false);
  },
  handleDatePickerClose: function() {
    // ugly hack to force another mobile closing behaviour
    if (this.mobileDatePickerMediaMatch.matches) {
      var daterangepicker = this.datepicker.daterangepicker('widget');
      daterangepicker.show();
      daterangepicker.css('top', '100vh');
    }
  },
  setupWhatAutosuggest: function() {
    if(this.inputQuery.length > 0) {
      var autocompleteOptions = {
        adapter: new imx.Autocomplete.AjaxAdapter({
          url: portal.uri + '/' + portal.permalink + '/' + portal.language + '/action/autosuggest',
          extraParams: {
            widgetToken: portal.token,
            types: ['what']
          }
        }),
        delay: 200,
        minChars: 3,
        columnsReverse: false,
        events: {
          show: jQuery.proxy(this.handleWhatSuggestShow, this),
          change: jQuery.proxy(this.handleWhatSuggestChange, this),
        }
      };

      this.inputQuery.on('input', jQuery.proxy(this.handleWhatSuggestInputChange, this));

      this.whatAutosuggest = new imx.Autocomplete(this.inputQuery, jQuery('#-IMXEVNT-contentForm__autocompleteCategory', this.container), autocompleteOptions);
      this.whatAutosuggest.create();

      jQuery('#-IMXEVNT-contentForm__autocompleteCategory .-IMXEVNT-scroller', this.container).nanoScroller({
        alwaysVisible: true,
        contentClass: '-IMXEVNT-scrollerArea',
        paneClass: '-IMXEVNT-scrollPane',
        sliderClass: '-IMXEVNT-scrollSlider',
        iOSNativeScrolling: true
      });
    }
  },
  handleWhatSuggestInputChange: function() {
    this.inputEventSerieId.val('');
    this.inputCriterionId.val('');
  },
  handleWhatSuggestShow: function() {
    jQuery('#-IMXEVNT-contentForm__autocompleteCategory .-IMXEVNT-scroller', this.container).nanoScroller();
  },
  handleWhatSuggestChange: function(item) {
    if(item.internal_type == 'term') {
      this.inputEventSerieId.val('');
    } else if(item.internal_type == 'series') {
      this.inputEventSerieId.val(item.value);
    } else if(item.internal_type == 'criteria') {
      this.inputCriterionId.val(item.value);
    }
  },
  setupEventHandlers: function() {
    this.checkboxWithoutDate.click(jQuery.proxy(this.handleWithoutDateClick, this));

    this.checkboxBookable.click(jQuery.proxy(this.handleBookableClick, this));
    this.checkboxFreeEntry.click(jQuery.proxy(this.handleFreeEntryClick, this));

    //this.checkboxUseGeoLocation.click(jQuery.proxy(this.handleUseGeoLocationClick, this));
    this.form.submit(jQuery.proxy(this.handleFormSubmit, this));
    jQuery(window).resize(jQuery.proxy(this.handleWindowResize, this));
  },
  handleWindowResize: function(ev) {
    var maxHeight = 0;
    jQuery('.-IMXEVNT-contentForm__fieldsetHelper legend', this.container).css('height', '');
    jQuery('.-IMXEVNT-contentForm__fieldsetHelper legend', this.container).each(function(idx, elem) {
      outerElementHeight = jQuery(elem).outerHeight();
      if(maxHeight < outerElementHeight) {
        maxHeight = outerElementHeight;
      }
    });
    jQuery('.-IMXEVNT-contentForm__fieldsetHelper legend', this.container).css('height', maxHeight);
  },
  handleDatepickerRangeChange: function(dateRange) {
    if(!dateRange) {
      dateRange = this.datepicker.daterangepicker('getRange');
    }

    var start = moment(dateRange.start).format('YYYY-MM-DD');
    var end = moment(dateRange.start).format('YYYY-MM-DD');

    if(dateRange.end) {
      end = moment(dateRange.end).format('YYYY-MM-DD');
    }

    this.inputDateFrom.val(start);
    this.inputDateTo.val(end);

    this.dateRangePresets.each(function() {
      var container = this;
      var button = container.querySelector('button');

      if(button.dataset.start === start && button.dataset.end === end) {
        container.classList.add('-IMXEVNT-contentForm__inputDate__item--active');
      }else {
        container.classList.remove('-IMXEVNT-contentForm__inputDate__item--active');
      }
    });

    if(this.dateRangePresets.filter('.-IMXEVNT-contentForm__inputDate__item--active').length === 0) {
      this.dateRangePicker.addClass('-IMXEVNT-contentForm__inputDate__item--active');
    }else {
      this.dateRangePicker.removeClass('-IMXEVNT-contentForm__inputDate__item--active');
    }

    this.checkboxWithoutDate.prop('checked', false);
    if(this.timeSlider && this.timeSlider.getAttribute('disabled')) {
      this.enableTimeSlider();
    }

    if(dateRange.end) {
      this.datepicker.daterangepicker('close');
    }
  },
  handleTimeSliderChange: function(values, handle) {
    if(this.inputTimeFrom.val()) {
      this.inputTimeFrom.val(values[handle]);
    }
  },
  handleDistanceSliderChange: function(values, handle) {
    this.labelDistance.text(values[handle]);
    this.inputDistance.val(values[handle]);
  },
  handleWithoutDateClick: function(ev) {
    if(this.checkboxWithoutDate.prop('checked')) {
      this.disableTimeSlider();
      this.clearDatepicker();
    } else {
      this.enableTimeSlider();
      this.setDefaultsForDatepicker();
    }
  },
  handleFreeEntryClick: function(ev) {
    if(this.checkboxBookable.prop('checked')) {
      this.checkboxBookable.prop('checked', false);
      this.checkboxFreeEntry.prop('checked', true);
    }
  },
  handleBookableClick: function(ev) {
    if(this.checkboxFreeEntry.prop('checked')) {
      this.checkboxFreeEntry.prop('checked', false);
      this.checkboxBookable.prop('checked', true);
    }
  },
  handleFormSubmit: function(ev) {
    if(this.inputEventSerieId.val() != '' || this.inputCriterionId.val() != '') {
      this.inputQuery.attr('disabled', true);
    }

    if(this.checkboxWithoutDate.prop('checked')) {
      this.inputDateFrom.attr('disabled', true);
      this.inputDateTo.attr('disabled', true);
      this.inputTimeFrom.attr('disabled', true);
    }

    jQuery('input', this.container).each(function(idx, elem) {
      if(jQuery(elem).val() == '') {
        jQuery(elem).attr('disabled', true);
      }
    });

    jQuery(document).trigger('-IMXEVNT-searchSubmit');

    return true;
  },
  handleFilterFormSubmit: function(ev) {
    ev.preventDefault();

    // copy category/criteria checkboxes to main form
    jQuery('input[name="categoryIds[]"]:checked, input[name="categoryCriteriaIds[]"]:checked, input[name="criteriaIds[]"]:checked', this.offCanvasContainer).clone().appendTo('form', this.container);

    jQuery('input[name="searchType"]',this.form).val("filter");

      failSaveStorage.setItem(portal.token + ';scrollToSearchItems', JSON.stringify(true));
    jQuery(this.form).trigger('submit');
  },
  handleFilterFormReset: function(ev) {
    ev.preventDefault();
    jQuery('input[type="checkbox"]', this.offCanvasContainer).prop('checked', false);
      failSaveStorage.setItem(portal.token + ';scrollToSearchItems', JSON.stringify(true));
  },
  disableTimeSlider: function() {
    if(this.timeSlider) {
      this.timeSlider.noUiSlider.set(0);
      this.timeSlider.setAttribute('disabled', true);
      jQuery(this.timeSlider).parents('.-IMXEVNT-contentForm__sliderArea').css('display', 'none');
    }
  },
  enableTimeSlider: function(doNotSetDefaultValue) {
    if(this.timeSlider) {
      this.timeSlider.removeAttribute('disabled');
      jQuery(this.timeSlider).parents('.-IMXEVNT-contentForm__sliderArea').css('display', 'block');
      if(!doNotSetDefaultValue) {
        this.timeSlider.noUiSlider.set(portal.defaults.search.timeFrom);
      }
    }
  },
  disableDistanceSlider: function() {
    if(this.distanceSlider) {
      this.distanceSlider.setAttribute('disabled', true);
      jQuery(this.distanceSlider).parents('.-IMXEVNT-contentForm__sliderArea').css('display', 'none');
    }
  },
  enableDistanceSlider: function() {
    if(this.distanceSlider) {
      this.distanceSlider.removeAttribute('disabled');
      jQuery(this.distanceSlider).parents('.-IMXEVNT-contentForm__sliderArea').css('display', 'block');
    }
  },
  clearDatepicker: function() {
    this.dateRangePresets.removeClass('-IMXEVNT-contentForm__inputDate__item--active');
    this.dateRangePicker.removeClass('-IMXEVNT-contentForm__inputDate__item--active');

    if(this.datepicker) {
      this.datepicker.daterangepicker('clearRange');
    }
  },
  setDefaultsForDatepicker: function() {
    // read defaults from widget configuration
    var fixedDate = moment(portal.defaults.search.fixedDate);
    var dateFrom = null;

    if (fixedDate.isAfter(moment())){
      dateFrom = fixedDate;
    }else{
      dateFrom = moment(portal.defaults.search.dateFrom);
    }

    var dateTo = moment(portal.defaults.search.dateTo);

    if(dateFrom.isValid() && dateTo.isValid()) {
      this.datepicker.daterangepicker('setRange', {start: dateFrom.toDate(), end: dateTo.toDate()});
    }
  },
});

var AbstractMap = Class.extend({
  nodes: {},
  imxMap: null,
  activePoi: null,

  /**
   *
   * @param {HTMLElement} container
   */
  init: function(container) {
    this.nodes = {
      map: container.querySelector('.-IMXEVNT-mapContainer__map'),
      plus: container.querySelector('.-IMXEVNT-mapContainer__zoom__button--plus'),
      minus: container.querySelector('.-IMXEVNT-mapContainer__zoom__button--minus')
    };
  },
  start: function() {
    this.imxMap = imx.Mapwork.createMap(this.nodes.map.id, this.getConfig(), true);

    if(portal.map.mapStyle) {
      this.imxMap.getMap().setOptions({
        'styles': portal.map.mapStyle
      });
    }

    this.nodes.plus.addEventListener('click', this.zoomIn.bind(this));
    this.nodes.minus.addEventListener('click', this.zoomOut.bind(this));
  },
  /**
   *
   * @returns {AbstractMap}
   */
  open: function() {
    var that = this;

    var couldInstantExectuted = ConsentHelper.addListener('Google Maps', 'S1pcEj_jZX', function () {
      that.start();
    });

    if (couldInstantExectuted === false){
      const outerContainer = document.createElement('div');
      outerContainer.classList.add('-IMXEVENT-consentReminder__outerContainer');
      const innerContainer = document.createElement('div');
      innerContainer.classList.add('-IMXEVENT-consentReminder__innerContainer');
      const paragraph = document.createElement('p');
      paragraph.innerHTML='Sie müssen Google Maps erlauben: ';
      const cta = document.createElement('button');
      cta.innerHTML='Consent ändern';
      cta.classList.add('button');

      if( typeof uc === 'object') {
        cta.addEventListener('click',event => {
          event.preventDefault();
          uc.showSecondLayer();
        });
      }else {
        cta.addEventListener('click',event => {
          event.preventDefault();
          window.parent.postMessage({type: 'requestConsent'}, '*');
        });
      }

      innerContainer.appendChild(paragraph);
      innerContainer.appendChild(cta);
      outerContainer.appendChild(innerContainer);
      document.getElementById(this.nodes.map.id).appendChild(outerContainer);

    }

    return this;
  },
  /**
   *
   * @returns {imx.Mapwork.Configuration}
   */
  getConfig: function() {
    var vendorId = imx.Mapwork.vendorId.GOOGLE;
    var that = this;

    var vendorConfig = {
      infoWindowEnabled: false,
      mapIcon: function(poi, originMethod, index, marker) {
        var content = document.createElement('div');
        var markerElement = document.createElement('div');
        markerElement.classList.add('-IMXEVNT-poiMarker');
        if (that.activePoi !== null && that.activePoi.id === poi.id) {
          markerElement.classList.add('-IMXEVNT-poiMarker--active');
        }

        markerElement.innerHTML = '' +
        '<svg width="35" height="48" viewBox="0 0 35 48" fill="none" xmlns="http://www.w3.org/2000/svg">\n' +
        ' <path class="-IMXEVNT-poiMarker" d="M17.3838 0C7.79832 0 0 7.79832 0 17.3837C0 29.2795 15.5568 46.7431 16.2191 47.4808C16.8413 48.1737 17.9275 48.1725 18.5485 47.4808C19.2108 46.7431 34.7676 29.2795 34.7676 17.3837C34.7674 7.79832 26.9692 0 17.3838 0ZM17.3838 26.1299C12.5611 26.1299 8.63767 22.2064 8.63767 17.3837C8.63767 12.561 12.5612 8.63757 17.3838 8.63757C22.2064 8.63757 26.1298 12.5611 26.1298 17.3838C26.1298 22.2065 22.2064 26.1299 17.3838 26.1299Z" />\n' +
        '</svg>';

        content.innerHTML = markerElement.outerHTML;
        if (typeof portal.map.leaflet !== 'undefined') {
          return L.divIcon({
            html: content.innerHTML,
            iconSize: [35,48],
            iconAnchor: [0, 0]
          });
        }else{
          return content;
        }
      },
      clusterIcon: function(cluster, marker, count) {
        var counter = 0;

        for(var i in cluster.pois) {
          counter++;
        }

        var content = document.createElement('div');
        content.innerHTML = '' +
          '<svg width="36" height="36" viewBox="0 0 36 36" fill="none" xmlns="http://www.w3.org/2000/svg">\n' +
          ' <circle class="-IMXEVNT-clusterMaker__circle" cx="18" cy="18" r="16" fill="white" stroke="black" stroke-width="4"/>\n' +
          ' <text x="0" y="25" text-anchor="middle" alignment-baseline="central" >\n' +
          '  <tspan x="18" dy="0" fill="black">' + counter + '</tspan>\n' +
          ' </text>' +
          '</svg>';

        if (typeof portal.map.leaflet !== 'undefined') {
          return L.divIcon({
            html: content.innerHTML,
            className: '-IMXEVNT-clusterMaker',
            iconSize: [35,48],
            iconAnchor: [0, 0]
          });
        }else{
          content.classList.add('-IMXEVNT-clusterMaker');
          return content;
        }
      }
    };

    if(portal.map.leaflet) {
      vendorId = imx.Mapwork.vendorId.LEAFLET;
      vendorConfig.tileLayers = [
        {
          id: 1,
          url: portal.map.leaflet.url,
          options: {
            attribution: portal.map.leaflet.attribution,
            subdomains: portal.map.leaflet.subdomains
          }
        }
      ];
    }

    var config = new imx.Mapwork.Configuration();

    config.setMapConfig({
      center: new imx.Mapwork.LatLng(portal.map.default.latitude, portal.map.default.longitude),
      zoom: portal.map.default.zoom,
      mapTypeId: 1,
      scrollwheel: false,
      draggable: true
    });

    config.setVendorId(vendorId);
    config.setVendorConfig(vendorConfig);
    config.setClusterServerUri('/portal/clusterserver.php');
    config.setReadyCallback(this.readyCallback.bind(this));

    return config;
  },
  /**
   * Called after the map is ready.
   *
   * If the map being used is based on Leaflet and if it's shown a mobile device two finger scrolling will be activated.
   * This was inspired by https://codepen.io/surisdziugas/pen/LzXPwz
   *
   * @param {imx.Mapwork.Map.Google|imx.Mapwork.Map.Leaflet} map
   */
  readyCallback: function(map) {
    console.log('Map in container with ID "' + map.getId() + '" is ready.');

    if(portal.map.leaflet && /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
      var leafletMap = map.getMap();

      var onTwoFingerDrag = function(event) {
        if(event.type === 'touchstart' && event.touches.length === 1) {
          event.currentTarget.classList.add('-IMXEVNT-mapContainer__map--swiping');
        }else {
          event.currentTarget.classList.remove('-IMXEVNT-mapContainer__map--swiping');
        }
      };

      leafletMap.dragging.disable();

      if(leafletMap.tap) {
        leafletMap.tap.disable();
      }

      // Binds event listeners for the map and calls the function
      this.nodes.map.addEventListener('touchstart', onTwoFingerDrag);
      this.nodes.map.addEventListener('touchend', onTwoFingerDrag);
    }
  },
  zoomIn: function() {
    this.imxMap.setZoom(this.imxMap.getZoom() + 1);
  },
  zoomOut: function() {
    this.imxMap.setZoom(this.imxMap.getZoom() - 1);
  }
});

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2023 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Florian Müller <mueller@infomax-it.de>
 * @since      21.06.23
 */
var ConsentHelper = (function() {

  /**
   * holds callbacks to be executed when consent is given
   * @type {*[]}
   */
  var callbacks = [];
  /**
   * holds consent information received by postMessage from parent frame or by consent tool directly (in standalone version)
   * @type {{}}
   */
  var consents = {};

  /**
   * The script runs either in an iframe as widget or as standalone script.
   * As standalone we can access the usercentrics object directly and check for the consent.
   * As widget we have to check agains the consent information that is sent by postMessage.
   *
   *
   * @param consentInEvent
   * @param consentInUc
   * @param callback
   * @returns {boolean}
   *  true - could be executed
   *  false - could not be executed (waiting for consent)
   */
  var addListener = function(consentInEvent, consentInUc, callback) {
    if((typeof uc === 'object' && uc.whitelisted.has(consentInUc)) || consents[consentInEvent] === true) {
      callback();
      return true;
    }else {
      callbacks.push({consent: consentInEvent, callback: callback});
      return false;
    }
  };

  var notify = function() {
    var constentsAsArray = Object.keys(consents);
    if(callbacks.length === 0 || constentsAsArray.length === 0) return;

    for(var i = 0; i < constentsAsArray.length; i++) {
      for(var j = 0; j < callbacks.length; j++) {
        if(callbacks[j].consent === constentsAsArray[i] && consents[constentsAsArray[i]] === true) {
          callbacks[j].callback();
          callbacks.splice(j, 1);
        }
      }
    }
  };

  listener = function(event) {
    if (event.detail !== undefined) {
      var constentsAsArray = Object.keys(event.detail);
      if (constentsAsArray.length > 0) {
        consents = event.detail;
        notify();
      }
    }
  };
  window.addEventListener('usercentrics_consent', listener);
  return {
    addListener: addListener
  };
})();

var ContentMap = AbstractMap.extend({
  /**
   *
   * @param {imx.Mapwork.Map.Google|imx.Mapwork.Map.Leaflet} map
   */
  readyCallback: function(map) {
    this._super(map);
    map.setPois(JSON.parse(this.nodes.map.dataset.pois));
  },
  /**
   *
   * @returns {imx.Mapwork.Configuration}
   */
  getConfig: function() {
    var config = this._super();
    var vendorConfig = config.getVendorConfig();

    vendorConfig.maxZoomOnSetPois = portal.map.default.maxZoomOnSetPois.detail;

    return config;
  }
});

var SearchMap = AbstractMap.extend({
  listStateHistory: null,
  urlHelper: null,
  /**
   *
   * @param {HTMLElement} container
   * @param {ListStateHistory} listStateHistory
   * @param {UrlHelper} urlHelper
   */
  init: function(container, listStateHistory, urlHelper) {
    this._super(container);
    this.listStateHistory = listStateHistory;
    this.urlHelper = urlHelper;
  },
  /**
   *
   * @returns {imx.Mapwork.Configuration}
   */
  getConfig: function() {
    var config = this._super();
    var mapConfig = config.getMapConfig();
    var vendorConfig = config.getVendorConfig();
    var mapState = this.listStateHistory.getMapState();

    if(mapState !== null) {
      mapConfig.zoom = mapState.zoom;
      mapConfig.center = new imx.Mapwork.LatLng(mapState.center.latitude, mapState.center.longitude);
    }

    vendorConfig.mapMarkerClick = jQuery.proxy(this._handleSinglePoiClick, this);
    vendorConfig.miniMapMarkerClick = jQuery.proxy(this._handleSinglePoiClick, this);
    vendorConfig.mapClusterMarkerClick = jQuery.proxy(this._handleClusterPoiClick, this);
    vendorConfig.maxZoomOnSetPois = portal.map.default.maxZoomOnSetPois.search;

    return config;
  },
  /**
   *
   * @param {imx.Mapwork.Map.Google|imx.Mapwork.Map.Leaflet} map
   */
  readyCallback: function(map) {
    var that = this;
    this._super(map);
    map.setClusteredPois(JSON.parse(this.nodes.map.dataset.pois), null, null, this.listStateHistory.getMapState() !== null);
    window.addEventListener('OffCanvasClose', function(evt) {
      that.activePoi = null;
      that.imxMap.refresh(); // trigger refresh to update activePoi state
    });
  },
  _handleSinglePoiClick: function(poi) {
    this.activePoi = poi;
    var ident = 'event_' + poi.id;
    var container = jQuery('#-IMXEVNT-offCanvasArea__infoBoard-detail .-IMXEVNT-scrollerArea');

    container.empty();

    this._loadPoiInfo(ident, 'infoboardsingle', container);

    setTimeout(function() {
      document.querySelector('#-IMXEVNT-offCanvasArea__infoBoard-detail').scrollIntoView({behavior: 'smooth', block: 'end'});
    },500);
    IMXEVNT_offCanvas.openOffCanvas('right', '-IMXEVNT-offCanvasArea__infoBoard-detail');
    this.imxMap.refresh(); // trigger refresh to update activePoi state
  },
  _handleClusterPoiClick: function(marker) {
    this.activePoi = null;
    var pois = marker.pois;
    var container = jQuery('#-IMXEVNT-offCanvasArea__infoBoard-list .-IMXEVNT-scrollerArea');

    container.empty();

    jQuery.each(pois, jQuery.proxy(function(idx, elem) {
      var ident = 'event_' + elem.id;
      this._loadPoiInfo(ident, 'infoboardlist', container);
    }, this));

    IMXEVNT_offCanvas.openOffCanvas('right', '-IMXEVNT-offCanvasArea__infoBoard-list');
  },
  _loadPoiInfo: function(ident, layout, container) {
    var uriToLoad = new URI(portal.uri);

    uriToLoad.pathname(portal.permalink + '/' + portal.language + '/action/item');
    uriToLoad.setSearch('widgetToken', portal.token);
    uriToLoad.setSearch('object', ident);
    uriToLoad.setSearch('layout', layout);

    this.urlHelper.applyCurrentSearchConfigurationToUri(uriToLoad);

    var placeholder = jQuery('<article><img src="/portal/frontend/components/v3/assets/images/environment/ajax-loader.gif" alt=""></article>');

    jQuery(container).append(placeholder);

    jQuery(document).trigger('-IMXEVNT-mapStateChange', [
      this.imxMap.getZoom(),
      this.imxMap.getCenter()
    ]);

    jQuery.ajax({
      type: 'GET',
      url: uriToLoad.toString(),
      context: placeholder,
      success: function(responseHTML) {
        var articleElem = null;

        jQuery(responseHTML).each(function(idx, elem) {
          if(elem && elem.nodeName === 'ARTICLE' || elem.nodeName === 'DIV') {
            articleElem = elem;
          }
        });

        jQuery(this).replaceWith(articleElem);
        jQuery(document).trigger('-IMXEVNT-dataLoaded', ['-IMXEVNT-offCanvasInfoboard', 1]);
      },
      error: function() {
        jQuery(this).remove();
      }
    });
  }
});

var SearchHistory = Class.extend({
  stateIdentifier: null,
  init: function() {
    this.stateIdentifier = portal.token + ';searchState';
  },
  saveState: function(lastSearchUrl) {
    try {
        failSaveStorage.setItem(this.stateIdentifier, lastSearchUrl);
    } catch(error) { }
  },
  getLastState: function() {
      return failSaveStorage.getItem(this.stateIdentifier) || '';
  },
  restoreLastState: function() {
    var lastSearchUrl = this.getLastState();

      if(lastSearchUrl != '') {
      window.location.href = lastSearchUrl;
    } else {
      window.location.href = portal.defaultUrl;
    }
  }
});

var Clipboard = Class.extend({
  clipboardIdentifier: null,
  init: function() {
    this.clipboardIdentifier = portal.token + ';clipboard';
  },
  addItem: function(ident) {
    var objectIds = this._getItems();
    var objectIdAlreadyInStore = false;

    jQuery.each(objectIds, function(idx, elem) {
      if(elem == ident) {
        objectIdAlreadyInStore = true;
      }
    });

    if(!objectIdAlreadyInStore) {
      objectIds.push(ident);
      this._setItems(objectIds);
    }

    this._triggerChange();
  },
  removeItem: function(ident) {
    var currentObjectIds = this._getItems();
    var newObjectIds = [];

    jQuery.each(currentObjectIds, function(idx, elem) {
      if(elem != ident) {
        newObjectIds.push(elem);
      }
    });

    this._setItems(newObjectIds);
    this._triggerChange();
  },
  removeAll: function() {
    var currentObjectIds = this._getItems();

    jQuery.each(currentObjectIds, function(idx, elem) {
      var input = document.querySelector('.-IMXEVNT-collector input[data-ident="'+ elem +'"]');
      if (input) {
        input.checked = false;
      }
    });

    this._setItems([]);
    this._triggerChange();
  },
  hasItem: function(ident) {
    var objectIds = this._getItems();
    var objectIdAlreadyInStore = false;

    jQuery.each(objectIds, function(idx, elem) {
      if(elem == ident) {
        objectIdAlreadyInStore = true;
      }
    });

    return objectIdAlreadyInStore;
  },
  _getItems: function() {
      return JSON.parse(failSaveStorage.getItem(this.clipboardIdentifier)) || [];
  },
  _setItems: function(items) {
    try {
        failSaveStorage.setItem(this.clipboardIdentifier, JSON.stringify(items));
    } catch(error) {
    }
  },
  _triggerChange: function() {
    jQuery(document).trigger('-IMXEVNT-clipboardChange', [this._getItems()]);
  },
  getCount: function() {
      return this._getItems().length;
  }
});

var OffCanvasCart = Class.extend({
  requests: {},
  container: null,
  clipboard: null,
  init: function(container, clipboard) {
    this.container = container;
    this.clipboard = clipboard;

    this.initEventHandlers();

    var $collectButton = jQuery('#-IMXEVNT-articleTools a.-IMXEVNT-collect');
    var ident = $collectButton.data('ident');
    if(ident !== '' && this.clipboard.hasItem(ident)) {
      var $parent = $collectButton.parents('.-IMXEVNT-articleTools__element');
      $parent.addClass('-IMXEVNT-articleTools__element--active');
      $collectButton.find('.text').text($collectButton.data('collectedtext'));
    }
  },
  initEventHandlers: function() {
    jQuery(this.container).on('-IMXEVNT-offCanvasOpened', jQuery.proxy(this.handleCartMenuOpen, this));
    jQuery(document).on('change', '.-IMXEVNT-collector input[type="checkbox"]', jQuery.proxy(this.handleCartCheckboxChange, this));
    jQuery(document).on('click', '#-IMXEVNT-articleTools a.-IMXEVNT-collect', jQuery.proxy(this.addToCart, this));
    jQuery(document).on('-IMXEVNT-clipboardChange', jQuery.proxy(this.handleClipboardChange, this));
    jQuery(document).on('-IMXEVNT-dataLoaded', jQuery.proxy(this.validateItemStates, this));
    jQuery(this.container).on('click', '.-IMXEVNT-offCanvasArea__delete a', jQuery.proxy(this.handleResetWatchlist, this));
    jQuery(this.container).on('click', '.-IMXEVNT-offCanvasArea__share', jQuery.proxy(this.handleShareClick, this));
    jQuery(document).on('-IMXEVNT-dataLoaded -IMXEVNT-clipboardChange', jQuery.proxy(this.handleShareChange, this));
  },
  handleResetWatchlist: function() {
    if(document.querySelector('.-IMXEVNT-scrollerArea .-IMXEVNT-offCanvasArea__content')) {
      window.IMXEVNT.clipboard.removeAll();
      document.querySelector('.-IMXEVNT-offCanvasArea__delete').style.display = 'none';
    }
  },
  handleShareChange: function() {
    jQuery('.-IMXEVNT-offCanvasArea__share').toggle(jQuery('[data-eventid]', this.container).length > 0);
  },
  handleShareClick: function() {
    var uriToLoad = new URI(portal.uri);

    var ids = jQuery('[data-eventid]', this.container).map(function() {
      return this.dataset.eventid;
    }).get().filter(function(value, index, self) {
      return (self.indexOf(value) === index);
    }).sort();

    uriToLoad.pathname(portal.permalink + '/' + portal.language + '/action/cart');
    uriToLoad.setSearch('widgetToken', portal.token);
    uriToLoad.setSearch('ids', ids.join(','));

    jQuery.fancybox.open({
      href: uriToLoad.toString(),
      type: 'iframe'
    });
  },
  ensureCartItemsLoaded: function() {
    var loadedIdents = [];

    // check if nodes need to be removed
    jQuery('.-IMXEVNT-offCanvasArea__listElement', this.container).each(jQuery.proxy(function(idx, elem) {
      var ident = jQuery('.-IMXEVNT-collector input[type="checkbox"]', elem).data('ident');
      if(!this.clipboard.hasItem(ident)) {
        jQuery(elem).remove();
      } else {
        loadedIdents.push(ident);
      }
    }, this));

    // check if elements must be loaded
    jQuery.each(this.clipboard._getItems(), jQuery.proxy(function(idx, ident) {
      var requests = this.requests;

      if(loadedIdents.indexOf(ident) < 0 && !requests[ident]) {

        // load item
        var uriToLoad = new URI(portal.uri);
        uriToLoad.pathname(portal.permalink + '/' + portal.language + '/action/item');
        uriToLoad.setSearch('widgetToken', portal.token);
        uriToLoad.setSearch('object', ident);
        uriToLoad.setSearch('layout', 'cart');

        var placeholder = jQuery('<div><img src="/portal/frontend/components/v3/assets/images/environment/ajax-loader.gif" alt="" /></div>');
        jQuery('.-IMXEVNT-scrollerArea .-IMXEVNT-offCanvasArea__content', this.container).append(placeholder);

        requests[ident] = jQuery.ajax({
          type: 'GET',
          url: uriToLoad.toString(),
          context: placeholder,
          success: function(responseHTML) {
            delete requests[ident];

            var articleElem = null;

            jQuery(responseHTML).each(function(idx, elem) {
              if(elem && elem.nodeName === 'DIV') {
                articleElem = elem;
              }
            });

            jQuery(this).replaceWith(articleElem);
            jQuery(document).trigger('-IMXEVNT-dataLoaded', ['-IMXEVNT-offCanvasClipboard', idx]);

            if(document.querySelector('.-IMXEVNT-scrollerArea .-IMXEVNT-offCanvasArea__content .-IMXEVNT-collector')) {
              document.querySelector('.-IMXEVNT-offCanvasArea__delete').style.display = 'block';
            }
          },
          error: function() {
            delete requests[ident];
            jQuery(this).remove();
          }
        });
      }
    }, this));
  },
  changeRemberedItemCounter: function() {
    var rememberedListItemsCount = this.clipboard.getCount();

    if(!document.querySelector('.-IMXEVNT-sticky__buttons--cartCounterRememberedItems')) {
      if(document.querySelector('.-IMXEVNT-openOffCanvas__cart')) {
        var openOffCanvasCartButtons = document.querySelectorAll('.-IMXEVNT-openOffCanvas__cart');

        [].forEach.call(openOffCanvasCartButtons, function(openOffCanvasCartButton) {
          var element = document.createElement("div");
          var count = document.createTextNode(rememberedListItemsCount);
          element.classList.add('-IMXEVNT-sticky__buttons--cartCounterRememberedItems');
          element.append(count);
          openOffCanvasCartButton.append(element);
        });
      }
    } else {
      var cartCountRememberedItems = document.querySelectorAll('.-IMXEVNT-sticky__buttons--cartCounterRememberedItems');

      [].forEach.call(cartCountRememberedItems, function(cartCountRememberedItem) {
        cartCountRememberedItem.innerHTML = String(rememberedListItemsCount);
      });
    }
  },
  validateItemStates: function() {
    jQuery('.-IMXEVNT-collector input[type="checkbox"]').each(jQuery.proxy(function(idx, elem) {
      var ident = jQuery(elem).data('ident');
      if(this.clipboard.hasItem(ident)) {
        jQuery(elem).prop('checked', true);
      } else {
        jQuery(elem).prop('checked', false);
      }
    }, this));

    this.changeRemberedItemCounter();
  },
  handleCartCheckboxChange: function(ev) {
    var ident = jQuery(ev.currentTarget).data('ident');
    if(ident !== '') {
      if(jQuery(ev.currentTarget).prop('checked')) {
        this.clipboard.addItem(ident);
        this.handleKeepStatus(true, ident);
      } else {
        this.clipboard.removeItem(ident);
        this.handleKeepStatus(false, ident);
      }
    }
  },
  addToCart: function(ev) {
    var ident = jQuery(ev.currentTarget).data('ident');
    if(ident !== '') {
      if(!this.clipboard.hasItem(ident)) {
        this.clipboard.addItem(ident);
        this.handleKeepStatus(true, ident);
      } else {
        this.clipboard.removeItem(ident);
        this.handleKeepStatus(false, ident);
      }
    }
  },
  handleKeepStatus: function(collected, ident) {
    var $element = jQuery('#-IMXEVNT-articleTools a.-IMXEVNT-collect[data-ident="' + ident + '"]');
    var $parent = $element.parents('.-IMXEVNT-articleTools__element');
    if(collected) {
      $parent.addClass('-IMXEVNT-articleTools__element--active');
      $element.find('.text').text($element.data('collectedtext'));
    } else {
      $parent.removeClass('-IMXEVNT-articleTools__element--active');
      $element.find('.text').text($element.data('collecttext'));
    }
  },
  handleClipboardChange: function() {
    this.validateItemStates();
    this.ensureCartItemsLoaded();
    this.changeRemberedItemCounter();
  },
  handleCartMenuOpen: function() {
    this.ensureCartItemsLoaded();
  }
});

var ListStateHistory = Class.extend({
  stateIdentifier: null,
  init: function() {
    this.isDetailpage = !!document.querySelector(".-IMXEVNT-isDetailpage-Js");
    this.stateIdentifier = portal.token + ';searchListState';

    if(!this.isDetailpage){
      this.handleListScroll(this);
    }

    jQuery(document).on('-IMXEVNT-pageInitialized', jQuery.proxy(this.initEventHandlers, this));
  },
  initEventHandlers: function() {
    var isDetailpage = !!document.querySelector(".-IMXEVNT-isDetailpage-Js");
    // listen for form submissions
    jQuery(document).on('-IMXEVNT-searchSubmit', jQuery.proxy(this.clearState, this));

    // listen for items loaded
    jQuery(document).on('-IMXEVNT-dataLoaded', jQuery.proxy(this.handleDataLoaded, this));

    // listen for scroll changes
    if(!isDetailpage){
      jQuery(window).on('scroll', jQuery.proxy(this.handleScrollChange, this));
    }
    // handle map event handlers
    jQuery(document).on('-IMXEVNT-mapStateChange', jQuery.proxy(this.handleMapStateChange, this));
  },
  handleListScroll: function(){
    var state = this.getState();
    window.frames.scrollTo(0, state.scrollTop);
  },
  handleScrollChange: function(ev) {
    var state = this.getState();
    var scrollOffset = jQuery(ev.currentTarget).scrollTop();
    state.scrollTop = scrollOffset;

    this.setState(state);
  },
  clearState: function() {
    try {
        failSaveStorage.setItem(this.stateIdentifier, '');
    } catch(error) { }
  },
  getState: function() {
      var json = failSaveStorage.getItem(this.stateIdentifier) || '{}';
    return JSON.parse(json);
  },
  getStateForContainer: function(id) {
    var state = this.getState();
    if(state.containers && state.containers[id]) {
      return state.containers[id];
    }
    return 0;
  },
  getScrollOffset: function() {
    var state = this.getState();
    if(state.scrollTop) {
      return state.scrollTop;
    }
    return 0;
  },
  getMapState: function() {
    var state = this.getState();
    if (this.isDetailpage){
      return null;
    }
    return state.mapState || null;
  },
  setState: function(state) {
    try {
        failSaveStorage.setItem(this.stateIdentifier, JSON.stringify(state));
    } catch(error) { }
  },
  handleDataLoaded: function(ev, id, objectIdx) {
    var state = this.getState();

    if(!state.containers) {
      state.containers = {};
    }

    if(state.containers[id]) {
      if(state.containers[id] < objectIdx) {
        state.containers[id] = objectIdx;
      }
    } else {
      state.containers[id] = objectIdx;
    }

    this.setState(state);
  },
  /**
   *
   * @param {Event} ev
   * @param {Number} zoom
   * @param {imx.Mapwork.LatLng} center
   */
  handleMapStateChange: function(ev, zoom, center) {
    if (!this.isDetailpage){
      var state = this.getState();

      state.mapState = {
        zoom: zoom,
        center: {
          latitude: center.getLatitude(),
          longitude: center.getLongitude()
        }
      };

      this.setState(state);
    }
  }
});

/* datepicker article */
jQuery(function() {
  jQuery('.-IMXEVNT-articleContext__calendar').each(function(idx, datepickerElement) {
    var calendarData = jQuery(datepickerElement).data('dates');
    var dayData = {};

    for(var index = 0; index < calendarData.dates.length; index++) {
      var elem = calendarData.dates[index];

      if(!dayData[elem.date]) {
        dayData[elem.date] = [];
      }
      dayData[elem.date].push(elem);
    }

    jQuery(datepickerElement).datepicker({
      showOtherMonths: true,
      selectOtherMonths: true,
      defaultDate: moment(jQuery(datepickerElement).data('default')).toDate(),
      minDate: moment(calendarData.min).startOf('month').toDate(),
      maxDate: moment(calendarData.max).endOf('month').toDate(),
      beforeShowDay: function(date) {
        var momentDate = moment(date);
        var formattedDate = momentDate.format('YYYY-MM-DD');
        var selectedDate = moment(jQuery(datepickerElement).data('default'));
        var formattedSelectedDate = selectedDate.format('YYYY-MM-DD');
        var isToday = false;
        var hasEvent = false;
        var isSelected = false;
        var classSelector = '';

        if(formattedDate === formattedSelectedDate) {
          isSelected = true;
        }

        if(dayData[formattedDate]) {
          hasEvent = true;
        }
        if(moment().isSame(momentDate, 'day')) {
          isToday = true;
        }

        if(isSelected && hasEvent) {
          classSelector = 'ui-state-hasevent ui-state-selected';
        } else if(hasEvent) {
          classSelector = 'ui-state-hasevent';
        } else if(isToday) {
          classSelector = 'ui-state-today';
        } else {
          classSelector = '';
        }

        return [
          true,
          classSelector
        ];
      },
      onSelect: function(dateText, datepicker) {
        var momentDate = moment(dateText, portal.formats.date);
        var formattedDate = momentDate.format('YYYY-MM-DD');
        var detailDates = [];

        if(dayData[formattedDate]) {
          detailDates = dayData[formattedDate];
        }

        detailDates.sort(function(a, b) {
          var momentA = moment(a.date + ' ' + a.begin);
          var momentB = moment(b.date + ' ' + b.begin);

          if(momentA.isBefore(momentB)) {
            return -1;
          } else if(momentB.isBefore(momentA)) {
            return 1;
          }

          return 0;
        });

        if(detailDates.length > 0) {
          // show popup layer
          var positionOfAnchor = {
            left: null,
            top: null
          };

          jQuery('.ui-datepicker-calendar td.ui-state-hasevent', datepickerElement).each(function(idx, elem) {
            if(jQuery(elem).data('month') == momentDate.month() && jQuery(elem).data('year') == momentDate.year() && jQuery('a', elem).text() == momentDate.date()) {
              positionOfAnchor = jQuery(elem).position();
              positionOfAnchor.left += jQuery(elem).width() / 2;
            }
          });

          if(positionOfAnchor.left != null && positionOfAnchor.top != null) {
            // render popup

            jQuery('#-IMXEVNT-datepickerPopup .-IMXEVNT-datepickerPopup__body > ul').empty();
            jQuery.each(detailDates, function(idx, elem) {
              var link = elem.bookingLink;
              var target = '_blank';
              if(!link) {
                var uri = new URI();
                uri.setQuery({
                  'eventDateId': elem.id
                });
                link = uri.toString();
                target = '';
              }

              var item = '<a href="' + link + '" target="' + target + '" class="-IMXEVNT-datepickerPopup__time">';
              if(elem.begin) {
                item += elem.begin + ' ' + portal.translations['time.clock'];
              } else {
                item += portal.translations['time.day'];
              }
              item += '</a>';

              jQuery('#-IMXEVNT-datepickerPopup .-IMXEVNT-datepickerPopup__body > ul').append('<li>' + item + '</li>');
            });

            jQuery('#-IMXEVNT-datepickerPopup .-IMXEVNT-datepickerPopup__date').text(momentDate.format(portal.formats.date));

            jQuery('#-IMXEVNT-datepickerPopup').show();

            var position = {
              top: positionOfAnchor.top - jQuery('#-IMXEVNT-datepickerPopup').height(),
              left: positionOfAnchor.left - jQuery('#-IMXEVNT-datepickerPopup').width() / 2
            };

            if(position.left < 0) {
              position.left = 1;
            }

            jQuery('#-IMXEVNT-datepickerPopup').css('top', position.top);
            jQuery('#-IMXEVNT-datepickerPopup').css('left', position.left);
          }
        }
      }
    });
  });

  jQuery('#-IMXEVNT-datepickerPopup .-IMXEVNT-datepickerPopup__closer').click(function(ev) {
    jQuery(ev.currentTarget).parents('#-IMXEVNT-datepickerPopup').hide();
  });
});

var IMXEVNT_main = (function() {

  var getClassCollectionForWidth = function(width) {
    for(var i = 0; i < breakPoints.length; i++) {
      if(width >= breakPoints[i].minWidth) {
        return breakPoints[i];
      }
    }
  };

  var stripSizeClassesFromMainNode = function(newClass) {
    for(var i = 0; i < breakPoints.length; i++) {
      var classToStrip = classPrefix + breakPoints[i].class;

      if(classToStrip !== newClass && mainNode.classList.contains(classToStrip)) {
        mainNode.classList.remove(classToStrip);
      }
    }
  };

  var checkForTransitionArea = function(hostNodeWidth, newClassCollection) {
    if(hostNodeWidth - newClassCollection.transition < newClassCollection.minWidth) {
      mainNode.classList.add(classPrefix + 'transitionArea');
    } else {
      mainNode.classList.remove(classPrefix + 'transitionArea');
    }
  };

  var checkHostNodeWidth = function() {
    var hostNodeWidth = parseInt(hostNode.offsetWidth);

    var newClassCollection = getClassCollectionForWidth(hostNodeWidth);
    var newClass = classPrefix + newClassCollection['class'];

    stripSizeClassesFromMainNode(newClass);
    checkForTransitionArea(hostNodeWidth, newClassCollection);

    if(!mainNode.classList.contains(newClass)) {
      mainNode.classList.add(newClass);
      jQuery(document).trigger('-IMXEVNT_mediaChanged', [newClassCollection['class']]);
    }

    jQuery('#-IMXEVNT-pageHeader__logo').hide();
    setTimeout(function() {
      jQuery('#-IMXEVNT-pageHeader__logo').show();
    }, 1);

    jQuery(document).trigger('-IMXEVNT-layoutChanged');
  };

  var registerResizeEvents = function() {
    jQuery(document).on('-IMXEVNT_mediaChanged', function(ev, size) {
      if(portal.searchui.allSearchDisplayType == 0) {
        if(size == 'medium' || size == 'small' || size == 'tiny') {
          jQuery('.-IMXEVNT-contentForm__mobileCollapsed').prop('checked', false);
          jQuery('#-IMXEVNT-heroimage__form fieldset > input[type="checkbox"]').prop('disabled', false);
          jQuery('#-IMXEVNT-heroimage__form fieldset > legend > label').removeClass('-IMXEVNT-heroimage__form__noArrow');
        } else {
          jQuery('.-IMXEVNT-contentForm__mobileCollapsed').prop('checked', true);
          jQuery('#-IMXEVNT-heroimage__form fieldset > input[type="checkbox"]').prop('disabled', true);
          jQuery('#-IMXEVNT-heroimage__form fieldset > legend > label').addClass('-IMXEVNT-heroimage__form__noArrow');
        }
      }
    });

    window.addEventListener('resize', function() {
      checkHostNodeWidth();
    });
    checkHostNodeWidth();
  };

  jQuery('#-IMXEVNT-heroimage__form fieldset > input[type="checkbox"]').on('change', function(ev) {
    if(window.innerWidth > 810) {
      jQuery('#-IMXEVNT-heroimage__form fieldset > input[type="checkbox"]').prop('checked', jQuery(ev.currentTarget).prop('checked'));
    }
    jQuery('.-IMXEVNT-contentForm__mobileCollapsed').removeClass('-IMXEVNT-contentForm__mobileCollapsed');
    jQuery(document).trigger('-IMXEVNT-layoutChanged');
  });

  var hostNode = document.getElementById('-IMXEVNT-host');
  var mainNode = document.getElementById('-IMXEVNT-main');

  var classPrefix = '-IMXEVNT-main--';

  var breakPoints = [
    {
      minWidth: 1600,
      transition: 0,
      class: 'large'
    },
    {
      minWidth: 1110,
      transition: 200,
      class: 'normal'
    },
    {
      minWidth: 930,
      transition: 150,
      class: 'normal'
    },
    {
      minWidth: 810,
      transition: 150,
      class: 'medium'
    },
    {
      minWidth: 510,
      transition: 150,
      class: 'small'
    },
    {
      minWidth: 0,
      transition: 400,
      class: 'tiny'
    }
  ];

  if(hostNode && mainNode) {
    registerResizeEvents();
  }

})();

(function(){

  var calculateVisuals = function(container){
    var image = container.querySelector('img');

    var originalWidth = parseInt(image.naturalWidth);
    var orignalHeight = parseInt(image.naturalHeight);

    return originalWidth / orignalHeight;
  };

  var registerResizeHandler = function(){
    window.addEventListener('resize', function(){
      setTimeout(updateVisuals, 500);
    });
    updateVisuals();
  };

  var updateVisuals = function(){
    var ratio = calculateVisuals(heroImageContainer);
    var hostContainer = document.getElementById('-IMXEVNT-host');

    var windowWidth = parseInt(hostContainer.offsetWidth);
    var windowHeight = parseInt(heroImageContainer.offsetHeight);
    var windowRatio = windowWidth / windowHeight;

    if(windowRatio > ratio){
      heroImageContainer.classList.add('-IMXEVNT-heroimage--verticalyCropped');
    } else {
      heroImageContainer.classList.remove('-IMXEVNT-heroimage--verticalyCropped');
    }
  };

  var heroImageContainer = document.getElementById('-IMXEVNT-heroimage');
  if(heroImageContainer && !heroImageContainer.classList.contains('noImage') && heroImageContainer.querySelector('img')) {
    registerResizeHandler();
  }

})();

var IMXEVNT_offCanvas = (function(){

  var _stripOffCanvasClassesFromMainNode = function(){
    document.querySelector('html').classList.remove('-IMXEVNT-main--noscroll');
    _hideVisibleOffCanvasContainer();
  };

  var _hideVisibleOffCanvasContainer = function(){
    var visibleContainer = document.getElementsByClassName('-IMXEVNT-offCanvasArea--visible')[0];
    if(visibleContainer){
      visibleContainer.classList.remove('-IMXEVNT-offCanvasArea--visible');
    }
  };

  var openOffCanvas = function(side, targetId){
    var targetElement = document.getElementById(targetId);
    var targetElementId = targetElement.id;
    var infoboardId = '-IMXEVNT-offCanvasArea__infoBoard-detail';
    var infoboardListId = '-IMXEVNT-offCanvasArea__infoBoard-list';

    _stripOffCanvasClassesFromMainNode();
    _hideVisibleOffCanvasContainer();

    targetElement.classList.add('-IMXEVNT-offCanvasArea--visible');
    jQuery('#' + targetId).trigger('-IMXEVNT-offCanvasOpened');

    if(targetElementId !== infoboardId && targetElementId !== infoboardListId){
      document.querySelector('html').classList.add('-IMXEVNT-main--noscroll');
    }
  };

  var closeOffCanvas = function(){
    _stripOffCanvasClassesFromMainNode();
    [].forEach.call(document.querySelectorAll('.-IMXEVNT-offCanvasArea--visible'), function(el) {
      el.classList.remove('-IMXEVNT-offCanvasArea--visible');
    });

    var event = document.createEvent('CustomEvent');
    event.initCustomEvent('OffCanvasClose', false, false, {});
    window.dispatchEvent(event);
  };

  return {
    openOffCanvas : openOffCanvas,
    closeOffCanvas : closeOffCanvas
  };

})();

(function(jQuery) {

  var _checkAllSubCheckboxes = function(collection) {
    for(var i = 0; i < collection.length; i++) {
      collection[i].checked = true;
    }
  };

  var _uncheckAllSubCheckboxes = function(collection) {
    for(var i = 0; i < collection.length; i++) {
      collection[i].checked = false;
    }
  };

  var _watchMasterCheckbox = function(collection, master) {
    master.addEventListener('change', function() {

      master.classList.remove('semiactive');

      if(master.checked) {
        _checkAllSubCheckboxes(collection);
      } else {
        _uncheckAllSubCheckboxes(collection);
      }
    });
  };

  var _testAllSubCheckboxes = function(collection, master) {
    var activeCheckboxes = 0;

    for(var i = 0; i < collection.length; i++) {
      if(collection[i].checked) {
        activeCheckboxes++;
      }
    }

    if(activeCheckboxes > 0) {
      if(activeCheckboxes === collection.length) {
        master.checked = true;
        master.classList.remove('semiactive');
      } else {
        master.checked = false;
        master.classList.add('semiactive');
      }
    } else {
      master.checked = false;
      master.classList.remove('semiactive');
    }
  };

  var _watchAllSubCheckboxes = function(collection, master) {
    for(var i = 0; i < collection.length; i++) {
      collection[i].addEventListener('change', _testAllSubCheckboxes.bind(null, collection, master));
    }
    _testAllSubCheckboxes(collection, master);
  };

  var _watchSubFilter = function(labelNode) {
    var subFilterRootNode = labelNode.parentNode.parentNode;
    var checkbox = subFilterRootNode.querySelector('[type="checkbox"]:not([id*="subfilter"])');

    labelNode.addEventListener('click', function() {
      console.log(labelNode);
      labelNode.classList.toggle('dropdown--active');
    });

    var subFilterList = subFilterRootNode.getElementsByTagName('ul')[0];
    var subFilterCheckboxCollection = subFilterList.getElementsByTagName('input');

    _watchMasterCheckbox(subFilterCheckboxCollection, checkbox);
    _watchAllSubCheckboxes(subFilterCheckboxCollection, checkbox);
  };

  var _watchTopFilter = function(labelNode) {
    var subFilterRootNode = labelNode.parentNode.parentNode;
    var checkbox = subFilterRootNode.querySelector('[type="checkbox"]:not([id*="subfilter"])');

    var subFilterList = subFilterRootNode.getElementsByTagName('ul')[0];
    var subFilterCheckboxCollection = subFilterList.getElementsByTagName('input');

    _watchMasterCheckbox(subFilterCheckboxCollection, checkbox);
    _watchAllSubCheckboxes(subFilterCheckboxCollection, checkbox);
  };

  var offCanvasFilterNode = document.getElementById('-IMXEVNT-filter');

  function _topLevelFilter(filter) {
    var subFilterFakeCheckbox = filter.parentNode.querySelector('.fakeCheckbox--subFilter');
    filter.addEventListener('change', function(evt) {
      if(filter.checked) {
        subFilterFakeCheckbox.checked = true;
      }
    });
  }

  if(offCanvasFilterNode) {
    var subFilterCollection = offCanvasFilterNode.getElementsByClassName('dropdown');
    if(subFilterCollection) {
      for(var i = 0; i < subFilterCollection.length; i++) {
        _watchSubFilter(subFilterCollection[i]);
      }
    }

    var topLevelFilterCollection = offCanvasFilterNode.getElementsByClassName('fakeCheckbox--topFilter');
    if(topLevelFilterCollection) {
      for(var j = 0; j < topLevelFilterCollection.length; j++) {
        _topLevelFilter(topLevelFilterCollection[j]);
      }
    }
  }

  [].forEach.call(document.querySelectorAll('.-IMXEVNT-filterGroup__list'), function(list) {
    var more = list.querySelector('.more__show');
    if(more) {
      more.addEventListener('click', function() {
        [].forEach.call(list.querySelectorAll('.moreFilter'), function(moreFilter) {
          moreFilter.classList.add('moreFilter--visible');
        });
        more.style.display = 'none';
      });
    }
  });

  //counter for the selected filters
  if(document.querySelector('.-IMXEVNT-filterGroup__list')) {
    var filterGroupLists = document.querySelectorAll('.-IMXEVNT-filterGroup__list');

    if(!document.querySelector('.-IMXEVNT-filter--counter')) {
      var checkedCheckboxesCount = document.querySelectorAll(".-IMXEVNT-filterGroup__list input[type=checkbox]:checked:not(.fakeCheckbox--subFilter):not(.fakeCheckbox--topFilter)").length;
      var element = document.createElement("div");

      element.classList.add('-IMXEVNT-filter--counter');
      element.innerHTML = String(checkedCheckboxesCount);
      document.querySelector('.-IMXEVNT-openOffCanvas__filter').append(element);

      if(document.querySelector('.-IMXEVNT-filter__title')){
        var desktopElement = document.createElement("div");
        desktopElement.classList.add('-IMXEVNT-filter--counter');
        desktopElement.innerHTML = String(checkedCheckboxesCount);
        document.querySelector('.-IMXEVNT-filter__title').append(desktopElement);
      }
    }

    [].forEach.call(filterGroupLists, function(filterGroupList) {
      filterGroupList.addEventListener('change', function() {
        var checkedCheckboxesCount = document.querySelectorAll(".-IMXEVNT-filterGroup__list input[type=checkbox]:checked:not(.fakeCheckbox--subFilter):not(.fakeCheckbox--topFilter)").length;

        if(document.querySelector('.-IMXEVNT-filter__title .-IMXEVNT-filter--counter')) {
          document.querySelector('.-IMXEVNT-filter__title .-IMXEVNT-filter--counter').innerHTML = String(checkedCheckboxesCount);
        }

        if(document.querySelector('.-IMXEVNT-sticky__buttons--filter .-IMXEVNT-filter--counter')) {
          document.querySelector('.-IMXEVNT-sticky__buttons--filter .-IMXEVNT-filter--counter').innerHTML = String(checkedCheckboxesCount);
        }
      });
    });
  }

  jQuery(document).on('-IMXEVNT-iframeScrollUpdate', function(ev, data) {
    var $main = jQuery('#-IMXEVNT-main');
    var $filterButtons = jQuery('#-IMXEVNT-filter').find('.-IMXEVNT-filter__button');

    $filterButtons.css('top', data.relativeScrollPosition + data.visibleHeight - $filterButtons.outerHeight());
    $filterButtons.css('bottom', 'inherit');

    var $cartContent = jQuery('#-IMXEVNT-offCanvasArea__list');
    var cartContentMargin = parseInt($cartContent.css('margin-top')) || 0;
    if(!$main.hasClass('-IMXEVNT-main--offCanvasRight') || cartContentMargin > data.relativeScrollPosition) {
      $cartContent.css('margin-top', data.relativeScrollPosition);
    }
  });

})(jQuery);

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-29
 */
/**
 *
 * @returns {void}
 */
var IMXEVNT_search_Util = (function(document, window, Date, setTimeout, clearTimeout, portal) {
  'use strict';

  var scrollData = {};

  window.addEventListener('message', function(message) {
    var messageData = message.data;

    if(messageData.hasOwnProperty('relativeScrollPosition') && messageData.hasOwnProperty('visibleHeight')) {
      scrollData = messageData;
    }
  });

  /**
   * Checks if the given selector is available within the given element at least one time.
   *
   * @param {HTMLElement} element
   * @param {String} selector
   * @returns {boolean}
   */
  function contains(element, selector) {
    return (element.querySelectorAll(selector).length > 0);
  }

  /**
   * Chunks the given array to smaller arrays containing at max values as the given size.
   * If the given size is zero or smaller it will return one large chunked array containing all values.
   *
   * @param {Array} array
   * @param {Number} size
   * @param {Number} firstElementSize
   * @returns {Array}
   */
  function chunk(array, size, firstElementSize) {
    if (typeof firstElementSize === 'undefined'){
      firstElementSize = 0;
    }

    var chunks = [];

    if(size <= 0) {
      return [array];
    }

    chunks.push(array.slice(0, firstElementSize));

    for(var index = firstElementSize; index < array.length; index += size) {
      chunks.push(array.slice(index, (index + size)));
    }
    return chunks;
  }

  /**
   * Throttles events, so they happen only at the defined threshold and not more often.
   *
   * @see https://nimius.net/blog/artikel/javascript-debounce-throttle/
   *
   * @param {Function} func
   * @param {Number} threshold
   * @returns {Function}
   */
  function throttle(func, threshold) {
    var last;
    var deferTimer;

    return function() {
      var now = +new Date();
      var args = arguments;

      if(last && now < last + threshold) {
        clearTimeout(deferTimer);

        deferTimer = setTimeout(function() {
          last = now;
          func.apply(null, args);
        }, threshold);
      }else {
        last = now;
        func.apply(null, args);
      }
    };
  }

  /**
   * Debounces events, so they happen only only once after the defined wait time.
   *
   * @see https://nimius.net/blog/artikel/javascript-debounce-throttle/
   *
   * @param {Function} func
   * @param {Number} wait
   * @returns {Function}
   */
  function debounce(func, wait) {
    var timeout;

    return function() {
      var args = arguments;

      var later = function() {
        timeout = null;
        func.apply(null, args);
      };

      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  /**
   * Checks if the given element is basically visible and currently shown within the viewport, even when only partially.
   *
   * @param {HTMLElement} element
   * @returns {boolean}
   */
  function isVisible(element) {
    var isVisible = !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length);

    if(isVisible) {
      var originalRectangle = element.getBoundingClientRect();
      var viewportHeight = 0;
      var rectangle = {
        bottom: 0,
        top: 0
      };

      if(scrollData.relativeScrollPosition || scrollData.visibleHeight) {
        viewportHeight = scrollData.visibleHeight;
        rectangle = {
          bottom: originalRectangle.bottom - scrollData.relativeScrollPosition,
          top: originalRectangle.top - scrollData.relativeScrollPosition
        };
      }else {
        viewportHeight = (window.innerHeight || document.documentElement.clientHeight);
        rectangle = originalRectangle;
      }
      return rectangle.bottom > 0 && rectangle.top <= viewportHeight;
    }
    return false;
  }

  /**
   * Creates the link to a controller action and sets the given params in the request.
   *
   * @param {String} actionName
   * @param {Object} params
   * @returns {string}
   */
  function buildActionLink(actionName, params) {
    var uri = new URI(portal.uri);

    uri.pathname(portal.permalink + '/' + portal.language + '/action/' + actionName);
    uri.setSearch('widgetToken', portal.token);
    uri.setSearch('source', (window.location === window.parent.location) ? 'standalone' : 'widget');

    if(portal.isPreview) {
      uri.setSearch('wysiwyg', 'true');
    }

    for(var key in params) {
      if(!params.hasOwnProperty(key)) {
        continue;
      }

      if(typeof params[key] === 'object') {
        uri.setSearch(key + '[]', params[key]);
      }else if(typeof params[key] !== 'undefined' && params[key] !== null) {
        uri.setSearch(key, params[key]);
      }
    }
    return uri.toString();
  }

  return {
    contains: contains,
    chunk: chunk,
    throttle: throttle,
    debounce: debounce,
    isVisible: isVisible,
    buildActionLink: buildActionLink
  };

}).apply(null, [
  document,
  window,
  Date,
  setTimeout,
  clearTimeout,
  portal
]);

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-02-12
 */

/**
 * Creates a new item and provides methods for recalculating its contents.
 *
 * @param {HTMLElement} item
 * @constructor
 */
function IMXEVNT_search_Item(item) {
  'use strict';

  var ratios = {
    IMAGE_ASPECT: 1.56,
    IMAGE_COLUMN: 0.333333
  };

  var ignoredClasses = [
      '-IMXEVNT-listElement__text__extended',
      '-IMXEVNT-collector'
  ];

  var textNode = item.querySelector('.-IMXEVNT-listElement__text');
  var textElement = textNode.querySelector('.-IMXEVNT-listElement__text__extended');
  var fixedElements = [];

  [].forEach.call(textNode.children, function(element) {
    var ignoredClassesCount = ignoredClasses.length;

    for(var index = 0; index < ignoredClassesCount; index++) {
      if(element.classList.contains(ignoredClasses[index])) {
        return;
      }
    }

    fixedElements.push(element);
  });

  /**
   * Calculates the height of the given element including margins.
   *
   * @param {HTMLElement} element
   * @returns {number}
   */
  function outerHeight(element) {
    var height = element.offsetHeight;
    var style = getComputedStyle(element);

    height += parseInt(style.marginTop) + parseInt(style.marginBottom);
    return height;
  }

  /**
   *
   * @returns {IMXEVNT_search_Item}
   */
  this.recalculate = function() {
    window.requestAnimationFrame(function() {
      item.classList.remove('-IMXEVNT-listElement--init');

      var itemHeight = (item.offsetWidth * ratios.IMAGE_COLUMN / ratios.IMAGE_ASPECT);
      var fixedElementsHeight = 0;

      fixedElements.forEach(function(element) {
        fixedElementsHeight += outerHeight(element);
      });

      var targetHeight = (itemHeight - fixedElementsHeight - 20);

        textElement.style.display = 'block';
        textElement.style.maxHeight = Math.max(0, targetHeight) + 'px';

        // I hate jQuery, but in this case it's a lifesaver. There's no real alternative to this plugin in vanilla JS.
        jQuery(textElement).ellipsis('p');
    });

    return this;
  };
}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-02-12
 */

/**
 * Creates a new item manager.
 * If an element is passed to it when creating a new instance items will automatically be sought within.
 *
 * @constructor
 */
function IMXEVNT_search_ItemManager() {
  'use strict';

  var items = [];

  /**
   * Recalculates every teaser being managed.
   */
  function recalculate() {
    var teaserCount = items.length;

    for(var index = 0; index < teaserCount; index++) {
      items[index].recalculate();
    }
  }

  /**
   * Finds items in the givene element and initializes them.
   * Also saves them for future resizes of the window, so they can be recalculated.
   *
   * @param {HTMLElement} element
   * @returns {IMXEVNT_search_ItemManager}
   */
  this.find = function(element) {
    if(element) {
      [].forEach.call(element.querySelectorAll('.-IMXEVNT-listElement--init'), function(item) {
        items.push(new IMXEVNT_search_Item(item).recalculate());
      });
    }

    return this;
  };

  window.addEventListener('resize', IMXEVNT_search_Util.debounce(recalculate, 250));

  [].forEach.call(document.querySelectorAll('.-IMXEVNT-switchArea__tabCheckbox'), function(checkbox) {
    checkbox.addEventListener('change', recalculate);
  });
}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-31
 */

/**
 * Creates a new teaser and provides methods for recalculating its contents.
 *
 * @param {HTMLElement} element
 * @constructor
 */
//function IMXEVNT_search_Teaser(element) {
//  'use strict';
//
//  var textNode = element.querySelector('.-IMXEVNT-galleryTeaser__text');
//  var hoverNode = textNode.querySelector('.-IMXEVNT-galleryTeaser__text__hoverinfo');
//
//  /**
//   * Calculates and sets the offset of the text node of the teaser, so the hover info is hidden
//   * and only gets shown on hover (done by CSS).
//   *
//   * @returns {IMXEVNT_search_Teaser}
//   */
//  this.recalculate = function() {
//    window.requestAnimationFrame(function() {
//      element.classList.remove('-IMXEVNT-galleryTeaser--init');
//
//      setTimeout(function() {
//        textNode.style.transform = 'translateY(' + (hoverNode.offsetHeight + 21) + 'px)';
//      }, 50);
//    });
//
//    return this;
//  };
//}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-31
 */

/**
 * Creates a new teaser manager.
 * If an element is passed to it when creating a new instance teasers will automatically be sought within.
 *
 * @constructor
 */
//function IMXEVNT_search_TeaserManager() {
//  'use strict';
//
//  var teasers = [];
//
//  /**
//   * Recalculates every teaser being managed.
//   */
//  function recalculate() {
//    var teaserCount = teasers.length;
//
//    for(var index = 0; index < teaserCount; index++) {
//      teasers[index].recalculate();
//    }
//  }
//
//  /**
//   * Finds teasers in the givene element and initializes them.
//   * Also saves them for future resizes of the window, so they can be recalculated.
//   *
//   * @param {HTMLElement} element
//   * @returns {IMXEVNT_search_TeaserManager}
//   */
//  this.find = function(element) {
//    if(element) {
//      [].forEach.call(element.querySelectorAll('.-IMXEVNT-galleryTeaser--init'), function(teaser) {
//        teasers.push(new IMXEVNT_search_Teaser(teaser).recalculate());
//      });
//    }
//
//    return this;
//  };
//
//  window.addEventListener('resize', IMXEVNT_search_Util.debounce(recalculate, 250));
//
//  [].forEach.call(document.querySelectorAll('.-IMXEVNT-switchArea__tabCheckbox'), function(checkbox) {
//    checkbox.addEventListener('change', recalculate);
//  });
//}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-31
 */

/**
 * Manages the cache for a list by using the given id and storage.
 * This class can only handle one list at a time and expects only HTML to be saved in it, no complex objects.
 *
 * @param {String} id
 * @param {Storage} storage
 * @constructor
 */
function IMXEVNT_search_ListCache(id, storage) {
  'use strict';

  var tokenizedId = 'v3; ' + portal.token + ';' + portal.language + ';' + id;

  /**
   *
   *
   * @returns {Object}
   */
  this.get = function() {
    if(portal.isPreview) {
      storage.removeItem(tokenizedId);
      return {};
    }
    return JSON.parse(storage.getItem(tokenizedId) || '{}');
  };

  /**
   *
   *
   * @param {Number} page
   * @param {String} html
   * @returns {IMXEVNT_search_ListCache}
   */
  this.addPage = function(page, html) {
    if(!portal.isPreview) {
      try {
        var pages = this.get();

        pages[page] = html;

        storage.setItem(tokenizedId, JSON.stringify(pages));
      }catch(error) {
      }
    }

    return this;
  };
}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-26
 */

/**
 * Creates a new list and provides methods for preloading and showing pages within.
 *
 * @param {HTMLElement} element
 * @param {HTMLElement} [button]
 * @param {number} globalPosition
 * @constructor
 */
function IMXEVNT_search_List(element, button, globalPosition) {
  'use strict';

  var config = {
    idents: (typeof element.dataset.idents === 'string') ? element.dataset.idents.split(',') : [],
    pageSize: (typeof element.dataset.pagesize === 'string') ? parseInt(element.dataset.pagesize) : 0,
    initialPageSize: (typeof element.dataset.initialpagesize === 'string') ? parseInt(element.dataset.initialpagesize) : 0,
    layout: (typeof element.dataset.layout === 'string') ? element.dataset.layout : null,
    withDate: (typeof element.dataset.withdate === 'string') ? element.dataset.withdate : null
  };

  var state = {
    pages: IMXEVNT_search_Util.chunk(config.idents, config.pageSize, config.initialPageSize),
    lastPage: element.querySelector('.-IMXEVENT-lazyLoadList__page:last-of-type'),
    lastPageNumber: element.querySelector('.-IMXEVENT-lazyLoadList__page:last-of-type') ? 0 : -1,
    nextPage: '',
    nextPageNumber: -1,
    currentlyLoading: false,
    loadedPages: []
  };

  var pageLoadStatus = {
    UNKNOWN_PAGE: 1,
    SUCCESS: 2,
    ERROR: 3
  };

  var listCache = new IMXEVNT_search_ListCache(element.id, failSaveStorage);
  var itemManager = new IMXEVNT_search_ItemManager();
  //var teaserManager = new IMXEVNT_search_TeaserManager();

  /**
   * Creates and dispatches a custom event.
   * Has a fallback builtin to support Internet Explorer, whcih does not know about "CustomEvent" yet.
   *
   * @param {Node} element
   * @param {String} name
   * @param {*} [data]
   */
  function sendCustomEvent(element, name, data) {
    var event = null;
    var options = {};

    if(data) {
      options.detail = data;
    }

    if(typeof window.CustomEvent === 'function') {
      event = new CustomEvent(name, options);
    }else {
      event = document.createEvent('CustomEvent');
      event.initCustomEvent(name, false, false, options);
    }

    element.dispatchEvent(event);
  }

  /**
   * Checks if the button is available and can be removed. If so it will get removed from the DOM.
   */
  function removeButton() {
    window.requestAnimationFrame(function() {
      if(button && button.parentNode) {
        button.parentNode.removeChild(button);
      }
    });
  }

  /**
   * Controls the loading state of the list and also toggles a class on the button to indicate it for the user.
   */
  function showLoadingState(show) {
    state.currentlyLoading = show;

    if(button) {
      if(show) {
        button.classList.add('-IMXEVENT-lazyLoadButton--loading');
      }else {
        button.classList.remove('-IMXEVENT-lazyLoadButton--loading');
      }
    }
  }

  /**
   *
   * @param eventIDsList
   * @param eventIDsList
   * @returns {string}
   */
  function getUriToLoad(eventIDsList, templateFile) {
    var searchDateFrom = '';
    var searchDateTo = '';

    if(document.querySelector('input[name="dateFrom"]')){
      searchDateFrom = document.querySelector('input[name="dateFrom"]').value;
    }
    if(document.querySelector('input[name="dateTo"]')){
      searchDateTo = document.querySelector('input[name="dateTo"]').value;
    }
    return IMXEVNT_search_Util.buildActionLink('items', {
      outputType: templateFile,
      object: eventIDsList,
      layout: config.layout,
      showDate: config.withDate,
      searchDateFrom: searchDateFrom,
      searchDateTo: searchDateTo
    });
  }

  function handleResponse(request, callback, onlyInsert) {
    var isCallbackAvailable = (typeof callback === 'function');
    if(isCallbackAvailable) {
      if(request.status >= 200 && request.status < 400) {
        callback(pageLoadStatus.SUCCESS, request.responseText, onlyInsert);
      }else {
        callback(pageLoadStatus.ERROR, '', false);
      }
    }
    showLoadingState(false);
  }

  /**
   *
   * @param uriToLoad
   * @param callback
   * @param onlyInsert
   */
  function doRequest(uriToLoad, callback, onlyInsert) {
    var request = new XMLHttpRequest();

    request.open('GET', uriToLoad, true);

    request.onload = function(event) {
      callback(event);
    };

    sendCustomEvent(document, '-IMXEVNT-beforeDataLoad');
    showLoadingState(true);
    request.send();
  }

  /**
   * Loads the desired page by using the given number and if the XHR request succeeds passes the HTML response to the given callback.
   * If the desired page does not exist no request will be sent.
   *
   * @param {Number} page
   * @param {Function} callback
   */
  function loadPage(page, callback) {
    var isCallbackAvailable = (typeof callback === 'function');

    if(!state.pages[page]) {
      if(isCallbackAvailable) {
        callback(pageLoadStatus.UNKNOWN_PAGE, '');
      }
      return;
    }

    var eventIDsList = state.pages[page];
    var onlyInsert = globalPosition === 0;
    var chunked = IMXEVNT_search_Util.chunk(eventIDsList, 10, 10);

    /**
     *  Accummulates chunks and renders them in one go. This has to be done since the render function discards the html if
     *  the page is 0 and there is already elements in the list. Thus on the first page all chunks except the first one would be discarded.
     * @type {HTMLDivElement}
     */
    var pool = document.createElement('div');
    var pooledResponseCallback = function (status, responsetext) {
      var page = pool.querySelector('.-IMXEVENT-lazyLoadList__page');
      if (page) {
        page.insertAdjacentHTML('beforeend', responsetext);
      } else {
        pool.insertAdjacentHTML('beforeend', responsetext);
      }
    };

    var chunkCallback = function (event) {
      handleResponse(event.currentTarget, pooledResponseCallback, onlyInsert && chunked.length === 0);
      if (chunked.length > 0) {
        doRequest(getUriToLoad(chunked.shift(), 'simpleBlocks'), chunkCallback);
      } else {
        callback(pageLoadStatus.SUCCESS, pool.innerHTML, onlyInsert);
      }
    };
    doRequest(getUriToLoad(chunked.shift(), 'itemsPage'), chunkCallback);
  }

  /**
   * Inserts the given HTML into the element this list is based an and updates its buttons numbers based on the given page.
   * If no next page is available anymore the button will be removed from DOM.
   *
   * @param {Number} page
   * @param {String} html
   * @param {Boolean} onlyInsert
   */
  function renderPage(page, html, onlyInsert) {
    console.trace();
    window.requestAnimationFrame(function() {
      var pageWrapperNode = element.querySelector('.-IMXEVENT-lazyLoadList__page');

      if (onlyInsert && globalPosition === 0 && element.innerHTML.trim() !== '') {
        if (pageWrapperNode) {
          pageWrapperNode.insertAdjacentHTML('beforeend', html);
          listCache.addPage(page, element.innerHTML);
          itemManager.find(state.lastPage);
          //teaserManager.find(state.lastPage);
        }
      } else {
        if (page === 0 && element.innerHTML.trim() !== '') {
          return;
        }

        var countBeforeInsert = document.querySelectorAll('.-IMXEVNT-listElement:not(.-IMXEVNT-listElement--psuedo)').length;
        if (pageWrapperNode) {
          var wrap = document.createElement('div');
          wrap.innerHTML = html;
          var pageNode = wrap.querySelector('.-IMXEVENT-lazyLoadList__page');
          if (pageNode) {
            pageWrapperNode.insertAdjacentHTML('beforeend', pageNode.innerHTML);
          }
        } else {
          element.insertAdjacentHTML('beforeend', html);
        }
        state.lastPage = element.querySelector('.-IMXEVENT-lazyLoadList__page:last-of-type');

        if (countBeforeInsert % 2 === 1) {
          /* create a hidden pseudo list element to fix the background color styling */
          state.lastPage.insertAdjacentHTML('afterbegin', '<article class="-IMXEVNT-listElement -IMXEVNT-listElement--psuedo" style="display: none"><div class="-IMXEVNT-listElement__text"></div> </article>');
        }
        state.lastPageNumber = page;

        state.nextPage = '';
        state.nextPageNumber = -1;

        listCache.addPage(page, html);
        itemManager.find(state.lastPage);
        //teaserManager.find(state.lastPage);

        sendCustomEvent(document, '-IMXEVNT-dataLoaded', [
          element.id,
          page
        ]);

        if(button) {
          button.classList.remove('-IMXEVENT-lazyLoadButton--initial');
          var next = button.querySelector('[data-type="next"]');
          var remaining = button.querySelector('[data-type="remaining"]');

          if(!state.pages[page + 1]) {
            removeButton();
          }else {
            next.innerHTML = state.pages[page + 1].length.toString();
            remaining.innerHTML = (parseInt(remaining.innerHTML) - state.pages[page].length).toString();
          }
        }
      }
    });
  }

  /**
   * Saves the given HTML for insertion into the DOM when requested. If already html saved, the new html is appended. This way no html is
   * lost while the pages are loaded in chunks. After inserting the html to the page, the cache was cleared.
   *
   * @param {Number} page
   * @param {String} html
   */
  function savePage(page, html) {
    state.nextPage += html;
    state.nextPageNumber = page;
  }

  /**
   * Checks if the list is basically visible and currently shown within the viewport, even when only partially.
   *
   * @returns {boolean}
   */
  function isVisible() {
    return IMXEVNT_search_Util.isVisible(element);
  }

  /**
   * Checks if the list should load the next page.
   * For this it checks the current loading state and if the last page is currently visible or if there is any.
   *
   * @returns {boolean}
   */
  function shouldLoad() {
    switch(true) {
      case (state.currentlyLoading || state.nextPage !== ''):
        return false;
      default:
        return false;
      case !state.lastPage:
        return true;
      case !!state.lastPage:
        return IMXEVNT_search_Util.isVisible(state.lastPage);
    }
  }

  /**
   * Loads the next page of the current list by using XHR.
   * There is no error handling, so the user does not see if something went wrong without looking into dev tools.
   * The rendering of the page, instead of saving it for later, can be forced. But this should be done very carefully.
   *
   * @param {Boolean} [forceRendering]
   */
  function load(forceRendering) {
    var page = (state.lastPageNumber + 1);

    if(state.loadedPages.indexOf(page) === -1) {
      state.loadedPages.push(page);
      loadPage(page, function(status, html, onlyInsert) {
        if(status === pageLoadStatus.SUCCESS) {
          if(page === 0 || forceRendering) {
            renderPage(page, html, onlyInsert);
          }else {
            savePage(page, html);
          }
        }else if(status === pageLoadStatus.UNKNOWN_PAGE && button) {
          removeButton();
        }
      });
    }
  }

  /**
   * Checks if there is already a next page saved for display and renders it.
   * Otherwise it will load the next page and force render it.
   */
  function show() {
    if(state.nextPage !== '') {
      renderPage(state.nextPageNumber, state.nextPage, false);
    }else if(!state.currentlyLoading) {
      load(true);
    }
  }

  /**
   * Initializes the list and sets up the item/teaser manager and utilizes the list cache for inserting previosly loaded pages directly into the DOM.
   */
  function init() {
    var pages = listCache.get();

    itemManager.find(state.lastPage);
    //teaserManager.find(state.lastPage);

    for(var page in pages) {
      if(pages.hasOwnProperty(page)) {
        renderPage(parseInt(page), pages[page], false);
      }
    }
  }

  this.init = init;
  this.load = load;
  this.show = show;
  this.isVisible = isVisible;
  this.shouldLoad = shouldLoad;
}


/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2018 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Benjamin Hofmann <hofmann@infomax-it.de>
 * @since      2018-01-26
 */
/**
 *
 * @returns {void}
 */
(function(window, document, IMXEVNT_search_Util, IMXEVNT_search_List) {
  'use strict';

  var lists = [];

  var listNodes = document.querySelectorAll('[id^="-IMXEVENT-lazyLoadList--"]');
  var listNodesLength = listNodes.length;

  for(var i = 0; i < listNodesLength; i++) {
    var element = listNodes[i];
    var button = (element.nextElementSibling) ? element.nextElementSibling.querySelector('.-IMXEVENT-lazyLoadButton') : null;
    var list = new IMXEVNT_search_List(element, button, i);

    list.init();

    if(button) {
      button.addEventListener('click', list.show);
    }

    lists.push(list);
  }

  /**
   * Checks if the next day/category has to be prefetched before the user scrolls into it.
   * If the current list has an empty one directly below it, the first elements of the next will be loaded and injected into the HTML.
   */
  function handleLoading() {
    var listsCount = lists.length;

    for(var index = 0; index < listsCount; index++) {
      var currentList = lists[index];
      var nextList = lists[index + 1];
      if(currentList.isVisible()) {
        // load current if needed
        if(currentList.shouldLoad()) {
          currentList.load();
        }
        // also load next if needed
        if(nextList && nextList.shouldLoad()) {
          nextList.load();
        }
      }
    }
  }

  var listener = IMXEVNT_search_Util.throttle(window.requestAnimationFrame.bind(null, handleLoading), 250);
  ['load', 'scroll', 'message'].forEach(function(name) {
    window.addEventListener(name, listener);
  });

}).apply(null, [
  window,
  document,
  IMXEVNT_search_Util,
  IMXEVNT_search_List
]);

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2021 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Florian Müller <mueller@infomax-it.de>
 * @since      14.04.21
 */

function IMXEVNT_search_fields_TokenInputField(inputConfig) {
  'use strict';

  var tokens = [];
  var config = inputConfig;

  this.add = function(token) {
    if (!this.has(token)) {
      tokens.push(token);
      this.buildDeselector(token);
      this.buildInputEntry();
    }else{
      this.highlightDeselector(token);
    }
    if (typeof config.changeCallback === 'function') config.changeCallback(tokens);
  };

  this.removeByTypeAndValue = function(token) {
    var that = this;
    tokens = tokens.filter(function(entry) {
      if (entry.value === token.value && entry.type === token.type) {
        var deselector = that.findDelesector(entry);
        deselector.parentNode.removeChild(deselector);
        return false;
      }else {
        return true;
      }
    });
    this.buildInputEntry();
    if (typeof config.changeCallback === 'function') config.changeCallback(tokens);
  };

  this.removeByType = function(type) {
    var that = this;
    tokens = tokens.filter(function(entry) {
      if (entry.type === type) {
        var deselector = that.findDelesectorByType(entry);
        deselector.parentNode.removeChild(deselector);
        return false;
      }else {
        return true;
      }
    });
    this.buildInputEntry();
    if (typeof config.changeCallback === 'function') config.changeCallback(tokens);
  };

  this.has = function(token) {
    for(var i = 0; i< tokens.length; i++) {
      var entry = tokens[i];
      if (entry.value === token.value && entry.type === token.type) {
        return true;
      }
    }
    return false;
  };

  this.buildDeselector = function(token) {
    var that = this;
    var deselector = document.createElement('div');
    deselector.className = '-IMXEVNT-deselector';
    deselector.dataset.type = token.type;
    deselector.dataset.value = token.value;

    var tokenContent = document.createElement('span');
    tokenContent.className = '-IMXEVNT-deselector__tokenContent';
    tokenContent.innerText = token.label;
    deselector.appendChild(tokenContent);

    var closer = document.createElement('span');
    closer.className = '-IMXEVNT-deselector__closer icon-closer';
    closer.addEventListener('click', function() {
      config.fakeInput.focus();
      that.removeByTypeAndValue(token);
    });
    deselector.appendChild(closer);

    deselector.remove = function() {
      deselector.parentNode.removeChild(deselector);
    };

    config.fakeInput.insertAdjacentElement('beforebegin', deselector);
  };

  this.highlightDeselector = function(token) {
    var deselector = this.findDelesector(token);
    deselector.classList.add('-IMXEVNT-deselector--highlight');
    setTimeout(function() {
      deselector.classList.remove('-IMXEVNT-deselector--highlight');
    },1000);
  };

  this.findDelesector = function(token) {
    return document.querySelector('.-IMXEVNT-deselector[data-type="'+token.type+'"][data-value="'+token.value + '"]');
  };

  this.findDelesectorByType = function(token) {
    return document.querySelector('.-IMXEVNT-deselector[data-type="'+token.type+'"]');
  };

  /**
   *
   * @returns {self}
   */
  this.buildInputEntry = function() {
    console.log(config.input,  JSON.stringify(tokens));
    config.input.value = JSON.stringify(tokens);
  };

  this.expandField = function() {
    config.container.classList.add('-IMXEVNT-contentForm__tokenInputField--expanded');
  };

  this.collapseField = function() {
    config.container.classList.remove('-IMXEVNT-contentForm__tokenInputField--expanded');
    config.fakeInput.value = '';
  };

  this.init = function() {
    try {
     var tokensToAdd = JSON.parse(config.input.value);
     for(var token in tokensToAdd) {
       if (tokensToAdd.hasOwnProperty(token)) {
         this.add(tokensToAdd[token]);
       }
     }
    }catch(e) {
      console.log(e);
    }
  };
}

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2021 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Florian Müller <mueller@infomax-it.de>
 * @since      14.04.21
 */
(function(doc) {
  'use strict';

  var buildAutocomplete = function(tokenInputField, fakeInput, contentArea, container) {
    var $container = $(container);
    var autocompleteOptions = {
      adapter: new imx.Autocomplete.AjaxAdapter({
        url: portal.uri + '/' + portal.permalink + '/' + portal.language + '/action/autosuggest',
        extraParams: {
          widgetToken: portal.token,
          types: ['where']
        }
      }),
      delay: 200,
      minChars: 3,
      mustSelect: false,
      events: {
        show: function() {
          jQuery('#-IMXEVNT-contentForm__autocompleteLocation .-IMXEVNT-scroller', $container).nanoScroller();
          var contentAreaComputed = window.getComputedStyle(container.parentNode);
          container.style.marginTop = parseInt(contentAreaComputed.marginTop) + 12 + 'px';
        },
        change: function(item) {
          tokenInputField.add({
            label: item.label,
            type: item.internal_type,
            value: item.value
          });
          fakeInput.value = '';
          requestAnimationFrame(function() {
            fakeInput.focus();
          });
        }
      }
    };

    var whereAutosuggest = new imx.Autocomplete($(fakeInput), $container, autocompleteOptions);
    whereAutosuggest.create();
  };

  var buildDynamicWidthinputField = function(fakeInput, contentArea) {
    var canvas = document.createElement('canvas');
    var font = window.getComputedStyle(fakeInput).font;
    var context = canvas.getContext("2d");
    context.font = font;

    fakeInput.addEventListener('keyup', function() {
      var text = context.measureText(fakeInput.value);
      if(text.length > 0) {
        contentArea.scrollTo(0, 9999999);
        fakeInput.style.width = Math.min(parseInt(text.width.toFixed(0)) + 20, 400) + 'px';
      }else {
        fakeInput.removeAttribute('style');
      }
    });
  };

  var handleFocus = function(container, contentArea, tokenInputField, fakeInput) {
    container.addEventListener('click', function(evt) {
      fakeInput.focus();
    });
    contentArea.addEventListener('focus', function(evt) {
      tokenInputField.expandField();
      fakeInput.focus();
      contentArea.scrollTo(0, 9999999);
    }, {capture: true});
    contentArea.addEventListener('blur', function(evt) {
      tokenInputField.collapseField();
    }, {capture: true});
  };

  var handleGeoLocation = function(checkboxUseGeoLocation, inputLocationError, tokenInputField) {
    var handleGeoError = function(message) {
      checkboxUseGeoLocation.checked = false;
      inputLocationError.innerText = message;
      inputLocationError.style.display = 'block';
    };
    checkboxUseGeoLocation.addEventListener('change', function() {
      if(checkboxUseGeoLocation.checked) {
        if(navigator.geolocation) {
          navigator.geolocation.getCurrentPosition(function(position) {
            var geocoder = new Geocoder();
            geocoder.geocode([position.coords.latitude, position.coords.longitude], function(results, status) {

              var location = '';

              if(status === 'OK') {
                results.forEach(function(result) {
                  result.address_components.forEach(function(address) {
                    if(address.types.indexOf('locality') > -1) {
                      location = address.long_name || address.short_name;
                    }
                  });
                });
              }

              if(location === '') {
                location = portal.translations['geolocation.myPosition'];
              }

              tokenInputField.removeByType('localization');
              tokenInputField.add({
                label: location,
                type: 'localization',
                value: position.coords.latitude + '|' + position.coords.longitude
              });
            });
          }, function() {
            handleGeoError(portal.translations['geolocation.nocoordinates']);
          });
        }else {
          handleGeoError(portal.translations['geolocation.nosupport']);
        }
      }else {
        tokenInputField.removeByType('localization');
      }
    });
  };

  var handleRadius = function(radiusBox, checkboxUseGeoLocation, tokens) {
    var hasLocation = false;
    var hasLocalization = false;
    for(var i = 0; i < tokens.length; i++) {
      var entry = tokens[i];
      if(entry.type === 'location') {
       hasLocation = true;
      }
      if (entry.type === 'localization') {
        hasLocalization = true;
      }
    }

    checkboxUseGeoLocation.checked = hasLocalization;
    radiusBox.style.display = hasLocation || hasLocalization ? 'block' : 'none';
  };

  var init = function() {
    var element = doc.querySelector('#-IMXEVNT-contentForm__locationInputSet');
    if(element) {
      var container = element.querySelector('.-IMXEVNT-contentForm__tokenInputField');
      var contentArea = element.querySelector('.-IMXEVNT-contentForm__tokenInputField__content');
      var input = element.querySelector('input[name="locationTokens"]');
      var fakeInput = element.querySelector('#-IMXEVNT-contentForm__inputLocation');
      var autocompleteContainer = doc.querySelector('#-IMXEVNT-contentForm__autocompleteLocation');
      var checkboxUseGeoLocation = doc.querySelector('input[name="geo[]"]');
      var inputLocationError = doc.querySelector('.-IMXEVNT-contentForm__errorMessage--location');
      var radiusBox = doc.querySelector('.-IMXEVNT-contentForm__sliderWrapper_distance');

      var tokenInputField = new IMXEVNT_search_fields_TokenInputField({
        container: container,
        fakeInput: fakeInput,
        input: input,
        changeCallback: checkboxUseGeoLocation ? handleRadius.bind(this, radiusBox, checkboxUseGeoLocation) : function(){}
      });
      if (checkboxUseGeoLocation) {
        handleGeoLocation(checkboxUseGeoLocation, inputLocationError, tokenInputField);
      }
      handleFocus(container, contentArea, tokenInputField, fakeInput);
      buildDynamicWidthinputField(fakeInput, contentArea);
      buildAutocomplete(tokenInputField, fakeInput, contentArea, autocompleteContainer);
      tokenInputField.init();
    }
  };

  init();

})(document);

/**
 * whlportal
 *
 * LICENSE
 *
 * This software and its source code is protected by copyright law (Sec. 69a ff. UrhG).
 * It is not allowed to make any kinds of modifications, nor must it be copied,
 * or published without explicit permission. Misuse will lead to persecution.
 *
 * @copyright  2021 infomax websolutions GmbH
 * @link       https://www.infomax-online.de
 * @author     Florian Müller <mueller@infomax-it.de>
 * @since      21.04.21
 */
(function() {

  var handleChange = function(input, addressIdInput, addressGroupIdInput, item) {
    input.value = item.label;

    addressIdInput.value = "";
    addressGroupIdInput.value = "";
    if(item.internal_type == 'address') {
      addressIdInput.value= item.value;
    } else if(item.internal_type == 'addressGroup') {
      addressGroupIdInput.value= item.value;
    }
  };

  var input = document.querySelector('#-IMXEVNT-contentForm__inputLocationDisplayName');
  var addressIdInput = document.querySelector('[name="addressId"]');
  var addressGroupIdInput = document.querySelector('[name="addressGroupId"]');

  if(input) {
    var values = JSON.parse(input.dataset.autocompleteValues);
    var autocompleteOptions = {
      adapter: new imx.Autocomplete.DataAttributeAdapter({
        values: values,
        sort: 'alphabetically'
      }),
      minChars: 0,
      delay: 0,
      events: {
        change: handleChange.bind(null, input, addressIdInput, addressGroupIdInput)
      }
    };

    var whereIdAutosuggest = new imx.Autocomplete(jQuery(input), jQuery('#-IMXEVNT-contentForm__autocompleteAddressId'), autocompleteOptions);

    whereIdAutosuggest.create();
    var that = this;
    input.addEventListener('click', function() {
      jQuery(input).trigger('keydown.autocomplete');
    });
  }
})();

/* global portal */

jQuery(document).ready(function() {

  // datepicker for routing
  jQuery('#-IMXEVNT-contentForm__input4').datepicker({});

  // fancyboxes for remind, report, ...
  jQuery('#-IMXEVNT-articleTools a.-IMXEVNT-popup').fancybox({
    type: 'iframe',
    maxWidth: 800,
    autoSize: true
  });
  jQuery('#-IMXEVNT-pageFooter a.-IMXEVNT-popup').fancybox({
    type: 'iframe',
    maxWidth: 800,
    autoSize: true
  });

  // fancybox for disclaimer
  jQuery('#-IMXEVNT-pageFooter a.-IMXEVNT-disclaimerLink').fancybox({
    type: 'iframe',
    maxWidth: 800,
    autoSize: true
  });

  // fancybox for legalDisclosure
  jQuery('#-IMXEVNT-pageFooter a.-IMXEVNT-legalDisclosureLink').fancybox({
    type: 'iframe',
    maxWidth: 800,
    autoSize: true
  });

  jQuery('form.-IMXEVNT-contentForm.-IMXEVNT-h-grid').submit(function() {
    var searchQuery = $('#-IMXEVNT-contentForm__inputCategory').val();

    if(typeof ga === 'function') {
      ga('send', 'event', 'search events button', 'click search events button', searchQuery);
    }
  });

  if(document.querySelector('#-IMXEVNT-filter__button__reset')) {
    document.querySelector('#-IMXEVNT-filter__button__reset').addEventListener('click', function(evt) {
      var checkedFilters = document.querySelectorAll('.-IMXEVNT-filter input[type="checkbox"]:checked');

      if(checkedFilters) {
        [].forEach.call(checkedFilters,function(checkedFilter) {
          checkedFilter.checked = false;
        });
      }
    });
  }

  jQuery('.-IMXEVNT-js-shortLink').click(function(e) {
    e.preventDefault();

    jQuery.ajax({
      url: this.href, success: function(link) {
        var $input = jQuery('<input />');
        $input.attr('value', link);
        var $button = jQuery('<button />');
        $button.addClass('button button--cta');
        $button.text(portal.translations.copyToClipboard);
        $button.click(
          function() {
            var input = $input.get(0);
            input.select();
            input.setSelectionRange(0, 99999);
            if(document.execCommand("copy")) {
              $button.text(portal.translations.copyToClipboardDone);
              setTimeout(function() {
                $button.text(portal.translations.copyToClipboard);
              }, 5000);
            }
          }
        );

        var $content = jQuery('<div />');
        $content.addClass('-IMXEVNT-shareLinkOverlay');
        $content.append($input, jQuery('<br/>'), $button);

        jQuery.fancybox.open({
          padding: 5,
          maxWidth: 800,
          autoSize: true,
          fitToView: true,
          content: $content
        });
      }
    });
  });
});

var IMXEVNT = (function() {
  var listStateHistory = new ListStateHistory();

  jQuery(document).on('click', '#-IMXEVNT-sticky a.-IMXEVNT-openOffCanvas__cart', function() {
    IMXEVNT_offCanvas.openOffCanvas('right', this.dataset.target);
  });
  jQuery(document).on('click', '#-IMXEVNT-articleTools a.-IMXEVNT-openOffCanvas__cart', function() {
    IMXEVNT_offCanvas.openOffCanvas('right', this.dataset.target);
  });
  jQuery(document).on('click', '#-IMXEVNT-sticky a.-IMXEVNT-openOffCanvas__filter', function() {
    IMXEVNT_offCanvas.openOffCanvas('left', this.dataset.target);
  });
  jQuery(document).on('click', 'input[type="text"], input[type="email"], textarea', function() {
    this.select();
  });

  var waitForListInitialization = function() {
    window.requestAnimationFrame(function() {
      if(listStateHistory.getScrollOffset() > 0) {
        jQuery(window).scrollTop(listStateHistory.getScrollOffset());
      }

      jQuery(document).trigger('-IMXEVNT-pageInitialized');
    });
  };

  jQuery(document).one('-IMXEVNT-dataLoaded', waitForListInitialization);

  var createScroller = function() {
      if (JSON.parse(failSaveStorage.getItem(portal.token + ';scrollToSearchItems')) === true) {
      try {
        if(!jQuery('html').hasClass('touch')) {
          jQuery('.-IMXEVNT-scroller').nanoScroller({
            scrollTo: jQuery('.-IMXEVNT-titleArea.-IMXEVNT-titleArea--light')
          });
        }else {
          jQuery(document).scrollTop(jQuery('.-IMXEVNT-titleArea.-IMXEVNT-titleArea--light').offset().top);
        }
      }catch(e) { /* may throw errors, which can be neglected, as scrolling works nethertheless */
      }
          failSaveStorage.setItem(portal.token + ';scrollToSearchItems', JSON.stringify(false));
    }
  };

  //new IMXEVNT_Sticky();
  createScroller();

  /*update the contents of title tabs when changing the active tab*/
  var searchMap = null;
  var searchMapContainer = document.getElementById('-IMXEVNT-fullMap__mapContainer');
  var initialActiveTab = parseInt(jQuery('#-IMXEVNT-main-wrapper').data('initial-tab-index'));
    var lastKnownActiveTab = parseInt(failSaveStorage.getItem(portal.token + ';lastKnownActiveTab'));
  var isDetailpage = !!document.querySelector(".-IMXEVNT-isDetailpage-Js");

  if(lastKnownActiveTab && !isDetailpage) {
    initialActiveTab = lastKnownActiveTab;
  }
  if(!initialActiveTab) {
    initialActiveTab = 0;
  }

  var handleChange = function(currentIndex) {
    jQuery(document).trigger('-IMXEVNT-tabChanged');
      failSaveStorage.setItem(portal.token + ';lastKnownActiveTab', currentIndex);
    if(currentIndex === titleTabs.length - 1) {
      jQuery('#-IMXEVNT-main').addClass('-IMXEVNT-mapActive');

      if(searchMapContainer && searchMap === null) {
        searchMap = new SearchMap(searchMapContainer, listStateHistory, new UrlHelper()).open();
      }
    }else {
      jQuery('#-IMXEVNT-main').removeClass('-IMXEVNT-mapActive');
    }
  };

  var titleTabs = document.getElementsByClassName('-IMXEVNT-switchArea__tabCheckbox');
  if(titleTabs.length > 0) {
    for(var i = 0; i < titleTabs.length; i++) {
      titleTabs[i].addEventListener('change', handleChange.bind(this, i));
    }

    jQuery('.-IMXEVNT-switchArea__tabCheckbox')
        .prop('checked', false)
        .eq(initialActiveTab).prop('checked', true);

    if(initialActiveTab === titleTabs.length - 1 /* map */ && searchMapContainer && searchMap === null) {
      searchMap = new SearchMap(searchMapContainer, listStateHistory, new UrlHelper()).open();

      jQuery('#-IMXEVNT-main').addClass('-IMXEVNT-mapActive');

      if(listStateHistory.getScrollOffset() > 0) {
        jQuery('#-IMXEVNT-host .-IMXEVNT-scrollerArea').scrollTop(listStateHistory.getScrollOffset());
      }

      jQuery(document).trigger('-IMXEVNT-pageInitialized');
    }
  }

  // initialize cart
  var clipboard = new Clipboard();
  var offCanvasCart = new OffCanvasCart(jQuery('#-IMXEVNT-offCanvasArea__list'), clipboard);
  offCanvasCart.changeRemberedItemCounter();

  return {
    clipboard: clipboard
  };
})();

String.prototype.capitalize = function() {
  return this.charAt(0).toUpperCase() + this.slice(1);
};

$.datepicker.setDefaults($.datepicker.regional[portal.language]);

jQuery(document).ready(function() {
  jQuery('.openGallery').fancybox({
    padding: 5
  });
});

var articleMapContainer = document.getElementById('-IMXEVENT-articleMap');

if(articleMapContainer) {
  new ContentMap(articleMapContainer).open();
}

jQuery(document).ready(function() {
  jQuery('form.ctrlRoutingForm').each(function(idx, elem) {
    new RoutingForm(elem);
  });
});
jQuery(document).ready(function() {
  if(jQuery('#-IMXEVNT-heroimage__form').length > 0) {
    new SearchForm(jQuery('#-IMXEVNT-heroimage__form').get(0), jQuery('#-IMXEVNT-offCanvasArea__filter'));
  } else if(jQuery('#-IMXEVNT-offCanvasArea__filter').length > 0) {
    new StandaloneFilterForm(jQuery('#-IMXEVNT-offCanvasArea__filter'));
  }
});
jQuery(document).ready(function() {
  // tell the parent, that the loading process is done
  // get location starting from path including query and fragments
  var loc = URI(window.location.href);
  loc.hostname('');
  loc.protocol('');
  var hashParams = false;
  if(portal.showUrlExtension) {
    hashParams = loc.toString();
  }
  window.parent.postMessage({
    loadDone: true,
    hashParams: hashParams
  }, '*');

  var sendCurrentHeightToParent = function(type) {
    var mainWrapper = document.getElementById('-IMXEVNT-main-wrapper');
    if(mainWrapper) {
      var height = mainWrapper.scrollHeight;

      window.parent.postMessage({
        height: height,
        isDetailPage: !!document.querySelector(".-IMXEVNT-isDetailpage-Js"),
        type: type
      }, '*');
    }
  };

  // initialize event handlers
  jQuery(document).on('-IMXEVNT-beforeDataLoad', sendCurrentHeightToParent.bind(null, 'beforeDataLoad'));
  jQuery(document).on('-IMXEVNT-dataLoaded', sendCurrentHeightToParent.bind(null, 'dataLoaded'));
  jQuery(document).on('-IMXEVNT-layoutChanged', sendCurrentHeightToParent.bind(null, 'layoutChanged'));
  jQuery(document).on('-IMXEVNT-tabChanged', sendCurrentHeightToParent.bind(null, 'tabChanged'));

  // initialize widget iframe and trigger an update after one second to prevent race condition problems
  sendCurrentHeightToParent('init');
  setTimeout(sendCurrentHeightToParent.bind(this, 'afterInit'), 1000);

  window.scrollTo(0, 0);

  var handleMessage = function(message) {
    var messageData = message.data;
    if(messageData.hasOwnProperty('relativeScrollPosition') && messageData.hasOwnProperty('visibleHeight')) {
      jQuery(document).trigger('-IMXEVNT-iframeScrollUpdate', messageData);
    }else if(messageData.originalEvent) {
      window.dispatchEvent(new CustomEvent(messageData.originalEvent,  messageData.data));
    }else if(messageData.type === 'requestConsent') {
      UC_UI.showSecondLayer();
    }else{
      try {
        var parsedJson = JSON.parse(messageData);
        if (parsedJson.hasOwnProperty('consent')) {
          window.dispatchEvent(new CustomEvent('usercentrics_consent', {
            detail: parsedJson.consent
          }));

          // keep the original message for page switches
          window.parent.postMessage({consent: messageData}, '*');
        }
      }catch(e) {}
    }
  };
  window.addEventListener('message', handleMessage.bind(this));
});

