PageSourceSearch

https://www.visithay.com.au/wp-content/themes/visithay/js/app.js?id=482e3e5deb9348b1381c2c45c2ae6cd5&ver=0.1.1

js visithay.com.au collected 2026-10-02 08:26:25 UTC 602,852 bytes, 19,463 lines download raw bytes

1/******/ (() => { // webpackBootstrap
2/******/ 	var __webpack_modules__ = ({
3
4/***/ "./resources/js/app.js":
5/*!*****************************!*\
6  !*** ./resources/js/app.js ***!
7  \*****************************/
8/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
9
10"use strict";
11__webpack_require__.r(__webpack_exports__);
12/* harmony import */ var _sliders__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./sliders */ "./resources/js/sliders.js");
13/* harmony import */ var _maps__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./maps */ "./resources/js/maps.js");
14/* harmony import */ var superfish__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! superfish */ "./node_modules/superfish/dist/js/superfish.js");
15/* harmony import */ var superfish__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(superfish__WEBPACK_IMPORTED_MODULE_2__);
16
17
18
19
20/** Nav Menu Toggle*/
21if (window.innerWidth < 768) {
22  document.querySelector("#primary-menu").setAttribute("data-menu-hidden", "true");
23  // document.querySelector("#primary-menu").classList.add("hidden");
24
25  var menuToggle = document.querySelector("#primary-menu-toggle");
26  if (menuToggle) menuToggle.addEventListener("click", function () {
27    var _document$querySelect;
28    var current = (_document$querySelect = document.querySelector("#primary-menu").getAttribute("data-menu-hidden")) !== null && _document$querySelect !== void 0 ? _document$querySelect : "false";
29    if (current === "true") {
30      document.querySelector("#primary-menu").setAttribute("data-menu-hidden", "false");
31      document.querySelector("#primary-menu").classList.remove("hidden");
32      return;
33    }
34    if (current === "false") {
35      document.querySelector("#primary-menu").setAttribute("data-menu-hidden", "true");
36      document.querySelector("#primary-menu").classList.add("hidden");
37      return;
38    }
39  });
40}
41jQuery("ul#menu-primary").superfish({});
42
43/***/ }),
44
45/***/ "./resources/js/maps.js":
46/*!******************************!*\
47  !*** ./resources/js/maps.js ***!
48  \******************************/
49/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
50
51"use strict";
52__webpack_require__.r(__webpack_exports__);
53/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! leaflet */ "./node_modules/leaflet/dist/leaflet-src.js");
54/* harmony import */ var leaflet__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(leaflet__WEBPACK_IMPORTED_MODULE_0__);
55/* harmony import */ var leaflet_dist_leaflet_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! leaflet/dist/leaflet.css */ "./node_modules/leaflet/dist/leaflet.css");
56
57
58
59// Initialize Leaflet map when DOM is ready
60document.addEventListener('DOMContentLoaded', function () {
61  var element = document.getElementById('map');
62  if (!element) return;
63  var lat = parseFloat(element.dataset.mapLatitude);
64  var lng = parseFloat(element.dataset.mapLongitude);
65  var position = [lat, lng];
66  var map = leaflet__WEBPACK_IMPORTED_MODULE_0___default().map(element, {
67    center: position,
68    zoom: 16
69  });
70
71  // OpenStreetMap tiles (replace with a different provider if needed)
72  leaflet__WEBPACK_IMPORTED_MODULE_0___default().tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
73    attribution: '&copy; OpenStreetMap contributors',
74    maxZoom: 19
75  }).addTo(map);
76
77  // Custom SVG icon marker
78  var svgIcon = encodeURIComponent("\n    <svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' width='48' height='48'>\n      <path d='M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7z' fill='#E11D48'/>\n      <circle cx='12' cy='9' r='2.5' fill='#fff'/>\n    </svg>\n  ");
79  var icon = leaflet__WEBPACK_IMPORTED_MODULE_0___default().icon({
80    iconUrl: "data:image/svg+xml;utf8,".concat(svgIcon),
81    iconSize: [48, 48],
82    iconAnchor: [24, 48],
83    popupAnchor: [0, -44],
84    className: 'leaflet-custom-icon'
85  });
86  var marker = leaflet__WEBPACK_IMPORTED_MODULE_0___default().marker(position, {
87    icon: icon
88  }).addTo(map);
89  var template = "\n        <div class=\"p-2 space-y-2 \">\n            <h2 class=\"text-lg font-bold tracking-normal\">\n                ".concat(element.dataset.locationName, "\n            </h2>\n            <p>").concat(element.dataset.locationAddress, "</p>\n            <p>\n                <a target=\"_blank\" class=\"border-b border-theme-1-base\" href=\"https://www.google.com/maps/search/").concat(encodeURI(element.dataset.locationName), "/@").concat(element.dataset.mapLatitude, ",").concat(element.dataset.mapLongitude, ",17z/\">\n                    View on Google Maps\n                </a>\n            </p>\n        </div>");
90  marker.bindPopup(template);
91  marker.on('click', function () {
92    marker.openPopup();
93  });
94});
95
96/***/ }),
97
98/***/ "./resources/js/sliders.js":
99/*!*********************************!*\
100  !*** ./resources/js/sliders.js ***!
101  \*********************************/
102/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
103
104"use strict";
105__webpack_require__.r(__webpack_exports__);
106/* harmony import */ var _glidejs_glide__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @glidejs/glide */ "./node_modules/@glidejs/glide/dist/glide.esm.js");
107/** Sliders */
108
109var sliders = document.querySelectorAll(".glide.terms");
110sliders.forEach(function (slider) {
111  var cols = slider.dataset.columns || 1;
112  new _glidejs_glide__WEBPACK_IMPORTED_MODULE_0__["default"](slider, {
113    perView: 4,
114    type: "carousel",
115    breakpoints: {
116      800: {
117        perView: 1
118      }
119    }
120  }).mount();
121});
122var galleries = document.querySelectorAll(".glide.gallery");
123galleries.forEach(function (gallery) {
124  new _glidejs_glide__WEBPACK_IMPORTED_MODULE_0__["default"](gallery, {
125    type: "carousel",
126    perView: 1,
127    peek: 100,
128    focusAt: "center",
129    breakpoints: {
130      800: {
131        peek: 20
132      }
133    }
134  }).mount();
135});
136
137/***/ }),
138
139/***/ "./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[2]!./node_modules/leaflet/dist/leaflet.css":
140/*!*********************************************************************************************************************************************************************************************************!*\
141  !*** ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[2]!./node_modules/leaflet/dist/leaflet.css ***!
142  \*********************************************************************************************************************************************************************************************************/
143/***/ ((module, __webpack_exports__, __webpack_require__) => {
144
145"use strict";
146__webpack_require__.r(__webpack_exports__);
147/* harmony export */ __webpack_require__.d(__webpack_exports__, {
148/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
149/* harmony export */ });
150/* harmony import */ var _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../css-loader/dist/runtime/api.js */ "./node_modules/css-loader/dist/runtime/api.js");
151/* harmony import */ var _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0__);
152// Imports
153
154var ___CSS_LOADER_EXPORT___ = _css_loader_dist_runtime_api_js__WEBPACK_IMPORTED_MODULE_0___default()(function(i){return i[1]});
155// Module
156___CSS_LOADER_EXPORT___.push([module.id, "/* required styles */\r\n\r\n.leaflet-pane,\r\n.leaflet-tile,\r\n.leaflet-marker-icon,\r\n.leaflet-marker-shadow,\r\n.leaflet-tile-container,\r\n.leaflet-pane > svg,\r\n.leaflet-pane > canvas,\r\n.leaflet-zoom-box,\r\n.leaflet-image-layer,\r\n.leaflet-layer {\r\n\tposition: absolute;\r\n\tleft: 0;\r\n\ttop: 0;\r\n\t}\r\n\r\n.leaflet-container {\r\n\toverflow: hidden;\r\n\t}\r\n\r\n.leaflet-tile,\r\n.leaflet-marker-icon,\r\n.leaflet-marker-shadow {\r\n\t-webkit-user-select: none;\r\n\t   -moz-user-select: none;\r\n\t        user-select: none;\r\n\t  -webkit-user-drag: none;\r\n\t}\r\n\r\n/* Prevents IE11 from highlighting tiles in blue */\r\n\r\n.leaflet-tile::-moz-selection {\r\n\tbackground: transparent;\r\n}\r\n\r\n.leaflet-tile::selection {\r\n\tbackground: transparent;\r\n}\r\n\r\n/* Safari renders non-retina tile on retina better with this, but Chrome is worse */\r\n\r\n.leaflet-safari .leaflet-tile {\r\n\timage-rendering: -webkit-optimize-contrast;\r\n\t}\r\n\r\n/* hack that prevents hw layers \"stretching\" when loading new tiles */\r\n\r\n.leaflet-safari .leaflet-tile-container {\r\n\twidth: 1600px;\r\n\theight: 1600px;\r\n\t-webkit-transform-origin: 0 0;\r\n\t}\r\n\r\n.leaflet-marker-icon,\r\n.leaflet-marker-shadow {\r\n\tdisplay: block;\r\n\t}\r\n\r\n/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */\r\n\r\n/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */\r\n\r\n.leaflet-container .leaflet-overlay-pane svg {\r\n\tmax-width: none !important;\r\n\tmax-height: none !important;\r\n\t}\r\n\r\n.leaflet-container .leaflet-marker-pane img,\r\n.leaflet-container .leaflet-shadow-
156pane img,\r\n.leaflet-container .leaflet-tile-pane img,\r\n.leaflet-container img.leaflet-image-layer,\r\n.leaflet-container .leaflet-tile {\r\n\tmax-width: none !important;\r\n\tmax-height: none !important;\r\n\twidth: auto;\r\n\tpadding: 0;\r\n\t}\r\n\r\n.leaflet-container img.leaflet-tile {\r\n\t/* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */\r\n\tmix-blend-mode: plus-lighter;\r\n}\r\n\r\n.leaflet-container.leaflet-touch-zoom {\r\n\ttouch-action: pan-x pan-y;\r\n\t}\r\n\r\n.leaflet-container.leaflet-touch-drag {\r\n\t/* Fallback for FF which doesn't support pinch-zoom */\r\n\ttouch-action: none;\r\n\ttouch-action: pinch-zoom;\r\n}\r\n\r\n.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {\r\n\ttouch-action: none;\r\n}\r\n\r\n.leaflet-container {\r\n\t-webkit-tap-highlight-color: transparent;\r\n}\r\n\r\n.leaflet-container a {\r\n\t-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);\r\n}\r\n\r\n.leaflet-tile {\r\n\tfilter: inherit;\r\n\tvisibility: hidden;\r\n\t}\r\n\r\n.leaflet-tile-loaded {\r\n\tvisibility: inherit;\r\n\t}\r\n\r\n.leaflet-zoom-box {\r\n\twidth: 0;\r\n\theight: 0;\r\n\tbox-sizing: border-box;\r\n\tz-index: 800;\r\n\t}\r\n\r\n/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */\r\n\r\n.leaflet-overlay-pane svg {\r\n\t-moz-user-select: none;\r\n\t}\r\n\r\n.leaflet-pane         { z-index: 400; }\r\n\r\n.leaflet-tile-pane    { z-index: 200; }\r\n\r\n.leaflet-overlay-pane { z-index: 400; }\r\n\r\n.leaflet-shadow-pane  { z-index: 500; }\r\n\r\n.leaflet-marker-pane  { z-index: 600; }\r\n\r\n.leaflet-tooltip-pane   { z-index: 650; }\r\n\r\n.leaflet-popup-pane   { z-index: 700; }\r\n\r\n.leaflet-map-pane canvas { z-index: 100; }\r\n\r\n.leaflet-map-pane svg    { z-index: 200; }\r\n\r\n.leaflet-vml-shape {\r\n\twidth: 1px;\r\n\theight: 1px;\r\n\t}\r\n\r\n.lvml {\r\n\tbehavior: url(#default#VML);\r\n\tdisplay: inline-block;\r\n\tposition: absolute;\r\n\t}\r\n\r\n/* control positioning */\r\n\r\n.leaflet-control {\r\n\tposition: relative;\r\n\tz-index: 800;\r\n\tpointer-events: visiblePainted; /* IE 9-10 doesn't have auto */\r\n\tpointer-events: auto;\r\n\t}\r\n\r\n.leaflet-top,\r\n.leaflet-bottom {\r\n\tposition: absolute;\r\n\tz-index: 1000;\r\n\tpointer-events: none;\r\n\t}\r\n\r\n.leaflet-top {\r\n\ttop: 0;\r\n\t}\r\n\r\n.leaflet-right {\r\n\tright: 0;\r\n\t}\r\n\r\n.leaflet-bottom {\r\n\tbottom: 0;\r\n\t}\r\n\r\n.leaflet-left {\r\n\tleft: 0;\r\n\t}\r\n\r\n.leaflet-control {\r\n\tfloat: left;\r\n\tclear: both;\r\n\t}\r\n\r\n.leaflet-right .leaflet-control {\r\n\tfloat: right;\r\n\t}\r\n\r\n.leaflet-top .leaflet-control {\r\n\tmargin-top: 10px;\r\n\t}\r\n\r\n.leaflet-bottom .leaflet-control {\r\n\tmargin-bottom: 10px;\r\n\t}\r\n\r\n.leaflet-left .leaflet-control {\r\n\tmargin-left: 10px;\r\n\t}\r\n\r\n.leaflet-right .leaflet-control {\r\n\tmargin-right: 10px;\r\n\t}\r\n\r\n/* zoom and fade animations */\r\n\r\n.leaflet-fade-anim .leaflet-popup {\r\n\topacity: 0;\r\n\ttransition: opacity 0.2s linear;\r\n\t}\r\n\r\n.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {\r\n\topacity: 1;\r\n\t}\r\n\r\n.leaflet-zoom-animated {\r\n\ttransform-origin: 0 0;\r\n\t}\r\n\r\nsvg.leaflet-zoom-animated {\r\n\twill-change: transform;\r\n}\r\n\r\n.leaflet-zoom-anim .leaflet-zoom-animated {\r\n\ttransition:         transform 0.25s cubic-bezier(0,0,0.25,1);\r\n\t}\r\n\r\n.leaflet-zoom-anim .leaflet-tile,\r\n.leaflet-pan-anim .leaflet-tile {\r\n\ttransition: none;\r\n\t}\r\n\r\n.leaflet-zoom-anim .leaflet-zoom-hide {\r\n\tvisibility: hidden;\r\n\t}\r\n\r\n/* cursors */\r\n\r\n.leaflet-interactive {\r\n\tcursor: pointer;\r\n\t}\r\n\r\n.leaflet-grab {\r\n\tcursor:         grab;\r\n\t}\r\n\r\n.leaflet-crosshair,\r\n.leaflet-crosshair .leaflet-interactive {\r\n\tcursor: crosshair;\r\n\t}\r\n\r\n.leaflet-popup-pane,\r\n.leaflet-control {\r\n\tcursor: auto;\r\n\t}\r\n\r\n.leaflet-dragging .leaflet-grab,\r\n.leaflet-dragging .leaflet-grab .leaflet-interactive,\r\n.leaflet-dragging .leaflet-marker-draggable {\r\n\tcursor: move;\r\n\tcursor:         grabbing;\r\n\t}\r\n\r\n/* marker & overlays interactivity */\r\n\r\n.leaflet-marker-icon,\r\n.leaflet-marker-shadow,\r\n.leaflet-image-layer,\r\n.leaflet-pane > svg path,\r\n.leaflet-tile-container {\r\n\tpointer-events: none;\r\n\t}\r\n\r\n.leaflet-marker-icon.leaflet-interactive,\r\n.leaflet-image-layer.leaflet-interactive,\r\n.leaflet-pane > svg path.leaflet-interactive,\r\nsvg.leaflet-image-layer.leaflet-interactive path {\r\n\tpointer-events: visiblePainted; /* IE 9-10 doesn't have auto */\r\n\tpointer-events: auto;\r\n\t}\r\n\r\n/* visual tweaks */\r\n\r\n.leaflet-container {\r\n\tbackground: #ddd;\r\n\toutline-offset: 1px;\r\n\t}\r\n\r\n.leaflet-container a {\r\n\tcolor: #0078A8;\r\n\t}\r\n\r\n.leaflet-zoom-box {\r\n\tborder: 2px dotted #38f;\r\n\tbackground: rgba(255,255,255,0.5);\r\n\t}\r\n\r\n/* general typography */\r\n\r\n.leaflet-container {\r\n\tfont-family: \"Helvetica Neue\", Arial, Helvetica, sans-serif;\r\n\tfont-size: 12px;\r\n\tfont-size: 0.75rem;\r\n\tline-height: 1.5;\r\n\t}\r\n\r\n/* general toolbar styles */\r\n\r\n.leaflet-bar {\r\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.65);\r\n\tborder-radius: 4px;\r\n\t}\r\n\r\n.leaflet-bar a {\r\n\tbackground-color: #fff;\r\n\tborder-bottom: 1px solid #ccc;\r\n\twidth: 26px;
156\r\n\theight: 26px;\r\n\tline-height: 26px;\r\n\tdisplay: block;\r\n\ttext-align: center;\r\n\ttext-decoration: none;\r\n\tcolor: black;\r\n\t}\r\n\r\n.leaflet-bar a,\r\n.leaflet-control-layers-toggle {\r\n\tbackground-position: 50% 50%;\r\n\tbackground-repeat: no-repeat;\r\n\tdisplay: block;\r\n\t}\r\n\r\n.leaflet-bar a:hover,\r\n.leaflet-bar a:focus {\r\n\tbackground-color: #f4f4f4;\r\n\t}\r\n\r\n.leaflet-bar a:first-child {\r\n\tborder-top-left-radius: 4px;\r\n\tborder-top-right-radius: 4px;\r\n\t}\r\n\r\n.leaflet-bar a:last-child {\r\n\tborder-bottom-left-radius: 4px;\r\n\tborder-bottom-right-radius: 4px;\r\n\tborder-bottom: none;\r\n\t}\r\n\r\n.leaflet-bar a.leaflet-disabled {\r\n\tcursor: default;\r\n\tbackground-color: #f4f4f4;\r\n\tcolor: #bbb;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-bar a {\r\n\twidth: 30px;\r\n\theight: 30px;\r\n\tline-height: 30px;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-bar a:first-child {\r\n\tborder-top-left-radius: 2px;\r\n\tborder-top-right-radius: 2px;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-bar a:last-child {\r\n\tborder-bottom-left-radius: 2px;\r\n\tborder-bottom-right-radius: 2px;\r\n\t}\r\n\r\n/* zoom control */\r\n\r\n.leaflet-control-zoom-in,\r\n.leaflet-control-zoom-out {\r\n\tfont: bold 18px 'Lucida Console', Monaco, monospace;\r\n\ttext-indent: 1px;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out  {\r\n\tfont-size: 22px;\r\n\t}\r\n\r\n/* layers control */\r\n\r\n.leaflet-control-layers {\r\n\tbox-shadow: 0 1px 5px rgba(0,0,0,0.4);\r\n\tbackground: #fff;\r\n\tborder-radius: 5px;\r\n\t}\r\n\r\n.leaflet-control-layers-toggle {\r\n\tbackground-image: url(images/layers.png);\r\n\twidth: 36px;\r\n\theight: 36px;\r\n\t}\r\n\r\n.leaflet-retina .leaflet-control-layers-toggle {\r\n\tbackground-image: url(images/layers-2x.png);\r\n\tbackground-size: 26px 26px;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-control-layers-toggle {\r\n\twidth: 44px;\r\n\theight: 44px;\r\n\t}\r\n\r\n.leaflet-control-layers .leaflet-control-layers-list,\r\n.leaflet-control-layers-expanded .leaflet-control-layers-toggle {\r\n\tdisplay: none;\r\n\t}\r\n\r\n.leaflet-control-layers-expanded .leaflet-control-layers-list {\r\n\tdisplay: block;\r\n\tposition: relative;\r\n\t}\r\n\r\n.leaflet-control-layers-expanded {\r\n\tpadding: 6px 10px 6px 6px;\r\n\tcolor: #333;\r\n\tbackground: #fff;\r\n\t}\r\n\r\n.leaflet-control-layers-scrollbar {\r\n\toverflow-y: scroll;\r\n\toverflow-x: hidden;\r\n\tpadding-right: 5px;\r\n\t}\r\n\r\n.leaflet-control-layers-selector {\r\n\tmargin-top: 2px;\r\n\tposition: relative;\r\n\ttop: 1px;\r\n\t}\r\n\r\n.leaflet-control-layers label {\r\n\tdisplay: block;\r\n\tfont-size: 13px;\r\n\tfont-size: 1.08333em;\r\n\t}\r\n\r\n.leaflet-control-layers-separator {\r\n\theight: 0;\r\n\tborder-top: 1px solid #ddd;\r\n\tmargin: 5px -10px 5px -6px;\r\n\t}\r\n\r\n/* Default icon URLs */\r\n\r\n.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */\r\n\tbackground-image: url(images/marker-icon.png);\r\n\t}\r\n\r\n/* attribution and scale controls */\r\n\r\n.leaflet-container .leaflet-control-attribution {\r\n\tbackground: #fff;\r\n\tbackground: rgba(255, 255, 255, 0.8);\r\n\tmargin: 0;\r\n\t}\r\n\r\n.leaflet-control-attribution,\r\n.leaflet-control-scale-line {\r\n\tpadding: 0 5px;\r\n\tcolor: #333;\r\n\tline-height: 1.4;\r\n\t}\r\n\r\n.leaflet-control-attribution a {\r\n\ttext-decoration: none;\r\n\t}\r\n\r\n.leaflet-control-attribution a:hover,\r\n.leaflet-control-attribution a:focus {\r\n\ttext-decoration: underline;\r\n\t}\r\n\r\n.leaflet-attribution-flag {\r\n\tdisplay: inline !important;\r\n\tvertical-align: baseline !important;\r\n\twidth: 1em;\r\n\theight: 0.6669em;\r\n\t}\r\n\r\n.leaflet-left .leaflet-control-scale {\r\n\tmargin-left: 5px;\r\n\t}\r\n\r\n.leaflet-bottom .leaflet-control-scale {\r\n\tmargin-bottom: 5px;\r\n\t}\r\n\r\n.leaflet-control-scale-line {\r\n\tborder: 2px solid #777;\r\n\tborder-top: none;\r\n\tline-height: 1.1;\r\n\tpadding: 2px 5px 1px;\r\n\twhite-space: nowrap;\r\n\tbox-sizing: border-box;\r\n\tbackground: rgba(255, 255, 255, 0.8);\r\n\ttext-shadow: 1px 1px #fff;\r\n\t}\r\n\r\n.leaflet-control-scale-line:not(:first-child) {\r\n\tborder-top: 2px solid #777;\r\n\tborder-bottom: none;\r\n\tmargin-top: -2px;\r\n\t}\r\n\r\n.leaflet-control-scale-line:not(:first-child):not(:last-child) {\r\n\tborder-bottom: 2px solid #777;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-control-attribution,\r\n.leaflet-touch .leaflet-control-layers,\r\n.leaflet-touch .leaflet-bar {\r\n\tbox-shadow: none;\r\n\t}\r\n\r\n.leaflet-touch .leaflet-control-layers,\r\n.leaflet-touch .leaflet-bar {\r\n\tborder: 2px solid rgba(0,0,0,0.2);\r\n\tbackground-clip: padding-box;\r\n\t}\r\n\r\n/* popup */\r\n\r\n.leaflet-popup {\r\n\tposition: absolute;\r\n\ttext-align: center;\r\n\tmargin-bottom: 20px;\r\n\t}\r\n\r\n.leaflet-popup-content-wrapper {\r\n\tpadding: 1px;\r\n\ttext-align: left;\r\n\tborder-radius: 12px;\r\n\t}\r\n\r\n.leaflet-popup-content {\r\n\tmargin: 13px 24px 13px 20px;\r\n\tline-height: 1.3;\r\n\tfont-size: 13px;\r\n\tfont-size: 1.08333em;\r\n\tmin-height: 1px;\r\n\t}\r\n\r\n.leaflet-popup-content p {\r\n\tmargin: 17px 0;\r\n\tmargin: 1.3em 0;\r\n\t}\r\n\r\n.leaflet-popup-tip-container {\r\n\twidth: 40px;\r\n\theight: 20px;\r\n\tposition: absolute;\r\n\tleft: 50%;
156\r\n\tmargin-top: -1px;\r\n\tmargin-left: -20px;\r\n\toverflow: hidden;\r\n\tpointer-events: none;\r\n\t}\r\n\r\n.leaflet-popup-tip {\r\n\twidth: 17px;\r\n\theight: 17px;\r\n\tpadding: 1px;\r\n\r\n\tmargin: -10px auto 0;\r\n\tpointer-events: auto;\r\n\ttransform: rotate(45deg);\r\n\t}\r\n\r\n.leaflet-popup-content-wrapper,\r\n.leaflet-popup-tip {\r\n\tbackground: white;\r\n\tcolor: #333;\r\n\tbox-shadow: 0 3px 14px rgba(0,0,0,0.4);\r\n\t}\r\n\r\n.leaflet-container a.leaflet-popup-close-button {\r\n\tposition: absolute;\r\n\ttop: 0;\r\n\tright: 0;\r\n\tborder: none;\r\n\ttext-align: center;\r\n\twidth: 24px;\r\n\theight: 24px;\r\n\tfont: 16px/24px Tahoma, Verdana, sans-serif;\r\n\tcolor: #757575;\r\n\ttext-decoration: none;\r\n\tbackground: transparent;\r\n\t}\r\n\r\n.leaflet-container a.leaflet-popup-close-button:hover,\r\n.leaflet-container a.leaflet-popup-close-button:focus {\r\n\tcolor: #585858;\r\n\t}\r\n\r\n.leaflet-popup-scrolled {\r\n\toverflow: auto;\r\n\t}\r\n\r\n.leaflet-oldie .leaflet-popup-content-wrapper {\r\n\t-ms-zoom: 1;\r\n\t}\r\n\r\n.leaflet-oldie .leaflet-popup-tip {\r\n\twidth: 24px;\r\n\tmargin: 0 auto;\r\n\r\n\t-ms-filter: \"progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)\";\r\n\tfilter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);\r\n\t}\r\n\r\n.leaflet-oldie .leaflet-control-zoom,\r\n.leaflet-oldie .leaflet-control-layers,\r\n.leaflet-oldie .leaflet-popup-content-wrapper,\r\n.leaflet-oldie .leaflet-popup-tip {\r\n\tborder: 1px solid #999;\r\n\t}\r\n\r\n/* div icon */\r\n\r\n.leaflet-div-icon {\r\n\tbackground: #fff;\r\n\tborder: 1px solid #666;\r\n\t}\r\n\r\n/* Tooltip */\r\n\r\n/* Base styles for the element that has a tooltip */\r\n\r\n.leaflet-tooltip {\r\n\tposition: absolute;\r\n\tpadding: 6px;\r\n\tbackground-color: #fff;\r\n\tborder: 1px solid #fff;\r\n\tborder-radius: 3px;\r\n\tcolor: #222;\r\n\twhite-space: nowrap;\r\n\t-webkit-user-select: none;\r\n\t-moz-user-select: none;\r\n\tuser-select: none;\r\n\tpointer-events: none;\r\n\tbox-shadow: 0 1px 3px rgba(0,0,0,0.4);\r\n\t}\r\n\r\n.leaflet-tooltip.leaflet-interactive {\r\n\tcursor: pointer;\r\n\tpointer-events: auto;\r\n\t}\r\n\r\n.leaflet-tooltip-top:before,\r\n.leaflet-tooltip-bottom:before,\r\n.leaflet-tooltip-left:before,\r\n.leaflet-tooltip-right:before {\r\n\tposition: absolute;\r\n\tpointer-events: none;\r\n\tborder: 6px solid transparent;\r\n\tbackground: transparent;\r\n\tcontent: \"\";\r\n\t}\r\n\r\n/* Directions */\r\n\r\n.leaflet-tooltip-bottom {\r\n\tmargin-top: 6px;\r\n}\r\n\r\n.leaflet-tooltip-top {\r\n\tmargin-top: -6px;\r\n}\r\n\r\n.leaflet-tooltip-bottom:before,\r\n.leaflet-tooltip-top:before {\r\n\tleft: 50%;\r\n\tmargin-left: -6px;\r\n\t}\r\n\r\n.leaflet-tooltip-top:before {\r\n\tbottom: 0;\r\n\tmargin-bottom: -12px;\r\n\tborder-top-color: #fff;\r\n\t}\r\n\r\n.leaflet-tooltip-bottom:before {\r\n\ttop: 0;\r\n\tmargin-top: -12px;\r\n\tmargin-left: -6px;\r\n\tborder-bottom-color: #fff;\r\n\t}\r\n\r\n.leaflet-tooltip-left {\r\n\tmargin-left: -6px;\r\n}\r\n\r\n.leaflet-tooltip-right {\r\n\tmargin-left: 6px;\r\n}\r\n\r\n.leaflet-tooltip-left:before,\r\n.leaflet-tooltip-right:before {\r\n\ttop: 50%;\r\n\tmargin-top: -6px;\r\n\t}\r\n\r\n.leaflet-tooltip-left:before {\r\n\tright: 0;\r\n\tmargin-right: -12px;\r\n\tborder-left-color: #fff;\r\n\t}\r\n\r\n.leaflet-tooltip-right:before {\r\n\tleft: 0;\r\n\tmargin-left: -12px;\r\n\tborder-right-color: #fff;\r\n\t}\r\n\r\n/* Printing */\r\n\r\n@media print {\r\n\t/* Prevent printers from removing background-images of controls. */\r\n\t.leaflet-control {\r\n\t\t-webkit-print-color-adjust: exact;\r\n\t\tprint-color-adjust: exact;\r\n\t\t}\r\n\t}\r\n", ""]);
157// Exports
158/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (___CSS_LOADER_EXPORT___);
159
160
161/***/ }),
162
vendor: 1,948 bytes, lines 163-238
163/***/ "./node_modules/css-loader/dist/runtime/api.js":
164/*!*****************************************************!*\
165  !*** ./node_modules/css-loader/dist/runtime/api.js ***!
166  \*****************************************************/
167/***/ ((module) => {
168
169"use strict";
170
171
172/*
173  MIT License http://www.opensource.org/licenses/mit-license.php
174  Author Tobias Koppers @sokra
175*/
176// css base code, injected by the css-loader
177// eslint-disable-next-line func-names
178module.exports = function (cssWithMappingToString) {
179  var list = []; // return the list of modules as css string
180
181  list.toString = function toString() {
182    return this.map(function (item) {
183      var content = cssWithMappingToString(item);
184
185      if (item[2]) {
186        return "@media ".concat(item[2], " {").concat(content, "}");
187      }
188
189      return content;
190    }).join("");
191  }; // import a list of modules into the list
192  // eslint-disable-next-line func-names
193
194
195  list.i = function (modules, mediaQuery, dedupe) {
196    if (typeof modules === "string") {
197      // eslint-disable-next-line no-param-reassign
198      modules = [[null, modules, ""]];
199    }
200
201    var alreadyImportedModules = {};
202
203    if (dedupe) {
204      for (var i = 0; i < this.length; i++) {
205        // eslint-disable-next-line prefer-destructuring
206        var id = this[i][0];
207
208        if (id != null) {
209          alreadyImportedModules[id] = true;
210        }
211      }
212    }
213
214    for (var _i = 0; _i < modules.length; _i++) {
215      var item = [].concat(modules[_i]);
216
217      if (dedupe && alreadyImportedModules[item[0]]) {
218        // eslint-disable-next-line no-continue
219        continue;
220      }
221
222      if (mediaQuery) {
223        if (!item[2]) {
224          item[2] = mediaQuery;
225        } else {
226          item[2] = "".concat(mediaQuery, " and ").concat(item[2]);
227        }
228      }
229
230      list.push(item);
231    }
232  };
233
234  return list;
235};
236
237/***/ }),
238
vendor: 455,849 bytes, lines 239-14759
239/***/ "./node_modules/leaflet/dist/leaflet-src.js":
240/*!**************************************************!*\
241  !*** ./node_modules/leaflet/dist/leaflet-src.js ***!
242  \**************************************************/
243/***/ (function(__unused_webpack_module, exports) {
244
245/* @preserve
246 * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com
247 * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade
248 */
249
250(function (global, factory) {
251   true ? factory(exports) :
252  0;
253})(this, (function (exports) { 'use strict';
254
255  var version = "1.9.4";
256
257  /*
258   * @namespace Util
259   *
260   * Various utility functions, used by Leaflet internally.
261   */
262
263  // @function extend(dest: Object, src?: Object): Object
264  // Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
265  function extend(dest) {
266  	var i, j, len, src;
267
268  	for (j = 1, len = arguments.length; j < len; j++) {
269  		src = arguments[j];
270  		for (i in src) {
271  			dest[i] = src[i];
272  		}
273  	}
274  	return dest;
275  }
276
277  // @function create(proto: Object, properties?: Object): Object
278  // Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
279  var create$2 = Object.create || (function () {
280  	function F() {}
281  	return function (proto) {
282  		F.prototype = proto;
283  		return new F();
284  	};
285  })();
286
287  // @function bind(fn: Function, …): Function
288  // Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
289  // Has a `L.bind()` shortcut.
290  function bind(fn, obj) {
291  	var slice = Array.prototype.slice;
292
293  	if (fn.bind) {
294  		return fn.bind.apply(fn, slice.call(arguments, 1));
295  	}
296
297  	var args = slice.call(arguments, 2);
298
299  	return function () {
300  		return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
301  	};
302  }
303
304  // @property lastId: Number
305  // Last unique ID used by [`stamp()`](#util-stamp)
306  var lastId = 0;
307
308  // @function stamp(obj: Object): Number
309  // Returns the unique ID of an object, assigning it one if it doesn't have it.
310  function stamp(obj) {
311  	if (!('_leaflet_id' in obj)) {
312  		obj['_leaflet_id'] = ++lastId;
313  	}
314  	return obj._leaflet_id;
315  }
316
317  // @function throttle(fn: Function, time: Number, context: Object): Function
318  // Returns a function which executes function `fn` with the given scope `context`
319  // (so that the `this` keyword refers to `context` inside `fn`'s code). The function
320  // `fn` will be called no more than one time per given amount of `time`. The arguments
321  // received by the bound function will be any arguments passed when binding the
322  // function, followed by any arguments passed when invoking the bound function.
323  // Has an `L.throttle` shortcut.
324  function throttle(fn, time, context) {
325  	var lock, args, wrapperFn, later;
326
327  	later = function () {
328  		// reset lock and call if queued
329  		lock = false;
330  		if (args) {
331  			wrapperFn.apply(context, args);
332  			args = false;
333  		}
334  	};
335
336  	wrapperFn = function () {
337  		if (lock) {
338  			// called too soon, queue to call later
339  			args = arguments;
340
341  		} else {
342  			// call and lock until later
343  			fn.apply(context, arguments);
344  			setTimeout(later, time);
345  			lock = true;
346  		}
347  	};
348
349  	return wrapperFn;
350  }
351
352  // @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
353  // Returns the number `num` modulo `range` in such a way so it lies within
354  // `range[0]` and `range[1]`. The returned value will be always smaller than
355  // `range[1]` unless `includeMax` is set to `true`.
356  function wrapNum(x, range, includeMax) {
357  	var max = range[1],
358  	    min = range[0],
359  	    d = max - min;
360  	return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
361  }
362
363  // @function falseFn(): Function
364  // Returns a function which always returns `false`.
365  function falseFn() { return false; }
366
367  // @function formatNum(num: Number, precision?: Number|false): Number
368  // Returns the number `num` rounded with specified `precision`.
369  // The default `precision` value is 6 decimal places.
370  // `false` can be passed to skip any processing (can be useful to avoid round-off errors).
371  function formatNum(num, precision) {
372  	if (precision === false) { return num; }
373  	var pow = Math.pow(10, precision === undefined ? 6 : precision);
374  	return Math.round(num * pow) / pow;
375  }
376
377  // @function trim(str: String): String
378  // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
379  function trim(str) {
380  	return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
381  }
382
383  // @function splitWords(str: String): String[]
384  // Trims and splits the string on whitespace and returns the array of parts.
385  function splitWords(str) {
386  	return trim(str).split(/\s+/);
387  }
388
389  // @function setOptions(obj: Object, options: Object): Object
390  // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
391  function setOptions(obj, options) {
392  	if (!Object.prototype.hasOwnProperty.call(obj, 'options')) {
393  		obj.options = obj.options ? create$2(obj.options) : {};
394  	}
395  	for (var i in options) {
396  		obj.options[i] = options[i];
397  	}
398  	return obj.options;
399  }
400
401  // @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
402  // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
403  // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
404  // be appended at the end. If `uppercase` is `true`, the parameter names will
405  // be uppercased (e.g. `'?A=foo&B=bar'`)
406  function getParamString(obj, existingUrl, uppercase) {
407  	var params = [];
408  	for (var i in obj) {
409  		params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
410  	}
411  	return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
412  }
413
414  var templateRe = /\{ *([\w_ -]+) *\}/g;
415
416  // @function template(str: String, data: Object): String
417  // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
418  // and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
419  // `('Hello foo, bar')`. You can also specify functions instead of strings for
420  // data values — they will be evaluated passing `data` as an argument.
421  function template(str, data) {
422  	return str.replace(templateRe, function (str, key) {
423  		var value = data[key];
424
425  		if (value === undefined) {
426  			throw new Error('No value provided for variable ' + str);
427
428  		} else if (typeof value === 'function') {
429  			value = value(data);
430  		}
431  		return value;
432  	});
433  }
434
435  // @function isArray(obj): Boolean
436  // Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
437  var isArray = Array.isArray || function (obj) {
438  	return (Object.prototype.toString.call(obj) === '[object Array]');
439  };
440
441  // @function indexOf(array: Array, el: Object): Number
442  // Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
443  function indexOf(array, el) {
444  	for (var i = 0; i < array.length; i++) {
445  		if (array[i] === el) { return i; }
446  	}
447  	return -1;
448  }
449
450  // @property emptyImageUrl: String
451  // Data URI string containing a base64-encoded empty GIF image.
452  // Used as a hack to free memory from unused images on WebKit-powered
453  // mobile devices (by setting image `src` to this string).
454  var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=';
455
456  // inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/
457
458  function getPrefixed(name) {
459  	return window['webkit' + name] || window['moz' + name] || window['ms' + name];
460  }
461
462  var lastTime = 0;
463
464  // fallback for IE 7-8
465  function timeoutDefer(fn) {
466  	var time = +new Date(),
467  	    timeToCall = Math.max(0, 16 - (time - lastTime));
468
469  	lastTime = time + timeToCall;
470  	return window.setTimeout(fn, timeToCall);
471  }
472
473  var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer;
474  var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
475  		getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
476
477  // @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
478  // Schedules `fn` to be executed when the browser repaints. `fn` is bound to
479  // `context` if given. When `immediate` is set, `fn` is called immediately if
480  // the browser doesn't have native support for
481  // [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
482  // otherwise it's delayed. Returns a request ID that can be used to cancel the request.
483  function requestAnimFrame(fn, context, immediate) {
484  	if (immediate && requestFn === timeoutDefer) {
485  		fn.call(context);
486  	} else {
487  		return requestFn.call(window, bind(fn, context));
488  	}
489  }
490
491  // @function cancelAnimFrame(id: Number): undefined
492  // Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
493  function cancelAnimFrame(id) {
494  	if (id) {
495  		cancelFn.call(window, id);
496  	}
497  }
498
499  var Util = {
500    __proto__: null,
501    extend: extend,
502    create: create$2,
503    bind: bind,
504    get lastId () { return lastId; },
505    stamp: stamp,
506    throttle: throttle,
507    wrapNum: wrapNum,
508    falseFn: falseFn,
509    formatNum: formatNum,
510    trim: trim,
511    splitWords: splitWords,
512    setOptions: setOptions,
513    getParamString: getParamString,
514    template: template,
515    isArray: isArray,
516    indexOf: indexOf,
517    emptyImageUrl: emptyImageUrl,
518    requestFn: requestFn,
519    cancelFn: cancelFn,
520    requestAnimFrame: requestAnimFrame,
521    cancelAnimFrame: cancelAnimFrame
522  };
523
524  // @class Class
525  // @aka L.Class
526
527  // @section
528  // @uninheritable
529
530  // Thanks to John Resig and Dean Edwards for inspiration!
531
532  function Class() {}
533
534  Class.extend = function (props) {
535
536  	// @function extend(props: Object): Function
537  	// [Extends the current class](#class-inheritance) given the properties to be included.
538  	// Returns a Javascript function that is a class constructor (to be called with `new`).
539  	var NewClass = function () {
540
541  		setOptions(this);
542
543  		// call the constructor
544  		if (this.initialize) {
545  			this.initialize.apply(this, arguments);
546  		}
547
548  		// call all constructor hooks
549  		this.callInitHooks();
550  	};
551
552  	var parentProto = NewClass.__super__ = this.prototype;
553
554  	var proto = create$2(parentProto);
555  	proto.constructor = NewClass;
556
557  	NewClass.prototype = proto;
558
559  	// inherit parent's statics
560  	for (var i in this) {
561  		if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') {
562  			NewClass[i] = this[i];
563  		}
564  	}
565
566  	// mix static properties into the class
567  	if (props.statics) {
568  		extend(NewClass, props.statics);
569  	}
570
571  	// mix includes into the prototype
572  	if (props.includes) {
573  		checkDeprecatedMixinEvents(props.includes);
574  		extend.apply(null, [proto].concat(props.includes));
575  	}
576
577  	// mix given properties into the prototype
578  	extend(proto, props);
579  	delete proto.statics;
580  	delete proto.includes;
581
582  	// merge options
583  	if (proto.options) {
584  		proto.options = parentProto.options ? create$2(parentProto.options) : {};
585  		extend(proto.options, props.options);
586  	}
587
588  	proto._initHooks = [];
589
590  	// add method for calling all hooks
591  	proto.callInitHooks = function () {
592
593  		if (this._initHooksCalled) { return; }
594
595  		if (parentProto.callInitHooks) {
596  			parentProto.callInitHooks.call(this);
597  		}
598
599  		this._initHooksCalled = true;
600
601  		for (var i = 0, len = proto._initHooks.length; i < len; i++) {
602  			proto._initHooks[i].call(this);
603  		}
604  	};
605
606  	return NewClass;
607  };
608
609
610  // @function include(properties: Object): this
611  // [Includes a mixin](#class-includes) into the current class.
612  Class.include = function (props) {
613  	var parentOptions = this.prototype.options;
614  	extend(this.prototype, props);
615  	if (props.options) {
616  		this.prototype.options = parentOptions;
617  		this.mergeOptions(props.options);
618  	}
619  	return this;
620  };
621
622  // @function mergeOptions(options: Object): this
623  // [Merges `options`](#class-options) into the defaults of the class.
624  Class.mergeOptions = function (options) {
625  	extend(this.prototype.options, options);
626  	return this;
627  };
628
629  // @function addInitHook(fn: Function): this
630  // Adds a [constructor hook](#class-constructor-hooks) to the class.
631  Class.addInitHook = function (fn) { // (Function) || (String, args...)
632  	var args = Array.prototype.slice.call(arguments, 1);
633
634  	var init = typeof fn === 'function' ? fn : function () {
635  		this[fn].apply(this, args);
636  	};
637
638  	this.prototype._initHooks = this.prototype._initHooks || [];
639  	this.prototype._initHooks.push(init);
640  	return this;
641  };
642
643  function checkDeprecatedMixinEvents(includes) {
644  	/* global L: true */
645  	if (typeof L === 'undefined' || !L || !L.Mixin) { return; }
646
647  	includes = isArray(includes) ? includes : [includes];
648
649  	for (var i = 0; i < includes.length; i++) {
650  		if (includes[i] === L.Mixin.Events) {
651  			console.warn('Deprecated include of L.Mixin.Events: ' +
652  				'this property will be removed in future releases, ' +
653  				'please inherit from L.Evented instead.', new Error().stack);
654  		}
655  	}
656  }
657
658  /*
659   * @class Evented
660   * @aka L.Evented
661   * @inherits Class
662   *
663   * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).
664   *
665   * @example
666   *
667   * ```js
668   * map.on('click', function(e) {
669   * 	alert(e.latlng);
670   * } );
671   * ```
672   *
673   * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
674   *
675   * ```js
676   * function onClick(e) { ... }
677   *
678   * map.on('click', onClick);
679   * map.off('click', onClick);
680   * ```
681   */
682
683  var Events = {
684  	/* @method on(type: String, fn: Function, context?: Object): this
685  	 * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).
686  	 *
687  	 * @alternative
688  	 * @method on(eventMap: Object): this
689  	 * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
690  	 */
691  	on: function (types, fn, context) {
692
693  		// types can be a map of types/handlers
694  		if (typeof types === 'object') {
695  			for (var type in types) {
696  				// we don't process space-separated events here for performance;
697  				// it's a hot path since Layer uses the on(obj) syntax
698  				this._on(type, types[type], fn);
699  			}
700
701  		} else {
702  			// types can be a string of space-separated words
703  			types = splitWords(types);
704
705  			for (var i = 0, len = types.length; i < len; i++) {
706  				this._on(types[i], fn, context);
707  			}
708  		}
709
710  		return this;
711  	},
712
713  	/* @method off(type: String, fn?: Function, context?: Object): this
714  	 * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.
715  	 *
716  	 * @alternative
717  	 * @method off(eventMap: Object): this
718  	 * Removes a set of type/listener pairs.
719  	 *
720  	 * @alternative
721  	 * @method off: this
722  	 * Removes all listeners to all events on the object. This includes implicitly attached events.
723  	 */
724  	off: function (types, fn, context) {
725
726  		if (!arguments.length) {
727  			// clear all listeners if called without arguments
728  			delete this._events;
729
730  		} else if (typeof types === 'object') {
731  			for (var type in types) {
732  				this._off(type, types[type], fn);
733  			}
734
735  		} else {
736  			types = splitWords(types);
737
738  			var removeAll = arguments.length === 1;
739  			for (var i = 0, len = types.length; i < len; i++) {
740  				if (removeAll) {
741  					this._off(types[i]);
742  				} else {
743  					this._off(types[i], fn, context);
744  				}
745  			}
746  		}
747
748  		return this;
749  	},
750
751  	// attach listener (without syntactic sugar now)
752  	_on: function (type, fn, context, _once) {
753  		if (typeof fn !== 'function') {
754  			console.warn('wrong listener type: ' + typeof fn);
755  			return;
756  		}
757
758  		// check if fn already there
759  		if (this._listens(type, fn, context) !== false) {
760  			return;
761  		}
762
763  		if (context === this) {
764  			// Less memory footprint.
765  			context = undefined;
766  		}
767
768  		var newListener = {fn: fn, ctx: context};
769  		if (_once) {
770  			newListener.once = true;
771  		}
772
773  		this._events = this._events || {};
774  		this._events[type] = this._events[type] || [];
775  		this._events[type].push(newListener);
776  	},
777
778  	_off: function (type, fn, context) {
779  		var listeners,
780  		    i,
781  		    len;
782
783  		if (!this._events) {
784  			return;
785  		}
786
787  		listeners = this._events[type];
788  		if (!listeners) {
789  			return;
790  		}
791
792  		if (arguments.length === 1) { // remove all
793  			if (this._firingCount) {
794  				// Set all removed listeners to noop
795  				// so they are not called if remove happens in fire
796  				for (i = 0, len = listeners.length; i < len; i++) {
797  					listeners[i].fn = falseFn;
798  				}
799  			}
800  			// clear all listeners for a type if function isn't specified
801  			delete this._events[type];
802  			return;
803  		}
804
805  		if (typeof fn !== 'function') {
806  			console.warn('wrong listener type: ' + typeof fn);
807  			return;
808  		}
809
810  		// find fn and remove it
811  		var index = this._listens(type, fn, context);
812  		if (index !== false) {
813  			var listener = listeners[index];
814  			if (this._firingCount) {
815  				// set the removed listener to noop so that's not called if remove happens in fire
816  				listener.fn = falseFn;
817
818  				/* copy array in case events are being fired */
819  				this._events[type] = listeners = listeners.slice();
820  			}
821  			listeners.splice(index, 1);
822  		}
823  	},
824
825  	// @method fire(type: String, data?: Object, propagate?: Boolean): this
826  	// Fires an event of the specified type. You can optionally provide a data
827  	// object — the first argument of the listener function will contain its
828  	// properties. The event can optionally be propagated to event parents.
829  	fire: function (type, data, propagate) {
830  		if (!this.listens(type, propagate)) { return this; }
831
832  		var event = extend({}, data, {
833  			type: type,
834  			target: this,
835  			sourceTarget: data && data.sourceTarget || this
836  		});
837
838  		if (this._events) {
839  			var listeners = this._events[type];
840  			if (listeners) {
841  				this._firingCount = (this._firingCount + 1) || 1;
842  				for (var i = 0, len = listeners.length; i < len; i++) {
843  					var l = listeners[i];
844  					// off overwrites l.fn, so we need to copy fn to a var
845  					var fn = l.fn;
846  					if (l.once) {
847  						this.off(type, fn, l.ctx);
848  					}
849  					fn.call(l.ctx || this, event);
850  				}
851
852  				this._firingCount--;
853  			}
854  		}
855
856  		if (propagate) {
857  			// propagate the event to parents (set with addEventParent)
858  			this._propagateEvent(event);
859  		}
860
861  		return this;
862  	},
863
864  	// @method listens(type: String, propagate?: Boolean): Boolean
865  	// @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean
866  	// Returns `true` if a particular event type has any listeners attached to it.
867  	// The verification can optionally be propagated, it will return `true` if parents have the listener attached to it.
868  	listens: function (type, fn, context, propagate) {
869  		if (typeof type !== 'string') {
870  			console.warn('"string" type argument expected');
871  		}
872
873  		// we don't overwrite the input `fn` value, because we need to use it for propagation
874  		var _fn = fn;
875  		if (typeof fn !== 'function') {
876  			propagate = !!fn;
877  			_fn = undefined;
878  			context = undefined;
879  		}
880
881  		var listeners = this._events && this._events[type];
882  		if (listeners && listeners.length) {
883  			if (this._listens(type, _fn, context) !== false) {
884  				return true;
885  			}
886  		}
887
888  		if (propagate) {
889  			// also check parents for listeners if event propagates
890  			for (var id in this._eventParents) {
891  				if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; }
892  			}
893  		}
894  		return false;
895  	},
896
897  	// returns the index (number) or false
898  	_listens: function (type, fn, context) {
899  		if (!this._events) {
900  			return false;
901  		}
902
903  		var listeners = this._events[type] || [];
904  		if (!fn) {
905  			return !!listeners.length;
906  		}
907
908  		if (context === this) {
909  			// Less memory footprint.
910  			context = undefined;
911  		}
912
913  		for (var i = 0, len = listeners.length; i < len; i++) {
914  			if (listeners[i].fn === fn && listeners[i].ctx === context) {
915  				return i;
916  			}
917  		}
918  		return false;
919
920  	},
921
922  	// @method once(…): this
923  	// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
924  	once: function (types, fn, context) {
925
926  		// types can be a map of types/handlers
927  		if (typeof types === 'object') {
928  			for (var type in types) {
929  				// we don't process space-separated events here for performance;
930  				// it's a hot path since Layer uses the on(obj) syntax
931  				this._on(type, types[type], fn, true);
932  			}
933
934  		} else {
935  			// types can be a string of space-separated words
936  			types = splitWords(types);
937
938  			for (var i = 0, len = types.length; i < len; i++) {
939  				this._on(types[i], fn, context, true);
940  			}
941  		}
942
943  		return this;
944  	},
945
946  	// @method addEventParent(obj: Evented): this
947  	// Adds an event parent - an `Evented` that will receive propagated events
948  	addEventParent: function (obj) {
949  		this._eventParents = this._eventParents || {};
950  		this._eventParents[stamp(obj)] = obj;
951  		return this;
952  	},
953
954  	// @method removeEventParent(obj: Evented): this
955  	// Removes an event parent, so it will stop receiving propagated events
956  	removeEventParent: function (obj) {
957  		if (this._eventParents) {
958  			delete this._eventParents[stamp(obj)];
959  		}
960  		return this;
961  	},
962
963  	_propagateEvent: function (e) {
964  		for (var id in this._eventParents) {
965  			this._eventParents[id].fire(e.type, extend({
966  				layer: e.target,
967  				propagatedFrom: e.target
968  			}, e), true);
969  		}
970  	}
971  };
972
973  // aliases; we should ditch those eventually
974
975  // @method addEventListener(…): this
976  // Alias to [`on(…)`](#evented-on)
977  Events.addEventListener = Events.on;
978
979  // @method removeEventListener(…): this
980  // Alias to [`off(…)`](#evented-off)
981
982  // @method clearAllEventListeners(…): this
983  // Alias to [`off()`](#evented-off)
984  Events.removeEventListener = Events.clearAllEventListeners = Events.off;
985
986  // @method addOneTimeEventListener(…): this
987  // Alias to [`once(…)`](#evented-once)
988  Events.addOneTimeEventListener = Events.once;
989
990  // @method fireEvent(…): this
991  // Alias to [`fire(…)`](#evented-fire)
992  Events.fireEvent = Events.fire;
993
994  // @method hasEventListeners(…): Boolean
995  // Alias to [`listens(…)`](#evented-listens)
996  Events.hasEventListeners = Events.listens;
997
998  var Evented = Class.extend(Events);
999
1000  /*
1001   * @class Point
1002   * @aka L.Point
1003   *
1004   * Represents a point with `x` and `y` coordinates in pixels.
1005   *
1006   * @example
1007   *
1008   * ```js
1009   * var point = L.point(200, 300);
1010   * ```
1011   *
1012   * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:
1013   *
1014   * ```js
1015   * map.panBy([200, 300]);
1016   * map.panBy(L.point(200, 300));
1017   * ```
1018   *
1019   * Note that `Point` does not inherit from Leaflet's `Class` object,
1020   * which means new classes can't inherit from it, and new methods
1021   * can't be added to it with the `include` function.
1022   */
1023
1024  function Point(x, y, round) {
1025  	// @property x: Number; The `x` coordinate of the point
1026  	this.x = (round ? Math.round(x) : x);
1027  	// @property y: Number; The `y` coordinate of the point
1028  	this.y = (round ? Math.round(y) : y);
1029  }
1030
1031  var trunc = Math.trunc || function (v) {
1032  	return v > 0 ? Math.floor(v) : Math.ceil(v);
1033  };
1034
1035  Point.prototype = {
1036
1037  	// @method clone(): Point
1038  	// Returns a copy of the current point.
1039  	clone: function () {
1040  		return new Point(this.x, this.y);
1041  	},
1042
1043  	// @method add(otherPoint: Point): Point
1044  	// Returns the result of addition of the current and the given points.
1045  	add: function (point) {
1046  		// non-destructive, returns a new point
1047  		return this.clone()._add(toPoint(point));
1048  	},
1049
1050  	_add: function (point) {
1051  		// destructive, used directly for performance in situations where it's safe to modify existing point
1052  		this.x += point.x;
1053  		this.y += point.y;
1054  		return this;
1055  	},
1056
1057  	// @method subtract(otherPoint: Point): Point
1058  	// Returns the result of subtraction of the given point from the current.
1059  	subtract: function (point) {
1060  		return this.clone()._subtract(toPoint(point));
1061  	},
1062
1063  	_subtract: function (point) {
1064  		this.x -= point.x;
1065  		this.y -= point.y;
1066  		return this;
1067  	},
1068
1069  	// @method divideBy(num: Number): Point
1070  	// Returns the result of division of the current point by the given number.
1071  	divideBy: function (num) {
1072  		return this.clone()._divideBy(num);
1073  	},
1074
1075  	_divideBy: function (num) {
1076  		this.x /= num;
1077  		this.y /= num;
1078  		return this;
1079  	},
1080
1081  	// @method multiplyBy(num: Number): Point
1082  	// Returns the result of multiplication of the current point by the given number.
1083  	multiplyBy: function (num) {
1084  		return this.clone()._multiplyBy(num);
1085  	},
1086
1087  	_multiplyBy: function (num) {
1088  		this.x *= num;
1089  		this.y *= num;
1090  		return this;
1091  	},
1092
1093  	// @method scaleBy(scale: Point): Point
1094  	// Multiply each coordinate of the current point by each coordinate of
1095  	// `scale`. In linear algebra terms, multiply the point by the
1096  	// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
1097  	// defined by `scale`.
1098  	scaleBy: function (point) {
1099  		return new Point(this.x * point.x, this.y * point.y);
1100  	},
1101
1102  	// @method unscaleBy(scale: Point): Point
1103  	// Inverse of `scaleBy`. Divide each coordinate of the current point by
1104  	// each coordinate of `scale`.
1105  	unscaleBy: function (point) {
1106  		return new Point(this.x / point.x, this.y / point.y);
1107  	},
1108
1109  	// @method round(): Point
1110  	// Returns a copy of the current point with rounded coordinates.
1111  	round: function () {
1112  		return this.clone()._round();
1113  	},
1114
1115  	_round: function () {
1116  		this.x = Math.round(this.x);
1117  		this.y = Math.round(this.y);
1118  		return this;
1119  	},
1120
1121  	// @method floor(): Point
1122  	// Returns a copy of the current point with floored coordinates (rounded down).
1123  	floor: function () {
1124  		return this.clone()._floor();
1125  	},
1126
1127  	_floor: function () {
1128  		this.x = Math.floor(this.x);
1129  		this.y = Math.floor(this.y);
1130  		return this;
1131  	},
1132
1133  	// @method ceil(): Point
1134  	// Returns a copy of the current point with ceiled coordinates (rounded up).
1135  	ceil: function () {
1136  		return this.clone()._ceil();
1137  	},
1138
1139  	_ceil: function () {
1140  		this.x = Math.ceil(this.x);
1141  		this.y = Math.ceil(this.y);
1142  		return this;
1143  	},
1144
1145  	// @method trunc(): Point
1146  	// Returns a copy of the current point with truncated coordinates (rounded towards zero).
1147  	trunc: function () {
1148  		return this.clone()._trunc();
1149  	},
1150
1151  	_trunc: function () {
1152  		this.x = trunc(this.x);
1153  		this.y = trunc(this.y);
1154  		return this;
1155  	},
1156
1157  	// @method distanceTo(otherPoint: Point): Number
1158  	// Returns the cartesian distance between the current and the given points.
1159  	distanceTo: function (point) {
1160  		point = toPoint(point);
1161
1162  		var x = point.x - this.x,
1163  		    y = point.y - this.y;
1164
1165  		return Math.sqrt(x * x + y * y);
1166  	},
1167
1168  	// @method equals(otherPoint: Point): Boolean
1169  	// Returns `true` if the given point has the same coordinates.
1170  	equals: function (point) {
1171  		point = toPoint(point);
1172
1173  		return point.x === this.x &&
1174  		       point.y === this.y;
1175  	},
1176
1177  	// @method contains(otherPoint: Point): Boolean
1178  	// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
1179  	contains: function (point) {
1180  		point = toPoint(point);
1181
1182  		return Math.abs(point.x) <= Math.abs(this.x) &&
1183  		       Math.abs(point.y) <= Math.abs(this.y);
1184  	},
1185
1186  	// @method toString(): String
1187  	// Returns a string representation of the point for debugging purposes.
1188  	toString: function () {
1189  		return 'Point(' +
1190  		        formatNum(this.x) + ', ' +
1191  		        formatNum(this.y) + ')';
1192  	}
1193  };
1194
1195  // @factory L.point(x: Number, y: Number, round?: Boolean)
1196  // Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.
1197
1198  // @alternative
1199  // @factory L.point(coords: Number[])
1200  // Expects an array of the form `[x, y]` instead.
1201
1202  // @alternative
1203  // @factory L.point(coords: Object)
1204  // Expects a plain object of the form `{x: Number, y: Number}` instead.
1205  function toPoint(x, y, round) {
1206  	if (x instanceof Point) {
1207  		return x;
1208  	}
1209  	if (isArray(x)) {
1210  		return new Point(x[0], x[1]);
1211  	}
1212  	if (x === undefined || x === null) {
1213  		return x;
1214  	}
1215  	if (typeof x === 'object' && 'x' in x && 'y' in x) {
1216  		return new Point(x.x, x.y);
1217  	}
1218  	return new Point(x, y, round);
1219  }
1220
1221  /*
1222   * @class Bounds
1223   * @aka L.Bounds
1224   *
1225   * Represents a rectangular area in pixel coordinates.
1226   *
1227   * @example
1228   *
1229   * ```js
1230   * var p1 = L.point(10, 10),
1231   * p2 = L.point(40, 60),
1232   * bounds = L.bounds(p1, p2);
1233   * ```
1234   *
1235   * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
1236   *
1237   * ```js
1238   * otherBounds.intersects([[10, 10], [40, 60]]);
1239   * ```
1240   *
1241   * Note that `Bounds` does not inherit from Leaflet's `Class` object,
1242   * which means new classes can't inherit from it, and new methods
1243   * can't be added to it with the `include` function.
1244   */
1245
1246  function Bounds(a, b) {
1247  	if (!a) { return; }
1248
1249  	var points = b ? [a, b] : a;
1250
1251  	for (var i = 0, len = points.length; i < len; i++) {
1252  		this.extend(points[i]);
1253  	}
1254  }
1255
1256  Bounds.prototype = {
1257  	// @method extend(point: Point): this
1258  	// Extends the bounds to contain the given point.
1259
1260  	// @alternative
1261  	// @method extend(otherBounds: Bounds): this
1262  	// Extend the bounds to contain the given bounds
1263  	extend: function (obj) {
1264  		var min2, max2;
1265  		if (!obj) { return this; }
1266
1267  		if (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) {
1268  			min2 = max2 = toPoint(obj);
1269  		} else {
1270  			obj = toBounds(obj);
1271  			min2 = obj.min;
1272  			max2 = obj.max;
1273
1274  			if (!min2 || !max2) { return this; }
1275  		}
1276
1277  		// @property min: Point
1278  		// The top left corner of the rectangle.
1279  		// @property max: Point
1280  		// The bottom right corner of the rectangle.
1281  		if (!this.min && !this.max) {
1282  			this.min = min2.clone();
1283  			this.max = max2.clone();
1284  		} else {
1285  			this.min.x = Math.min(min2.x, this.min.x);
1286  			this.max.x = Math.max(max2.x, this.max.x);
1287  			this.min.y = Math.min(min2.y, this.min.y);
1288  			this.max.y = Math.max(max2.y, this.max.y);
1289  		}
1290  		return this;
1291  	},
1292
1293  	// @method getCenter(round?: Boolean): Point
1294  	// Returns the center point of the bounds.
1295  	getCenter: function (round) {
1296  		return toPoint(
1297  		        (this.min.x + this.max.x) / 2,
1298  		        (this.min.y + this.max.y) / 2, round);
1299  	},
1300
1301  	// @method getBottomLeft(): Point
1302  	// Returns the bottom-left point of the bounds.
1303  	getBottomLeft: function () {
1304  		return toPoint(this.min.x, this.max.y);
1305  	},
1306
1307  	// @method getTopRight(): Point
1308  	// Returns the top-right point of the bounds.
1309  	getTopRight: function () { // -> Point
1310  		return toPoint(this.max.x, this.min.y);
1311  	},
1312
1313  	// @method getTopLeft(): Point
1314  	// Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)).
1315  	getTopLeft: function () {
1316  		return this.min; // left, top
1317  	},
1318
1319  	// @method getBottomRight(): Point
1320  	// Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)).
1321  	getBottomRight: function () {
1322  		return this.max; // right, bottom
1323  	},
1324
1325  	// @method getSize(): Point
1326  	// Returns the size of the given bounds
1327  	getSize: function () {
1328  		return this.max.subtract(this.min);
1329  	},
1330
1331  	// @method contains(otherBounds: Bounds): Boolean
1332  	// Returns `true` if the rectangle contains the given one.
1333  	// @alternative
1334  	// @method contains(point: Point): Boolean
1335  	// Returns `true` if the rectangle contains the given point.
1336  	contains: function (obj) {
1337  		var min, max;
1338
1339  		if (typeof obj[0] === 'number' || obj instanceof Point) {
1340  			obj = toPoint(obj);
1341  		} else {
1342  			obj = toBounds(obj);
1343  		}
1344
1345  		if (obj instanceof Bounds) {
1346  			min = obj.min;
1347  			max = obj.max;
1348  		} else {
1349  			min = max = obj;
1350  		}
1351
1352  		return (min.x >= this.min.x) &&
1353  		       (max.x <= this.max.x) &&
1354  		       (min.y >= this.min.y) &&
1355  		       (max.y <= this.max.y);
1356  	},
1357
1358  	// @method intersects(otherBounds: Bounds): Boolean
1359  	// Returns `true` if the rectangle intersects the given bounds. Two bounds
1360  	// intersect if they have at least one point in common.
1361  	intersects: function (bounds) { // (Bounds) -> Boolean
1362  		bounds = toBounds(bounds);
1363
1364  		var min = this.min,
1365  		    max = this.max,
1366  		    min2 = bounds.min,
1367  		    max2 = bounds.max,
1368  		    xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
1369  		    yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
1370
1371  		return xIntersects && yIntersects;
1372  	},
1373
1374  	// @method overlaps(otherBounds: Bounds): Boolean
1375  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds
1376  	// overlap if their intersection is an area.
1377  	overlaps: function (bounds) { // (Bounds) -> Boolean
1378  		bounds = toBounds(bounds);
1379
1380  		var min = this.min,
1381  		    max = this.max,
1382  		    min2 = bounds.min,
1383  		    max2 = bounds.max,
1384  		    xOverlaps = (max2.x > min.x) && (min2.x < max.x),
1385  		    yOverlaps = (max2.y > min.y) && (min2.y < max.y);
1386
1387  		return xOverlaps && yOverlaps;
1388  	},
1389
1390  	// @method isValid(): Boolean
1391  	// Returns `true` if the bounds are properly initialized.
1392  	isValid: function () {
1393  		return !!(this.min && this.max);
1394  	},
1395
1396
1397  	// @method pad(bufferRatio: Number): Bounds
1398  	// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1399  	// For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1400  	// Negative values will retract the bounds.
1401  	pad: function (bufferRatio) {
1402  		var min = this.min,
1403  		max = this.max,
1404  		heightBuffer = Math.abs(min.x - max.x) * bufferRatio,
1405  		widthBuffer = Math.abs(min.y - max.y) * bufferRatio;
1406
1407
1408  		return toBounds(
1409  			toPoint(min.x - heightBuffer, min.y - widthBuffer),
1410  			toPoint(max.x + heightBuffer, max.y + widthBuffer));
1411  	},
1412
1413
1414  	// @method equals(otherBounds: Bounds): Boolean
1415  	// Returns `true` if the rectangle is equivalent to the given bounds.
1416  	equals: function (bounds) {
1417  		if (!bounds) { return false; }
1418
1419  		bounds = toBounds(bounds);
1420
1421  		return this.min.equals(bounds.getTopLeft()) &&
1422  			this.max.equals(bounds.getBottomRight());
1423  	},
1424  };
1425
1426
1427  // @factory L.bounds(corner1: Point, corner2: Point)
1428  // Creates a Bounds object from two corners coordinate pairs.
1429  // @alternative
1430  // @factory L.bounds(points: Point[])
1431  // Creates a Bounds object from the given array of points.
1432  function toBounds(a, b) {
1433  	if (!a || a instanceof Bounds) {
1434  		return a;
1435  	}
1436  	return new Bounds(a, b);
1437  }
1438
1439  /*
1440   * @class LatLngBounds
1441   * @aka L.LatLngBounds
1442   *
1443   * Represents a rectangular geographical area on a map.
1444   *
1445   * @example
1446   *
1447   * ```js
1448   * var corner1 = L.latLng(40.712, -74.227),
1449   * corner2 = L.latLng(40.774, -74.125),
1450   * bounds = L.latLngBounds(corner1, corner2);
1451   * ```
1452   *
1453   * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
1454   *
1455   * ```js
1456   * map.fitBounds([
1457   * 	[40.712, -74.227],
1458   * 	[40.774, -74.125]
1459   * ]);
1460   * ```
1461   *
1462   * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.
1463   *
1464   * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object,
1465   * which means new classes can't inherit from it, and new methods
1466   * can't be added to it with the `include` function.
1467   */
1468
1469  function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
1470  	if (!corner1) { return; }
1471
1472  	var latlngs = corner2 ? [corner1, corner2] : corner1;
1473
1474  	for (var i = 0, len = latlngs.length; i < len; i++) {
1475  		this.extend(latlngs[i]);
1476  	}
1477  }
1478
1479  LatLngBounds.prototype = {
1480
1481  	// @method extend(latlng: LatLng): this
1482  	// Extend the bounds to contain the given point
1483
1484  	// @alternative
1485  	// @method extend(otherBounds: LatLngBounds): this
1486  	// Extend the bounds to contain the given bounds
1487  	extend: function (obj) {
1488  		var sw = this._southWest,
1489  		    ne = this._northEast,
1490  		    sw2, ne2;
1491
1492  		if (obj instanceof LatLng) {
1493  			sw2 = obj;
1494  			ne2 = obj;
1495
1496  		} else if (obj instanceof LatLngBounds) {
1497  			sw2 = obj._southWest;
1498  			ne2 = obj._northEast;
1499
1500  			if (!sw2 || !ne2) { return this; }
1501
1502  		} else {
1503  			return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this;
1504  		}
1505
1506  		if (!sw && !ne) {
1507  			this._southWest = new LatLng(sw2.lat, sw2.lng);
1508  			this._northEast = new LatLng(ne2.lat, ne2.lng);
1509  		} else {
1510  			sw.lat = Math.min(sw2.lat, sw.lat);
1511  			sw.lng = Math.min(sw2.lng, sw.lng);
1512  			ne.lat = Math.max(ne2.lat, ne.lat);
1513  			ne.lng = Math.max(ne2.lng, ne.lng);
1514  		}
1515
1516  		return this;
1517  	},
1518
1519  	// @method pad(bufferRatio: Number): LatLngBounds
1520  	// Returns bounds created by extending or retracting the current bounds by a given ratio in each direction.
1521  	// For example, a ratio of 0.5 extends the bounds by 50% in each direction.
1522  	// Negative values will retract the bounds.
1523  	pad: function (bufferRatio) {
1524  		var sw = this._southWest,
1525  		    ne = this._northEast,
1526  		    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
1527  		    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
1528
1529  		return new LatLngBounds(
1530  		        new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
1531  		        new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
1532  	},
1533
1534  	// @method getCenter(): LatLng
1535  	// Returns the center point of the bounds.
1536  	getCenter: function () {
1537  		return new LatLng(
1538  		        (this._southWest.lat + this._northEast.lat) / 2,
1539  		        (this._southWest.lng + this._northEast.lng) / 2);
1540  	},
1541
1542  	// @method getSouthWest(): LatLng
1543  	// Returns the south-west point of the bounds.
1544  	getSouthWest: function () {
1545  		return this._southWest;
1546  	},
1547
1548  	// @method getNorthEast(): LatLng
1549  	// Returns the north-east point of the bounds.
1550  	getNorthEast: function () {
1551  		return this._northEast;
1552  	},
1553
1554  	// @method getNorthWest(): LatLng
1555  	// Returns the north-west point of the bounds.
1556  	getNorthWest: function () {
1557  		return new LatLng(this.getNorth(), this.getWest());
1558  	},
1559
1560  	// @method getSouthEast(): LatLng
1561  	// Returns the south-east point of the bounds.
1562  	getSouthEast: function () {
1563  		return new LatLng(this.getSouth(), this.getEast());
1564  	},
1565
1566  	// @method getWest(): Number
1567  	// Returns the west longitude of the bounds
1568  	getWest: function () {
1569  		return this._southWest.lng;
1570  	},
1571
1572  	// @method getSouth(): Number
1573  	// Returns the south latitude of the bounds
1574  	getSouth: function () {
1575  		return this._southWest.lat;
1576  	},
1577
1578  	// @method getEast(): Number
1579  	// Returns the east longitude of the bounds
1580  	getEast: function () {
1581  		return this._northEast.lng;
1582  	},
1583
1584  	// @method getNorth(): Number
1585  	// Returns the north latitude of the bounds
1586  	getNorth: function () {
1587  		return this._northEast.lat;
1588  	},
1589
1590  	// @method contains(otherBounds: LatLngBounds): Boolean
1591  	// Returns `true` if the rectangle contains the given one.
1592
1593  	// @alternative
1594  	// @method contains (latlng: LatLng): Boolean
1595  	// Returns `true` if the rectangle contains the given point.
1596  	contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
1597  		if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) {
1598  			obj = toLatLng(obj);
1599  		} else {
1600  			obj = toLatLngBounds(obj);
1601  		}
1602
1603  		var sw = this._southWest,
1604  		    ne = this._northEast,
1605  		    sw2, ne2;
1606
1607  		if (obj instanceof LatLngBounds) {
1608  			sw2 = obj.getSouthWest();
1609  			ne2 = obj.getNorthEast();
1610  		} else {
1611  			sw2 = ne2 = obj;
1612  		}
1613
1614  		return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
1615  		       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
1616  	},
1617
1618  	// @method intersects(otherBounds: LatLngBounds): Boolean
1619  	// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
1620  	intersects: function (bounds) {
1621  		bounds = toLatLngBounds(bounds);
1622
1623  		var sw = this._southWest,
1624  		    ne = this._northEast,
1625  		    sw2 = bounds.getSouthWest(),
1626  		    ne2 = bounds.getNorthEast(),
1627
1628  		    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
1629  		    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
1630
1631  		return latIntersects && lngIntersects;
1632  	},
1633
1634  	// @method overlaps(otherBounds: LatLngBounds): Boolean
1635  	// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
1636  	overlaps: function (bounds) {
1637  		bounds = toLatLngBounds(bounds);
1638
1639  		var sw = this._southWest,
1640  		    ne = this._northEast,
1641  		    sw2 = bounds.getSouthWest(),
1642  		    ne2 = bounds.getNorthEast(),
1643
1644  		    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
1645  		    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
1646
1647  		return latOverlaps && lngOverlaps;
1648  	},
1649
1650  	// @method toBBoxString(): String
1651  	// Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
1652  	toBBoxString: function () {
1653  		return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
1654  	},
1655
1656  	// @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean
1657  	// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number.
1658  	equals: function (bounds, maxMargin) {
1659  		if (!bounds) { return false; }
1660
1661  		bounds = toLatLngBounds(bounds);
1662
1663  		return this._southWest.equals(bounds.getSouthWest(), maxMargin) &&
1664  		       this._northEast.equals(bounds.getNorthEast(), maxMargin);
1665  	},
1666
1667  	// @method isValid(): Boolean
1668  	// Returns `true` if the bounds are properly initialized.
1669  	isValid: function () {
1670  		return !!(this._southWest && this._northEast);
1671  	}
1672  };
1673
1674  // TODO International date line?
1675
1676  // @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
1677  // Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
1678
1679  // @alternative
1680  // @factory L.latLngBounds(latlngs: LatLng[])
1681  // Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
1682  function toLatLngBounds(a, b) {
1683  	if (a instanceof LatLngBounds) {
1684  		return a;
1685  	}
1686  	return new LatLngBounds(a, b);
1687  }
1688
1689  /* @class LatLng
1690   * @aka L.LatLng
1691   *
1692   * Represents a geographical point with a certain latitude and longitude.
1693   *
1694   * @example
1695   *
1696   * ```
1697   * var latlng = L.latLng(50.5, 30.5);
1698   * ```
1699   *
1700   * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:
1701   *
1702   * ```
1703   * map.panTo([50, 30]);
1704   * map.panTo({lon: 30, lat: 50});
1705   * map.panTo({lat: 50, lng: 30});
1706   * map.panTo(L.latLng(50, 30));
1707   * ```
1708   *
1709   * Note that `LatLng` does not inherit from Leaflet's `Class` object,
1710   * which means new classes can't inherit from it, and new methods
1711   * can't be added to it with the `include` function.
1712   */
1713
1714  function LatLng(lat, lng, alt) {
1715  	if (isNaN(lat) || isNaN(lng)) {
1716  		throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
1717  	}
1718
1719  	// @property lat: Number
1720  	// Latitude in degrees
1721  	this.lat = +lat;
1722
1723  	// @property lng: Number
1724  	// Longitude in degrees
1725  	this.lng = +lng;
1726
1727  	// @property alt: Number
1728  	// Altitude in meters (optional)
1729  	if (alt !== undefined) {
1730  		this.alt = +alt;
1731  	}
1732  }
1733
1734  LatLng.prototype = {
1735  	// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
1736  	// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number.
1737  	equals: function (obj, maxMargin) {
1738  		if (!obj) { return false; }
1739
1740  		obj = toLatLng(obj);
1741
1742  		var margin = Math.max(
1743  		        Math.abs(this.lat - obj.lat),
1744  		        Math.abs(this.lng - obj.lng));
1745
1746  		return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
1747  	},
1748
1749  	// @method toString(): String
1750  	// Returns a string representation of the point (for debugging purposes).
1751  	toString: function (precision) {
1752  		return 'LatLng(' +
1753  		        formatNum(this.lat, precision) + ', ' +
1754  		        formatNum(this.lng, precision) + ')';
1755  	},
1756
1757  	// @method distanceTo(otherLatLng: LatLng): Number
1758  	// Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines).
1759  	distanceTo: function (other) {
1760  		return Earth.distance(this, toLatLng(other));
1761  	},
1762
1763  	// @method wrap(): LatLng
1764  	// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
1765  	wrap: function () {
1766  		return Earth.wrapLatLng(this);
1767  	},
1768
1769  	// @method toBounds(sizeInMeters: Number): LatLngBounds
1770  	// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
1771  	toBounds: function (sizeInMeters) {
1772  		var latAccuracy = 180 * sizeInMeters / 40075017,
1773  		    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
1774
1775  		return toLatLngBounds(
1776  		        [this.lat - latAccuracy, this.lng - lngAccuracy],
1777  		        [this.lat + latAccuracy, this.lng + lngAccuracy]);
1778  	},
1779
1780  	clone: function () {
1781  		return new LatLng(this.lat, this.lng, this.alt);
1782  	}
1783  };
1784
1785
1786
1787  // @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
1788  // Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
1789
1790  // @alternative
1791  // @factory L.latLng(coords: Array): LatLng
1792  // Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
1793
1794  // @alternative
1795  // @factory L.latLng(coords: Object): LatLng
1796  // Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
1797
1798  function toLatLng(a, b, c) {
1799  	if (a instanceof LatLng) {
1800  		return a;
1801  	}
1802  	if (isArray(a) && typeof a[0] !== 'object') {
1803  		if (a.length === 3) {
1804  			return new LatLng(a[0], a[1], a[2]);
1805  		}
1806  		if (a.length === 2) {
1807  			return new LatLng(a[0], a[1]);
1808  		}
1809  		return null;
1810  	}
1811  	if (a === undefined || a === null) {
1812  		return a;
1813  	}
1814  	if (typeof a === 'object' && 'lat' in a) {
1815  		return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
1816  	}
1817  	if (b === undefined) {
1818  		return null;
1819  	}
1820  	return new LatLng(a, b, c);
1821  }
1822
1823  /*
1824   * @namespace CRS
1825   * @crs L.CRS.Base
1826   * Object that defines coordinate reference systems for projecting
1827   * geographical points into pixel (screen) coordinates and back (and to
1828   * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
1829   * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system).
1830   *
1831   * Leaflet defines the most usual CRSs by default. If you want to use a
1832   * CRS not defined by default, take a look at the
1833   * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
1834   *
1835   * Note that the CRS instances do not inherit from Leaflet's `Class` object,
1836   * and can't be instantiated. Also, new classes can't inherit from them,
1837   * and methods can't be added to them with the `include` function.
1838   */
1839
1840  var CRS = {
1841  	// @method latLngToPoint(latlng: LatLng, zoom: Number): Point
1842  	// Projects geographical coordinates into pixel coordinates for a given zoom.
1843  	latLngToPoint: function (latlng, zoom) {
1844  		var projectedPoint = this.projection.project(latlng),
1845  		    scale = this.scale(zoom);
1846
1847  		return this.transformation._transform(projectedPoint, scale);
1848  	},
1849
1850  	// @method pointToLatLng(point: Point, zoom: Number): LatLng
1851  	// The inverse of `latLngToPoint`. Projects pixel coordinates on a given
1852  	// zoom into geographical coordinates.
1853  	pointToLatLng: function (point, zoom) {
1854  		var scale = this.scale(zoom),
1855  		    untransformedPoint = this.transformation.untransform(point, scale);
1856
1857  		return this.projection.unproject(untransformedPoint);
1858  	},
1859
1860  	// @method project(latlng: LatLng): Point
1861  	// Projects geographical coordinates into coordinates in units accepted for
1862  	// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
1863  	project: function (latlng) {
1864  		return this.projection.project(latlng);
1865  	},
1866
1867  	// @method unproject(point: Point): LatLng
1868  	// Given a projected coordinate returns the corresponding LatLng.
1869  	// The inverse of `project`.
1870  	unproject: function (point) {
1871  		return this.projection.unproject(point);
1872  	},
1873
1874  	// @method scale(zoom: Number): Number
1875  	// Returns the scale used when transforming projected coordinates into
1876  	// pixel coordinates for a particular zoom. For example, it returns
1877  	// `256 * 2^zoom` for Mercator-based CRS.
1878  	scale: function (zoom) {
1879  		return 256 * Math.pow(2, zoom);
1880  	},
1881
1882  	// @method zoom(scale: Number): Number
1883  	// Inverse of `scale()`, returns the zoom level corresponding to a scale
1884  	// factor of `scale`.
1885  	zoom: function (scale) {
1886  		return Math.log(scale / 256) / Math.LN2;
1887  	},
1888
1889  	// @method getProjectedBounds(zoom: Number): Bounds
1890  	// Returns the projection's bounds scaled and transformed for the provided `zoom`.
1891  	getProjectedBounds: function (zoom) {
1892  		if (this.infinite) { return null; }
1893
1894  		var b = this.projection.bounds,
1895  		    s = this.scale(zoom),
1896  		    min = this.transformation.transform(b.min, s),
1897  		    max = this.transformation.transform(b.max, s);
1898
1899  		return new Bounds(min, max);
1900  	},
1901
1902  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
1903  	// Returns the distance between two geographical coordinates.
1904
1905  	// @property code: String
1906  	// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
1907  	//
1908  	// @property wrapLng: Number[]
1909  	// An array of two numbers defining whether the longitude (horizontal) coordinate
1910  	// axis wraps around a given range and how. Defaults to `[-180, 180]` in most
1911  	// geographical CRSs. If `undefined`, the longitude axis does not wrap around.
1912  	//
1913  	// @property wrapLat: Number[]
1914  	// Like `wrapLng`, but for the latitude (vertical) axis.
1915
1916  	// wrapLng: [min, max],
1917  	// wrapLat: [min, max],
1918
1919  	// @property infinite: Boolean
1920  	// If true, the coordinate space will be unbounded (infinite in both axes)
1921  	infinite: false,
1922
1923  	// @method wrapLatLng(latlng: LatLng): LatLng
1924  	// Returns a `LatLng` where lat and lng has been wrapped according to the
1925  	// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
1926  	wrapLatLng: function (latlng) {
1927  		var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
1928  		    lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
1929  		    alt = latlng.alt;
1930
1931  		return new LatLng(lat, lng, alt);
1932  	},
1933
1934  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
1935  	// Returns a `LatLngBounds` with the same size as the given one, ensuring
1936  	// that its center is within the CRS's bounds.
1937  	// Only accepts actual `L.LatLngBounds` instances, not arrays.
1938  	wrapLatLngBounds: function (bounds) {
1939  		var center = bounds.getCenter(),
1940  		    newCenter = this.wrapLatLng(center),
1941  		    latShift = center.lat - newCenter.lat,
1942  		    lngShift = center.lng - newCenter.lng;
1943
1944  		if (latShift === 0 && lngShift === 0) {
1945  			return bounds;
1946  		}
1947
1948  		var sw = bounds.getSouthWest(),
1949  		    ne = bounds.getNorthEast(),
1950  		    newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift),
1951  		    newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift);
1952
1953  		return new LatLngBounds(newSw, newNe);
1954  	}
1955  };
1956
1957  /*
1958   * @namespace CRS
1959   * @crs L.CRS.Earth
1960   *
1961   * Serves as the base for CRS that are global such that they cover the earth.
1962   * Can only be used as the base for other CRS and cannot be used directly,
1963   * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
1964   * meters.
1965   */
1966
1967  var Earth = extend({}, CRS, {
1968  	wrapLng: [-180, 180],
1969
1970  	// Mean Earth Radius, as recommended for use by
1971  	// the International Union of Geodesy and Geophysics,
1972  	// see https://rosettacode.org/wiki/Haversine_formula
1973  	R: 6371000,
1974
1975  	// distance between two geographical points using spherical law of cosines approximation
1976  	distance: function (latlng1, latlng2) {
1977  		var rad = Math.PI / 180,
1978  		    lat1 = latlng1.lat * rad,
1979  		    lat2 = latlng2.lat * rad,
1980  		    sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2),
1981  		    sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2),
1982  		    a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon,
1983  		    c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
1984  		return this.R * c;
1985  	}
1986  });
1987
1988  /*
1989   * @namespace Projection
1990   * @projection L.Projection.SphericalMercator
1991   *
1992   * Spherical Mercator projection — the most common projection for online maps,
1993   * used by almost all free and commercial tile providers. Assumes that Earth is
1994   * a sphere. Used by the `EPSG:3857` CRS.
1995   */
1996
1997  var earthRadius = 6378137;
1998
1999  var SphericalMercator = {
2000
2001  	R: earthRadius,
2002  	MAX_LATITUDE: 85.0511287798,
2003
2004  	project: function (latlng) {
2005  		var d = Math.PI / 180,
2006  		    max = this.MAX_LATITUDE,
2007  		    lat = Math.max(Math.min(max, latlng.lat), -max),
2008  		    sin = Math.sin(lat * d);
2009
2010  		return new Point(
2011  			this.R * latlng.lng * d,
2012  			this.R * Math.log((1 + sin) / (1 - sin)) / 2);
2013  	},
2014
2015  	unproject: function (point) {
2016  		var d = 180 / Math.PI;
2017
2018  		return new LatLng(
2019  			(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
2020  			point.x * d / this.R);
2021  	},
2022
2023  	bounds: (function () {
2024  		var d = earthRadius * Math.PI;
2025  		return new Bounds([-d, -d], [d, d]);
2026  	})()
2027  };
2028
2029  /*
2030   * @class Transformation
2031   * @aka L.Transformation
2032   *
2033   * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
2034   * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
2035   * the reverse. Used by Leaflet in its projections code.
2036   *
2037   * @example
2038   *
2039   * ```js
2040   * var transformation = L.transformation(2, 5, -1, 10),
2041   * 	p = L.point(1, 2),
2042   * 	p2 = transformation.transform(p), //  L.point(7, 8)
2043   * 	p3 = transformation.untransform(p2); //  L.point(1, 2)
2044   * ```
2045   */
2046
2047
2048  // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
2049  // Creates a `Transformation` object with the given coefficients.
2050  function Transformation(a, b, c, d) {
2051  	if (isArray(a)) {
2052  		// use array properties
2053  		this._a = a[0];
2054  		this._b = a[1];
2055  		this._c = a[2];
2056  		this._d = a[3];
2057  		return;
2058  	}
2059  	this._a = a;
2060  	this._b = b;
2061  	this._c = c;
2062  	this._d = d;
2063  }
2064
2065  Transformation.prototype = {
2066  	// @method transform(point: Point, scale?: Number): Point
2067  	// Returns a transformed point, optionally multiplied by the given scale.
2068  	// Only accepts actual `L.Point` instances, not arrays.
2069  	transform: function (point, scale) { // (Point, Number) -> Point
2070  		return this._transform(point.clone(), scale);
2071  	},
2072
2073  	// destructive transform (faster)
2074  	_transform: function (point, scale) {
2075  		scale = scale || 1;
2076  		point.x = scale * (this._a * point.x + this._b);
2077  		point.y = scale * (this._c * point.y + this._d);
2078  		return point;
2079  	},
2080
2081  	// @method untransform(point: Point, scale?: Number): Point
2082  	// Returns the reverse transformation of the given point, optionally divided
2083  	// by the given scale. Only accepts actual `L.Point` instances, not arrays.
2084  	untransform: function (point, scale) {
2085  		scale = scale || 1;
2086  		return new Point(
2087  		        (point.x / scale - this._b) / this._a,
2088  		        (point.y / scale - this._d) / this._c);
2089  	}
2090  };
2091
2092  // factory L.transformation(a: Number, b: Number, c: Number, d: Number)
2093
2094  // @factory L.transformation(a: Number, b: Number, c: Number, d: Number)
2095  // Instantiates a Transformation object with the given coefficients.
2096
2097  // @alternative
2098  // @factory L.transformation(coefficients: Array): Transformation
2099  // Expects an coefficients array of the form
2100  // `[a: Number, b: Number, c: Number, d: Number]`.
2101
2102  function toTransformation(a, b, c, d) {
2103  	return new Transformation(a, b, c, d);
2104  }
2105
2106  /*
2107   * @namespace CRS
2108   * @crs L.CRS.EPSG3857
2109   *
2110   * The most common CRS for online maps, used by almost all free and commercial
2111   * tile providers. Uses Spherical Mercator projection. Set in by default in
2112   * Map's `crs` option.
2113   */
2114
2115  var EPSG3857 = extend({}, Earth, {
2116  	code: 'EPSG:3857',
2117  	projection: SphericalMercator,
2118
2119  	transformation: (function () {
2120  		var scale = 0.5 / (Math.PI * SphericalMercator.R);
2121  		return toTransformation(scale, 0.5, -scale, 0.5);
2122  	}())
2123  });
2124
2125  var EPSG900913 = extend({}, EPSG3857, {
2126  	code: 'EPSG:900913'
2127  });
2128
2129  // @namespace SVG; @section
2130  // There are several static functions which can be called without instantiating L.SVG:
2131
2132  // @function create(name: String): SVGElement
2133  // Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
2134  // corresponding to the class name passed. For example, using 'line' will return
2135  // an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
2136  function svgCreate(name) {
2137  	return document.createElementNS('http://www.w3.org/2000/svg', name);
2138  }
2139
2140  // @function pointsToPath(rings: Point[], closed: Boolean): String
2141  // Generates a SVG path string for multiple rings, with each ring turning
2142  // into "M..L..L.." instructions
2143  function pointsToPath(rings, closed) {
2144  	var str = '',
2145  	i, j, len, len2, points, p;
2146
2147  	for (i = 0, len = rings.length; i < len; i++) {
2148  		points = rings[i];
2149
2150  		for (j = 0, len2 = points.length; j < len2; j++) {
2151  			p = points[j];
2152  			str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
2153  		}
2154
2155  		// closes the ring for polygons; "x" is VML syntax
2156  		str += closed ? (Browser.svg ? 'z' : 'x') : '';
2157  	}
2158
2159  	// SVG complains about empty path strings
2160  	return str || 'M0 0';
2161  }
2162
2163  /*
2164   * @namespace Browser
2165   * @aka L.Browser
2166   *
2167   * A namespace with static properties for browser/feature detection used by Leaflet internally.
2168   *
2169   * @example
2170   *
2171   * ```js
2172   * if (L.Browser.ielt9) {
2173   *   alert('Upgrade your browser, dude!');
2174   * }
2175   * ```
2176   */
2177
2178  var style = document.documentElement.style;
2179
2180  // @property ie: Boolean; `true` for all Internet Explorer versions (not Edge).
2181  var ie = 'ActiveXObject' in window;
2182
2183  // @property ielt9: Boolean; `true` for Internet Explorer versions less than 9.
2184  var ielt9 = ie && !document.addEventListener;
2185
2186  // @property edge: Boolean; `true` for the Edge web browser.
2187  var edge = 'msLaunchUri' in navigator && !('documentMode' in document);
2188
2189  // @property webkit: Boolean;
2190  // `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
2191  var webkit = userAgentContains('webkit');
2192
2193  // @property android: Boolean
2194  // **Deprecated.** `true` for any browser running on an Android platform.
2195  var android = userAgentContains('android');
2196
2197  // @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3.
2198  var android23 = userAgentContains('android 2') || userAgentContains('android 3');
2199
2200  /* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */
2201  var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit
2202  // @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome)
2203  var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window);
2204
2205  // @property opera: Boolean; `true` for the Opera browser
2206  var opera = !!window.opera;
2207
2208  // @property chrome: Boolean; `true` for the Chrome browser.
2209  var chrome = !edge && userAgentContains('chrome');
2210
2211  // @property gecko: Boolean; `true` for gecko-based browsers like Firefox.
2212  var gecko = userAgentContains('gecko') && !webkit && !opera && !ie;
2213
2214  // @property safari: Boolean; `true` for the Safari browser.
2215  var safari = !chrome && userAgentContains('safari');
2216
2217  var phantom = userAgentContains('phantom');
2218
2219  // @property opera12: Boolean
2220  // `true` for the Opera browser supporting CSS transforms (version 12 or later).
2221  var opera12 = 'OTransition' in style;
2222
2223  // @property win: Boolean; `true` when the browser is running in a Windows platform
2224  var win = navigator.platform.indexOf('Win') === 0;
2225
2226  // @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms.
2227  var ie3d = ie && ('transition' in style);
2228
2229  // @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms.
2230  var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23;
2231
2232  // @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms.
2233  var gecko3d = 'MozPerspective' in style;
2234
2235  // @property any3d: Boolean
2236  // `true` for all browsers supporting CSS transforms.
2237  var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom;
2238
2239  // @property mobile: Boolean; `true` for all browsers running in a mobile device.
2240  var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile');
2241
2242  // @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device.
2243  var mobileWebkit = mobile && webkit;
2244
2245  // @property mobileWebkit3d: Boolean
2246  // `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
2247  var mobileWebkit3d = mobile && webkit3d;
2248
2249  // @property msPointer: Boolean
2250  // `true` for browsers implementing the Microsoft touch events model (notably IE10).
2251  var msPointer = !window.PointerEvent && window.MSPointerEvent;
2252
2253  // @property pointer: Boolean
2254  // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
2255  var pointer = !!(window.PointerEvent || msPointer);
2256
2257  // @property touchNative: Boolean
2258  // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
2259  // **This does not necessarily mean** that the browser is running in a computer with
2260  // a touchscreen, it only means that the browser is capable of understanding
2261  // touch events.
2262  var touchNative = 'ontouchstart' in window || !!window.TouchEvent;
2263
2264  // @property touch: Boolean
2265  // `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events.
2266  // Note: pointer events will be preferred (if available), and processed for all `touch*` listeners.
2267  var touch = !window.L_NO_TOUCH && (touchNative || pointer);
2268
2269  // @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device.
2270  var mobileOpera = mobile && opera;
2271
2272  // @property mobileGecko: Boolean
2273  // `true` for gecko-based browsers running in a mobile device.
2274  var mobileGecko = mobile && gecko;
2275
2276  // @property retina: Boolean
2277  // `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%.
2278  var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1;
2279
2280  // @property passiveEvents: Boolean
2281  // `true` for browsers that support passive events.
2282  var passiveEvents = (function () {
2283  	var supportsPassiveOption = false;
2284  	try {
2285  		var opts = Object.defineProperty({}, 'passive', {
2286  			get: function () { // eslint-disable-line getter-return
2287  				supportsPassiveOption = true;
2288  			}
2289  		});
2290  		window.addEventListener('testPassiveEventSupport', falseFn, opts);
2291  		window.removeEventListener('testPassiveEventSupport', falseFn, opts);
2292  	} catch (e) {
2293  		// Errors can safely be ignored since this is only a browser support test.
2294  	}
2295  	return supportsPassiveOption;
2296  }());
2297
2298  // @property canvas: Boolean
2299  // `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
2300  var canvas$1 = (function () {
2301  	return !!document.createElement('canvas').getContext;
2302  }());
2303
2304  // @property svg: Boolean
2305  // `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
2306  var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect);
2307
2308  var inlineSvg = !!svg$1 && (function () {
2309  	var div = document.createElement('div');
2310  	div.innerHTML = '<svg/>';
2311  	return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';
2312  })();
2313
2314  // @property vml: Boolean
2315  // `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
2316  var vml = !svg$1 && (function () {
2317  	try {
2318  		var div = document.createElement('div');
2319  		div.innerHTML = '<v:shape adj="1"/>';
2320
2321  		var shape = div.firstChild;
2322  		shape.style.behavior = 'url(#default#VML)';
2323
2324  		return shape && (typeof shape.adj === 'object');
2325
2326  	} catch (e) {
2327  		return false;
2328  	}
2329  }());
2330
2331
2332  // @property mac: Boolean; `true` when the browser is running in a Mac platform
2333  var mac = navigator.platform.indexOf('Mac') === 0;
2334
2335  // @property mac: Boolean; `true` when the browser is running in a Linux platform
2336  var linux = navigator.platform.indexOf('Linux') === 0;
2337
2338  function userAgentContains(str) {
2339  	return navigator.userAgent.toLowerCase().indexOf(str) >= 0;
2340  }
2341
2342
2343  var Browser = {
2344  	ie: ie,
2345  	ielt9: ielt9,
2346  	edge: edge,
2347  	webkit: webkit,
2348  	android: android,
2349  	android23: android23,
2350  	androidStock: androidStock,
2351  	opera: opera,
2352  	chrome: chrome,
2353  	gecko: gecko,
2354  	safari: safari,
2355  	phantom: phantom,
2356  	opera12: opera12,
2357  	win: win,
2358  	ie3d: ie3d,
2359  	webkit3d: webkit3d,
2360  	gecko3d: gecko3d,
2361  	any3d: any3d,
2362  	mobile: mobile,
2363  	mobileWebkit: mobileWebkit,
2364  	mobileWebkit3d: mobileWebkit3d,
2365  	msPointer: msPointer,
2366  	pointer: pointer,
2367  	touch: touch,
2368  	touchNative: touchNative,
2369  	mobileOpera: mobileOpera,
2370  	mobileGecko: mobileGecko,
2371  	retina: retina,
2372  	passiveEvents: passiveEvents,
2373  	canvas: canvas$1,
2374  	svg: svg$1,
2375  	vml: vml,
2376  	inlineSvg: inlineSvg,
2377  	mac: mac,
2378  	linux: linux
2379  };
2380
2381  /*
2382   * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
2383   */
2384
2385  var POINTER_DOWN =   Browser.msPointer ? 'MSPointerDown'   : 'pointerdown';
2386  var POINTER_MOVE =   Browser.msPointer ? 'MSPointerMove'   : 'pointermove';
2387  var POINTER_UP =     Browser.msPointer ? 'MSPointerUp'     : 'pointerup';
2388  var POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel';
2389  var pEvent = {
2390  	touchstart  : POINTER_DOWN,
2391  	touchmove   : POINTER_MOVE,
2392  	touchend    : POINTER_UP,
2393  	touchcancel : POINTER_CANCEL
2394  };
2395  var handle = {
2396  	touchstart  : _onPointerStart,
2397  	touchmove   : _handlePointer,
2398  	touchend    : _handlePointer,
2399  	touchcancel : _handlePointer
2400  };
2401  var _pointers = {};
2402  var _pointerDocListener = false;
2403
2404  // Provides a touch events wrapper for (ms)pointer events.
2405  // ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
2406
2407  function addPointerListener(obj, type, handler) {
2408  	if (type === 'touchstart') {
2409  		_addPointerDocListener();
2410  	}
2411  	if (!handle[type]) {
2412  		console.warn('wrong event specified:', type);
2413  		return falseFn;
2414  	}
2415  	handler = handle[type].bind(this, handler);
2416  	obj.addEventListener(pEvent[type], handler, false);
2417  	return handler;
2418  }
2419
2420  function removePointerListener(obj, type, handler) {
2421  	if (!pEvent[type]) {
2422  		console.warn('wrong event specified:', type);
2423  		return;
2424  	}
2425  	obj.removeEventListener(pEvent[type], handler, false);
2426  }
2427
2428  function _globalPointerDown(e) {
2429  	_pointers[e.pointerId] = e;
2430  }
2431
2432  function _globalPointerMove(e) {
2433  	if (_pointers[e.pointerId]) {
2434  		_pointers[e.pointerId] = e;
2435  	}
2436  }
2437
2438  function _globalPointerUp(e) {
2439  	delete _pointers[e.pointerId];
2440  }
2441
2442  function _addPointerDocListener() {
2443  	// need to keep track of what pointers and how many are active to provide e.touches emulation
2444  	if (!_pointerDocListener) {
2445  		// we listen document as any drags that end by moving the touch off the screen get fired there
2446  		document.addEventListener(POINTER_DOWN, _globalPointerDown, true);
2447  		document.addEventListener(POINTER_MOVE, _globalPointerMove, true);
2448  		document.addEventListener(POINTER_UP, _globalPointerUp, true);
2449  		document.addEventListener(POINTER_CANCEL, _globalPointerUp, true);
2450
2451  		_pointerDocListener = true;
2452  	}
2453  }
2454
2455  function _handlePointer(handler, e) {
2456  	if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; }
2457
2458  	e.touches = [];
2459  	for (var i in _pointers) {
2460  		e.touches.push(_pointers[i]);
2461  	}
2462  	e.changedTouches = [e];
2463
2464  	handler(e);
2465  }
2466
2467  function _onPointerStart(handler, e) {
2468  	// IE10 specific: MsTouch needs preventDefault. See #2000
2469  	if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) {
2470  		preventDefault(e);
2471  	}
2472  	_handlePointer(handler, e);
2473  }
2474
2475  /*
2476   * Extends the event handling code with double tap support for mobile browsers.
2477   *
2478   * Note: currently most browsers fire native dblclick, with only a few exceptions
2479   * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386)
2480   */
2481
2482  function makeDblclick(event) {
2483  	// in modern browsers `type` cannot be just overridden:
2484  	// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only
2485  	var newEvent = {},
2486  	    prop, i;
2487  	for (i in event) {
2488  		prop = event[i];
2489  		newEvent[i] = prop && prop.bind ? prop.bind(event) : prop;
2490  	}
2491  	event = newEvent;
2492  	newEvent.type = 'dblclick';
2493  	newEvent.detail = 2;
2494  	newEvent.isTrusted = false;
2495  	newEvent._simulated = true; // for debug purposes
2496  	return newEvent;
2497  }
2498
2499  var delay = 200;
2500  function addDoubleTapListener(obj, handler) {
2501  	// Most browsers handle double tap natively
2502  	obj.addEventListener('dblclick', handler);
2503
2504  	// On some platforms the browser doesn't fire native dblclicks for touch events.
2505  	// It seems that in all such cases `detail` property of `click` event is always `1`.
2506  	// So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed.
2507  	var last = 0,
2508  	    detail;
2509  	function simDblclick(e) {
2510  		if (e.detail !== 1) {
2511  			detail = e.detail; // keep in sync to avoid false dblclick in some cases
2512  			return;
2513  		}
2514
2515  		if (e.pointerType === 'mouse' ||
2516  			(e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) {
2517
2518  			return;
2519  		}
2520
2521  		// When clicking on an <input>, the browser generates a click on its
2522  		// <label> (and vice versa) triggering two clicks in quick succession.
2523  		// This ignores clicks on elements which are a label with a 'for'
2524  		// attribute (or children of such a label), but not children of
2525  		// a <input>.
2526  		var path = getPropagationPath(e);
2527  		if (path.some(function (el) {
2528  			return el instanceof HTMLLabelElement && el.attributes.for;
2529  		}) &&
2530  			!path.some(function (el) {
2531  				return (
2532  					el instanceof HTMLInputElement ||
2533  					el instanceof HTMLSelectElement
2534  				);
2535  			})
2536  		) {
2537  			return;
2538  		}
2539
2540  		var now = Date.now();
2541  		if (now - last <= delay) {
2542  			detail++;
2543  			if (detail === 2) {
2544  				handler(makeDblclick(e));
2545  			}
2546  		} else {
2547  			detail = 1;
2548  		}
2549  		last = now;
2550  	}
2551
2552  	obj.addEventListener('click', simDblclick);
2553
2554  	return {
2555  		dblclick: handler,
2556  		simDblclick: simDblclick
2557  	};
2558  }
2559
2560  function removeDoubleTapListener(obj, handlers) {
2561  	obj.removeEventListener('dblclick', handlers.dblclick);
2562  	obj.removeEventListener('click', handlers.simDblclick);
2563  }
2564
2565  /*
2566   * @namespace DomUtil
2567   *
2568   * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
2569   * tree, used by Leaflet internally.
2570   *
2571   * Most functions expecting or returning a `HTMLElement` also work for
2572   * SVG elements. The only difference is that classes refer to CSS classes
2573   * in HTML and SVG classes in SVG.
2574   */
2575
2576
2577  // @property TRANSFORM: String
2578  // Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit).
2579  var TRANSFORM = testProp(
2580  	['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
2581
2582  // webkitTransition comes first because some browser versions that drop vendor prefix don't do
2583  // the same for the transitionend event, in particular the Android 4.1 stock browser
2584
2585  // @property TRANSITION: String
2586  // Vendor-prefixed transition style name.
2587  var TRANSITION = testProp(
2588  	['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
2589
2590  // @property TRANSITION_END: String
2591  // Vendor-prefixed transitionend event name.
2592  var TRANSITION_END =
2593  	TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend';
2594
2595
2596  // @function get(id: String|HTMLElement): HTMLElement
2597  // Returns an element given its DOM id, or returns the element itself
2598  // if it was passed directly.
2599  function get(id) {
2600  	return typeof id === 'string' ? document.getElementById(id) : id;
2601  }
2602
2603  // @function getStyle(el: HTMLElement, styleAttrib: String): String
2604  // Returns the value for a certain style attribute on an element,
2605  // including computed values or values set through CSS.
2606  function getStyle(el, style) {
2607  	var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
2608
2609  	if ((!value || value === 'auto') && document.defaultView) {
2610  		var css = document.defaultView.getComputedStyle(el, null);
2611  		value = css ? css[style] : null;
2612  	}
2613  	return value === 'auto' ? null : value;
2614  }
2615
2616  // @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
2617  // Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
2618  function create$1(tagName, className, container) {
2619  	var el = document.createElement(tagName);
2620  	el.className = className || '';
2621
2622  	if (container) {
2623  		container.appendChild(el);
2624  	}
2625  	return el;
2626  }
2627
2628  // @function remove(el: HTMLElement)
2629  // Removes `el` from its parent element
2630  function remove(el) {
2631  	var parent = el.parentNode;
2632  	if (parent) {
2633  		parent.removeChild(el);
2634  	}
2635  }
2636
2637  // @function empty(el: HTMLElement)
2638  // Removes all of `el`'s children elements from `el`
2639  function empty(el) {
2640  	while (el.firstChild) {
2641  		el.removeChild(el.firstChild);
2642  	}
2643  }
2644
2645  // @function toFront(el: HTMLElement)
2646  // Makes `el` the last child of its parent, so it renders in front of the other children.
2647  function toFront(el) {
2648  	var parent = el.parentNode;
2649  	if (parent && parent.lastChild !== el) {
2650  		parent.appendChild(el);
2651  	}
2652  }
2653
2654  // @function toBack(el: HTMLElement)
2655  // Makes `el` the first child of its parent, so it renders behind the other children.
2656  function toBack(el) {
2657  	var parent = el.parentNode;
2658  	if (parent && parent.firstChild !== el) {
2659  		parent.insertBefore(el, parent.firstChild);
2660  	}
2661  }
2662
2663  // @function hasClass(el: HTMLElement, name: String): Boolean
2664  // Returns `true` if the element's class attribute contains `name`.
2665  function hasClass(el, name) {
2666  	if (el.classList !== undefined) {
2667  		return el.classList.contains(name);
2668  	}
2669  	var className = getClass(el);
2670  	return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
2671  }
2672
2673  // @function addClass(el: HTMLElement, name: String)
2674  // Adds `name` to the element's class attribute.
2675  function addClass(el, name) {
2676  	if (el.classList !== undefined) {
2677  		var classes = splitWords(name);
2678  		for (var i = 0, len = classes.length; i < len; i++) {
2679  			el.classList.add(classes[i]);
2680  		}
2681  	} else if (!hasClass(el, name)) {
2682  		var className = getClass(el);
2683  		setClass(el, (className ? className + ' ' : '') + name);
2684  	}
2685  }
2686
2687  // @function removeClass(el: HTMLElement, name: String)
2688  // Removes `name` from the element's class attribute.
2689  function removeClass(el, name) {
2690  	if (el.classList !== undefined) {
2691  		el.classList.remove(name);
2692  	} else {
2693  		setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
2694  	}
2695  }
2696
2697  // @function setClass(el: HTMLElement, name: String)
2698  // Sets the element's class.
2699  function setClass(el, name) {
2700  	if (el.className.baseVal === undefined) {
2701  		el.className = name;
2702  	} else {
2703  		// in case of SVG element
2704  		el.className.baseVal = name;
2705  	}
2706  }
2707
2708  // @function getClass(el: HTMLElement): String
2709  // Returns the element's class.
2710  function getClass(el) {
2711  	// Check if the element is an SVGElementInstance and use the correspondingElement instead
2712  	// (Required for linked SVG elements in IE11.)
2713  	if (el.correspondingElement) {
2714  		el = el.correspondingElement;
2715  	}
2716  	return el.className.baseVal === undefined ? el.className : el.className.baseVal;
2717  }
2718
2719  // @function setOpacity(el: HTMLElement, opacity: Number)
2720  // Set the opacity of an element (including old IE support).
2721  // `opacity` must be a number from `0` to `1`.
2722  function setOpacity(el, value) {
2723  	if ('opacity' in el.style) {
2724  		el.style.opacity = value;
2725  	} else if ('filter' in el.style) {
2726  		_setOpacityIE(el, value);
2727  	}
2728  }
2729
2730  function _setOpacityIE(el, value) {
2731  	var filter = false,
2732  	    filterName = 'DXImageTransform.Microsoft.Alpha';
2733
2734  	// filters collection throws an error if we try to retrieve a filter that doesn't exist
2735  	try {
2736  		filter = el.filters.item(filterName);
2737  	} catch (e) {
2738  		// don't set opacity to 1 if we haven't already set an opacity,
2739  		// it isn't needed and breaks transparent pngs.
2740  		if (value === 1) { return; }
2741  	}
2742
2743  	value = Math.round(value * 100);
2744
2745  	if (filter) {
2746  		filter.Enabled = (value !== 100);
2747  		filter.Opacity = value;
2748  	} else {
2749  		el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
2750  	}
2751  }
2752
2753  // @function testProp(props: String[]): String|false
2754  // Goes through the array of style names and returns the first name
2755  // that is a valid style name for an element. If no such name is found,
2756  // it returns false. Useful for vendor-prefixed styles like `transform`.
2757  function testProp(props) {
2758  	var style = document.documentElement.style;
2759
2760  	for (var i = 0; i < props.length; i++) {
2761  		if (props[i] in style) {
2762  			return props[i];
2763  		}
2764  	}
2765  	return false;
2766  }
2767
2768  // @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
2769  // Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
2770  // and optionally scaled by `scale`. Does not have an effect if the
2771  // browser doesn't support 3D CSS transforms.
2772  function setTransform(el, offset, scale) {
2773  	var pos = offset || new Point(0, 0);
2774
2775  	el.style[TRANSFORM] =
2776  		(Browser.ie3d ?
2777  			'translate(' + pos.x + 'px,' + pos.y + 'px)' :
2778  			'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
2779  		(scale ? ' scale(' + scale + ')' : '');
2780  }
2781
2782  // @function setPosition(el: HTMLElement, position: Point)
2783  // Sets the position of `el` to coordinates specified by `position`,
2784  // using CSS translate or top/left positioning depending on the browser
2785  // (used by Leaflet internally to position its layers).
2786  function setPosition(el, point) {
2787
2788  	/*eslint-disable */
2789  	el._leaflet_pos = point;
2790  	/* eslint-enable */
2791
2792  	if (Browser.any3d) {
2793  		setTransform(el, point);
2794  	} else {
2795  		el.style.left = point.x + 'px';
2796  		el.style.top = point.y + 'px';
2797  	}
2798  }
2799
2800  // @function getPosition(el: HTMLElement): Point
2801  // Returns the coordinates of an element previously positioned with setPosition.
2802  function getPosition(el) {
2803  	// this method is only used for elements previously positioned using setPosition,
2804  	// so it's safe to cache the position for performance
2805
2806  	return el._leaflet_pos || new Point(0, 0);
2807  }
2808
2809  // @function disableTextSelection()
2810  // Prevents the user from generating `selectstart` DOM events, usually generated
2811  // when the user drags the mouse through a page with text. Used internally
2812  // by Leaflet to override the behaviour of any click-and-drag interaction on
2813  // the map. Affects drag interactions on the whole document.
2814
2815  // @function enableTextSelection()
2816  // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
2817  var disableTextSelection;
2818  var enableTextSelection;
2819  var _userSelect;
2820  if ('onselectstart' in document) {
2821  	disableTextSelection = function () {
2822  		on(window, 'selectstart', preventDefault);
2823  	};
2824  	enableTextSelection = function () {
2825  		off(window, 'selectstart', preventDefault);
2826  	};
2827  } else {
2828  	var userSelectProperty = testProp(
2829  		['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
2830
2831  	disableTextSelection = function () {
2832  		if (userSelectProperty) {
2833  			var style = document.documentElement.style;
2834  			_userSelect = style[userSelectProperty];
2835  			style[userSelectProperty] = 'none';
2836  		}
2837  	};
2838  	enableTextSelection = function () {
2839  		if (userSelectProperty) {
2840  			document.documentElement.style[userSelectProperty] = _userSelect;
2841  			_userSelect = undefined;
2842  		}
2843  	};
2844  }
2845
2846  // @function disableImageDrag()
2847  // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
2848  // for `dragstart` DOM events, usually generated when the user drags an image.
2849  function disableImageDrag() {
2850  	on(window, 'dragstart', preventDefault);
2851  }
2852
2853  // @function enableImageDrag()
2854  // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
2855  function enableImageDrag() {
2856  	off(window, 'dragstart', preventDefault);
2857  }
2858
2859  var _outlineElement, _outlineStyle;
2860  // @function preventOutline(el: HTMLElement)
2861  // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
2862  // of the element `el` invisible. Used internally by Leaflet to prevent
2863  // focusable elements from displaying an outline when the user performs a
2864  // drag interaction on them.
2865  function preventOutline(element) {
2866  	while (element.tabIndex === -1) {
2867  		element = element.parentNode;
2868  	}
2869  	if (!element.style) { return; }
2870  	restoreOutline();
2871  	_outlineElement = element;
2872  	_outlineStyle = element.style.outlineStyle;
2873  	element.style.outlineStyle = 'none';
2874  	on(window, 'keydown', restoreOutline);
2875  }
2876
2877  // @function restoreOutline()
2878  // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
2879  function restoreOutline() {
2880  	if (!_outlineElement) { return; }
2881  	_outlineElement.style.outlineStyle = _outlineStyle;
2882  	_outlineElement = undefined;
2883  	_outlineStyle = undefined;
2884  	off(window, 'keydown', restoreOutline);
2885  }
2886
2887  // @function getSizedParentNode(el: HTMLElement): HTMLElement
2888  // Finds the closest parent node which size (width and height) is not null.
2889  function getSizedParentNode(element) {
2890  	do {
2891  		element = element.parentNode;
2892  	} while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body);
2893  	return element;
2894  }
2895
2896  // @function getScale(el: HTMLElement): Object
2897  // Computes the CSS scale currently applied on the element.
2898  // Returns an object with `x` and `y` members as horizontal and vertical scales respectively,
2899  // and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
2900  function getScale(element) {
2901  	var rect = element.getBoundingClientRect(); // Read-only in old browsers.
2902
2903  	return {
2904  		x: rect.width / element.offsetWidth || 1,
2905  		y: rect.height / element.offsetHeight || 1,
2906  		boundingClientRect: rect
2907  	};
2908  }
2909
2910  var DomUtil = {
2911    __proto__: null,
2912    TRANSFORM: TRANSFORM,
2913    TRANSITION: TRANSITION,
2914    TRANSITION_END: TRANSITION_END,
2915    get: get,
2916    getStyle: getStyle,
2917    create: create$1,
2918    remove: remove,
2919    empty: empty,
2920    toFront: toFront,
2921    toBack: toBack,
2922    hasClass: hasClass,
2923    addClass: addClass,
2924    removeClass: removeClass,
2925    setClass: setClass,
2926    getClass: getClass,
2927    setOpacity: setOpacity,
2928    testProp: testProp,
2929    setTransform: setTransform,
2930    setPosition: setPosition,
2931    getPosition: getPosition,
2932    get disableTextSelection () { return disableTextSelection; },
2933    get enableTextSelection () { return enableTextSelection; },
2934    disableImageDrag: disableImageDrag,
2935    enableImageDrag: enableImageDrag,
2936    preventOutline: preventOutline,
2937    restoreOutline: restoreOutline,
2938    getSizedParentNode: getSizedParentNode,
2939    getScale: getScale
2940  };
2941
2942  /*
2943   * @namespace DomEvent
2944   * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
2945   */
2946
2947  // Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
2948
2949  // @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
2950  // Adds a listener function (`fn`) to a particular DOM event type of the
2951  // element `el`. You can optionally specify the context of the listener
2952  // (object the `this` keyword will point to). You can also pass several
2953  // space-separated types (e.g. `'click dblclick'`).
2954
2955  // @alternative
2956  // @function on(el: HTMLElement, eventMap: Object, context?: Object): this
2957  // Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2958  function on(obj, types, fn, context) {
2959
2960  	if (types && typeof types === 'object') {
2961  		for (var type in types) {
2962  			addOne(obj, type, types[type], fn);
2963  		}
2964  	} else {
2965  		types = splitWords(types);
2966
2967  		for (var i = 0, len = types.length; i < len; i++) {
2968  			addOne(obj, types[i], fn, context);
2969  		}
2970  	}
2971
2972  	return this;
2973  }
2974
2975  var eventsKey = '_leaflet_events';
2976
2977  // @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
2978  // Removes a previously added listener function.
2979  // Note that if you passed a custom context to on, you must pass the same
2980  // context to `off` in order to remove the listener.
2981
2982  // @alternative
2983  // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
2984  // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
2985
2986  // @alternative
2987  // @function off(el: HTMLElement, types: String): this
2988  // Removes all previously added listeners of given types.
2989
2990  // @alternative
2991  // @function off(el: HTMLElement): this
2992  // Removes all previously added listeners from given HTMLElement
2993  function off(obj, types, fn, context) {
2994
2995  	if (arguments.length === 1) {
2996  		batchRemove(obj);
2997  		delete obj[eventsKey];
2998
2999  	} else if (types && typeof types === 'object') {
3000  		for (var type in types) {
3001  			removeOne(obj, type, types[type], fn);
3002  		}
3003
3004  	} else {
3005  		types = splitWords(types);
3006
3007  		if (arguments.length === 2) {
3008  			batchRemove(obj, function (type) {
3009  				return indexOf(types, type) !== -1;
3010  			});
3011  		} else {
3012  			for (var i = 0, len = types.length; i < len; i++) {
3013  				removeOne(obj, types[i], fn, context);
3014  			}
3015  		}
3016  	}
3017
3018  	return this;
3019  }
3020
3021  function batchRemove(obj, filterFn) {
3022  	for (var id in obj[eventsKey]) {
3023  		var type = id.split(/\d/)[0];
3024  		if (!filterFn || filterFn(type)) {
3025  			removeOne(obj, type, null, null, id);
3026  		}
3027  	}
3028  }
3029
3030  var mouseSubst = {
3031  	mouseenter: 'mouseover',
3032  	mouseleave: 'mouseout',
3033  	wheel: !('onwheel' in window) && 'mousewheel'
3034  };
3035
3036  function addOne(obj, type, fn, context) {
3037  	var id = type + stamp(fn) + (context ? '_' + stamp(context) : '');
3038
3039  	if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
3040
3041  	var handler = function (e) {
3042  		return fn.call(context || obj, e || window.event);
3043  	};
3044
3045  	var originalHandler = handler;
3046
3047  	if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {
3048  		// Needs DomEvent.Pointer.js
3049  		handler = addPointerListener(obj, type, handler);
3050
3051  	} else if (Browser.touch && (type === 'dblclick')) {
3052  		handler = addDoubleTapListener(obj, handler);
3053
3054  	} else if ('addEventListener' in obj) {
3055
3056  		if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' ||  type === 'mousewheel') {
3057  			obj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false);
3058
3059  		} else if (type === 'mouseenter' || type === 'mouseleave') {
3060  			handler = function (e) {
3061  				e = e || window.event;
3062  				if (isExternalTarget(obj, e)) {
3063  					originalHandler(e);
3064  				}
3065  			};
3066  			obj.addEventListener(mouseSubst[type], handler, false);
3067
3068  		} else {
3069  			obj.addEventListener(type, originalHandler, false);
3070  		}
3071
3072  	} else {
3073  		obj.attachEvent('on' + type, handler);
3074  	}
3075
3076  	obj[eventsKey] = obj[eventsKey] || {};
3077  	obj[eventsKey][id] = handler;
3078  }
3079
3080  function removeOne(obj, type, fn, context, id) {
3081  	id = id || type + stamp(fn) + (context ? '_' + stamp(context) : '');
3082  	var handler = obj[eventsKey] && obj[eventsKey][id];
3083
3084  	if (!handler) { return this; }
3085
3086  	if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) {
3087  		removePointerListener(obj, type, handler);
3088
3089  	} else if (Browser.touch && (type === 'dblclick')) {
3090  		removeDoubleTapListener(obj, handler);
3091
3092  	} else if ('removeEventListener' in obj) {
3093
3094  		obj.removeEventListener(mouseSubst[type] || type, handler, false);
3095
3096  	} else {
3097  		obj.detachEvent('on' + type, handler);
3098  	}
3099
3100  	obj[eventsKey][id] = null;
3101  }
3102
3103  // @function stopPropagation(ev: DOMEvent): this
3104  // Stop the given event from propagation to parent elements. Used inside the listener functions:
3105  // ```js
3106  // L.DomEvent.on(div, 'click', function (ev) {
3107  // 	L.DomEvent.stopPropagation(ev);
3108  // });
3109  // ```
3110  function stopPropagation(e) {
3111
3112  	if (e.stopPropagation) {
3113  		e.stopPropagation();
3114  	} else if (e.originalEvent) {  // In case of Leaflet event.
3115  		e.originalEvent._stopped = true;
3116  	} else {
3117  		e.cancelBubble = true;
3118  	}
3119
3120  	return this;
3121  }
3122
3123  // @function disableScrollPropagation(el: HTMLElement): this
3124  // Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants).
3125  function disableScrollPropagation(el) {
3126  	addOne(el, 'wheel', stopPropagation);
3127  	return this;
3128  }
3129
3130  // @function disableClickPropagation(el: HTMLElement): this
3131  // Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`,
3132  // `'mousedown'` and `'touchstart'` events (plus browser variants).
3133  function disableClickPropagation(el) {
3134  	on(el, 'mousedown touchstart dblclick contextmenu', stopPropagation);
3135  	el['_leaflet_disable_click'] = true;
3136  	return this;
3137  }
3138
3139  // @function preventDefault(ev: DOMEvent): this
3140  // Prevents the default action of the DOM Event `ev` from happening (such as
3141  // following a link in the href of the a element, or doing a POST request
3142  // with page reload when a `<form>` is submitted).
3143  // Use it inside listener functions.
3144  function preventDefault(e) {
3145  	if (e.preventDefault) {
3146  		e.preventDefault();
3147  	} else {
3148  		e.returnValue = false;
3149  	}
3150  	return this;
3151  }
3152
3153  // @function stop(ev: DOMEvent): this
3154  // Does `stopPropagation` and `preventDefault` at the same time.
3155  function stop(e) {
3156  	preventDefault(e);
3157  	stopPropagation(e);
3158  	return this;
3159  }
3160
3161  // @function getPropagationPath(ev: DOMEvent): Array
3162  // Compatibility polyfill for [`Event.composedPath()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath).
3163  // Returns an array containing the `HTMLElement`s that the given DOM event
3164  // should propagate to (if not stopped).
3165  function getPropagationPath(ev) {
3166  	if (ev.composedPath) {
3167  		return ev.composedPath();
3168  	}
3169
3170  	var path = [];
3171  	var el = ev.target;
3172
3173  	while (el) {
3174  		path.push(el);
3175  		el = el.parentNode;
3176  	}
3177  	return path;
3178  }
3179
3180
3181  // @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
3182  // Gets normalized mouse position from a DOM event relative to the
3183  // `container` (border excluded) or to the whole page if not specified.
3184  function getMousePosition(e, container) {
3185  	if (!container) {
3186  		return new Point(e.clientX, e.clientY);
3187  	}
3188
3189  	var scale = getScale(container),
3190  	    offset = scale.boundingClientRect; // left and top  values are in page scale (like the event clientX/Y)
3191
3192  	return new Point(
3193  		// offset.left/top values are in page scale (like clientX/Y),
3194  		// whereas clientLeft/Top (border width) values are the original values (before CSS scale applies).
3195  		(e.clientX - offset.left) / scale.x - container.clientLeft,
3196  		(e.clientY - offset.top) / scale.y - container.clientTop
3197  	);
3198  }
3199
3200
3201  //  except , Safari and
3202  // We need double the scroll pixels (see #7403 and #4538) for all Browsers
3203  // except OSX (Mac) -> 3x, Chrome running on Linux 1x
3204
3205  var wheelPxFactor =
3206  	(Browser.linux && Browser.chrome) ? window.devicePixelRatio :
3207  	Browser.mac ? window.devicePixelRatio * 3 :
3208  	window.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1;
3209  // @function getWheelDelta(ev: DOMEvent): Number
3210  // Gets normalized wheel delta from a wheel DOM event, in vertical
3211  // pixels scrolled (negative if scrolling down).
3212  // Events from pointing devices without precise scrolling are mapped to
3213  // a best guess of 60 pixels.
3214  function getWheelDelta(e) {
3215  	return (Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
3216  	       (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels
3217  	       (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
3218  	       (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
3219  	       (e.deltaX || e.deltaZ) ? 0 :	// Skip horizontal/depth wheel events
3220  	       e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
3221  	       (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
3222  	       e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
3223  	       0;
3224  }
3225
3226  // check if element really left/entered the event target (for mouseenter/mouseleave)
3227  function isExternalTarget(el, e) {
3228
3229  	var related = e.relatedTarget;
3230
3231  	if (!related) { return true; }
3232
3233  	try {
3234  		while (related && (related !== el)) {
3235  			related = related.parentNode;
3236  		}
3237  	} catch (err) {
3238  		return false;
3239  	}
3240  	return (related !== el);
3241  }
3242
3243  var DomEvent = {
3244    __proto__: null,
3245    on: on,
3246    off: off,
3247    stopPropagation: stopPropagation,
3248    disableScrollPropagation: disableScrollPropagation,
3249    disableClickPropagation: disableClickPropagation,
3250    preventDefault: preventDefault,
3251    stop: stop,
3252    getPropagationPath: getPropagationPath,
3253    getMousePosition: getMousePosition,
3254    getWheelDelta: getWheelDelta,
3255    isExternalTarget: isExternalTarget,
3256    addListener: on,
3257    removeListener: off
3258  };
3259
3260  /*
3261   * @class PosAnimation
3262   * @aka L.PosAnimation
3263   * @inherits Evented
3264   * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
3265   *
3266   * @example
3267   * ```js
3268   * var myPositionMarker = L.marker([48.864716, 2.294694]).addTo(map);
3269   *
3270   * myPositionMarker.on("click", function() {
3271   * 	var pos = map.latLngToLayerPoint(myPositionMarker.getLatLng());
3272   * 	pos.y -= 25;
3273   * 	var fx = new L.PosAnimation();
3274   *
3275   * 	fx.once('end',function() {
3276   * 		pos.y += 25;
3277   * 		fx.run(myPositionMarker._icon, pos, 0.8);
3278   * 	});
3279   *
3280   * 	fx.run(myPositionMarker._icon, pos, 0.3);
3281   * });
3282   *
3283   * ```
3284   *
3285   * @constructor L.PosAnimation()
3286   * Creates a `PosAnimation` object.
3287   *
3288   */
3289
3290  var PosAnimation = Evented.extend({
3291
3292  	// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
3293  	// Run an animation of a given element to a new position, optionally setting
3294  	// duration in seconds (`0.25` by default) and easing linearity factor (3rd
3295  	// argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1),
3296  	// `0.5` by default).
3297  	run: function (el, newPos, duration, easeLinearity) {
3298  		this.stop();
3299
3300  		this._el = el;
3301  		this._inProgress = true;
3302  		this._duration = duration || 0.25;
3303  		this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
3304
3305  		this._startPos = getPosition(el);
3306  		this._offset = newPos.subtract(this._startPos);
3307  		this._startTime = +new Date();
3308
3309  		// @event start: Event
3310  		// Fired when the animation starts
3311  		this.fire('start');
3312
3313  		this._animate();
3314  	},
3315
3316  	// @method stop()
3317  	// Stops the animation (if currently running).
3318  	stop: function () {
3319  		if (!this._inProgress) { return; }
3320
3321  		this._step(true);
3322  		this._complete();
3323  	},
3324
3325  	_animate: function () {
3326  		// animation loop
3327  		this._animId = requestAnimFrame(this._animate, this);
3328  		this._step();
3329  	},
3330
3331  	_step: function (round) {
3332  		var elapsed = (+new Date()) - this._startTime,
3333  		    duration = this._duration * 1000;
3334
3335  		if (elapsed < duration) {
3336  			this._runFrame(this._easeOut(elapsed / duration), round);
3337  		} else {
3338  			this._runFrame(1);
3339  			this._complete();
3340  		}
3341  	},
3342
3343  	_runFrame: function (progress, round) {
3344  		var pos = this._startPos.add(this._offset.multiplyBy(progress));
3345  		if (round) {
3346  			pos._round();
3347  		}
3348  		setPosition(this._el, pos);
3349
3350  		// @event step: Event
3351  		// Fired continuously during the animation.
3352  		this.fire('step');
3353  	},
3354
3355  	_complete: function () {
3356  		cancelAnimFrame(this._animId);
3357
3358  		this._inProgress = false;
3359  		// @event end: Event
3360  		// Fired when the animation ends.
3361  		this.fire('end');
3362  	},
3363
3364  	_easeOut: function (t) {
3365  		return 1 - Math.pow(1 - t, this._easeOutPower);
3366  	}
3367  });
3368
3369  /*
3370   * @class Map
3371   * @aka L.Map
3372   * @inherits Evented
3373   *
3374   * The central class of the API — it is used to create a map on a page and manipulate it.
3375   *
3376   * @example
3377   *
3378   * ```js
3379   * // initialize the map on the "map" div with a given center and zoom
3380   * var map = L.map('map', {
3381   * 	center: [51.505, -0.09],
3382   * 	zoom: 13
3383   * });
3384   * ```
3385   *
3386   */
3387
3388  var Map = Evented.extend({
3389
3390  	options: {
3391  		// @section Map State Options
3392  		// @option crs: CRS = L.CRS.EPSG3857
3393  		// The [Coordinate Reference System](#crs) to use. Don't change this if you're not
3394  		// sure what it means.
3395  		crs: EPSG3857,
3396
3397  		// @option center: LatLng = undefined
3398  		// Initial geographic center of the map
3399  		center: undefined,
3400
3401  		// @option zoom: Number = undefined
3402  		// Initial map zoom level
3403  		zoom: undefined,
3404
3405  		// @option minZoom: Number = *
3406  		// Minimum zoom level of the map.
3407  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3408  		// the lowest of their `minZoom` options will be used instead.
3409  		minZoom: undefined,
3410
3411  		// @option maxZoom: Number = *
3412  		// Maximum zoom level of the map.
3413  		// If not specified and at least one `GridLayer` or `TileLayer` is in the map,
3414  		// the highest of their `maxZoom` options will be used instead.
3415  		maxZoom: undefined,
3416
3417  		// @option layers: Layer[] = []
3418  		// Array of layers that will be added to the map initially
3419  		layers: [],
3420
3421  		// @option maxBounds: LatLngBounds = null
3422  		// When this option is set, the map restricts the view to the given
3423  		// geographical bounds, bouncing the user back if the user tries to pan
3424  		// outside the view. To set the restriction dynamically, use
3425  		// [`setMaxBounds`](#map-setmaxbounds) method.
3426  		maxBounds: undefined,
3427
3428  		// @option renderer: Renderer = *
3429  		// The default method for drawing vector layers on the map. `L.SVG`
3430  		// or `L.Canvas` by default depending on browser support.
3431  		renderer: undefined,
3432
3433
3434  		// @section Animation Options
3435  		// @option zoomAnimation: Boolean = true
3436  		// Whether the map zoom animation is enabled. By default it's enabled
3437  		// in all browsers that support CSS3 Transitions except Android.
3438  		zoomAnimation: true,
3439
3440  		// @option zoomAnimationThreshold: Number = 4
3441  		// Won't animate zoom if the zoom difference exceeds this value.
3442  		zoomAnimationThreshold: 4,
3443
3444  		// @option fadeAnimation: Boolean = true
3445  		// Whether the tile fade animation is enabled. By default it's enabled
3446  		// in all browsers that support CSS3 Transitions except Android.
3447  		fadeAnimation: true,
3448
3449  		// @option markerZoomAnimation: Boolean = true
3450  		// Whether markers animate their zoom with the zoom animation, if disabled
3451  		// they will disappear for the length of the animation. By default it's
3452  		// enabled in all browsers that support CSS3 Transitions except Android.
3453  		markerZoomAnimation: true,
3454
3455  		// @option transform3DLimit: Number = 2^23
3456  		// Defines the maximum size of a CSS translation transform. The default
3457  		// value should not be changed unless a web browser positions layers in
3458  		// the wrong place after doing a large `panBy`.
3459  		transform3DLimit: 8388608, // Precision limit of a 32-bit float
3460
3461  		// @section Interaction Options
3462  		// @option zoomSnap: Number = 1
3463  		// Forces the map's zoom level to always be a multiple of this, particularly
3464  		// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
3465  		// By default, the zoom level snaps to the nearest integer; lower values
3466  		// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
3467  		// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
3468  		zoomSnap: 1,
3469
3470  		// @option zoomDelta: Number = 1
3471  		// Controls how much the map's zoom level will change after a
3472  		// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
3473  		// or `-` on the keyboard, or using the [zoom controls](#control-zoom).
3474  		// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
3475  		zoomDelta: 1,
3476
3477  		// @option trackResize: Boolean = true
3478  		// Whether the map automatically handles browser window resize to update itself.
3479  		trackResize: true
3480  	},
3481
3482  	initialize: function (id, options) { // (HTMLElement or String, Object)
3483  		options = setOptions(this, options);
3484
3485  		// Make sure to assign internal flags at the beginning,
3486  		// to avoid inconsistent state in some edge cases.
3487  		this._handlers = [];
3488  		this._layers = {};
3489  		this._zoomBoundLayers = {};
3490  		this._sizeChanged = true;
3491
3492  		this._initContainer(id);
3493  		this._initLayout();
3494
3495  		// hack for https://github.com/Leaflet/Leaflet/issues/1980
3496  		this._onResize = bind(this._onResize, this);
3497
3498  		this._initEvents();
3499
3500  		if (options.maxBounds) {
3501  			this.setMaxBounds(options.maxBounds);
3502  		}
3503
3504  		if (options.zoom !== undefined) {
3505  			this._zoom = this._limitZoom(options.zoom);
3506  		}
3507
3508  		if (options.center && options.zoom !== undefined) {
3509  			this.setView(toLatLng(options.center), options.zoom, {reset: true});
3510  		}
3511
3512  		this.callInitHooks();
3513
3514  		// don't animate on browsers without hardware-accelerated transitions or old Android/Opera
3515  		this._zoomAnimated = TRANSITION && Browser.any3d && !Browser.mobileOpera &&
3516  				this.options.zoomAnimation;
3517
3518  		// zoom transitions run with the same duration for all layers, so if one of transitionend events
3519  		// happens after starting zoom animation (propagating to the map pane), we know that it ended globally
3520  		if (this._zoomAnimated) {
3521  			this._createAnimProxy();
3522  			on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this);
3523  		}
3524
3525  		this._addLayers(this.options.layers);
3526  	},
3527
3528
3529  	// @section Methods for modifying map state
3530
3531  	// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
3532  	// Sets the view of the map (geographical center and zoom) with the given
3533  	// animation options.
3534  	setView: function (center, zoom, options) {
3535
3536  		zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
3537  		center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds);
3538  		options = options || {};
3539
3540  		this._stop();
3541
3542  		if (this._loaded && !options.reset && options !== true) {
3543
3544  			if (options.animate !== undefined) {
3545  				options.zoom = extend({animate: options.animate}, options.zoom);
3546  				options.pan = extend({animate: options.animate, duration: options.duration}, options.pan);
3547  			}
3548
3549  			// try animating pan or zoom
3550  			var moved = (this._zoom !== zoom) ?
3551  				this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
3552  				this._tryAnimatedPan(center, options.pan);
3553
3554  			if (moved) {
3555  				// prevent resize handler call, the view will refresh after animation anyway
3556  				clearTimeout(this._sizeTimer);
3557  				return this;
3558  			}
3559  		}
3560
3561  		// animation didn't start, just reset the map view
3562  		this._resetView(center, zoom, options.pan && options.pan.noMoveStart);
3563
3564  		return this;
3565  	},
3566
3567  	// @method setZoom(zoom: Number, options?: Zoom/pan options): this
3568  	// Sets the zoom of the map.
3569  	setZoom: function (zoom, options) {
3570  		if (!this._loaded) {
3571  			this._zoom = zoom;
3572  			return this;
3573  		}
3574  		return this.setView(this.getCenter(), zoom, {zoom: options});
3575  	},
3576
3577  	// @method zoomIn(delta?: Number, options?: Zoom options): this
3578  	// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3579  	zoomIn: function (delta, options) {
3580  		delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
3581  		return this.setZoom(this._zoom + delta, options);
3582  	},
3583
3584  	// @method zoomOut(delta?: Number, options?: Zoom options): this
3585  	// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
3586  	zoomOut: function (delta, options) {
3587  		delta = delta || (Browser.any3d ? this.options.zoomDelta : 1);
3588  		return this.setZoom(this._zoom - delta, options);
3589  	},
3590
3591  	// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
3592  	// Zooms the map while keeping a specified geographical point on the map
3593  	// stationary (e.g. used internally for scroll zoom and double-click zoom).
3594  	// @alternative
3595  	// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
3596  	// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
3597  	setZoomAround: function (latlng, zoom, options) {
3598  		var scale = this.getZoomScale(zoom),
3599  		    viewHalf = this.getSize().divideBy(2),
3600  		    containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng),
3601
3602  		    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
3603  		    newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
3604
3605  		return this.setView(newCenter, zoom, {zoom: options});
3606  	},
3607
3608  	_getBoundsCenterZoom: function (bounds, options) {
3609
3610  		options = options || {};
3611  		bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds);
3612
3613  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3614  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3615
3616  		    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
3617
3618  		zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
3619
3620  		if (zoom === Infinity) {
3621  			return {
3622  				center: bounds.getCenter(),
3623  				zoom: zoom
3624  			};
3625  		}
3626
3627  		var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
3628
3629  		    swPoint = this.project(bounds.getSouthWest(), zoom),
3630  		    nePoint = this.project(bounds.getNorthEast(), zoom),
3631  		    center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
3632
3633  		return {
3634  			center: center,
3635  			zoom: zoom
3636  		};
3637  	},
3638
3639  	// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
3640  	// Sets a map view that contains the given geographical bounds with the
3641  	// maximum zoom level possible.
3642  	fitBounds: function (bounds, options) {
3643
3644  		bounds = toLatLngBounds(bounds);
3645
3646  		if (!bounds.isValid()) {
3647  			throw new Error('Bounds are not valid.');
3648  		}
3649
3650  		var target = this._getBoundsCenterZoom(bounds, options);
3651  		return this.setView(target.center, target.zoom, options);
3652  	},
3653
3654  	// @method fitWorld(options?: fitBounds options): this
3655  	// Sets a map view that mostly contains the whole world with the maximum
3656  	// zoom level possible.
3657  	fitWorld: function (options) {
3658  		return this.fitBounds([[-90, -180], [90, 180]], options);
3659  	},
3660
3661  	// @method panTo(latlng: LatLng, options?: Pan options): this
3662  	// Pans the map to a given center.
3663  	panTo: function (center, options) { // (LatLng)
3664  		return this.setView(center, this._zoom, {pan: options});
3665  	},
3666
3667  	// @method panBy(offset: Point, options?: Pan options): this
3668  	// Pans the map by a given number of pixels (animated).
3669  	panBy: function (offset, options) {
3670  		offset = toPoint(offset).round();
3671  		options = options || {};
3672
3673  		if (!offset.x && !offset.y) {
3674  			return this.fire('moveend');
3675  		}
3676  		// If we pan too far, Chrome gets issues with tiles
3677  		// and makes them disappear or appear in the wrong place (slightly offset) #2602
3678  		if (options.animate !== true && !this.getSize().contains(offset)) {
3679  			this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
3680  			return this;
3681  		}
3682
3683  		if (!this._panAnim) {
3684  			this._panAnim = new PosAnimation();
3685
3686  			this._panAnim.on({
3687  				'step': this._onPanTransitionStep,
3688  				'end': this._onPanTransitionEnd
3689  			}, this);
3690  		}
3691
3692  		// don't fire movestart if animating inertia
3693  		if (!options.noMoveStart) {
3694  			this.fire('movestart');
3695  		}
3696
3697  		// animate pan unless animate: false specified
3698  		if (options.animate !== false) {
3699  			addClass(this._mapPane, 'leaflet-pan-anim');
3700
3701  			var newPos = this._getMapPanePos().subtract(offset).round();
3702  			this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
3703  		} else {
3704  			this._rawPanBy(offset);
3705  			this.fire('move').fire('moveend');
3706  		}
3707
3708  		return this;
3709  	},
3710
3711  	// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
3712  	// Sets the view of the map (geographical center and zoom) performing a smooth
3713  	// pan-zoom animation.
3714  	flyTo: function (targetCenter, targetZoom, options) {
3715
3716  		options = options || {};
3717  		if (options.animate === false || !Browser.any3d) {
3718  			return this.setView(targetCenter, targetZoom, options);
3719  		}
3720
3721  		this._stop();
3722
3723  		var from = this.project(this.getCenter()),
3724  		    to = this.project(targetCenter),
3725  		    size = this.getSize(),
3726  		    startZoom = this._zoom;
3727
3728  		targetCenter = toLatLng(targetCenter);
3729  		targetZoom = targetZoom === undefined ? startZoom : targetZoom;
3730
3731  		var w0 = Math.max(size.x, size.y),
3732  		    w1 = w0 * this.getZoomScale(startZoom, targetZoom),
3733  		    u1 = (to.distanceTo(from)) || 1,
3734  		    rho = 1.42,
3735  		    rho2 = rho * rho;
3736
3737  		function r(i) {
3738  			var s1 = i ? -1 : 1,
3739  			    s2 = i ? w1 : w0,
3740  			    t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
3741  			    b1 = 2 * s2 * rho2 * u1,
3742  			    b = t1 / b1,
3743  			    sq = Math.sqrt(b * b + 1) - b;
3744
3745  			    // workaround for floating point precision bug when sq = 0, log = -Infinite,
3746  			    // thus triggering an infinite loop in flyTo
3747  			    var log = sq < 0.000000001 ? -18 : Math.log(sq);
3748
3749  			return log;
3750  		}
3751
3752  		function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
3753  		function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
3754  		function tanh(n) { return sinh(n) / cosh(n); }
3755
3756  		var r0 = r(0);
3757
3758  		function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
3759  		function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
3760
3761  		function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
3762
3763  		var start = Date.now(),
3764  		    S = (r(1) - r0) / rho,
3765  		    duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
3766
3767  		function frame() {
3768  			var t = (Date.now() - start) / duration,
3769  			    s = easeOut(t) * S;
3770
3771  			if (t <= 1) {
3772  				this._flyToFrame = requestAnimFrame(frame, this);
3773
3774  				this._move(
3775  					this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
3776  					this.getScaleZoom(w0 / w(s), startZoom),
3777  					{flyTo: true});
3778
3779  			} else {
3780  				this
3781  					._move(targetCenter, targetZoom)
3782  					._moveEnd(true);
3783  			}
3784  		}
3785
3786  		this._moveStart(true, options.noMoveStart);
3787
3788  		frame.call(this);
3789  		return this;
3790  	},
3791
3792  	// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
3793  	// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
3794  	// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
3795  	flyToBounds: function (bounds, options) {
3796  		var target = this._getBoundsCenterZoom(bounds, options);
3797  		return this.flyTo(target.center, target.zoom, options);
3798  	},
3799
3800  	// @method setMaxBounds(bounds: LatLngBounds): this
3801  	// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
3802  	setMaxBounds: function (bounds) {
3803  		bounds = toLatLngBounds(bounds);
3804
3805  		if (this.listens('moveend', this._panInsideMaxBounds)) {
3806  			this.off('moveend', this._panInsideMaxBounds);
3807  		}
3808
3809  		if (!bounds.isValid()) {
3810  			this.options.maxBounds = null;
3811  			return this;
3812  		}
3813
3814  		this.options.maxBounds = bounds;
3815
3816  		if (this._loaded) {
3817  			this._panInsideMaxBounds();
3818  		}
3819
3820  		return this.on('moveend', this._panInsideMaxBounds);
3821  	},
3822
3823  	// @method setMinZoom(zoom: Number): this
3824  	// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
3825  	setMinZoom: function (zoom) {
3826  		var oldZoom = this.options.minZoom;
3827  		this.options.minZoom = zoom;
3828
3829  		if (this._loaded && oldZoom !== zoom) {
3830  			this.fire('zoomlevelschange');
3831
3832  			if (this.getZoom() < this.options.minZoom) {
3833  				return this.setZoom(zoom);
3834  			}
3835  		}
3836
3837  		return this;
3838  	},
3839
3840  	// @method setMaxZoom(zoom: Number): this
3841  	// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
3842  	setMaxZoom: function (zoom) {
3843  		var oldZoom = this.options.maxZoom;
3844  		this.options.maxZoom = zoom;
3845
3846  		if (this._loaded && oldZoom !== zoom) {
3847  			this.fire('zoomlevelschange');
3848
3849  			if (this.getZoom() > this.options.maxZoom) {
3850  				return this.setZoom(zoom);
3851  			}
3852  		}
3853
3854  		return this;
3855  	},
3856
3857  	// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
3858  	// Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.
3859  	panInsideBounds: function (bounds, options) {
3860  		this._enforcingBounds = true;
3861  		var center = this.getCenter(),
3862  		    newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds));
3863
3864  		if (!center.equals(newCenter)) {
3865  			this.panTo(newCenter, options);
3866  		}
3867
3868  		this._enforcingBounds = false;
3869  		return this;
3870  	},
3871
3872  	// @method panInside(latlng: LatLng, options?: padding options): this
3873  	// Pans the map the minimum amount to make the `latlng` visible. Use
3874  	// padding options to fit the display to more restricted bounds.
3875  	// If `latlng` is already within the (optionally padded) display bounds,
3876  	// the map will not be panned.
3877  	panInside: function (latlng, options) {
3878  		options = options || {};
3879
3880  		var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]),
3881  		    paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]),
3882  		    pixelCenter = this.project(this.getCenter()),
3883  		    pixelPoint = this.project(latlng),
3884  		    pixelBounds = this.getPixelBounds(),
3885  		    paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]),
3886  		    paddedSize = paddedBounds.getSize();
3887
3888  		if (!paddedBounds.contains(pixelPoint)) {
3889  			this._enforcingBounds = true;
3890  			var centerOffset = pixelPoint.subtract(paddedBounds.getCenter());
3891  			var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize);
3892  			pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x;
3893  			pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y;
3894  			this.panTo(this.unproject(pixelCenter), options);
3895  			this._enforcingBounds = false;
3896  		}
3897  		return this;
3898  	},
3899
3900  	// @method invalidateSize(options: Zoom/pan options): this
3901  	// Checks if the map container size changed and updates the map if so —
3902  	// call it after you've changed the map size dynamically, also animating
3903  	// pan by default. If `options.pan` is `false`, panning will not occur.
3904  	// If `options.debounceMoveend` is `true`, it will delay `moveend` event so
3905  	// that it doesn't happen often even if the method is called many
3906  	// times in a row.
3907
3908  	// @alternative
3909  	// @method invalidateSize(animate: Boolean): this
3910  	// Checks if the map container size changed and updates the map if so —
3911  	// call it after you've changed the map size dynamically, also animating
3912  	// pan by default.
3913  	invalidateSize: function (options) {
3914  		if (!this._loaded) { return this; }
3915
3916  		options = extend({
3917  			animate: false,
3918  			pan: true
3919  		}, options === true ? {animate: true} : options);
3920
3921  		var oldSize = this.getSize();
3922  		this._sizeChanged = true;
3923  		this._lastCenter = null;
3924
3925  		var newSize = this.getSize(),
3926  		    oldCenter = oldSize.divideBy(2).round(),
3927  		    newCenter = newSize.divideBy(2).round(),
3928  		    offset = oldCenter.subtract(newCenter);
3929
3930  		if (!offset.x && !offset.y) { return this; }
3931
3932  		if (options.animate && options.pan) {
3933  			this.panBy(offset);
3934
3935  		} else {
3936  			if (options.pan) {
3937  				this._rawPanBy(offset);
3938  			}
3939
3940  			this.fire('move');
3941
3942  			if (options.debounceMoveend) {
3943  				clearTimeout(this._sizeTimer);
3944  				this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200);
3945  			} else {
3946  				this.fire('moveend');
3947  			}
3948  		}
3949
3950  		// @section Map state change events
3951  		// @event resize: ResizeEvent
3952  		// Fired when the map is resized.
3953  		return this.fire('resize', {
3954  			oldSize: oldSize,
3955  			newSize: newSize
3956  		});
3957  	},
3958
3959  	// @section Methods for modifying map state
3960  	// @method stop(): this
3961  	// Stops the currently running `panTo` or `flyTo` animation, if any.
3962  	stop: function () {
3963  		this.setZoom(this._limitZoom(this._zoom));
3964  		if (!this.options.zoomSnap) {
3965  			this.fire('viewreset');
3966  		}
3967  		return this._stop();
3968  	},
3969
3970  	// @section Geolocation methods
3971  	// @method locate(options?: Locate options): this
3972  	// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
3973  	// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
3974  	// and optionally sets the map view to the user's location with respect to
3975  	// detection accuracy (or to the world view if geolocation failed).
3976  	// Note that, if your page doesn't use HTTPS, this method will fail in
3977  	// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
3978  	// See `Locate options` for more details.
3979  	locate: function (options) {
3980
3981  		options = this._locateOptions = extend({
3982  			timeout: 10000,
3983  			watch: false
3984  			// setView: false
3985  			// maxZoom: <Number>
3986  			// maximumAge: 0
3987  			// enableHighAccuracy: false
3988  		}, options);
3989
3990  		if (!('geolocation' in navigator)) {
3991  			this._handleGeolocationError({
3992  				code: 0,
3993  				message: 'Geolocation not supported.'
3994  			});
3995  			return this;
3996  		}
3997
3998  		var onResponse = bind(this._handleGeolocationResponse, this),
3999  		    onError = bind(this._handleGeolocationError, this);
4000
4001  		if (options.watch) {
4002  			this._locationWatchId =
4003  			        navigator.geolocation.watchPosition(onResponse, onError, options);
4004  		} else {
4005  			navigator.geolocation.getCurrentPosition(onResponse, onError, options);
4006  		}
4007  		return this;
4008  	},
4009
4010  	// @method stopLocate(): this
4011  	// Stops watching location previously initiated by `map.locate({watch: true})`
4012  	// and aborts resetting the map view if map.locate was called with
4013  	// `{setView: true}`.
4014  	stopLocate: function () {
4015  		if (navigator.geolocation && navigator.geolocation.clearWatch) {
4016  			navigator.geolocation.clearWatch(this._locationWatchId);
4017  		}
4018  		if (this._locateOptions) {
4019  			this._locateOptions.setView = false;
4020  		}
4021  		return this;
4022  	},
4023
4024  	_handleGeolocationError: function (error) {
4025  		if (!this._container._leaflet_id) { return; }
4026
4027  		var c = error.code,
4028  		    message = error.message ||
4029  		            (c === 1 ? 'permission denied' :
4030  		            (c === 2 ? 'position unavailable' : 'timeout'));
4031
4032  		if (this._locateOptions.setView && !this._loaded) {
4033  			this.fitWorld();
4034  		}
4035
4036  		// @section Location events
4037  		// @event locationerror: ErrorEvent
4038  		// Fired when geolocation (using the [`locate`](#map-locate) method) failed.
4039  		this.fire('locationerror', {
4040  			code: c,
4041  			message: 'Geolocation error: ' + message + '.'
4042  		});
4043  	},
4044
4045  	_handleGeolocationResponse: function (pos) {
4046  		if (!this._container._leaflet_id) { return; }
4047
4048  		var lat = pos.coords.latitude,
4049  		    lng = pos.coords.longitude,
4050  		    latlng = new LatLng(lat, lng),
4051  		    bounds = latlng.toBounds(pos.coords.accuracy * 2),
4052  		    options = this._locateOptions;
4053
4054  		if (options.setView) {
4055  			var zoom = this.getBoundsZoom(bounds);
4056  			this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
4057  		}
4058
4059  		var data = {
4060  			latlng: latlng,
4061  			bounds: bounds,
4062  			timestamp: pos.timestamp
4063  		};
4064
4065  		for (var i in pos.coords) {
4066  			if (typeof pos.coords[i] === 'number') {
4067  				data[i] = pos.coords[i];
4068  			}
4069  		}
4070
4071  		// @event locationfound: LocationEvent
4072  		// Fired when geolocation (using the [`locate`](#map-locate) method)
4073  		// went successfully.
4074  		this.fire('locationfound', data);
4075  	},
4076
4077  	// TODO Appropriate docs section?
4078  	// @section Other Methods
4079  	// @method addHandler(name: String, HandlerClass: Function): this
4080  	// Adds a new `Handler` to the map, given its name and constructor function.
4081  	addHandler: function (name, HandlerClass) {
4082  		if (!HandlerClass) { return this; }
4083
4084  		var handler = this[name] = new HandlerClass(this);
4085
4086  		this._handlers.push(handler);
4087
4088  		if (this.options[name]) {
4089  			handler.enable();
4090  		}
4091
4092  		return this;
4093  	},
4094
4095  	// @method remove(): this
4096  	// Destroys the map and clears all related event listeners.
4097  	remove: function () {
4098
4099  		this._initEvents(true);
4100  		if (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); }
4101
4102  		if (this._containerId !== this._container._leaflet_id) {
4103  			throw new Error('Map container is being reused by another instance');
4104  		}
4105
4106  		try {
4107  			// throws error in IE6-8
4108  			delete this._container._leaflet_id;
4109  			delete this._containerId;
4110  		} catch (e) {
4111  			/*eslint-disable */
4112  			this._container._leaflet_id = undefined;
4113  			/* eslint-enable */
4114  			this._containerId = undefined;
4115  		}
4116
4117  		if (this._locationWatchId !== undefined) {
4118  			this.stopLocate();
4119  		}
4120
4121  		this._stop();
4122
4123  		remove(this._mapPane);
4124
4125  		if (this._clearControlPos) {
4126  			this._clearControlPos();
4127  		}
4128  		if (this._resizeRequest) {
4129  			cancelAnimFrame(this._resizeRequest);
4130  			this._resizeRequest = null;
4131  		}
4132
4133  		this._clearHandlers();
4134
4135  		if (this._loaded) {
4136  			// @section Map state change events
4137  			// @event unload: Event
4138  			// Fired when the map is destroyed with [remove](#map-remove) method.
4139  			this.fire('unload');
4140  		}
4141
4142  		var i;
4143  		for (i in this._layers) {
4144  			this._layers[i].remove();
4145  		}
4146  		for (i in this._panes) {
4147  			remove(this._panes[i]);
4148  		}
4149
4150  		this._layers = [];
4151  		this._panes = [];
4152  		delete this._mapPane;
4153  		delete this._renderer;
4154
4155  		return this;
4156  	},
4157
4158  	// @section Other Methods
4159  	// @method createPane(name: String, container?: HTMLElement): HTMLElement
4160  	// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
4161  	// then returns it. The pane is created as a child of `container`, or
4162  	// as a child of the main map pane if not set.
4163  	createPane: function (name, container) {
4164  		var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
4165  		    pane = create$1('div', className, container || this._mapPane);
4166
4167  		if (name) {
4168  			this._panes[name] = pane;
4169  		}
4170  		return pane;
4171  	},
4172
4173  	// @section Methods for Getting Map State
4174
4175  	// @method getCenter(): LatLng
4176  	// Returns the geographical center of the map view
4177  	getCenter: function () {
4178  		this._checkIfLoaded();
4179
4180  		if (this._lastCenter && !this._moved()) {
4181  			return this._lastCenter.clone();
4182  		}
4183  		return this.layerPointToLatLng(this._getCenterLayerPoint());
4184  	},
4185
4186  	// @method getZoom(): Number
4187  	// Returns the current zoom level of the map view
4188  	getZoom: function () {
4189  		return this._zoom;
4190  	},
4191
4192  	// @method getBounds(): LatLngBounds
4193  	// Returns the geographical bounds visible in the current map view
4194  	getBounds: function () {
4195  		var bounds = this.getPixelBounds(),
4196  		    sw = this.unproject(bounds.getBottomLeft()),
4197  		    ne = this.unproject(bounds.getTopRight());
4198
4199  		return new LatLngBounds(sw, ne);
4200  	},
4201
4202  	// @method getMinZoom(): Number
4203  	// Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.
4204  	getMinZoom: function () {
4205  		return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
4206  	},
4207
4208  	// @method getMaxZoom(): Number
4209  	// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
4210  	getMaxZoom: function () {
4211  		return this.options.maxZoom === undefined ?
4212  			(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
4213  			this.options.maxZoom;
4214  	},
4215
4216  	// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number
4217  	// Returns the maximum zoom level on which the given bounds fit to the map
4218  	// view in its entirety. If `inside` (optional) is set to `true`, the method
4219  	// instead returns the minimum zoom level on which the map view fits into
4220  	// the given bounds in its entirety.
4221  	getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
4222  		bounds = toLatLngBounds(bounds);
4223  		padding = toPoint(padding || [0, 0]);
4224
4225  		var zoom = this.getZoom() || 0,
4226  		    min = this.getMinZoom(),
4227  		    max = this.getMaxZoom(),
4228  		    nw = bounds.getNorthWest(),
4229  		    se = bounds.getSouthEast(),
4230  		    size = this.getSize().subtract(padding),
4231  		    boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
4232  		    snap = Browser.any3d ? this.options.zoomSnap : 1,
4233  		    scalex = size.x / boundsSize.x,
4234  		    scaley = size.y / boundsSize.y,
4235  		    scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley);
4236
4237  		zoom = this.getScaleZoom(scale, zoom);
4238
4239  		if (snap) {
4240  			zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
4241  			zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
4242  		}
4243
4244  		return Math.max(min, Math.min(max, zoom));
4245  	},
4246
4247  	// @method getSize(): Point
4248  	// Returns the current size of the map container (in pixels).
4249  	getSize: function () {
4250  		if (!this._size || this._sizeChanged) {
4251  			this._size = new Point(
4252  				this._container.clientWidth || 0,
4253  				this._container.clientHeight || 0);
4254
4255  			this._sizeChanged = false;
4256  		}
4257  		return this._size.clone();
4258  	},
4259
4260  	// @method getPixelBounds(): Bounds
4261  	// Returns the bounds of the current map view in projected pixel
4262  	// coordinates (sometimes useful in layer and overlay implementations).
4263  	getPixelBounds: function (center, zoom) {
4264  		var topLeftPoint = this._getTopLeftPoint(center, zoom);
4265  		return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
4266  	},
4267
4268  	// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
4269  	// the map pane? "left point of the map layer" can be confusing, specially
4270  	// since there can be negative offsets.
4271  	// @method getPixelOrigin(): Point
4272  	// Returns the projected pixel coordinates of the top left point of
4273  	// the map layer (useful in custom layer and overlay implementations).
4274  	getPixelOrigin: function () {
4275  		this._checkIfLoaded();
4276  		return this._pixelOrigin;
4277  	},
4278
4279  	// @method getPixelWorldBounds(zoom?: Number): Bounds
4280  	// Returns the world's bounds in pixel coordinates for zoom level `zoom`.
4281  	// If `zoom` is omitted, the map's current zoom level is used.
4282  	getPixelWorldBounds: function (zoom) {
4283  		return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
4284  	},
4285
4286  	// @section Other Methods
4287
4288  	// @method getPane(pane: String|HTMLElement): HTMLElement
4289  	// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
4290  	getPane: function (pane) {
4291  		return typeof pane === 'string' ? this._panes[pane] : pane;
4292  	},
4293
4294  	// @method getPanes(): Object
4295  	// Returns a plain object containing the names of all [panes](#map-pane) as keys and
4296  	// the panes as values.
4297  	getPanes: function () {
4298  		return this._panes;
4299  	},
4300
4301  	// @method getContainer: HTMLElement
4302  	// Returns the HTML element that contains the map.
4303  	getContainer: function () {
4304  		return this._container;
4305  	},
4306
4307
4308  	// @section Conversion Methods
4309
4310  	// @method getZoomScale(toZoom: Number, fromZoom: Number): Number
4311  	// Returns the scale factor to be applied to a map transition from zoom level
4312  	// `fromZoom` to `toZoom`. Used internally to help with zoom animations.
4313  	getZoomScale: function (toZoom, fromZoom) {
4314  		// TODO replace with universal implementation after refactoring projections
4315  		var crs = this.options.crs;
4316  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
4317  		return crs.scale(toZoom) / crs.scale(fromZoom);
4318  	},
4319
4320  	// @method getScaleZoom(scale: Number, fromZoom: Number): Number
4321  	// Returns the zoom level that the map would end up at, if it is at `fromZoom`
4322  	// level and everything is scaled by a factor of `scale`. Inverse of
4323  	// [`getZoomScale`](#map-getZoomScale).
4324  	getScaleZoom: function (scale, fromZoom) {
4325  		var crs = this.options.crs;
4326  		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
4327  		var zoom = crs.zoom(scale * crs.scale(fromZoom));
4328  		return isNaN(zoom) ? Infinity : zoom;
4329  	},
4330
4331  	// @method project(latlng: LatLng, zoom: Number): Point
4332  	// Projects a geographical coordinate `LatLng` according to the projection
4333  	// of the map's CRS, then scales it according to `zoom` and the CRS's
4334  	// `Transformation`. The result is pixel coordinate relative to
4335  	// the CRS origin.
4336  	project: function (latlng, zoom) {
4337  		zoom = zoom === undefined ? this._zoom : zoom;
4338  		return this.options.crs.latLngToPoint(toLatLng(latlng), zoom);
4339  	},
4340
4341  	// @method unproject(point: Point, zoom: Number): LatLng
4342  	// Inverse of [`project`](#map-project).
4343  	unproject: function (point, zoom) {
4344  		zoom = zoom === undefined ? this._zoom : zoom;
4345  		return this.options.crs.pointToLatLng(toPoint(point), zoom);
4346  	},
4347
4348  	// @method layerPointToLatLng(point: Point): LatLng
4349  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
4350  	// returns the corresponding geographical coordinate (for the current zoom level).
4351  	layerPointToLatLng: function (point) {
4352  		var projectedPoint = toPoint(point).add(this.getPixelOrigin());
4353  		return this.unproject(projectedPoint);
4354  	},
4355
4356  	// @method latLngToLayerPoint(latlng: LatLng): Point
4357  	// Given a geographical coordinate, returns the corresponding pixel coordinate
4358  	// relative to the [origin pixel](#map-getpixelorigin).
4359  	latLngToLayerPoint: function (latlng) {
4360  		var projectedPoint = this.project(toLatLng(latlng))._round();
4361  		return projectedPoint._subtract(this.getPixelOrigin());
4362  	},
4363
4364  	// @method wrapLatLng(latlng: LatLng): LatLng
4365  	// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
4366  	// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
4367  	// CRS's bounds.
4368  	// By default this means longitude is wrapped around the dateline so its
4369  	// value is between -180 and +180 degrees.
4370  	wrapLatLng: function (latlng) {
4371  		return this.options.crs.wrapLatLng(toLatLng(latlng));
4372  	},
4373
4374  	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
4375  	// Returns a `LatLngBounds` with the same size as the given one, ensuring that
4376  	// its center is within the CRS's bounds.
4377  	// By default this means the center longitude is wrapped around the dateline so its
4378  	// value is between -180 and +180 degrees, and the majority of the bounds
4379  	// overlaps the CRS's bounds.
4380  	wrapLatLngBounds: function (latlng) {
4381  		return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng));
4382  	},
4383
4384  	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
4385  	// Returns the distance between two geographical coordinates according to
4386  	// the map's CRS. By default this measures distance in meters.
4387  	distance: function (latlng1, latlng2) {
4388  		return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2));
4389  	},
4390
4391  	// @method containerPointToLayerPoint(point: Point): Point
4392  	// Given a pixel coordinate relative to the map container, returns the corresponding
4393  	// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
4394  	containerPointToLayerPoint: function (point) { // (Point)
4395  		return toPoint(point).subtract(this._getMapPanePos());
4396  	},
4397
4398  	// @method layerPointToContainerPoint(point: Point): Point
4399  	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
4400  	// returns the corresponding pixel coordinate relative to the map container.
4401  	layerPointToContainerPoint: function (point) { // (Point)
4402  		return toPoint(point).add(this._getMapPanePos());
4403  	},
4404
4405  	// @method containerPointToLatLng(point: Point): LatLng
4406  	// Given a pixel coordinate relative to the map container, returns
4407  	// the corresponding geographical coordinate (for the current zoom level).
4408  	containerPointToLatLng: function (point) {
4409  		var layerPoint = this.containerPointToLayerPoint(toPoint(point));
4410  		return this.layerPointToLatLng(layerPoint);
4411  	},
4412
4413  	// @method latLngToContainerPoint(latlng: LatLng): Point
4414  	// Given a geographical coordinate, returns the corresponding pixel coordinate
4415  	// relative to the map container.
4416  	latLngToContainerPoint: function (latlng) {
4417  		return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng)));
4418  	},
4419
4420  	// @method mouseEventToContainerPoint(ev: MouseEvent): Point
4421  	// Given a MouseEvent object, returns the pixel coordinate relative to the
4422  	// map container where the event took place.
4423  	mouseEventToContainerPoint: function (e) {
4424  		return getMousePosition(e, this._container);
4425  	},
4426
4427  	// @method mouseEventToLayerPoint(ev: MouseEvent): Point
4428  	// Given a MouseEvent object, returns the pixel coordinate relative to
4429  	// the [origin pixel](#map-getpixelorigin) where the event took place.
4430  	mouseEventToLayerPoint: function (e) {
4431  		return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
4432  	},
4433
4434  	// @method mouseEventToLatLng(ev: MouseEvent): LatLng
4435  	// Given a MouseEvent object, returns geographical coordinate where the
4436  	// event took place.
4437  	mouseEventToLatLng: function (e) { // (MouseEvent)
4438  		return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
4439  	},
4440
4441
4442  	// map initialization methods
4443
4444  	_initContainer: function (id) {
4445  		var container = this._container = get(id);
4446
4447  		if (!container) {
4448  			throw new Error('Map container not found.');
4449  		} else if (container._leaflet_id) {
4450  			throw new Error('Map container is already initialized.');
4451  		}
4452
4453  		on(container, 'scroll', this._onScroll, this);
4454  		this._containerId = stamp(container);
4455  	},
4456
4457  	_initLayout: function () {
4458  		var container = this._container;
4459
4460  		this._fadeAnimated = this.options.fadeAnimation && Browser.any3d;
4461
4462  		addClass(container, 'leaflet-container' +
4463  			(Browser.touch ? ' leaflet-touch' : '') +
4464  			(Browser.retina ? ' leaflet-retina' : '') +
4465  			(Browser.ielt9 ? ' leaflet-oldie' : '') +
4466  			(Browser.safari ? ' leaflet-safari' : '') +
4467  			(this._fadeAnimated ? ' leaflet-fade-anim' : ''));
4468
4469  		var position = getStyle(container, 'position');
4470
4471  		if (position !== 'absolute' && position !== 'relative' && position !== 'fixed' && position !== 'sticky') {
4472  			container.style.position = 'relative';
4473  		}
4474
4475  		this._initPanes();
4476
4477  		if (this._initControlPos) {
4478  			this._initControlPos();
4479  		}
4480  	},
4481
4482  	_initPanes: function () {
4483  		var panes = this._panes = {};
4484  		this._paneRenderers = {};
4485
4486  		// @section
4487  		//
4488  		// Panes are DOM elements used to control the ordering of layers on the map. You
4489  		// can access panes with [`map.getPane`](#map-getpane) or
4490  		// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
4491  		// [`map.createPane`](#map-createpane) method.
4492  		//
4493  		// Every map has the following default panes that differ only in zIndex.
4494  		//
4495  		// @pane mapPane: HTMLElement = 'auto'
4496  		// Pane that contains all other map panes
4497
4498  		this._mapPane = this.createPane('mapPane', this._container);
4499  		setPosition(this._mapPane, new Point(0, 0));
4500
4501  		// @pane tilePane: HTMLElement = 200
4502  		// Pane for `GridLayer`s and `TileLayer`s
4503  		this.createPane('tilePane');
4504  		// @pane overlayPane: HTMLElement = 400
4505  		// Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s
4506  		this.createPane('overlayPane');
4507  		// @pane shadowPane: HTMLElement = 500
4508  		// Pane for overlay shadows (e.g. `Marker` shadows)
4509  		this.createPane('shadowPane');
4510  		// @pane markerPane: HTMLElement = 600
4511  		// Pane for `Icon`s of `Marker`s
4512  		this.createPane('markerPane');
4513  		// @pane tooltipPane: HTMLElement = 650
4514  		// Pane for `Tooltip`s.
4515  		this.createPane('tooltipPane');
4516  		// @pane popupPane: HTMLElement = 700
4517  		// Pane for `Popup`s.
4518  		this.createPane('popupPane');
4519
4520  		if (!this.options.markerZoomAnimation) {
4521  			addClass(panes.markerPane, 'leaflet-zoom-hide');
4522  			addClass(panes.shadowPane, 'leaflet-zoom-hide');
4523  		}
4524  	},
4525
4526
4527  	// private methods that modify map state
4528
4529  	// @section Map state change events
4530  	_resetView: function (center, zoom, noMoveStart) {
4531  		setPosition(this._mapPane, new Point(0, 0));
4532
4533  		var loading = !this._loaded;
4534  		this._loaded = true;
4535  		zoom = this._limitZoom(zoom);
4536
4537  		this.fire('viewprereset');
4538
4539  		var zoomChanged = this._zoom !== zoom;
4540  		this
4541  			._moveStart(zoomChanged, noMoveStart)
4542  			._move(center, zoom)
4543  			._moveEnd(zoomChanged);
4544
4545  		// @event viewreset: Event
4546  		// Fired when the map needs to redraw its content (this usually happens
4547  		// on map zoom or load). Very useful for creating custom overlays.
4548  		this.fire('viewreset');
4549
4550  		// @event load: Event
4551  		// Fired when the map is initialized (when its center and zoom are set
4552  		// for the first time).
4553  		if (loading) {
4554  			this.fire('load');
4555  		}
4556  	},
4557
4558  	_moveStart: function (zoomChanged, noMoveStart) {
4559  		// @event zoomstart: Event
4560  		// Fired when the map zoom is about to change (e.g. before zoom animation).
4561  		// @event movestart: Event
4562  		// Fired when the view of the map starts changing (e.g. user starts dragging the map).
4563  		if (zoomChanged) {
4564  			this.fire('zoomstart');
4565  		}
4566  		if (!noMoveStart) {
4567  			this.fire('movestart');
4568  		}
4569  		return this;
4570  	},
4571
4572  	_move: function (center, zoom, data, supressEvent) {
4573  		if (zoom === undefined) {
4574  			zoom = this._zoom;
4575  		}
4576  		var zoomChanged = this._zoom !== zoom;
4577
4578  		this._zoom = zoom;
4579  		this._lastCenter = center;
4580  		this._pixelOrigin = this._getNewPixelOrigin(center);
4581
4582  		if (!supressEvent) {
4583  			// @event zoom: Event
4584  			// Fired repeatedly during any change in zoom level,
4585  			// including zoom and fly animations.
4586  			if (zoomChanged || (data && data.pinch)) {	// Always fire 'zoom' if pinching because #3530
4587  				this.fire('zoom', data);
4588  			}
4589
4590  			// @event move: Event
4591  			// Fired repeatedly during any movement of the map,
4592  			// including pan and fly animations.
4593  			this.fire('move', data);
4594  		} else if (data && data.pinch) {	// Always fire 'zoom' if pinching because #3530
4595  			this.fire('zoom', data);
4596  		}
4597  		return this;
4598  	},
4599
4600  	_moveEnd: function (zoomChanged) {
4601  		// @event zoomend: Event
4602  		// Fired when the map zoom changed, after any animations.
4603  		if (zoomChanged) {
4604  			this.fire('zoomend');
4605  		}
4606
4607  		// @event moveend: Event
4608  		// Fired when the center of the map stops changing
4609  		// (e.g. user stopped dragging the map or after non-centered zoom).
4610  		return this.fire('moveend');
4611  	},
4612
4613  	_stop: function () {
4614  		cancelAnimFrame(this._flyToFrame);
4615  		if (this._panAnim) {
4616  			this._panAnim.stop();
4617  		}
4618  		return this;
4619  	},
4620
4621  	_rawPanBy: function (offset) {
4622  		setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
4623  	},
4624
4625  	_getZoomSpan: function () {
4626  		return this.getMaxZoom() - this.getMinZoom();
4627  	},
4628
4629  	_panInsideMaxBounds: function () {
4630  		if (!this._enforcingBounds) {
4631  			this.panInsideBounds(this.options.maxBounds);
4632  		}
4633  	},
4634
4635  	_checkIfLoaded: function () {
4636  		if (!this._loaded) {
4637  			throw new Error('Set map center and zoom first.');
4638  		}
4639  	},
4640
4641  	// DOM event handling
4642
4643  	// @section Interaction events
4644  	_initEvents: function (remove) {
4645  		this._targets = {};
4646  		this._targets[stamp(this._container)] = this;
4647
4648  		var onOff = remove ? off : on;
4649
4650  		// @event click: MouseEvent
4651  		// Fired when the user clicks (or taps) the map.
4652  		// @event dblclick: MouseEvent
4653  		// Fired when the user double-clicks (or double-taps) the map.
4654  		// @event mousedown: MouseEvent
4655  		// Fired when the user pushes the mouse button on the map.
4656  		// @event mouseup: MouseEvent
4657  		// Fired when the user releases the mouse button on the map.
4658  		// @event mouseover: MouseEvent
4659  		// Fired when the mouse enters the map.
4660  		// @event mouseout: MouseEvent
4661  		// Fired when the mouse leaves the map.
4662  		// @event mousemove: MouseEvent
4663  		// Fired while the mouse moves over the map.
4664  		// @event contextmenu: MouseEvent
4665  		// Fired when the user pushes the right mouse button on the map, prevents
4666  		// default browser context menu from showing if there are listeners on
4667  		// this event. Also fired on mobile when the user holds a single touch
4668  		// for a second (also called long press).
4669  		// @event keypress: KeyboardEvent
4670  		// Fired when the user presses a key from the keyboard that produces a character value while the map is focused.
4671  		// @event keydown: KeyboardEvent
4672  		// Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event,
4673  		// the `keydown` event is fired for keys that produce a character value and for keys
4674  		// that do not produce a character value.
4675  		// @event keyup: KeyboardEvent
4676  		// Fired when the user releases a key from the keyboard while the map is focused.
4677  		onOff(this._container, 'click dblclick mousedown mouseup ' +
4678  			'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this);
4679
4680  		if (this.options.trackResize) {
4681  			onOff(window, 'resize', this._onResize, this);
4682  		}
4683
4684  		if (Browser.any3d && this.options.transform3DLimit) {
4685  			(remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd);
4686  		}
4687  	},
4688
4689  	_onResize: function () {
4690  		cancelAnimFrame(this._resizeRequest);
4691  		this._resizeRequest = requestAnimFrame(
4692  		        function () { this.invalidateSize({debounceMoveend: true}); }, this);
4693  	},
4694
4695  	_onScroll: function () {
4696  		this._container.scrollTop  = 0;
4697  		this._container.scrollLeft = 0;
4698  	},
4699
4700  	_onMoveEnd: function () {
4701  		var pos = this._getMapPanePos();
4702  		if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
4703  			// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
4704  			// a pixel offset on very high values, see: https://jsfiddle.net/dg6r5hhb/
4705  			this._resetView(this.getCenter(), this.getZoom());
4706  		}
4707  	},
4708
4709  	_findEventTargets: function (e, type) {
4710  		var targets = [],
4711  		    target,
4712  		    isHover = type === 'mouseout' || type === 'mouseover',
4713  		    src = e.target || e.srcElement,
4714  		    dragging = false;
4715
4716  		while (src) {
4717  			target = this._targets[stamp(src)];
4718  			if (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) {
4719  				// Prevent firing click after you just dragged an object.
4720  				dragging = true;
4721  				break;
4722  			}
4723  			if (target && target.listens(type, true)) {
4724  				if (isHover && !isExternalTarget(src, e)) { break; }
4725  				targets.push(target);
4726  				if (isHover) { break; }
4727  			}
4728  			if (src === this._container) { break; }
4729  			src = src.parentNode;
4730  		}
4731  		if (!targets.length && !dragging && !isHover && this.listens(type, true)) {
4732  			targets = [this];
4733  		}
4734  		return targets;
4735  	},
4736
4737  	_isClickDisabled: function (el) {
4738  		while (el && el !== this._container) {
4739  			if (el['_leaflet_disable_click']) { return true; }
4740  			el = el.parentNode;
4741  		}
4742  	},
4743
4744  	_handleDOMEvent: function (e) {
4745  		var el = (e.target || e.srcElement);
4746  		if (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) {
4747  			return;
4748  		}
4749
4750  		var type = e.type;
4751
4752  		if (type === 'mousedown') {
4753  			// prevents outline when clicking on keyboard-focusable element
4754  			preventOutline(el);
4755  		}
4756
4757  		this._fireDOMEvent(e, type);
4758  	},
4759
4760  	_mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'],
4761
4762  	_fireDOMEvent: function (e, type, canvasTargets) {
4763
4764  		if (e.type === 'click') {
4765  			// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
4766  			// @event preclick: MouseEvent
4767  			// Fired before mouse click on the map (sometimes useful when you
4768  			// want something to happen on click before any existing click
4769  			// handlers start running).
4770  			var synth = extend({}, e);
4771  			synth.type = 'preclick';
4772  			this._fireDOMEvent(synth, synth.type, canvasTargets);
4773  		}
4774
4775  		// Find the layer the event is propagating from and its parents.
4776  		var targets = this._findEventTargets(e, type);
4777
4778  		if (canvasTargets) {
4779  			var filtered = []; // pick only targets with listeners
4780  			for (var i = 0; i < canvasTargets.length; i++) {
4781  				if (canvasTargets[i].listens(type, true)) {
4782  					filtered.push(canvasTargets[i]);
4783  				}
4784  			}
4785  			targets = filtered.concat(targets);
4786  		}
4787
4788  		if (!targets.length) { return; }
4789
4790  		if (type === 'contextmenu') {
4791  			preventDefault(e);
4792  		}
4793
4794  		var target = targets[0];
4795  		var data = {
4796  			originalEvent: e
4797  		};
4798
4799  		if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') {
4800  			var isMarker = target.getLatLng && (!target._radius || target._radius <= 10);
4801  			data.containerPoint = isMarker ?
4802  				this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
4803  			data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
4804  			data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
4805  		}
4806
4807  		for (i = 0; i < targets.length; i++) {
4808  			targets[i].fire(type, data, true);
4809  			if (data.originalEvent._stopped ||
4810  				(targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; }
4811  		}
4812  	},
4813
4814  	_draggableMoved: function (obj) {
4815  		obj = obj.dragging && obj.dragging.enabled() ? obj : this;
4816  		return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
4817  	},
4818
4819  	_clearHandlers: function () {
4820  		for (var i = 0, len = this._handlers.length; i < len; i++) {
4821  			this._handlers[i].disable();
4822  		}
4823  	},
4824
4825  	// @section Other Methods
4826
4827  	// @method whenReady(fn: Function, context?: Object): this
4828  	// Runs the given function `fn` when the map gets initialized with
4829  	// a view (center and zoom) and at least one layer, or immediately
4830  	// if it's already initialized, optionally passing a function context.
4831  	whenReady: function (callback, context) {
4832  		if (this._loaded) {
4833  			callback.call(context || this, {target: this});
4834  		} else {
4835  			this.on('load', callback, context);
4836  		}
4837  		return this;
4838  	},
4839
4840
4841  	// private methods for getting map state
4842
4843  	_getMapPanePos: function () {
4844  		return getPosition(this._mapPane) || new Point(0, 0);
4845  	},
4846
4847  	_moved: function () {
4848  		var pos = this._getMapPanePos();
4849  		return pos && !pos.equals([0, 0]);
4850  	},
4851
4852  	_getTopLeftPoint: function (center, zoom) {
4853  		var pixelOrigin = center && zoom !== undefined ?
4854  			this._getNewPixelOrigin(center, zoom) :
4855  			this.getPixelOrigin();
4856  		return pixelOrigin.subtract(this._getMapPanePos());
4857  	},
4858
4859  	_getNewPixelOrigin: function (center, zoom) {
4860  		var viewHalf = this.getSize()._divideBy(2);
4861  		return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
4862  	},
4863
4864  	_latLngToNewLayerPoint: function (latlng, zoom, center) {
4865  		var topLeft = this._getNewPixelOrigin(center, zoom);
4866  		return this.project(latlng, zoom)._subtract(topLeft);
4867  	},
4868
4869  	_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
4870  		var topLeft = this._getNewPixelOrigin(center, zoom);
4871  		return toBounds([
4872  			this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
4873  			this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
4874  			this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
4875  			this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
4876  		]);
4877  	},
4878
4879  	// layer point of the current center
4880  	_getCenterLayerPoint: function () {
4881  		return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
4882  	},
4883
4884  	// offset of the specified place to the current center in pixels
4885  	_getCenterOffset: function (latlng) {
4886  		return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
4887  	},
4888
4889  	// adjust center for view to get inside bounds
4890  	_limitCenter: function (center, zoom, bounds) {
4891
4892  		if (!bounds) { return center; }
4893
4894  		var centerPoint = this.project(center, zoom),
4895  		    viewHalf = this.getSize().divideBy(2),
4896  		    viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
4897  		    offset = this._getBoundsOffset(viewBounds, bounds, zoom);
4898
4899  		// If offset is less than a pixel, ignore.
4900  		// This prevents unstable projections from getting into
4901  		// an infinite loop of tiny offsets.
4902  		if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) {
4903  			return center;
4904  		}
4905
4906  		return this.unproject(centerPoint.add(offset), zoom);
4907  	},
4908
4909  	// adjust offset for view to get inside bounds
4910  	_limitOffset: function (offset, bounds) {
4911  		if (!bounds) { return offset; }
4912
4913  		var viewBounds = this.getPixelBounds(),
4914  		    newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
4915
4916  		return offset.add(this._getBoundsOffset(newBounds, bounds));
4917  	},
4918
4919  	// returns offset needed for pxBounds to get inside maxBounds at a specified zoom
4920  	_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
4921  		var projectedMaxBounds = toBounds(
4922  		        this.project(maxBounds.getNorthEast(), zoom),
4923  		        this.project(maxBounds.getSouthWest(), zoom)
4924  		    ),
4925  		    minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
4926  		    maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
4927
4928  		    dx = this._rebound(minOffset.x, -maxOffset.x),
4929  		    dy = this._rebound(minOffset.y, -maxOffset.y);
4930
4931  		return new Point(dx, dy);
4932  	},
4933
4934  	_rebound: function (left, right) {
4935  		return left + right > 0 ?
4936  			Math.round(left - right) / 2 :
4937  			Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
4938  	},
4939
4940  	_limitZoom: function (zoom) {
4941  		var min = this.getMinZoom(),
4942  		    max = this.getMaxZoom(),
4943  		    snap = Browser.any3d ? this.options.zoomSnap : 1;
4944  		if (snap) {
4945  			zoom = Math.round(zoom / snap) * snap;
4946  		}
4947  		return Math.max(min, Math.min(max, zoom));
4948  	},
4949
4950  	_onPanTransitionStep: function () {
4951  		this.fire('move');
4952  	},
4953
4954  	_onPanTransitionEnd: function () {
4955  		removeClass(this._mapPane, 'leaflet-pan-anim');
4956  		this.fire('moveend');
4957  	},
4958
4959  	_tryAnimatedPan: function (center, options) {
4960  		// difference between the new and current centers in pixels
4961  		var offset = this._getCenterOffset(center)._trunc();
4962
4963  		// don't animate too far unless animate: true specified in options
4964  		if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
4965
4966  		this.panBy(offset, options);
4967
4968  		return true;
4969  	},
4970
4971  	_createAnimProxy: function () {
4972
4973  		var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated');
4974  		this._panes.mapPane.appendChild(proxy);
4975
4976  		this.on('zoomanim', function (e) {
4977  			var prop = TRANSFORM,
4978  			    transform = this._proxy.style[prop];
4979
4980  			setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
4981
4982  			// workaround for case when transform is the same and so transitionend event is not fired
4983  			if (transform === this._proxy.style[prop] && this._animatingZoom) {
4984  				this._onZoomTransitionEnd();
4985  			}
4986  		}, this);
4987
4988  		this.on('load moveend', this._animMoveEnd, this);
4989
4990  		this._on('unload', this._destroyAnimProxy, this);
4991  	},
4992
4993  	_destroyAnimProxy: function () {
4994  		remove(this._proxy);
4995  		this.off('load moveend', this._animMoveEnd, this);
4996  		delete this._proxy;
4997  	},
4998
4999  	_animMoveEnd: function () {
5000  		var c = this.getCenter(),
5001  		    z = this.getZoom();
5002  		setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1));
5003  	},
5004
5005  	_catchTransitionEnd: function (e) {
5006  		if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
5007  			this._onZoomTransitionEnd();
5008  		}
5009  	},
5010
5011  	_nothingToAnimate: function () {
5012  		return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
5013  	},
5014
5015  	_tryAnimatedZoom: function (center, zoom, options) {
5016
5017  		if (this._animatingZoom) { return true; }
5018
5019  		options = options || {};
5020
5021  		// don't animate if disabled, not supported or zoom difference is too large
5022  		if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
5023  		        Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
5024
5025  		// offset is the pixel coords of the zoom origin relative to the current center
5026  		var scale = this.getZoomScale(zoom),
5027  		    offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
5028
5029  		// don't animate if the zoom origin isn't within one screen from the current center, unless forced
5030  		if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
5031
5032  		requestAnimFrame(function () {
5033  			this
5034  			    ._moveStart(true, options.noMoveStart || false)
5035  			    ._animateZoom(center, zoom, true);
5036  		}, this);
5037
5038  		return true;
5039  	},
5040
5041  	_animateZoom: function (center, zoom, startAnim, noUpdate) {
5042  		if (!this._mapPane) { return; }
5043
5044  		if (startAnim) {
5045  			this._animatingZoom = true;
5046
5047  			// remember what center/zoom to set after animation
5048  			this._animateToCenter = center;
5049  			this._animateToZoom = zoom;
5050
5051  			addClass(this._mapPane, 'leaflet-zoom-anim');
5052  		}
5053
5054  		// @section Other Events
5055  		// @event zoomanim: ZoomAnimEvent
5056  		// Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom.
5057  		this.fire('zoomanim', {
5058  			center: center,
5059  			zoom: zoom,
5060  			noUpdate: noUpdate
5061  		});
5062
5063  		if (!this._tempFireZoomEvent) {
5064  			this._tempFireZoomEvent = this._zoom !== this._animateToZoom;
5065  		}
5066
5067  		this._move(this._animateToCenter, this._animateToZoom, undefined, true);
5068
5069  		// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
5070  		setTimeout(bind(this._onZoomTransitionEnd, this), 250);
5071  	},
5072
5073  	_onZoomTransitionEnd: function () {
5074  		if (!this._animatingZoom) { return; }
5075
5076  		if (this._mapPane) {
5077  			removeClass(this._mapPane, 'leaflet-zoom-anim');
5078  		}
5079
5080  		this._animatingZoom = false;
5081
5082  		this._move(this._animateToCenter, this._animateToZoom, undefined, true);
5083
5084  		if (this._tempFireZoomEvent) {
5085  			this.fire('zoom');
5086  		}
5087  		delete this._tempFireZoomEvent;
5088
5089  		this.fire('move');
5090
5091  		this._moveEnd(true);
5092  	}
5093  });
5094
5095  // @section
5096
5097  // @factory L.map(id: String, options?: Map options)
5098  // Instantiates a map object given the DOM ID of a `<div>` element
5099  // and optionally an object literal with `Map options`.
5100  //
5101  // @alternative
5102  // @factory L.map(el: HTMLElement, options?: Map options)
5103  // Instantiates a map object given an instance of a `<div>` HTML element
5104  // and optionally an object literal with `Map options`.
5105  function createMap(id, options) {
5106  	return new Map(id, options);
5107  }
5108
5109  /*
5110   * @class Control
5111   * @aka L.Control
5112   * @inherits Class
5113   *
5114   * L.Control is a base class for implementing map controls. Handles positioning.
5115   * All other controls extend from this class.
5116   */
5117
5118  var Control = Class.extend({
5119  	// @section
5120  	// @aka Control Options
5121  	options: {
5122  		// @option position: String = 'topright'
5123  		// The position of the control (one of the map corners). Possible values are `'topleft'`,
5124  		// `'topright'`, `'bottomleft'` or `'bottomright'`
5125  		position: 'topright'
5126  	},
5127
5128  	initialize: function (options) {
5129  		setOptions(this, options);
5130  	},
5131
5132  	/* @section
5133  	 * Classes extending L.Control will inherit the following methods:
5134  	 *
5135  	 * @method getPosition: string
5136  	 * Returns the position of the control.
5137  	 */
5138  	getPosition: function () {
5139  		return this.options.position;
5140  	},
5141
5142  	// @method setPosition(position: string): this
5143  	// Sets the position of the control.
5144  	setPosition: function (position) {
5145  		var map = this._map;
5146
5147  		if (map) {
5148  			map.removeControl(this);
5149  		}
5150
5151  		this.options.position = position;
5152
5153  		if (map) {
5154  			map.addControl(this);
5155  		}
5156
5157  		return this;
5158  	},
5159
5160  	// @method getContainer: HTMLElement
5161  	// Returns the HTMLElement that contains the control.
5162  	getContainer: function () {
5163  		return this._container;
5164  	},
5165
5166  	// @method addTo(map: Map): this
5167  	// Adds the control to the given map.
5168  	addTo: function (map) {
5169  		this.remove();
5170  		this._map = map;
5171
5172  		var container = this._container = this.onAdd(map),
5173  		    pos = this.getPosition(),
5174  		    corner = map._controlCorners[pos];
5175
5176  		addClass(container, 'leaflet-control');
5177
5178  		if (pos.indexOf('bottom') !== -1) {
5179  			corner.insertBefore(container, corner.firstChild);
5180  		} else {
5181  			corner.appendChild(container);
5182  		}
5183
5184  		this._map.on('unload', this.remove, this);
5185
5186  		return this;
5187  	},
5188
5189  	// @method remove: this
5190  	// Removes the control from the map it is currently active on.
5191  	remove: function () {
5192  		if (!this._map) {
5193  			return this;
5194  		}
5195
5196  		remove(this._container);
5197
5198  		if (this.onRemove) {
5199  			this.onRemove(this._map);
5200  		}
5201
5202  		this._map.off('unload', this.remove, this);
5203  		this._map = null;
5204
5205  		return this;
5206  	},
5207
5208  	_refocusOnMap: function (e) {
5209  		// if map exists and event is not a keyboard event
5210  		if (this._map && e && e.screenX > 0 && e.screenY > 0) {
5211  			this._map.getContainer().focus();
5212  		}
5213  	}
5214  });
5215
5216  var control = function (options) {
5217  	return new Control(options);
5218  };
5219
5220  /* @section Extension methods
5221   * @uninheritable
5222   *
5223   * Every control should extend from `L.Control` and (re-)implement the following methods.
5224   *
5225   * @method onAdd(map: Map): HTMLElement
5226   * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
5227   *
5228   * @method onRemove(map: Map)
5229   * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
5230   */
5231
5232  /* @namespace Map
5233   * @section Methods for Layers and Controls
5234   */
5235  Map.include({
5236  	// @method addControl(control: Control): this
5237  	// Adds the given control to the map
5238  	addControl: function (control) {
5239  		control.addTo(this);
5240  		return this;
5241  	},
5242
5243  	// @method removeControl(control: Control): this
5244  	// Removes the given control from the map
5245  	removeControl: function (control) {
5246  		control.remove();
5247  		return this;
5248  	},
5249
5250  	_initControlPos: function () {
5251  		var corners = this._controlCorners = {},
5252  		    l = 'leaflet-',
5253  		    container = this._controlContainer =
5254  		            create$1('div', l + 'control-container', this._container);
5255
5256  		function createCorner(vSide, hSide) {
5257  			var className = l + vSide + ' ' + l + hSide;
5258
5259  			corners[vSide + hSide] = create$1('div', className, container);
5260  		}
5261
5262  		createCorner('top', 'left');
5263  		createCorner('top', 'right');
5264  		createCorner('bottom', 'left');
5265  		createCorner('bottom', 'right');
5266  	},
5267
5268  	_clearControlPos: function () {
5269  		for (var i in this._controlCorners) {
5270  			remove(this._controlCorners[i]);
5271  		}
5272  		remove(this._controlContainer);
5273  		delete this._controlCorners;
5274  		delete this._controlContainer;
5275  	}
5276  });
5277
5278  /*
5279   * @class Control.Layers
5280   * @aka L.Control.Layers
5281   * @inherits Control
5282   *
5283   * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`.
5284   *
5285   * @example
5286   *
5287   * ```js
5288   * var baseLayers = {
5289   * 	"Mapbox": mapbox,
5290   * 	"OpenStreetMap": osm
5291   * };
5292   *
5293   * var overlays = {
5294   * 	"Marker": marker,
5295   * 	"Roads": roadsLayer
5296   * };
5297   *
5298   * L.control.layers(baseLayers, overlays).addTo(map);
5299   * ```
5300   *
5301   * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
5302   *
5303   * ```js
5304   * {
5305   *     "<someName1>": layer1,
5306   *     "<someName2>": layer2
5307   * }
5308   * ```
5309   *
5310   * The layer names can contain HTML, which allows you to add additional styling to the items:
5311   *
5312   * ```js
5313   * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
5314   * ```
5315   */
5316
5317  var Layers = Control.extend({
5318  	// @section
5319  	// @aka Control.Layers options
5320  	options: {
5321  		// @option collapsed: Boolean = true
5322  		// If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation.
5323  		collapsed: true,
5324  		position: 'topright',
5325
5326  		// @option autoZIndex: Boolean = true
5327  		// If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.
5328  		autoZIndex: true,
5329
5330  		// @option hideSingleBase: Boolean = false
5331  		// If `true`, the base layers in the control will be hidden when there is only one.
5332  		hideSingleBase: false,
5333
5334  		// @option sortLayers: Boolean = false
5335  		// Whether to sort the layers. When `false`, layers will keep the order
5336  		// in which they were added to the control.
5337  		sortLayers: false,
5338
5339  		// @option sortFunction: Function = *
5340  		// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
5341  		// that will be used for sorting the layers, when `sortLayers` is `true`.
5342  		// The function receives both the `L.Layer` instances and their names, as in
5343  		// `sortFunction(layerA, layerB, nameA, nameB)`.
5344  		// By default, it sorts layers alphabetically by their name.
5345  		sortFunction: function (layerA, layerB, nameA, nameB) {
5346  			return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
5347  		}
5348  	},
5349
5350  	initialize: function (baseLayers, overlays, options) {
5351  		setOptions(this, options);
5352
5353  		this._layerControlInputs = [];
5354  		this._layers = [];
5355  		this._lastZIndex = 0;
5356  		this._handlingClick = false;
5357  		this._preventClick = false;
5358
5359  		for (var i in baseLayers) {
5360  			this._addLayer(baseLayers[i], i);
5361  		}
5362
5363  		for (i in overlays) {
5364  			this._addLayer(overlays[i], i, true);
5365  		}
5366  	},
5367
5368  	onAdd: function (map) {
5369  		this._initLayout();
5370  		this._update();
5371
5372  		this._map = map;
5373  		map.on('zoomend', this._checkDisabledLayers, this);
5374
5375  		for (var i = 0; i < this._layers.length; i++) {
5376  			this._layers[i].layer.on('add remove', this._onLayerChange, this);
5377  		}
5378
5379  		return this._container;
5380  	},
5381
5382  	addTo: function (map) {
5383  		Control.prototype.addTo.call(this, map);
5384  		// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.
5385  		return this._expandIfNotCollapsed();
5386  	},
5387
5388  	onRemove: function () {
5389  		this._map.off('zoomend', this._checkDisabledLayers, this);
5390
5391  		for (var i = 0; i < this._layers.length; i++) {
5392  			this._layers[i].layer.off('add remove', this._onLayerChange, this);
5393  		}
5394  	},
5395
5396  	// @method addBaseLayer(layer: Layer, name: String): this
5397  	// Adds a base layer (radio button entry) with the given name to the control.
5398  	addBaseLayer: function (layer, name) {
5399  		this._addLayer(layer, name);
5400  		return (this._map) ? this._update() : this;
5401  	},
5402
5403  	// @method addOverlay(layer: Layer, name: String): this
5404  	// Adds an overlay (checkbox entry) with the given name to the control.
5405  	addOverlay: function (layer, name) {
5406  		this._addLayer(layer, name, true);
5407  		return (this._map) ? this._update() : this;
5408  	},
5409
5410  	// @method removeLayer(layer: Layer): this
5411  	// Remove the given layer from the control.
5412  	removeLayer: function (layer) {
5413  		layer.off('add remove', this._onLayerChange, this);
5414
5415  		var obj = this._getLayer(stamp(layer));
5416  		if (obj) {
5417  			this._layers.splice(this._layers.indexOf(obj), 1);
5418  		}
5419  		return (this._map) ? this._update() : this;
5420  	},
5421
5422  	// @method expand(): this
5423  	// Expand the control container if collapsed.
5424  	expand: function () {
5425  		addClass(this._container, 'leaflet-control-layers-expanded');
5426  		this._section.style.height = null;
5427  		var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
5428  		if (acceptableHeight < this._section.clientHeight) {
5429  			addClass(this._section, 'leaflet-control-layers-scrollbar');
5430  			this._section.style.height = acceptableHeight + 'px';
5431  		} else {
5432  			removeClass(this._section, 'leaflet-control-layers-scrollbar');
5433  		}
5434  		this._checkDisabledLayers();
5435  		return this;
5436  	},
5437
5438  	// @method collapse(): this
5439  	// Collapse the control container if expanded.
5440  	collapse: function () {
5441  		removeClass(this._container, 'leaflet-control-layers-expanded');
5442  		return this;
5443  	},
5444
5445  	_initLayout: function () {
5446  		var className = 'leaflet-control-layers',
5447  		    container = this._container = create$1('div', className),
5448  		    collapsed = this.options.collapsed;
5449
5450  		// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
5451  		container.setAttribute('aria-haspopup', true);
5452
5453  		disableClickPropagation(container);
5454  		disableScrollPropagation(container);
5455
5456  		var section = this._section = create$1('section', className + '-list');
5457
5458  		if (collapsed) {
5459  			this._map.on('click', this.collapse, this);
5460
5461  			on(container, {
5462  				mouseenter: this._expandSafely,
5463  				mouseleave: this.collapse
5464  			}, this);
5465  		}
5466
5467  		var link = this._layersLink = create$1('a', className + '-toggle', container);
5468  		link.href = '#';
5469  		link.title = 'Layers';
5470  		link.setAttribute('role', 'button');
5471
5472  		on(link, {
5473  			keydown: function (e) {
5474  				if (e.keyCode === 13) {
5475  					this._expandSafely();
5476  				}
5477  			},
5478  			// Certain screen readers intercept the key event and instead send a click event
5479  			click: function (e) {
5480  				preventDefault(e);
5481  				this._expandSafely();
5482  			}
5483  		}, this);
5484
5485  		if (!collapsed) {
5486  			this.expand();
5487  		}
5488
5489  		this._baseLayersList = create$1('div', className + '-base', section);
5490  		this._separator = create$1('div', className + '-separator', section);
5491  		this._overlaysList = create$1('div', className + '-overlays', section);
5492
5493  		container.appendChild(section);
5494  	},
5495
5496  	_getLayer: function (id) {
5497  		for (var i = 0; i < this._layers.length; i++) {
5498
5499  			if (this._layers[i] && stamp(this._layers[i].layer) === id) {
5500  				return this._layers[i];
5501  			}
5502  		}
5503  	},
5504
5505  	_addLayer: function (layer, name, overlay) {
5506  		if (this._map) {
5507  			layer.on('add remove', this._onLayerChange, this);
5508  		}
5509
5510  		this._layers.push({
5511  			layer: layer,
5512  			name: name,
5513  			overlay: overlay
5514  		});
5515
5516  		if (this.options.sortLayers) {
5517  			this._layers.sort(bind(function (a, b) {
5518  				return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
5519  			}, this));
5520  		}
5521
5522  		if (this.options.autoZIndex && layer.setZIndex) {
5523  			this._lastZIndex++;
5524  			layer.setZIndex(this._lastZIndex);
5525  		}
5526
5527  		this._expandIfNotCollapsed();
5528  	},
5529
5530  	_update: function () {
5531  		if (!this._container) { return this; }
5532
5533  		empty(this._baseLayersList);
5534  		empty(this._overlaysList);
5535
5536  		this._layerControlInputs = [];
5537  		var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
5538
5539  		for (i = 0; i < this._layers.length; i++) {
5540  			obj = this._layers[i];
5541  			this._addItem(obj);
5542  			overlaysPresent = overlaysPresent || obj.overlay;
5543  			baseLayersPresent = baseLayersPresent || !obj.overlay;
5544  			baseLayersCount += !obj.overlay ? 1 : 0;
5545  		}
5546
5547  		// Hide base layers section if there's only one layer.
5548  		if (this.options.hideSingleBase) {
5549  			baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
5550  			this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
5551  		}
5552
5553  		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
5554
5555  		return this;
5556  	},
5557
5558  	_onLayerChange: function (e) {
5559  		if (!this._handlingClick) {
5560  			this._update();
5561  		}
5562
5563  		var obj = this._getLayer(stamp(e.target));
5564
5565  		// @namespace Map
5566  		// @section Layer events
5567  		// @event baselayerchange: LayersControlEvent
5568  		// Fired when the base layer is changed through the [layers control](#control-layers).
5569  		// @event overlayadd: LayersControlEvent
5570  		// Fired when an overlay is selected through the [layers control](#control-layers).
5571  		// @event overlayremove: LayersControlEvent
5572  		// Fired when an overlay is deselected through the [layers control](#control-layers).
5573  		// @namespace Control.Layers
5574  		var type = obj.overlay ?
5575  			(e.type === 'add' ? 'overlayadd' : 'overlayremove') :
5576  			(e.type === 'add' ? 'baselayerchange' : null);
5577
5578  		if (type) {
5579  			this._map.fire(type, obj);
5580  		}
5581  	},
5582
5583  	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079)
5584  	_createRadioElement: function (name, checked) {
5585
5586  		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
5587  				name + '"' + (checked ? ' checked="checked"' : '') + '/>';
5588
5589  		var radioFragment = document.createElement('div');
5590  		radioFragment.innerHTML = radioHtml;
5591
5592  		return radioFragment.firstChild;
5593  	},
5594
5595  	_addItem: function (obj) {
5596  		var label = document.createElement('label'),
5597  		    checked = this._map.hasLayer(obj.layer),
5598  		    input;
5599
5600  		if (obj.overlay) {
5601  			input = document.createElement('input');
5602  			input.type = 'checkbox';
5603  			input.className = 'leaflet-control-layers-selector';
5604  			input.defaultChecked = checked;
5605  		} else {
5606  			input = this._createRadioElement('leaflet-base-layers_' + stamp(this), checked);
5607  		}
5608
5609  		this._layerControlInputs.push(input);
5610  		input.layerId = stamp(obj.layer);
5611
5612  		on(input, 'click', this._onInputClick, this);
5613
5614  		var name = document.createElement('span');
5615  		name.innerHTML = ' ' + obj.name;
5616
5617  		// Helps from preventing layer control flicker when checkboxes are disabled
5618  		// https://github.com/Leaflet/Leaflet/issues/2771
5619  		var holder = document.createElement('span');
5620
5621  		label.appendChild(holder);
5622  		holder.appendChild(input);
5623  		holder.appendChild(name);
5624
5625  		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
5626  		container.appendChild(label);
5627
5628  		this._checkDisabledLayers();
5629  		return label;
5630  	},
5631
5632  	_onInputClick: function () {
5633  		// expanding the control on mobile with a click can cause adding a layer - we don't want this
5634  		if (this._preventClick) {
5635  			return;
5636  		}
5637
5638  		var inputs = this._layerControlInputs,
5639  		    input, layer;
5640  		var addedLayers = [],
5641  		    removedLayers = [];
5642
5643  		this._handlingClick = true;
5644
5645  		for (var i = inputs.length - 1; i >= 0; i--) {
5646  			input = inputs[i];
5647  			layer = this._getLayer(input.layerId).layer;
5648
5649  			if (input.checked) {
5650  				addedLayers.push(layer);
5651  			} else if (!input.checked) {
5652  				removedLayers.push(layer);
5653  			}
5654  		}
5655
5656  		// Bugfix issue 2318: Should remove all old layers before readding new ones
5657  		for (i = 0; i < removedLayers.length; i++) {
5658  			if (this._map.hasLayer(removedLayers[i])) {
5659  				this._map.removeLayer(removedLayers[i]);
5660  			}
5661  		}
5662  		for (i = 0; i < addedLayers.length; i++) {
5663  			if (!this._map.hasLayer(addedLayers[i])) {
5664  				this._map.addLayer(addedLayers[i]);
5665  			}
5666  		}
5667
5668  		this._handlingClick = false;
5669
5670  		this._refocusOnMap();
5671  	},
5672
5673  	_checkDisabledLayers: function () {
5674  		var inputs = this._layerControlInputs,
5675  		    input,
5676  		    layer,
5677  		    zoom = this._map.getZoom();
5678
5679  		for (var i = inputs.length - 1; i >= 0; i--) {
5680  			input = inputs[i];
5681  			layer = this._getLayer(input.layerId).layer;
5682  			input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
5683  			                 (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
5684
5685  		}
5686  	},
5687
5688  	_expandIfNotCollapsed: function () {
5689  		if (this._map && !this.options.collapsed) {
5690  			this.expand();
5691  		}
5692  		return this;
5693  	},
5694
5695  	_expandSafely: function () {
5696  		var section = this._section;
5697  		this._preventClick = true;
5698  		on(section, 'click', preventDefault);
5699  		this.expand();
5700  		var that = this;
5701  		setTimeout(function () {
5702  			off(section, 'click', preventDefault);
5703  			that._preventClick = false;
5704  		});
5705  	}
5706
5707  });
5708
5709
5710  // @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
5711  // Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.
5712  var layers = function (baseLayers, overlays, options) {
5713  	return new Layers(baseLayers, overlays, options);
5714  };
5715
5716  /*
5717   * @class Control.Zoom
5718   * @aka L.Control.Zoom
5719   * @inherits Control
5720   *
5721   * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.
5722   */
5723
5724  var Zoom = Control.extend({
5725  	// @section
5726  	// @aka Control.Zoom options
5727  	options: {
5728  		position: 'topleft',
5729
5730  		// @option zoomInText: String = '<span aria-hidden="true">+</span>'
5731  		// The text set on the 'zoom in' button.
5732  		zoomInText: '<span aria-hidden="true">+</span>',
5733
5734  		// @option zoomInTitle: String = 'Zoom in'
5735  		// The title set on the 'zoom in' button.
5736  		zoomInTitle: 'Zoom in',
5737
5738  		// @option zoomOutText: String = '<span aria-hidden="true">&#x2212;</span>'
5739  		// The text set on the 'zoom out' button.
5740  		zoomOutText: '<span aria-hidden="true">&#x2212;</span>',
5741
5742  		// @option zoomOutTitle: String = 'Zoom out'
5743  		// The title set on the 'zoom out' button.
5744  		zoomOutTitle: 'Zoom out'
5745  	},
5746
5747  	onAdd: function (map) {
5748  		var zoomName = 'leaflet-control-zoom',
5749  		    container = create$1('div', zoomName + ' leaflet-bar'),
5750  		    options = this.options;
5751
5752  		this._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,
5753  		        zoomName + '-in',  container, this._zoomIn);
5754  		this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
5755  		        zoomName + '-out', container, this._zoomOut);
5756
5757  		this._updateDisabled();
5758  		map.on('zoomend zoomlevelschange', this._updateDisabled, this);
5759
5760  		return container;
5761  	},
5762
5763  	onRemove: function (map) {
5764  		map.off('zoomend zoomlevelschange', this._updateDisabled, this);
5765  	},
5766
5767  	disable: function () {
5768  		this._disabled = true;
5769  		this._updateDisabled();
5770  		return this;
5771  	},
5772
5773  	enable: function () {
5774  		this._disabled = false;
5775  		this._updateDisabled();
5776  		return this;
5777  	},
5778
5779  	_zoomIn: function (e) {
5780  		if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
5781  			this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5782  		}
5783  	},
5784
5785  	_zoomOut: function (e) {
5786  		if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
5787  			this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
5788  		}
5789  	},
5790
5791  	_createButton: function (html, title, className, container, fn) {
5792  		var link = create$1('a', className, container);
5793  		link.innerHTML = html;
5794  		link.href = '#';
5795  		link.title = title;
5796
5797  		/*
5798  		 * Will force screen readers like VoiceOver to read this as "Zoom in - button"
5799  		 */
5800  		link.setAttribute('role', 'button');
5801  		link.setAttribute('aria-label', title);
5802
5803  		disableClickPropagation(link);
5804  		on(link, 'click', stop);
5805  		on(link, 'click', fn, this);
5806  		on(link, 'click', this._refocusOnMap, this);
5807
5808  		return link;
5809  	},
5810
5811  	_updateDisabled: function () {
5812  		var map = this._map,
5813  		    className = 'leaflet-disabled';
5814
5815  		removeClass(this._zoomInButton, className);
5816  		removeClass(this._zoomOutButton, className);
5817  		this._zoomInButton.setAttribute('aria-disabled', 'false');
5818  		this._zoomOutButton.setAttribute('aria-disabled', 'false');
5819
5820  		if (this._disabled || map._zoom === map.getMinZoom()) {
5821  			addClass(this._zoomOutButton, className);
5822  			this._zoomOutButton.setAttribute('aria-disabled', 'true');
5823  		}
5824  		if (this._disabled || map._zoom === map.getMaxZoom()) {
5825  			addClass(this._zoomInButton, className);
5826  			this._zoomInButton.setAttribute('aria-disabled', 'true');
5827  		}
5828  	}
5829  });
5830
5831  // @namespace Map
5832  // @section Control options
5833  // @option zoomControl: Boolean = true
5834  // Whether a [zoom control](#control-zoom) is added to the map by default.
5835  Map.mergeOptions({
5836  	zoomControl: true
5837  });
5838
5839  Map.addInitHook(function () {
5840  	if (this.options.zoomControl) {
5841  		// @section Controls
5842  		// @property zoomControl: Control.Zoom
5843  		// The default zoom control (only available if the
5844  		// [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map).
5845  		this.zoomControl = new Zoom();
5846  		this.addControl(this.zoomControl);
5847  	}
5848  });
5849
5850  // @namespace Control.Zoom
5851  // @factory L.control.zoom(options: Control.Zoom options)
5852  // Creates a zoom control
5853  var zoom = function (options) {
5854  	return new Zoom(options);
5855  };
5856
5857  /*
5858   * @class Control.Scale
5859   * @aka L.Control.Scale
5860   * @inherits Control
5861   *
5862   * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
5863   *
5864   * @example
5865   *
5866   * ```js
5867   * L.control.scale().addTo(map);
5868   * ```
5869   */
5870
5871  var Scale = Control.extend({
5872  	// @section
5873  	// @aka Control.Scale options
5874  	options: {
5875  		position: 'bottomleft',
5876
5877  		// @option maxWidth: Number = 100
5878  		// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
5879  		maxWidth: 100,
5880
5881  		// @option metric: Boolean = True
5882  		// Whether to show the metric scale line (m/km).
5883  		metric: true,
5884
5885  		// @option imperial: Boolean = True
5886  		// Whether to show the imperial scale line (mi/ft).
5887  		imperial: true
5888
5889  		// @option updateWhenIdle: Boolean = false
5890  		// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
5891  	},
5892
5893  	onAdd: function (map) {
5894  		var className = 'leaflet-control-scale',
5895  		    container = create$1('div', className),
5896  		    options = this.options;
5897
5898  		this._addScales(options, className + '-line', container);
5899
5900  		map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5901  		map.whenReady(this._update, this);
5902
5903  		return container;
5904  	},
5905
5906  	onRemove: function (map) {
5907  		map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
5908  	},
5909
5910  	_addScales: function (options, className, container) {
5911  		if (options.metric) {
5912  			this._mScale = create$1('div', className, container);
5913  		}
5914  		if (options.imperial) {
5915  			this._iScale = create$1('div', className, container);
5916  		}
5917  	},
5918
5919  	_update: function () {
5920  		var map = this._map,
5921  		    y = map.getSize().y / 2;
5922
5923  		var maxMeters = map.distance(
5924  			map.containerPointToLatLng([0, y]),
5925  			map.containerPointToLatLng([this.options.maxWidth, y]));
5926
5927  		this._updateScales(maxMeters);
5928  	},
5929
5930  	_updateScales: function (maxMeters) {
5931  		if (this.options.metric && maxMeters) {
5932  			this._updateMetric(maxMeters);
5933  		}
5934  		if (this.options.imperial && maxMeters) {
5935  			this._updateImperial(maxMeters);
5936  		}
5937  	},
5938
5939  	_updateMetric: function (maxMeters) {
5940  		var meters = this._getRoundNum(maxMeters),
5941  		    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
5942
5943  		this._updateScale(this._mScale, label, meters / maxMeters);
5944  	},
5945
5946  	_updateImperial: function (maxMeters) {
5947  		var maxFeet = maxMeters * 3.2808399,
5948  		    maxMiles, miles, feet;
5949
5950  		if (maxFeet > 5280) {
5951  			maxMiles = maxFeet / 5280;
5952  			miles = this._getRoundNum(maxMiles);
5953  			this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
5954
5955  		} else {
5956  			feet = this._getRoundNum(maxFeet);
5957  			this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
5958  		}
5959  	},
5960
5961  	_updateScale: function (scale, text, ratio) {
5962  		scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
5963  		scale.innerHTML = text;
5964  	},
5965
5966  	_getRoundNum: function (num) {
5967  		var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
5968  		    d = num / pow10;
5969
5970  		d = d >= 10 ? 10 :
5971  		    d >= 5 ? 5 :
5972  		    d >= 3 ? 3 :
5973  		    d >= 2 ? 2 : 1;
5974
5975  		return pow10 * d;
5976  	}
5977  });
5978
5979
5980  // @factory L.control.scale(options?: Control.Scale options)
5981  // Creates an scale control with the given options.
5982  var scale = function (options) {
5983  	return new Scale(options);
5984  };
5985
5986  var ukrainianFlag = '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg>';
5987
5988
5989  /*
5990   * @class Control.Attribution
5991   * @aka L.Control.Attribution
5992   * @inherits Control
5993   *
5994   * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
5995   */
5996
5997  var Attribution = Control.extend({
5998  	// @section
5999  	// @aka Control.Attribution options
6000  	options: {
6001  		position: 'bottomright',
6002
6003  		// @option prefix: String|false = 'Leaflet'
6004  		// The HTML text shown before the attributions. Pass `false` to disable.
6005  		prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>'
6006  	},
6007
6008  	initialize: function (options) {
6009  		setOptions(this, options);
6010
6011  		this._attributions = {};
6012  	},
6013
6014  	onAdd: function (map) {
6015  		map.attributionControl = this;
6016  		this._container = create$1('div', 'leaflet-control-attribution');
6017  		disableClickPropagation(this._container);
6018
6019  		// TODO ugly, refactor
6020  		for (var i in map._layers) {
6021  			if (map._layers[i].getAttribution) {
6022  				this.addAttribution(map._layers[i].getAttribution());
6023  			}
6024  		}
6025
6026  		this._update();
6027
6028  		map.on('layeradd', this._addAttribution, this);
6029
6030  		return this._container;
6031  	},
6032
6033  	onRemove: function (map) {
6034  		map.off('layeradd', this._addAttribution, this);
6035  	},
6036
6037  	_addAttribution: function (ev) {
6038  		if (ev.layer.getAttribution) {
6039  			this.addAttribution(ev.layer.getAttribution());
6040  			ev.layer.once('remove', function () {
6041  				this.removeAttribution(ev.layer.getAttribution());
6042  			}, this);
6043  		}
6044  	},
6045
6046  	// @method setPrefix(prefix: String|false): this
6047  	// The HTML text shown before the attributions. Pass `false` to disable.
6048  	setPrefix: function (prefix) {
6049  		this.options.prefix = prefix;
6050  		this._update();
6051  		return this;
6052  	},
6053
6054  	// @method addAttribution(text: String): this
6055  	// Adds an attribution text (e.g. `'&copy; OpenStreetMap contributors'`).
6056  	addAttribution: function (text) {
6057  		if (!text) { return this; }
6058
6059  		if (!this._attributions[text]) {
6060  			this._attributions[text] = 0;
6061  		}
6062  		this._attributions[text]++;
6063
6064  		this._update();
6065
6066  		return this;
6067  	},
6068
6069  	// @method removeAttribution(text: String): this
6070  	// Removes an attribution text.
6071  	removeAttribution: function (text) {
6072  		if (!text) { return this; }
6073
6074  		if (this._attributions[text]) {
6075  			this._attributions[text]--;
6076  			this._update();
6077  		}
6078
6079  		return this;
6080  	},
6081
6082  	_update: function () {
6083  		if (!this._map) { return; }
6084
6085  		var attribs = [];
6086
6087  		for (var i in this._attributions) {
6088  			if (this._attributions[i]) {
6089  				attribs.push(i);
6090  			}
6091  		}
6092
6093  		var prefixAndAttribs = [];
6094
6095  		if (this.options.prefix) {
6096  			prefixAndAttribs.push(this.options.prefix);
6097  		}
6098  		if (attribs.length) {
6099  			prefixAndAttribs.push(attribs.join(', '));
6100  		}
6101
6102  		this._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden="true">|</span> ');
6103  	}
6104  });
6105
6106  // @namespace Map
6107  // @section Control options
6108  // @option attributionControl: Boolean = true
6109  // Whether a [attribution control](#control-attribution) is added to the map by default.
6110  Map.mergeOptions({
6111  	attributionControl: true
6112  });
6113
6114  Map.addInitHook(function () {
6115  	if (this.options.attributionControl) {
6116  		new Attribution().addTo(this);
6117  	}
6118  });
6119
6120  // @namespace Control.Attribution
6121  // @factory L.control.attribution(options: Control.Attribution options)
6122  // Creates an attribution control.
6123  var attribution = function (options) {
6124  	return new Attribution(options);
6125  };
6126
6127  Control.Layers = Layers;
6128  Control.Zoom = Zoom;
6129  Control.Scale = Scale;
6130  Control.Attribution = Attribution;
6131
6132  control.layers = layers;
6133  control.zoom = zoom;
6134  control.scale = scale;
6135  control.attribution = attribution;
6136
6137  /*
6138  	L.Handler is a base class for handler classes that are used internally to inject
6139  	interaction features like dragging to classes like Map and Marker.
6140  */
6141
6142  // @class Handler
6143  // @aka L.Handler
6144  // Abstract class for map interaction handlers
6145
6146  var Handler = Class.extend({
6147  	initialize: function (map) {
6148  		this._map = map;
6149  	},
6150
6151  	// @method enable(): this
6152  	// Enables the handler
6153  	enable: function () {
6154  		if (this._enabled) { return this; }
6155
6156  		this._enabled = true;
6157  		this.addHooks();
6158  		return this;
6159  	},
6160
6161  	// @method disable(): this
6162  	// Disables the handler
6163  	disable: function () {
6164  		if (!this._enabled) { return this; }
6165
6166  		this._enabled = false;
6167  		this.removeHooks();
6168  		return this;
6169  	},
6170
6171  	// @method enabled(): Boolean
6172  	// Returns `true` if the handler is enabled
6173  	enabled: function () {
6174  		return !!this._enabled;
6175  	}
6176
6177  	// @section Extension methods
6178  	// Classes inheriting from `Handler` must implement the two following methods:
6179  	// @method addHooks()
6180  	// Called when the handler is enabled, should add event hooks.
6181  	// @method removeHooks()
6182  	// Called when the handler is disabled, should remove the event hooks added previously.
6183  });
6184
6185  // @section There is static function which can be called without instantiating L.Handler:
6186  // @function addTo(map: Map, name: String): this
6187  // Adds a new Handler to the given map with the given name.
6188  Handler.addTo = function (map, name) {
6189  	map.addHandler(name, this);
6190  	return this;
6191  };
6192
6193  var Mixin = {Events: Events};
6194
6195  /*
6196   * @class Draggable
6197   * @aka L.Draggable
6198   * @inherits Evented
6199   *
6200   * A class for making DOM elements draggable (including touch support).
6201   * Used internally for map and marker dragging. Only works for elements
6202   * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
6203   *
6204   * @example
6205   * ```js
6206   * var draggable = new L.Draggable(elementToDrag);
6207   * draggable.enable();
6208   * ```
6209   */
6210
6211  var START = Browser.touch ? 'touchstart mousedown' : 'mousedown';
6212
6213  var Draggable = Evented.extend({
6214
6215  	options: {
6216  		// @section
6217  		// @aka Draggable options
6218  		// @option clickTolerance: Number = 3
6219  		// The max number of pixels a user can shift the mouse pointer during a click
6220  		// for it to be considered a valid click (as opposed to a mouse drag).
6221  		clickTolerance: 3
6222  	},
6223
6224  	// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)
6225  	// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
6226  	initialize: function (element, dragStartTarget, preventOutline, options) {
6227  		setOptions(this, options);
6228
6229  		this._element = element;
6230  		this._dragStartTarget = dragStartTarget || element;
6231  		this._preventOutline = preventOutline;
6232  	},
6233
6234  	// @method enable()
6235  	// Enables the dragging ability
6236  	enable: function () {
6237  		if (this._enabled) { return; }
6238
6239  		on(this._dragStartTarget, START, this._onDown, this);
6240
6241  		this._enabled = true;
6242  	},
6243
6244  	// @method disable()
6245  	// Disables the dragging ability
6246  	disable: function () {
6247  		if (!this._enabled) { return; }
6248
6249  		// If we're currently dragging this draggable,
6250  		// disabling it counts as first ending the drag.
6251  		if (Draggable._dragging === this) {
6252  			this.finishDrag(true);
6253  		}
6254
6255  		off(this._dragStartTarget, START, this._onDown, this);
6256
6257  		this._enabled = false;
6258  		this._moved = false;
6259  	},
6260
6261  	_onDown: function (e) {
6262  		// Ignore the event if disabled; this happens in IE11
6263  		// under some circumstances, see #3666.
6264  		if (!this._enabled) { return; }
6265
6266  		this._moved = false;
6267
6268  		if (hasClass(this._element, 'leaflet-zoom-anim')) { return; }
6269
6270  		if (e.touches && e.touches.length !== 1) {
6271  			// Finish dragging to avoid conflict with touchZoom
6272  			if (Draggable._dragging === this) {
6273  				this.finishDrag();
6274  			}
6275  			return;
6276  		}
6277
6278  		if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
6279  		Draggable._dragging = this;  // Prevent dragging multiple objects at once.
6280
6281  		if (this._preventOutline) {
6282  			preventOutline(this._element);
6283  		}
6284
6285  		disableImageDrag();
6286  		disableTextSelection();
6287
6288  		if (this._moving) { return; }
6289
6290  		// @event down: Event
6291  		// Fired when a drag is about to start.
6292  		this.fire('down');
6293
6294  		var first = e.touches ? e.touches[0] : e,
6295  		    sizedParent = getSizedParentNode(this._element);
6296
6297  		this._startPoint = new Point(first.clientX, first.clientY);
6298  		this._startPos = getPosition(this._element);
6299
6300  		// Cache the scale, so that we can continuously compensate for it during drag (_onMove).
6301  		this._parentScale = getScale(sizedParent);
6302
6303  		var mouseevent = e.type === 'mousedown';
6304  		on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this);
6305  		on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this);
6306  	},
6307
6308  	_onMove: function (e) {
6309  		// Ignore the event if disabled; this happens in IE11
6310  		// under some circumstances, see #3666.
6311  		if (!this._enabled) { return; }
6312
6313  		if (e.touches && e.touches.length > 1) {
6314  			this._moved = true;
6315  			return;
6316  		}
6317
6318  		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
6319  		    offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint);
6320
6321  		if (!offset.x && !offset.y) { return; }
6322  		if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
6323
6324  		// We assume that the parent container's position, border and scale do not change for the duration of the drag.
6325  		// Therefore there is no need to account for the position and border (they are eliminated by the subtraction)
6326  		// and we can use the cached value for the scale.
6327  		offset.x /= this._parentScale.x;
6328  		offset.y /= this._parentScale.y;
6329
6330  		preventDefault(e);
6331
6332  		if (!this._moved) {
6333  			// @event dragstart: Event
6334  			// Fired when a drag starts
6335  			this.fire('dragstart');
6336
6337  			this._moved = true;
6338
6339  			addClass(document.body, 'leaflet-dragging');
6340
6341  			this._lastTarget = e.target || e.srcElement;
6342  			// IE and Edge do not give the <use> element, so fetch it
6343  			// if necessary
6344  			if (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) {
6345  				this._lastTarget = this._lastTarget.correspondingUseElement;
6346  			}
6347  			addClass(this._lastTarget, 'leaflet-drag-target');
6348  		}
6349
6350  		this._newPos = this._startPos.add(offset);
6351  		this._moving = true;
6352
6353  		this._lastEvent = e;
6354  		this._updatePosition();
6355  	},
6356
6357  	_updatePosition: function () {
6358  		var e = {originalEvent: this._lastEvent};
6359
6360  		// @event predrag: Event
6361  		// Fired continuously during dragging *before* each corresponding
6362  		// update of the element's position.
6363  		this.fire('predrag', e);
6364  		setPosition(this._element, this._newPos);
6365
6366  		// @event drag: Event
6367  		// Fired continuously during dragging.
6368  		this.fire('drag', e);
6369  	},
6370
6371  	_onUp: function () {
6372  		// Ignore the event if disabled; this happens in IE11
6373  		// under some circumstances, see #3666.
6374  		if (!this._enabled) { return; }
6375  		this.finishDrag();
6376  	},
6377
6378  	finishDrag: function (noInertia) {
6379  		removeClass(document.body, 'leaflet-dragging');
6380
6381  		if (this._lastTarget) {
6382  			removeClass(this._lastTarget, 'leaflet-drag-target');
6383  			this._lastTarget = null;
6384  		}
6385
6386  		off(document, 'mousemove touchmove', this._onMove, this);
6387  		off(document, 'mouseup touchend touchcancel', this._onUp, this);
6388
6389  		enableImageDrag();
6390  		enableTextSelection();
6391
6392  		var fireDragend = this._moved && this._moving;
6393
6394  		this._moving = false;
6395  		Draggable._dragging = false;
6396
6397  		if (fireDragend) {
6398  			// @event dragend: DragEndEvent
6399  			// Fired when the drag ends.
6400  			this.fire('dragend', {
6401  				noInertia: noInertia,
6402  				distance: this._newPos.distanceTo(this._startPos)
6403  			});
6404  		}
6405  	}
6406
6407  });
6408
6409  /*
6410   * @namespace PolyUtil
6411   * Various utility functions for polygon geometries.
6412   */
6413
6414  /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
6415   * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
6416   * Used by Leaflet to only show polygon points that are on the screen or near, increasing
6417   * performance. Note that polygon points needs different algorithm for clipping
6418   * than polyline, so there's a separate method for it.
6419   */
6420  function clipPolygon(points, bounds, round) {
6421  	var clippedPoints,
6422  	    edges = [1, 4, 2, 8],
6423  	    i, j, k,
6424  	    a, b,
6425  	    len, edge, p;
6426
6427  	for (i = 0, len = points.length; i < len; i++) {
6428  		points[i]._code = _getBitCode(points[i], bounds);
6429  	}
6430
6431  	// for each edge (left, bottom, right, top)
6432  	for (k = 0; k < 4; k++) {
6433  		edge = edges[k];
6434  		clippedPoints = [];
6435
6436  		for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
6437  			a = points[i];
6438  			b = points[j];
6439
6440  			// if a is inside the clip window
6441  			if (!(a._code & edge)) {
6442  				// if b is outside the clip window (a->b goes out of screen)
6443  				if (b._code & edge) {
6444  					p = _getEdgeIntersection(b, a, edge, bounds, round);
6445  					p._code = _getBitCode(p, bounds);
6446  					clippedPoints.push(p);
6447  				}
6448  				clippedPoints.push(a);
6449
6450  			// else if b is inside the clip window (a->b enters the screen)
6451  			} else if (!(b._code & edge)) {
6452  				p = _getEdgeIntersection(b, a, edge, bounds, round);
6453  				p._code = _getBitCode(p, bounds);
6454  				clippedPoints.push(p);
6455  			}
6456  		}
6457  		points = clippedPoints;
6458  	}
6459
6460  	return points;
6461  }
6462
6463  /* @function polygonCenter(latlngs: LatLng[], crs: CRS): LatLng
6464   * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon.
6465   */
6466  function polygonCenter(latlngs, crs) {
6467  	var i, j, p1, p2, f, area, x, y, center;
6468
6469  	if (!latlngs || latlngs.length === 0) {
6470  		throw new Error('latlngs not passed');
6471  	}
6472
6473  	if (!isFlat(latlngs)) {
6474  		console.warn('latlngs are not flat! Only the first ring will be used');
6475  		latlngs = latlngs[0];
6476  	}
6477
6478  	var centroidLatLng = toLatLng([0, 0]);
6479
6480  	var bounds = toLatLngBounds(latlngs);
6481  	var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
6482  	// tests showed that below 1700 rounding errors are happening
6483  	if (areaBounds < 1700) {
6484  		// getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors
6485  		centroidLatLng = centroid(latlngs);
6486  	}
6487
6488  	var len = latlngs.length;
6489  	var points = [];
6490  	for (i = 0; i < len; i++) {
6491  		var latlng = toLatLng(latlngs[i]);
6492  		points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
6493  	}
6494
6495  	area = x = y = 0;
6496
6497  	// polygon centroid algorithm;
6498  	for (i = 0, j = len - 1; i < len; j = i++) {
6499  		p1 = points[i];
6500  		p2 = points[j];
6501
6502  		f = p1.y * p2.x - p2.y * p1.x;
6503  		x += (p1.x + p2.x) * f;
6504  		y += (p1.y + p2.y) * f;
6505  		area += f * 3;
6506  	}
6507
6508  	if (area === 0) {
6509  		// Polygon is so small that all points are on same pixel.
6510  		center = points[0];
6511  	} else {
6512  		center = [x / area, y / area];
6513  	}
6514
6515  	var latlngCenter = crs.unproject(toPoint(center));
6516  	return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
6517  }
6518
6519  /* @function centroid(latlngs: LatLng[]): LatLng
6520   * Returns the 'center of mass' of the passed LatLngs.
6521   */
6522  function centroid(coords) {
6523  	var latSum = 0;
6524  	var lngSum = 0;
6525  	var len = 0;
6526  	for (var i = 0; i < coords.length; i++) {
6527  		var latlng = toLatLng(coords[i]);
6528  		latSum += latlng.lat;
6529  		lngSum += latlng.lng;
6530  		len++;
6531  	}
6532  	return toLatLng([latSum / len, lngSum / len]);
6533  }
6534
6535  var PolyUtil = {
6536    __proto__: null,
6537    clipPolygon: clipPolygon,
6538    polygonCenter: polygonCenter,
6539    centroid: centroid
6540  };
6541
6542  /*
6543   * @namespace LineUtil
6544   *
6545   * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.
6546   */
6547
6548  // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
6549  // Improves rendering performance dramatically by lessening the number of points to draw.
6550
6551  // @function simplify(points: Point[], tolerance: Number): Point[]
6552  // Dramatically reduces the number of points in a polyline while retaining
6553  // its shape and returns a new array of simplified points, using the
6554  // [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm).
6555  // Used for a huge performance boost when processing/displaying Leaflet polylines for
6556  // each zoom level and also reducing visual noise. tolerance affects the amount of
6557  // simplification (lesser value means higher quality but slower and with more points).
6558  // Also released as a separated micro-library [Simplify.js](https://mourner.github.io/simplify-js/).
6559  function simplify(points, tolerance) {
6560  	if (!tolerance || !points.length) {
6561  		return points.slice();
6562  	}
6563
6564  	var sqTolerance = tolerance * tolerance;
6565
6566  	    // stage 1: vertex reduction
6567  	    points = _reducePoints(points, sqTolerance);
6568
6569  	    // stage 2: Douglas-Peucker simplification
6570  	    points = _simplifyDP(points, sqTolerance);
6571
6572  	return points;
6573  }
6574
6575  // @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
6576  // Returns the distance between point `p` and segment `p1` to `p2`.
6577  function pointToSegmentDistance(p, p1, p2) {
6578  	return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));
6579  }
6580
6581  // @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
6582  // Returns the closest point from a point `p` on a segment `p1` to `p2`.
6583  function closestPointOnSegment(p, p1, p2) {
6584  	return _sqClosestPointOnSegment(p, p1, p2);
6585  }
6586
6587  // Ramer-Douglas-Peucker simplification, see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm
6588  function _simplifyDP(points, sqTolerance) {
6589
6590  	var len = points.length,
6591  	    ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
6592  	    markers = new ArrayConstructor(len);
6593
6594  	    markers[0] = markers[len - 1] = 1;
6595
6596  	_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
6597
6598  	var i,
6599  	    newPoints = [];
6600
6601  	for (i = 0; i < len; i++) {
6602  		if (markers[i]) {
6603  			newPoints.push(points[i]);
6604  		}
6605  	}
6606
6607  	return newPoints;
6608  }
6609
6610  function _simplifyDPStep(points, markers, sqTolerance, first, last) {
6611
6612  	var maxSqDist = 0,
6613  	index, i, sqDist;
6614
6615  	for (i = first + 1; i <= last - 1; i++) {
6616  		sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);
6617
6618  		if (sqDist > maxSqDist) {
6619  			index = i;
6620  			maxSqDist = sqDist;
6621  		}
6622  	}
6623
6624  	if (maxSqDist > sqTolerance) {
6625  		markers[index] = 1;
6626
6627  		_simplifyDPStep(points, markers, sqTolerance, first, index);
6628  		_simplifyDPStep(points, markers, sqTolerance, index, last);
6629  	}
6630  }
6631
6632  // reduce points that are too close to each other to a single point
6633  function _reducePoints(points, sqTolerance) {
6634  	var reducedPoints = [points[0]];
6635
6636  	for (var i = 1, prev = 0, len = points.length; i < len; i++) {
6637  		if (_sqDist(points[i], points[prev]) > sqTolerance) {
6638  			reducedPoints.push(points[i]);
6639  			prev = i;
6640  		}
6641  	}
6642  	if (prev < len - 1) {
6643  		reducedPoints.push(points[len - 1]);
6644  	}
6645  	return reducedPoints;
6646  }
6647
6648  var _lastCode;
6649
6650  // @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
6651  // Clips the segment a to b by rectangular bounds with the
6652  // [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
6653  // (modifying the segment points directly!). Used by Leaflet to only show polyline
6654  // points that are on the screen or near, increasing performance.
6655  function clipSegment(a, b, bounds, useLastCode, round) {
6656  	var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),
6657  	    codeB = _getBitCode(b, bounds),
6658
6659  	    codeOut, p, newCode;
6660
6661  	    // save 2nd code to avoid calculating it on the next segment
6662  	    _lastCode = codeB;
6663
6664  	while (true) {
6665  		// if a,b is inside the clip window (trivial accept)
6666  		if (!(codeA | codeB)) {
6667  			return [a, b];
6668  		}
6669
6670  		// if a,b is outside the clip window (trivial reject)
6671  		if (codeA & codeB) {
6672  			return false;
6673  		}
6674
6675  		// other cases
6676  		codeOut = codeA || codeB;
6677  		p = _getEdgeIntersection(a, b, codeOut, bounds, round);
6678  		newCode = _getBitCode(p, bounds);
6679
6680  		if (codeOut === codeA) {
6681  			a = p;
6682  			codeA = newCode;
6683  		} else {
6684  			b = p;
6685  			codeB = newCode;
6686  		}
6687  	}
6688  }
6689
6690  function _getEdgeIntersection(a, b, code, bounds, round) {
6691  	var dx = b.x - a.x,
6692  	    dy = b.y - a.y,
6693  	    min = bounds.min,
6694  	    max = bounds.max,
6695  	    x, y;
6696
6697  	if (code & 8) { // top
6698  		x = a.x + dx * (max.y - a.y) / dy;
6699  		y = max.y;
6700
6701  	} else if (code & 4) { // bottom
6702  		x = a.x + dx * (min.y - a.y) / dy;
6703  		y = min.y;
6704
6705  	} else if (code & 2) { // right
6706  		x = max.x;
6707  		y = a.y + dy * (max.x - a.x) / dx;
6708
6709  	} else if (code & 1) { // left
6710  		x = min.x;
6711  		y = a.y + dy * (min.x - a.x) / dx;
6712  	}
6713
6714  	return new Point(x, y, round);
6715  }
6716
6717  function _getBitCode(p, bounds) {
6718  	var code = 0;
6719
6720  	if (p.x < bounds.min.x) { // left
6721  		code |= 1;
6722  	} else if (p.x > bounds.max.x) { // right
6723  		code |= 2;
6724  	}
6725
6726  	if (p.y < bounds.min.y) { // bottom
6727  		code |= 4;
6728  	} else if (p.y > bounds.max.y) { // top
6729  		code |= 8;
6730  	}
6731
6732  	return code;
6733  }
6734
6735  // square distance (to avoid unnecessary Math.sqrt calls)
6736  function _sqDist(p1, p2) {
6737  	var dx = p2.x - p1.x,
6738  	    dy = p2.y - p1.y;
6739  	return dx * dx + dy * dy;
6740  }
6741
6742  // return closest point on segment or distance to that point
6743  function _sqClosestPointOnSegment(p, p1, p2, sqDist) {
6744  	var x = p1.x,
6745  	    y = p1.y,
6746  	    dx = p2.x - x,
6747  	    dy = p2.y - y,
6748  	    dot = dx * dx + dy * dy,
6749  	    t;
6750
6751  	if (dot > 0) {
6752  		t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
6753
6754  		if (t > 1) {
6755  			x = p2.x;
6756  			y = p2.y;
6757  		} else if (t > 0) {
6758  			x += dx * t;
6759  			y += dy * t;
6760  		}
6761  	}
6762
6763  	dx = p.x - x;
6764  	dy = p.y - y;
6765
6766  	return sqDist ? dx * dx + dy * dy : new Point(x, y);
6767  }
6768
6769
6770  // @function isFlat(latlngs: LatLng[]): Boolean
6771  // Returns true if `latlngs` is a flat array, false is nested.
6772  function isFlat(latlngs) {
6773  	return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
6774  }
6775
6776  function _flat(latlngs) {
6777  	console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');
6778  	return isFlat(latlngs);
6779  }
6780
6781  /* @function polylineCenter(latlngs: LatLng[], crs: CRS): LatLng
6782   * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polyline.
6783   */
6784  function polylineCenter(latlngs, crs) {
6785  	var i, halfDist, segDist, dist, p1, p2, ratio, center;
6786
6787  	if (!latlngs || latlngs.length === 0) {
6788  		throw new Error('latlngs not passed');
6789  	}
6790
6791  	if (!isFlat(latlngs)) {
6792  		console.warn('latlngs are not flat! Only the first ring will be used');
6793  		latlngs = latlngs[0];
6794  	}
6795
6796  	var centroidLatLng = toLatLng([0, 0]);
6797
6798  	var bounds = toLatLngBounds(latlngs);
6799  	var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest());
6800  	// tests showed that below 1700 rounding errors are happening
6801  	if (areaBounds < 1700) {
6802  		// getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors
6803  		centroidLatLng = centroid(latlngs);
6804  	}
6805
6806  	var len = latlngs.length;
6807  	var points = [];
6808  	for (i = 0; i < len; i++) {
6809  		var latlng = toLatLng(latlngs[i]);
6810  		points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng])));
6811  	}
6812
6813  	for (i = 0, halfDist = 0; i < len - 1; i++) {
6814  		halfDist += points[i].distanceTo(points[i + 1]) / 2;
6815  	}
6816
6817  	// The line is so small in the current view that all points are on the same pixel.
6818  	if (halfDist === 0) {
6819  		center = points[0];
6820  	} else {
6821  		for (i = 0, dist = 0; i < len - 1; i++) {
6822  			p1 = points[i];
6823  			p2 = points[i + 1];
6824  			segDist = p1.distanceTo(p2);
6825  			dist += segDist;
6826
6827  			if (dist > halfDist) {
6828  				ratio = (dist - halfDist) / segDist;
6829  				center = [
6830  					p2.x - ratio * (p2.x - p1.x),
6831  					p2.y - ratio * (p2.y - p1.y)
6832  				];
6833  				break;
6834  			}
6835  		}
6836  	}
6837
6838  	var latlngCenter = crs.unproject(toPoint(center));
6839  	return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]);
6840  }
6841
6842  var LineUtil = {
6843    __proto__: null,
6844    simplify: simplify,
6845    pointToSegmentDistance: pointToSegmentDistance,
6846    closestPointOnSegment: closestPointOnSegment,
6847    clipSegment: clipSegment,
6848    _getEdgeIntersection: _getEdgeIntersection,
6849    _getBitCode: _getBitCode,
6850    _sqClosestPointOnSegment: _sqClosestPointOnSegment,
6851    isFlat: isFlat,
6852    _flat: _flat,
6853    polylineCenter: polylineCenter
6854  };
6855
6856  /*
6857   * @namespace Projection
6858   * @section
6859   * Leaflet comes with a set of already defined Projections out of the box:
6860   *
6861   * @projection L.Projection.LonLat
6862   *
6863   * Equirectangular, or Plate Carree projection — the most simple projection,
6864   * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
6865   * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
6866   * `EPSG:4326` and `Simple` CRS.
6867   */
6868
6869  var LonLat = {
6870  	project: function (latlng) {
6871  		return new Point(latlng.lng, latlng.lat);
6872  	},
6873
6874  	unproject: function (point) {
6875  		return new LatLng(point.y, point.x);
6876  	},
6877
6878  	bounds: new Bounds([-180, -90], [180, 90])
6879  };
6880
6881  /*
6882   * @namespace Projection
6883   * @projection L.Projection.Mercator
6884   *
6885   * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS.
6886   */
6887
6888  var Mercator = {
6889  	R: 6378137,
6890  	R_MINOR: 6356752.314245179,
6891
6892  	bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
6893
6894  	project: function (latlng) {
6895  		var d = Math.PI / 180,
6896  		    r = this.R,
6897  		    y = latlng.lat * d,
6898  		    tmp = this.R_MINOR / r,
6899  		    e = Math.sqrt(1 - tmp * tmp),
6900  		    con = e * Math.sin(y);
6901
6902  		var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
6903  		y = -r * Math.log(Math.max(ts, 1E-10));
6904
6905  		return new Point(latlng.lng * d * r, y);
6906  	},
6907
6908  	unproject: function (point) {
6909  		var d = 180 / Math.PI,
6910  		    r = this.R,
6911  		    tmp = this.R_MINOR / r,
6912  		    e = Math.sqrt(1 - tmp * tmp),
6913  		    ts = Math.exp(-point.y / r),
6914  		    phi = Math.PI / 2 - 2 * Math.atan(ts);
6915
6916  		for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
6917  			con = e * Math.sin(phi);
6918  			con = Math.pow((1 - con) / (1 + con), e / 2);
6919  			dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
6920  			phi += dphi;
6921  		}
6922
6923  		return new LatLng(phi * d, point.x * d / r);
6924  	}
6925  };
6926
6927  /*
6928   * @class Projection
6929
6930   * An object with methods for projecting geographical coordinates of the world onto
6931   * a flat surface (and back). See [Map projection](https://en.wikipedia.org/wiki/Map_projection).
6932
6933   * @property bounds: Bounds
6934   * The bounds (specified in CRS units) where the projection is valid
6935
6936   * @method project(latlng: LatLng): Point
6937   * Projects geographical coordinates into a 2D point.
6938   * Only accepts actual `L.LatLng` instances, not arrays.
6939
6940   * @method unproject(point: Point): LatLng
6941   * The inverse of `project`. Projects a 2D point into a geographical location.
6942   * Only accepts actual `L.Point` instances, not arrays.
6943
6944   * Note that the projection instances do not inherit from Leaflet's `Class` object,
6945   * and can't be instantiated. Also, new classes can't inherit from them,
6946   * and methods can't be added to them with the `include` function.
6947
6948   */
6949
6950  var index = {
6951    __proto__: null,
6952    LonLat: LonLat,
6953    Mercator: Mercator,
6954    SphericalMercator: SphericalMercator
6955  };
6956
6957  /*
6958   * @namespace CRS
6959   * @crs L.CRS.EPSG3395
6960   *
6961   * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
6962   */
6963  var EPSG3395 = extend({}, Earth, {
6964  	code: 'EPSG:3395',
6965  	projection: Mercator,
6966
6967  	transformation: (function () {
6968  		var scale = 0.5 / (Math.PI * Mercator.R);
6969  		return toTransformation(scale, 0.5, -scale, 0.5);
6970  	}())
6971  });
6972
6973  /*
6974   * @namespace CRS
6975   * @crs L.CRS.EPSG4326
6976   *
6977   * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
6978   *
6979   * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
6980   * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`
6981   * with this CRS, ensure that there are two 256x256 pixel tiles covering the
6982   * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
6983   * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
6984   */
6985
6986  var EPSG4326 = extend({}, Earth, {
6987  	code: 'EPSG:4326',
6988  	projection: LonLat,
6989  	transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)
6990  });
6991
6992  /*
6993   * @namespace CRS
6994   * @crs L.CRS.Simple
6995   *
6996   * A simple CRS that maps longitude and latitude into `x` and `y` directly.
6997   * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
6998   * axis should still be inverted (going from bottom to top). `distance()` returns
6999   * simple euclidean distance.
7000   */
7001
7002  var Simple = extend({}, CRS, {
7003  	projection: LonLat,
7004  	transformation: toTransformation(1, 0, -1, 0),
7005
7006  	scale: function (zoom) {
7007  		return Math.pow(2, zoom);
7008  	},
7009
7010  	zoom: function (scale) {
7011  		return Math.log(scale) / Math.LN2;
7012  	},
7013
7014  	distance: function (latlng1, latlng2) {
7015  		var dx = latlng2.lng - latlng1.lng,
7016  		    dy = latlng2.lat - latlng1.lat;
7017
7018  		return Math.sqrt(dx * dx + dy * dy);
7019  	},
7020
7021  	infinite: true
7022  });
7023
7024  CRS.Earth = Earth;
7025  CRS.EPSG3395 = EPSG3395;
7026  CRS.EPSG3857 = EPSG3857;
7027  CRS.EPSG900913 = EPSG900913;
7028  CRS.EPSG4326 = EPSG4326;
7029  CRS.Simple = Simple;
7030
7031  /*
7032   * @class Layer
7033   * @inherits Evented
7034   * @aka L.Layer
7035   * @aka ILayer
7036   *
7037   * A set of methods from the Layer base class that all Leaflet layers use.
7038   * Inherits all methods, options and events from `L.Evented`.
7039   *
7040   * @example
7041   *
7042   * ```js
7043   * var layer = L.marker(latlng).addTo(map);
7044   * layer.addTo(map);
7045   * layer.remove();
7046   * ```
7047   *
7048   * @event add: Event
7049   * Fired after the layer is added to a map
7050   *
7051   * @event remove: Event
7052   * Fired after the layer is removed from a map
7053   */
7054
7055
7056  var Layer = Evented.extend({
7057
7058  	// Classes extending `L.Layer` will inherit the following options:
7059  	options: {
7060  		// @option pane: String = 'overlayPane'
7061  		// By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.
7062  		pane: 'overlayPane',
7063
7064  		// @option attribution: String = null
7065  		// String to be shown in the attribution control, e.g. "© OpenStreetMap contributors". It describes the layer data and is often a legal obligation towards copyright holders and tile providers.
7066  		attribution: null,
7067
7068  		bubblingMouseEvents: true
7069  	},
7070
7071  	/* @section
7072  	 * Classes extending `L.Layer` will inherit the following methods:
7073  	 *
7074  	 * @method addTo(map: Map|LayerGroup): this
7075  	 * Adds the layer to the given map or layer group.
7076  	 */
7077  	addTo: function (map) {
7078  		map.addLayer(this);
7079  		return this;
7080  	},
7081
7082  	// @method remove: this
7083  	// Removes the layer from the map it is currently active on.
7084  	remove: function () {
7085  		return this.removeFrom(this._map || this._mapToAdd);
7086  	},
7087
7088  	// @method removeFrom(map: Map): this
7089  	// Removes the layer from the given map
7090  	//
7091  	// @alternative
7092  	// @method removeFrom(group: LayerGroup): this
7093  	// Removes the layer from the given `LayerGroup`
7094  	removeFrom: function (obj) {
7095  		if (obj) {
7096  			obj.removeLayer(this);
7097  		}
7098  		return this;
7099  	},
7100
7101  	// @method getPane(name? : String): HTMLElement
7102  	// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
7103  	getPane: function (name) {
7104  		return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
7105  	},
7106
7107  	addInteractiveTarget: function (targetEl) {
7108  		this._map._targets[stamp(targetEl)] = this;
7109  		return this;
7110  	},
7111
7112  	removeInteractiveTarget: function (targetEl) {
7113  		delete this._map._targets[stamp(targetEl)];
7114  		return this;
7115  	},
7116
7117  	// @method getAttribution: String
7118  	// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
7119  	getAttribution: function () {
7120  		return this.options.attribution;
7121  	},
7122
7123  	_layerAdd: function (e) {
7124  		var map = e.target;
7125
7126  		// check in case layer gets added and then removed before the map is ready
7127  		if (!map.hasLayer(this)) { return; }
7128
7129  		this._map = map;
7130  		this._zoomAnimated = map._zoomAnimated;
7131
7132  		if (this.getEvents) {
7133  			var events = this.getEvents();
7134  			map.on(events, this);
7135  			this.once('remove', function () {
7136  				map.off(events, this);
7137  			}, this);
7138  		}
7139
7140  		this.onAdd(map);
7141
7142  		this.fire('add');
7143  		map.fire('layeradd', {layer: this});
7144  	}
7145  });
7146
7147  /* @section Extension methods
7148   * @uninheritable
7149   *
7150   * Every layer should extend from `L.Layer` and (re-)implement the following methods.
7151   *
7152   * @method onAdd(map: Map): this
7153   * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).
7154   *
7155   * @method onRemove(map: Map): this
7156   * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).
7157   *
7158   * @method getEvents(): Object
7159   * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.
7160   *
7161   * @method getAttribution(): String
7162   * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
7163   *
7164   * @method beforeAdd(map: Map): this
7165   * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.
7166   */
7167
7168
7169  /* @namespace Map
7170   * @section Layer events
7171   *
7172   * @event layeradd: LayerEvent
7173   * Fired when a new layer is added to the map.
7174   *
7175   * @event layerremove: LayerEvent
7176   * Fired when some layer is removed from the map
7177   *
7178   * @section Methods for Layers and Controls
7179   */
7180  Map.include({
7181  	// @method addLayer(layer: Layer): this
7182  	// Adds the given layer to the map
7183  	addLayer: function (layer) {
7184  		if (!layer._layerAdd) {
7185  			throw new Error('The provided object is not a Layer.');
7186  		}
7187
7188  		var id = stamp(layer);
7189  		if (this._layers[id]) { return this; }
7190  		this._layers[id] = layer;
7191
7192  		layer._mapToAdd = this;
7193
7194  		if (layer.beforeAdd) {
7195  			layer.beforeAdd(this);
7196  		}
7197
7198  		this.whenReady(layer._layerAdd, layer);
7199
7200  		return this;
7201  	},
7202
7203  	// @method removeLayer(layer: Layer): this
7204  	// Removes the given layer from the map.
7205  	removeLayer: function (layer) {
7206  		var id = stamp(layer);
7207
7208  		if (!this._layers[id]) { return this; }
7209
7210  		if (this._loaded) {
7211  			layer.onRemove(this);
7212  		}
7213
7214  		delete this._layers[id];
7215
7216  		if (this._loaded) {
7217  			this.fire('layerremove', {layer: layer});
7218  			layer.fire('remove');
7219  		}
7220
7221  		layer._map = layer._mapToAdd = null;
7222
7223  		return this;
7224  	},
7225
7226  	// @method hasLayer(layer: Layer): Boolean
7227  	// Returns `true` if the given layer is currently added to the map
7228  	hasLayer: function (layer) {
7229  		return stamp(layer) in this._layers;
7230  	},
7231
7232  	/* @method eachLayer(fn: Function, context?: Object): this
7233  	 * Iterates over the layers of the map, optionally specifying context of the iterator function.
7234  	 * ```
7235  	 * map.eachLayer(function(layer){
7236  	 *     layer.bindPopup('Hello');
7237  	 * });
7238  	 * ```
7239  	 */
7240  	eachLayer: function (method, context) {
7241  		for (var i in this._layers) {
7242  			method.call(context, this._layers[i]);
7243  		}
7244  		return this;
7245  	},
7246
7247  	_addLayers: function (layers) {
7248  		layers = layers ? (isArray(layers) ? layers : [layers]) : [];
7249
7250  		for (var i = 0, len = layers.length; i < len; i++) {
7251  			this.addLayer(layers[i]);
7252  		}
7253  	},
7254
7255  	_addZoomLimit: function (layer) {
7256  		if (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
7257  			this._zoomBoundLayers[stamp(layer)] = layer;
7258  			this._updateZoomLevels();
7259  		}
7260  	},
7261
7262  	_removeZoomLimit: function (layer) {
7263  		var id = stamp(layer);
7264
7265  		if (this._zoomBoundLayers[id]) {
7266  			delete this._zoomBoundLayers[id];
7267  			this._updateZoomLevels();
7268  		}
7269  	},
7270
7271  	_updateZoomLevels: function () {
7272  		var minZoom = Infinity,
7273  		    maxZoom = -Infinity,
7274  		    oldZoomSpan = this._getZoomSpan();
7275
7276  		for (var i in this._zoomBoundLayers) {
7277  			var options = this._zoomBoundLayers[i].options;
7278
7279  			minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
7280  			maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
7281  		}
7282
7283  		this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
7284  		this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
7285
7286  		// @section Map state change events
7287  		// @event zoomlevelschange: Event
7288  		// Fired when the number of zoomlevels on the map is changed due
7289  		// to adding or removing a layer.
7290  		if (oldZoomSpan !== this._getZoomSpan()) {
7291  			this.fire('zoomlevelschange');
7292  		}
7293
7294  		if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
7295  			this.setZoom(this._layersMaxZoom);
7296  		}
7297  		if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
7298  			this.setZoom(this._layersMinZoom);
7299  		}
7300  	}
7301  });
7302
7303  /*
7304   * @class LayerGroup
7305   * @aka L.LayerGroup
7306   * @inherits Interactive layer
7307   *
7308   * Used to group several layers and handle them as one. If you add it to the map,
7309   * any layers added or removed from the group will be added/removed on the map as
7310   * well. Extends `Layer`.
7311   *
7312   * @example
7313   *
7314   * ```js
7315   * L.layerGroup([marker1, marker2])
7316   * 	.addLayer(polyline)
7317   * 	.addTo(map);
7318   * ```
7319   */
7320
7321  var LayerGroup = Layer.extend({
7322
7323  	initialize: function (layers, options) {
7324  		setOptions(this, options);
7325
7326  		this._layers = {};
7327
7328  		var i, len;
7329
7330  		if (layers) {
7331  			for (i = 0, len = layers.length; i < len; i++) {
7332  				this.addLayer(layers[i]);
7333  			}
7334  		}
7335  	},
7336
7337  	// @method addLayer(layer: Layer): this
7338  	// Adds the given layer to the group.
7339  	addLayer: function (layer) {
7340  		var id = this.getLayerId(layer);
7341
7342  		this._layers[id] = layer;
7343
7344  		if (this._map) {
7345  			this._map.addLayer(layer);
7346  		}
7347
7348  		return this;
7349  	},
7350
7351  	// @method removeLayer(layer: Layer): this
7352  	// Removes the given layer from the group.
7353  	// @alternative
7354  	// @method removeLayer(id: Number): this
7355  	// Removes the layer with the given internal ID from the group.
7356  	removeLayer: function (layer) {
7357  		var id = layer in this._layers ? layer : this.getLayerId(layer);
7358
7359  		if (this._map && this._layers[id]) {
7360  			this._map.removeLayer(this._layers[id]);
7361  		}
7362
7363  		delete this._layers[id];
7364
7365  		return this;
7366  	},
7367
7368  	// @method hasLayer(layer: Layer): Boolean
7369  	// Returns `true` if the given layer is currently added to the group.
7370  	// @alternative
7371  	// @method hasLayer(id: Number): Boolean
7372  	// Returns `true` if the given internal ID is currently added to the group.
7373  	hasLayer: function (layer) {
7374  		var layerId = typeof layer === 'number' ? layer : this.getLayerId(layer);
7375  		return layerId in this._layers;
7376  	},
7377
7378  	// @method clearLayers(): this
7379  	// Removes all the layers from the group.
7380  	clearLayers: function () {
7381  		return this.eachLayer(this.removeLayer, this);
7382  	},
7383
7384  	// @method invoke(methodName: String, …): this
7385  	// Calls `methodName` on every layer contained in this group, passing any
7386  	// additional parameters. Has no effect if the layers contained do not
7387  	// implement `methodName`.
7388  	invoke: function (methodName) {
7389  		var args = Array.prototype.slice.call(arguments, 1),
7390  		    i, layer;
7391
7392  		for (i in this._layers) {
7393  			layer = this._layers[i];
7394
7395  			if (layer[methodName]) {
7396  				layer[methodName].apply(layer, args);
7397  			}
7398  		}
7399
7400  		return this;
7401  	},
7402
7403  	onAdd: function (map) {
7404  		this.eachLayer(map.addLayer, map);
7405  	},
7406
7407  	onRemove: function (map) {
7408  		this.eachLayer(map.removeLayer, map);
7409  	},
7410
7411  	// @method eachLayer(fn: Function, context?: Object): this
7412  	// Iterates over the layers of the group, optionally specifying context of the iterator function.
7413  	// ```js
7414  	// group.eachLayer(function (layer) {
7415  	// 	layer.bindPopup('Hello');
7416  	// });
7417  	// ```
7418  	eachLayer: function (method, context) {
7419  		for (var i in this._layers) {
7420  			method.call(context, this._layers[i]);
7421  		}
7422  		return this;
7423  	},
7424
7425  	// @method getLayer(id: Number): Layer
7426  	// Returns the layer with the given internal ID.
7427  	getLayer: function (id) {
7428  		return this._layers[id];
7429  	},
7430
7431  	// @method getLayers(): Layer[]
7432  	// Returns an array of all the layers added to the group.
7433  	getLayers: function () {
7434  		var layers = [];
7435  		this.eachLayer(layers.push, layers);
7436  		return layers;
7437  	},
7438
7439  	// @method setZIndex(zIndex: Number): this
7440  	// Calls `setZIndex` on every layer contained in this group, passing the z-index.
7441  	setZIndex: function (zIndex) {
7442  		return this.invoke('setZIndex', zIndex);
7443  	},
7444
7445  	// @method getLayerId(layer: Layer): Number
7446  	// Returns the internal ID for a layer
7447  	getLayerId: function (layer) {
7448  		return stamp(layer);
7449  	}
7450  });
7451
7452
7453  // @factory L.layerGroup(layers?: Layer[], options?: Object)
7454  // Create a layer group, optionally given an initial set of layers and an `options` object.
7455  var layerGroup = function (layers, options) {
7456  	return new LayerGroup(layers, options);
7457  };
7458
7459  /*
7460   * @class FeatureGroup
7461   * @aka L.FeatureGroup
7462   * @inherits LayerGroup
7463   *
7464   * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
7465   *  * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
7466   *  * Events are propagated to the `FeatureGroup`, so if the group has an event
7467   * handler, it will handle events from any of the layers. This includes mouse events
7468   * and custom events.
7469   *  * Has `layeradd` and `layerremove` events
7470   *
7471   * @example
7472   *
7473   * ```js
7474   * L.featureGroup([marker1, marker2, polyline])
7475   * 	.bindPopup('Hello world!')
7476   * 	.on('click', function() { alert('Clicked on a member of the group!'); })
7477   * 	.addTo(map);
7478   * ```
7479   */
7480
7481  var FeatureGroup = LayerGroup.extend({
7482
7483  	addLayer: function (layer) {
7484  		if (this.hasLayer(layer)) {
7485  			return this;
7486  		}
7487
7488  		layer.addEventParent(this);
7489
7490  		LayerGroup.prototype.addLayer.call(this, layer);
7491
7492  		// @event layeradd: LayerEvent
7493  		// Fired when a layer is added to this `FeatureGroup`
7494  		return this.fire('layeradd', {layer: layer});
7495  	},
7496
7497  	removeLayer: function (layer) {
7498  		if (!this.hasLayer(layer)) {
7499  			return this;
7500  		}
7501  		if (layer in this._layers) {
7502  			layer = this._layers[layer];
7503  		}
7504
7505  		layer.removeEventParent(this);
7506
7507  		LayerGroup.prototype.removeLayer.call(this, layer);
7508
7509  		// @event layerremove: LayerEvent
7510  		// Fired when a layer is removed from this `FeatureGroup`
7511  		return this.fire('layerremove', {layer: layer});
7512  	},
7513
7514  	// @method setStyle(style: Path options): this
7515  	// Sets the given path options to each layer of the group that has a `setStyle` method.
7516  	setStyle: function (style) {
7517  		return this.invoke('setStyle', style);
7518  	},
7519
7520  	// @method bringToFront(): this
7521  	// Brings the layer group to the top of all other layers
7522  	bringToFront: function () {
7523  		return this.invoke('bringToFront');
7524  	},
7525
7526  	// @method bringToBack(): this
7527  	// Brings the layer group to the back of all other layers
7528  	bringToBack: function () {
7529  		return this.invoke('bringToBack');
7530  	},
7531
7532  	// @method getBounds(): LatLngBounds
7533  	// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
7534  	getBounds: function () {
7535  		var bounds = new LatLngBounds();
7536
7537  		for (var id in this._layers) {
7538  			var layer = this._layers[id];
7539  			bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
7540  		}
7541  		return bounds;
7542  	}
7543  });
7544
7545  // @factory L.featureGroup(layers?: Layer[], options?: Object)
7546  // Create a feature group, optionally given an initial set of layers and an `options` object.
7547  var featureGroup = function (layers, options) {
7548  	return new FeatureGroup(layers, options);
7549  };
7550
7551  /*
7552   * @class Icon
7553   * @aka L.Icon
7554   *
7555   * Represents an icon to provide when creating a marker.
7556   *
7557   * @example
7558   *
7559   * ```js
7560   * var myIcon = L.icon({
7561   *     iconUrl: 'my-icon.png',
7562   *     iconRetinaUrl: '[email protected]',
7563   *     iconSize: [38, 95],
7564   *     iconAnchor: [22, 94],
7565   *     popupAnchor: [-3, -76],
7566   *     shadowUrl: 'my-icon-shadow.png',
7567   *     shadowRetinaUrl: '[email protected]',
7568   *     shadowSize: [68, 95],
7569   *     shadowAnchor: [22, 94]
7570   * });
7571   *
7572   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
7573   * ```
7574   *
7575   * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
7576   *
7577   */
7578
7579  var Icon = Class.extend({
7580
7581  	/* @section
7582  	 * @aka Icon options
7583  	 *
7584  	 * @option iconUrl: String = null
7585  	 * **(required)** The URL to the icon image (absolute or relative to your script path).
7586  	 *
7587  	 * @option iconRetinaUrl: String = null
7588  	 * The URL to a retina sized version of the icon image (absolute or relative to your
7589  	 * script path). Used for Retina screen devices.
7590  	 *
7591  	 * @option iconSize: Point = null
7592  	 * Size of the icon image in pixels.
7593  	 *
7594  	 * @option iconAnchor: Point = null
7595  	 * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
7596  	 * will be aligned so that this point is at the marker's geographical location. Centered
7597  	 * by default if size is specified, also can be set in CSS with negative margins.
7598  	 *
7599  	 * @option popupAnchor: Point = [0, 0]
7600  	 * The coordinates of the point from which popups will "open", relative to the icon anchor.
7601  	 *
7602  	 * @option tooltipAnchor: Point = [0, 0]
7603  	 * The coordinates of the point from which tooltips will "open", relative to the icon anchor.
7604  	 *
7605  	 * @option shadowUrl: String = null
7606  	 * The URL to the icon shadow image. If not specified, no shadow image will be created.
7607  	 *
7608  	 * @option shadowRetinaUrl: String = null
7609  	 *
7610  	 * @option shadowSize: Point = null
7611  	 * Size of the shadow image in pixels.
7612  	 *
7613  	 * @option shadowAnchor: Point = null
7614  	 * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
7615  	 * as iconAnchor if not specified).
7616  	 *
7617  	 * @option className: String = ''
7618  	 * A custom class name to assign to both icon and shadow images. Empty by default.
7619  	 */
7620
7621  	options: {
7622  		popupAnchor: [0, 0],
7623  		tooltipAnchor: [0, 0],
7624
7625  		// @option crossOrigin: Boolean|String = false
7626  		// Whether the crossOrigin attribute will be added to the tiles.
7627  		// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
7628  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
7629  		crossOrigin: false
7630  	},
7631
7632  	initialize: function (options) {
7633  		setOptions(this, options);
7634  	},
7635
7636  	// @method createIcon(oldIcon?: HTMLElement): HTMLElement
7637  	// Called internally when the icon has to be shown, returns a `<img>` HTML element
7638  	// styled according to the options.
7639  	createIcon: function (oldIcon) {
7640  		return this._createIcon('icon', oldIcon);
7641  	},
7642
7643  	// @method createShadow(oldIcon?: HTMLElement): HTMLElement
7644  	// As `createIcon`, but for the shadow beneath it.
7645  	createShadow: function (oldIcon) {
7646  		return this._createIcon('shadow', oldIcon);
7647  	},
7648
7649  	_createIcon: function (name, oldIcon) {
7650  		var src = this._getIconUrl(name);
7651
7652  		if (!src) {
7653  			if (name === 'icon') {
7654  				throw new Error('iconUrl not set in Icon options (see the docs).');
7655  			}
7656  			return null;
7657  		}
7658
7659  		var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
7660  		this._setIconStyles(img, name);
7661
7662  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
7663  			img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
7664  		}
7665
7666  		return img;
7667  	},
7668
7669  	_setIconStyles: function (img, name) {
7670  		var options = this.options;
7671  		var sizeOption = options[name + 'Size'];
7672
7673  		if (typeof sizeOption === 'number') {
7674  			sizeOption = [sizeOption, sizeOption];
7675  		}
7676
7677  		var size = toPoint(sizeOption),
7678  		    anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
7679  		            size && size.divideBy(2, true));
7680
7681  		img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
7682
7683  		if (anchor) {
7684  			img.style.marginLeft = (-anchor.x) + 'px';
7685  			img.style.marginTop  = (-anchor.y) + 'px';
7686  		}
7687
7688  		if (size) {
7689  			img.style.width  = size.x + 'px';
7690  			img.style.height = size.y + 'px';
7691  		}
7692  	},
7693
7694  	_createImg: function (src, el) {
7695  		el = el || document.createElement('img');
7696  		el.src = src;
7697  		return el;
7698  	},
7699
7700  	_getIconUrl: function (name) {
7701  		return Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
7702  	}
7703  });
7704
7705
7706  // @factory L.icon(options: Icon options)
7707  // Creates an icon instance with the given options.
7708  function icon(options) {
7709  	return new Icon(options);
7710  }
7711
7712  /*
7713   * @miniclass Icon.Default (Icon)
7714   * @aka L.Icon.Default
7715   * @section
7716   *
7717   * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
7718   * no icon is specified. Points to the blue marker image distributed with Leaflet
7719   * releases.
7720   *
7721   * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
7722   * (which is a set of `Icon options`).
7723   *
7724   * If you want to _completely_ replace the default icon, override the
7725   * `L.Marker.prototype.options.icon` with your own icon instead.
7726   */
7727
7728  var IconDefault = Icon.extend({
7729
7730  	options: {
7731  		iconUrl:       'marker-icon.png',
7732  		iconRetinaUrl: 'marker-icon-2x.png',
7733  		shadowUrl:     'marker-shadow.png',
7734  		iconSize:    [25, 41],
7735  		iconAnchor:  [12, 41],
7736  		popupAnchor: [1, -34],
7737  		tooltipAnchor: [16, -28],
7738  		shadowSize:  [41, 41]
7739  	},
7740
7741  	_getIconUrl: function (name) {
7742  		if (typeof IconDefault.imagePath !== 'string') {	// Deprecated, backwards-compatibility only
7743  			IconDefault.imagePath = this._detectIconPath();
7744  		}
7745
7746  		// @option imagePath: String
7747  		// `Icon.Default` will try to auto-detect the location of the
7748  		// blue icon images. If you are placing these images in a non-standard
7749  		// way, set this option to point to the right path.
7750  		return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);
7751  	},
7752
7753  	_stripUrl: function (path) {	// separate function to use in tests
7754  		var strip = function (str, re, idx) {
7755  			var match = re.exec(str);
7756  			return match && match[idx];
7757  		};
7758  		path = strip(path, /^url\((['"])?(.+)\1\)$/, 2);
7759  		return path && strip(path, /^(.*)marker-icon\.png$/, 1);
7760  	},
7761
7762  	_detectIconPath: function () {
7763  		var el = create$1('div',  'leaflet-default-icon-path', document.body);
7764  		var path = getStyle(el, 'background-image') ||
7765  		           getStyle(el, 'backgroundImage');	// IE8
7766
7767  		document.body.removeChild(el);
7768  		path = this._stripUrl(path);
7769  		if (path) { return path; }
7770  		var link = document.querySelector('link[href$="leaflet.css"]');
7771  		if (!link) { return ''; }
7772  		return link.href.substring(0, link.href.length - 'leaflet.css'.length - 1);
7773  	}
7774  });
7775
7776  /*
7777   * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
7778   */
7779
7780
7781  /* @namespace Marker
7782   * @section Interaction handlers
7783   *
7784   * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:
7785   *
7786   * ```js
7787   * marker.dragging.disable();
7788   * ```
7789   *
7790   * @property dragging: Handler
7791   * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).
7792   */
7793
7794  var MarkerDrag = Handler.extend({
7795  	initialize: function (marker) {
7796  		this._marker = marker;
7797  	},
7798
7799  	addHooks: function () {
7800  		var icon = this._marker._icon;
7801
7802  		if (!this._draggable) {
7803  			this._draggable = new Draggable(icon, icon, true);
7804  		}
7805
7806  		this._draggable.on({
7807  			dragstart: this._onDragStart,
7808  			predrag: this._onPreDrag,
7809  			drag: this._onDrag,
7810  			dragend: this._onDragEnd
7811  		}, this).enable();
7812
7813  		addClass(icon, 'leaflet-marker-draggable');
7814  	},
7815
7816  	removeHooks: function () {
7817  		this._draggable.off({
7818  			dragstart: this._onDragStart,
7819  			predrag: this._onPreDrag,
7820  			drag: this._onDrag,
7821  			dragend: this._onDragEnd
7822  		}, this).disable();
7823
7824  		if (this._marker._icon) {
7825  			removeClass(this._marker._icon, 'leaflet-marker-draggable');
7826  		}
7827  	},
7828
7829  	moved: function () {
7830  		return this._draggable && this._draggable._moved;
7831  	},
7832
7833  	_adjustPan: function (e) {
7834  		var marker = this._marker,
7835  		    map = marker._map,
7836  		    speed = this._marker.options.autoPanSpeed,
7837  		    padding = this._marker.options.autoPanPadding,
7838  		    iconPos = getPosition(marker._icon),
7839  		    bounds = map.getPixelBounds(),
7840  		    origin = map.getPixelOrigin();
7841
7842  		var panBounds = toBounds(
7843  			bounds.min._subtract(origin).add(padding),
7844  			bounds.max._subtract(origin).subtract(padding)
7845  		);
7846
7847  		if (!panBounds.contains(iconPos)) {
7848  			// Compute incremental movement
7849  			var movement = toPoint(
7850  				(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -
7851  				(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),
7852
7853  				(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -
7854  				(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)
7855  			).multiplyBy(speed);
7856
7857  			map.panBy(movement, {animate: false});
7858
7859  			this._draggable._newPos._add(movement);
7860  			this._draggable._startPos._add(movement);
7861
7862  			setPosition(marker._icon, this._draggable._newPos);
7863  			this._onDrag(e);
7864
7865  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7866  		}
7867  	},
7868
7869  	_onDragStart: function () {
7870  		// @section Dragging events
7871  		// @event dragstart: Event
7872  		// Fired when the user starts dragging the marker.
7873
7874  		// @event movestart: Event
7875  		// Fired when the marker starts moving (because of dragging).
7876
7877  		this._oldLatLng = this._marker.getLatLng();
7878
7879  		// When using ES6 imports it could not be set when `Popup` was not imported as well
7880  		this._marker.closePopup && this._marker.closePopup();
7881
7882  		this._marker
7883  			.fire('movestart')
7884  			.fire('dragstart');
7885  	},
7886
7887  	_onPreDrag: function (e) {
7888  		if (this._marker.options.autoPan) {
7889  			cancelAnimFrame(this._panRequest);
7890  			this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));
7891  		}
7892  	},
7893
7894  	_onDrag: function (e) {
7895  		var marker = this._marker,
7896  		    shadow = marker._shadow,
7897  		    iconPos = getPosition(marker._icon),
7898  		    latlng = marker._map.layerPointToLatLng(iconPos);
7899
7900  		// update shadow position
7901  		if (shadow) {
7902  			setPosition(shadow, iconPos);
7903  		}
7904
7905  		marker._latlng = latlng;
7906  		e.latlng = latlng;
7907  		e.oldLatLng = this._oldLatLng;
7908
7909  		// @event drag: Event
7910  		// Fired repeatedly while the user drags the marker.
7911  		marker
7912  		    .fire('move', e)
7913  		    .fire('drag', e);
7914  	},
7915
7916  	_onDragEnd: function (e) {
7917  		// @event dragend: DragEndEvent
7918  		// Fired when the user stops dragging the marker.
7919
7920  		 cancelAnimFrame(this._panRequest);
7921
7922  		// @event moveend: Event
7923  		// Fired when the marker stops moving (because of dragging).
7924  		delete this._oldLatLng;
7925  		this._marker
7926  		    .fire('moveend')
7927  		    .fire('dragend', e);
7928  	}
7929  });
7930
7931  /*
7932   * @class Marker
7933   * @inherits Interactive layer
7934   * @aka L.Marker
7935   * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
7936   *
7937   * @example
7938   *
7939   * ```js
7940   * L.marker([50.5, 30.5]).addTo(map);
7941   * ```
7942   */
7943
7944  var Marker = Layer.extend({
7945
7946  	// @section
7947  	// @aka Marker options
7948  	options: {
7949  		// @option icon: Icon = *
7950  		// Icon instance to use for rendering the marker.
7951  		// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.
7952  		// If not specified, a common instance of `L.Icon.Default` is used.
7953  		icon: new IconDefault(),
7954
7955  		// Option inherited from "Interactive layer" abstract class
7956  		interactive: true,
7957
7958  		// @option keyboard: Boolean = true
7959  		// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
7960  		keyboard: true,
7961
7962  		// @option title: String = ''
7963  		// Text for the browser tooltip that appear on marker hover (no tooltip by default).
7964  		// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
7965  		title: '',
7966
7967  		// @option alt: String = 'Marker'
7968  		// Text for the `alt` attribute of the icon image.
7969  		// [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled).
7970  		alt: 'Marker',
7971
7972  		// @option zIndexOffset: Number = 0
7973  		// By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).
7974  		zIndexOffset: 0,
7975
7976  		// @option opacity: Number = 1.0
7977  		// The opacity of the marker.
7978  		opacity: 1,
7979
7980  		// @option riseOnHover: Boolean = false
7981  		// If `true`, the marker will get on top of others when you hover the mouse over it.
7982  		riseOnHover: false,
7983
7984  		// @option riseOffset: Number = 250
7985  		// The z-index offset used for the `riseOnHover` feature.
7986  		riseOffset: 250,
7987
7988  		// @option pane: String = 'markerPane'
7989  		// `Map pane` where the markers icon will be added.
7990  		pane: 'markerPane',
7991
7992  		// @option shadowPane: String = 'shadowPane'
7993  		// `Map pane` where the markers shadow will be added.
7994  		shadowPane: 'shadowPane',
7995
7996  		// @option bubblingMouseEvents: Boolean = false
7997  		// When `true`, a mouse event on this marker will trigger the same event on the map
7998  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
7999  		bubblingMouseEvents: false,
8000
8001  		// @option autoPanOnFocus: Boolean = true
8002  		// When `true`, the map will pan whenever the marker is focused (via
8003  		// e.g. pressing `tab` on the keyboard) to ensure the marker is
8004  		// visible within the map's bounds
8005  		autoPanOnFocus: true,
8006
8007  		// @section Draggable marker options
8008  		// @option draggable: Boolean = false
8009  		// Whether the marker is draggable with mouse/touch or not.
8010  		draggable: false,
8011
8012  		// @option autoPan: Boolean = false
8013  		// Whether to pan the map when dragging this marker near its edge or not.
8014  		autoPan: false,
8015
8016  		// @option autoPanPadding: Point = Point(50, 50)
8017  		// Distance (in pixels to the left/right and to the top/bottom) of the
8018  		// map edge to start panning the map.
8019  		autoPanPadding: [50, 50],
8020
8021  		// @option autoPanSpeed: Number = 10
8022  		// Number of pixels the map should pan by.
8023  		autoPanSpeed: 10
8024  	},
8025
8026  	/* @section
8027  	 *
8028  	 * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
8029  	 */
8030
8031  	initialize: function (latlng, options) {
8032  		setOptions(this, options);
8033  		this._latlng = toLatLng(latlng);
8034  	},
8035
8036  	onAdd: function (map) {
8037  		this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
8038
8039  		if (this._zoomAnimated) {
8040  			map.on('zoomanim', this._animateZoom, this);
8041  		}
8042
8043  		this._initIcon();
8044  		this.update();
8045  	},
8046
8047  	onRemove: function (map) {
8048  		if (this.dragging && this.dragging.enabled()) {
8049  			this.options.draggable = true;
8050  			this.dragging.removeHooks();
8051  		}
8052  		delete this.dragging;
8053
8054  		if (this._zoomAnimated) {
8055  			map.off('zoomanim', this._animateZoom, this);
8056  		}
8057
8058  		this._removeIcon();
8059  		this._removeShadow();
8060  	},
8061
8062  	getEvents: function () {
8063  		return {
8064  			zoom: this.update,
8065  			viewreset: this.update
8066  		};
8067  	},
8068
8069  	// @method getLatLng: LatLng
8070  	// Returns the current geographical position of the marker.
8071  	getLatLng: function () {
8072  		return this._latlng;
8073  	},
8074
8075  	// @method setLatLng(latlng: LatLng): this
8076  	// Changes the marker position to the given point.
8077  	setLatLng: function (latlng) {
8078  		var oldLatLng = this._latlng;
8079  		this._latlng = toLatLng(latlng);
8080  		this.update();
8081
8082  		// @event move: Event
8083  		// Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
8084  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
8085  	},
8086
8087  	// @method setZIndexOffset(offset: Number): this
8088  	// Changes the [zIndex offset](#marker-zindexoffset) of the marker.
8089  	setZIndexOffset: function (offset) {
8090  		this.options.zIndexOffset = offset;
8091  		return this.update();
8092  	},
8093
8094  	// @method getIcon: Icon
8095  	// Returns the current icon used by the marker
8096  	getIcon: function () {
8097  		return this.options.icon;
8098  	},
8099
8100  	// @method setIcon(icon: Icon): this
8101  	// Changes the marker icon.
8102  	setIcon: function (icon) {
8103
8104  		this.options.icon = icon;
8105
8106  		if (this._map) {
8107  			this._initIcon();
8108  			this.update();
8109  		}
8110
8111  		if (this._popup) {
8112  			this.bindPopup(this._popup, this._popup.options);
8113  		}
8114
8115  		return this;
8116  	},
8117
8118  	getElement: function () {
8119  		return this._icon;
8120  	},
8121
8122  	update: function () {
8123
8124  		if (this._icon && this._map) {
8125  			var pos = this._map.latLngToLayerPoint(this._latlng).round();
8126  			this._setPos(pos);
8127  		}
8128
8129  		return this;
8130  	},
8131
8132  	_initIcon: function () {
8133  		var options = this.options,
8134  		    classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
8135
8136  		var icon = options.icon.createIcon(this._icon),
8137  		    addIcon = false;
8138
8139  		// if we're not reusing the icon, remove the old one and init new one
8140  		if (icon !== this._icon) {
8141  			if (this._icon) {
8142  				this._removeIcon();
8143  			}
8144  			addIcon = true;
8145
8146  			if (options.title) {
8147  				icon.title = options.title;
8148  			}
8149
8150  			if (icon.tagName === 'IMG') {
8151  				icon.alt = options.alt || '';
8152  			}
8153  		}
8154
8155  		addClass(icon, classToAdd);
8156
8157  		if (options.keyboard) {
8158  			icon.tabIndex = '0';
8159  			icon.setAttribute('role', 'button');
8160  		}
8161
8162  		this._icon = icon;
8163
8164  		if (options.riseOnHover) {
8165  			this.on({
8166  				mouseover: this._bringToFront,
8167  				mouseout: this._resetZIndex
8168  			});
8169  		}
8170
8171  		if (this.options.autoPanOnFocus) {
8172  			on(icon, 'focus', this._panOnFocus, this);
8173  		}
8174
8175  		var newShadow = options.icon.createShadow(this._shadow),
8176  		    addShadow = false;
8177
8178  		if (newShadow !== this._shadow) {
8179  			this._removeShadow();
8180  			addShadow = true;
8181  		}
8182
8183  		if (newShadow) {
8184  			addClass(newShadow, classToAdd);
8185  			newShadow.alt = '';
8186  		}
8187  		this._shadow = newShadow;
8188
8189
8190  		if (options.opacity < 1) {
8191  			this._updateOpacity();
8192  		}
8193
8194
8195  		if (addIcon) {
8196  			this.getPane().appendChild(this._icon);
8197  		}
8198  		this._initInteraction();
8199  		if (newShadow && addShadow) {
8200  			this.getPane(options.shadowPane).appendChild(this._shadow);
8201  		}
8202  	},
8203
8204  	_removeIcon: function () {
8205  		if (this.options.riseOnHover) {
8206  			this.off({
8207  				mouseover: this._bringToFront,
8208  				mouseout: this._resetZIndex
8209  			});
8210  		}
8211
8212  		if (this.options.autoPanOnFocus) {
8213  			off(this._icon, 'focus', this._panOnFocus, this);
8214  		}
8215
8216  		remove(this._icon);
8217  		this.removeInteractiveTarget(this._icon);
8218
8219  		this._icon = null;
8220  	},
8221
8222  	_removeShadow: function () {
8223  		if (this._shadow) {
8224  			remove(this._shadow);
8225  		}
8226  		this._shadow = null;
8227  	},
8228
8229  	_setPos: function (pos) {
8230
8231  		if (this._icon) {
8232  			setPosition(this._icon, pos);
8233  		}
8234
8235  		if (this._shadow) {
8236  			setPosition(this._shadow, pos);
8237  		}
8238
8239  		this._zIndex = pos.y + this.options.zIndexOffset;
8240
8241  		this._resetZIndex();
8242  	},
8243
8244  	_updateZIndex: function (offset) {
8245  		if (this._icon) {
8246  			this._icon.style.zIndex = this._zIndex + offset;
8247  		}
8248  	},
8249
8250  	_animateZoom: function (opt) {
8251  		var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
8252
8253  		this._setPos(pos);
8254  	},
8255
8256  	_initInteraction: function () {
8257
8258  		if (!this.options.interactive) { return; }
8259
8260  		addClass(this._icon, 'leaflet-interactive');
8261
8262  		this.addInteractiveTarget(this._icon);
8263
8264  		if (MarkerDrag) {
8265  			var draggable = this.options.draggable;
8266  			if (this.dragging) {
8267  				draggable = this.dragging.enabled();
8268  				this.dragging.disable();
8269  			}
8270
8271  			this.dragging = new MarkerDrag(this);
8272
8273  			if (draggable) {
8274  				this.dragging.enable();
8275  			}
8276  		}
8277  	},
8278
8279  	// @method setOpacity(opacity: Number): this
8280  	// Changes the opacity of the marker.
8281  	setOpacity: function (opacity) {
8282  		this.options.opacity = opacity;
8283  		if (this._map) {
8284  			this._updateOpacity();
8285  		}
8286
8287  		return this;
8288  	},
8289
8290  	_updateOpacity: function () {
8291  		var opacity = this.options.opacity;
8292
8293  		if (this._icon) {
8294  			setOpacity(this._icon, opacity);
8295  		}
8296
8297  		if (this._shadow) {
8298  			setOpacity(this._shadow, opacity);
8299  		}
8300  	},
8301
8302  	_bringToFront: function () {
8303  		this._updateZIndex(this.options.riseOffset);
8304  	},
8305
8306  	_resetZIndex: function () {
8307  		this._updateZIndex(0);
8308  	},
8309
8310  	_panOnFocus: function () {
8311  		var map = this._map;
8312  		if (!map) { return; }
8313
8314  		var iconOpts = this.options.icon.options;
8315  		var size = iconOpts.iconSize ? toPoint(iconOpts.iconSize) : toPoint(0, 0);
8316  		var anchor = iconOpts.iconAnchor ? toPoint(iconOpts.iconAnchor) : toPoint(0, 0);
8317
8318  		map.panInside(this._latlng, {
8319  			paddingTopLeft: anchor,
8320  			paddingBottomRight: size.subtract(anchor)
8321  		});
8322  	},
8323
8324  	_getPopupAnchor: function () {
8325  		return this.options.icon.options.popupAnchor;
8326  	},
8327
8328  	_getTooltipAnchor: function () {
8329  		return this.options.icon.options.tooltipAnchor;
8330  	}
8331  });
8332
8333
8334  // factory L.marker(latlng: LatLng, options? : Marker options)
8335
8336  // @factory L.marker(latlng: LatLng, options? : Marker options)
8337  // Instantiates a Marker object given a geographical point and optionally an options object.
8338  function marker(latlng, options) {
8339  	return new Marker(latlng, options);
8340  }
8341
8342  /*
8343   * @class Path
8344   * @aka L.Path
8345   * @inherits Interactive layer
8346   *
8347   * An abstract class that contains options and constants shared between vector
8348   * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
8349   */
8350
8351  var Path = Layer.extend({
8352
8353  	// @section
8354  	// @aka Path options
8355  	options: {
8356  		// @option stroke: Boolean = true
8357  		// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
8358  		stroke: true,
8359
8360  		// @option color: String = '#3388ff'
8361  		// Stroke color
8362  		color: '#3388ff',
8363
8364  		// @option weight: Number = 3
8365  		// Stroke width in pixels
8366  		weight: 3,
8367
8368  		// @option opacity: Number = 1.0
8369  		// Stroke opacity
8370  		opacity: 1,
8371
8372  		// @option lineCap: String= 'round'
8373  		// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
8374  		lineCap: 'round',
8375
8376  		// @option lineJoin: String = 'round'
8377  		// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
8378  		lineJoin: 'round',
8379
8380  		// @option dashArray: String = null
8381  		// A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
8382  		dashArray: null,
8383
8384  		// @option dashOffset: String = null
8385  		// A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
8386  		dashOffset: null,
8387
8388  		// @option fill: Boolean = depends
8389  		// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
8390  		fill: false,
8391
8392  		// @option fillColor: String = *
8393  		// Fill color. Defaults to the value of the [`color`](#path-color) option
8394  		fillColor: null,
8395
8396  		// @option fillOpacity: Number = 0.2
8397  		// Fill opacity.
8398  		fillOpacity: 0.2,
8399
8400  		// @option fillRule: String = 'evenodd'
8401  		// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
8402  		fillRule: 'evenodd',
8403
8404  		// className: '',
8405
8406  		// Option inherited from "Interactive layer" abstract class
8407  		interactive: true,
8408
8409  		// @option bubblingMouseEvents: Boolean = true
8410  		// When `true`, a mouse event on this path will trigger the same event on the map
8411  		// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).
8412  		bubblingMouseEvents: true
8413  	},
8414
8415  	beforeAdd: function (map) {
8416  		// Renderer is set here because we need to call renderer.getEvents
8417  		// before this.getEvents.
8418  		this._renderer = map.getRenderer(this);
8419  	},
8420
8421  	onAdd: function () {
8422  		this._renderer._initPath(this);
8423  		this._reset();
8424  		this._renderer._addPath(this);
8425  	},
8426
8427  	onRemove: function () {
8428  		this._renderer._removePath(this);
8429  	},
8430
8431  	// @method redraw(): this
8432  	// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
8433  	redraw: function () {
8434  		if (this._map) {
8435  			this._renderer._updatePath(this);
8436  		}
8437  		return this;
8438  	},
8439
8440  	// @method setStyle(style: Path options): this
8441  	// Changes the appearance of a Path based on the options in the `Path options` object.
8442  	setStyle: function (style) {
8443  		setOptions(this, style);
8444  		if (this._renderer) {
8445  			this._renderer._updateStyle(this);
8446  			if (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) {
8447  				this._updateBounds();
8448  			}
8449  		}
8450  		return this;
8451  	},
8452
8453  	// @method bringToFront(): this
8454  	// Brings the layer to the top of all path layers.
8455  	bringToFront: function () {
8456  		if (this._renderer) {
8457  			this._renderer._bringToFront(this);
8458  		}
8459  		return this;
8460  	},
8461
8462  	// @method bringToBack(): this
8463  	// Brings the layer to the bottom of all path layers.
8464  	bringToBack: function () {
8465  		if (this._renderer) {
8466  			this._renderer._bringToBack(this);
8467  		}
8468  		return this;
8469  	},
8470
8471  	getElement: function () {
8472  		return this._path;
8473  	},
8474
8475  	_reset: function () {
8476  		// defined in child classes
8477  		this._project();
8478  		this._update();
8479  	},
8480
8481  	_clickTolerance: function () {
8482  		// used when doing hit detection for Canvas layers
8483  		return (this.options.stroke ? this.options.weight / 2 : 0) +
8484  		  (this._renderer.options.tolerance || 0);
8485  	}
8486  });
8487
8488  /*
8489   * @class CircleMarker
8490   * @aka L.CircleMarker
8491   * @inherits Path
8492   *
8493   * A circle of a fixed size with radius specified in pixels. Extends `Path`.
8494   */
8495
8496  var CircleMarker = Path.extend({
8497
8498  	// @section
8499  	// @aka CircleMarker options
8500  	options: {
8501  		fill: true,
8502
8503  		// @option radius: Number = 10
8504  		// Radius of the circle marker, in pixels
8505  		radius: 10
8506  	},
8507
8508  	initialize: function (latlng, options) {
8509  		setOptions(this, options);
8510  		this._latlng = toLatLng(latlng);
8511  		this._radius = this.options.radius;
8512  	},
8513
8514  	// @method setLatLng(latLng: LatLng): this
8515  	// Sets the position of a circle marker to a new location.
8516  	setLatLng: function (latlng) {
8517  		var oldLatLng = this._latlng;
8518  		this._latlng = toLatLng(latlng);
8519  		this.redraw();
8520
8521  		// @event move: Event
8522  		// Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
8523  		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
8524  	},
8525
8526  	// @method getLatLng(): LatLng
8527  	// Returns the current geographical position of the circle marker
8528  	getLatLng: function () {
8529  		return this._latlng;
8530  	},
8531
8532  	// @method setRadius(radius: Number): this
8533  	// Sets the radius of a circle marker. Units are in pixels.
8534  	setRadius: function (radius) {
8535  		this.options.radius = this._radius = radius;
8536  		return this.redraw();
8537  	},
8538
8539  	// @method getRadius(): Number
8540  	// Returns the current radius of the circle
8541  	getRadius: function () {
8542  		return this._radius;
8543  	},
8544
8545  	setStyle : function (options) {
8546  		var radius = options && options.radius || this._radius;
8547  		Path.prototype.setStyle.call(this, options);
8548  		this.setRadius(radius);
8549  		return this;
8550  	},
8551
8552  	_project: function () {
8553  		this._point = this._map.latLngToLayerPoint(this._latlng);
8554  		this._updateBounds();
8555  	},
8556
8557  	_updateBounds: function () {
8558  		var r = this._radius,
8559  		    r2 = this._radiusY || r,
8560  		    w = this._clickTolerance(),
8561  		    p = [r + w, r2 + w];
8562  		this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));
8563  	},
8564
8565  	_update: function () {
8566  		if (this._map) {
8567  			this._updatePath();
8568  		}
8569  	},
8570
8571  	_updatePath: function () {
8572  		this._renderer._updateCircle(this);
8573  	},
8574
8575  	_empty: function () {
8576  		return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
8577  	},
8578
8579  	// Needed by the `Canvas` renderer for interactivity
8580  	_containsPoint: function (p) {
8581  		return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
8582  	}
8583  });
8584
8585
8586  // @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
8587  // Instantiates a circle marker object given a geographical point, and an optional options object.
8588  function circleMarker(latlng, options) {
8589  	return new CircleMarker(latlng, options);
8590  }
8591
8592  /*
8593   * @class Circle
8594   * @aka L.Circle
8595   * @inherits CircleMarker
8596   *
8597   * A class for drawing circle overlays on a map. Extends `CircleMarker`.
8598   *
8599   * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
8600   *
8601   * @example
8602   *
8603   * ```js
8604   * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
8605   * ```
8606   */
8607
8608  var Circle = CircleMarker.extend({
8609
8610  	initialize: function (latlng, options, legacyOptions) {
8611  		if (typeof options === 'number') {
8612  			// Backwards compatibility with 0.7.x factory (latlng, radius, options?)
8613  			options = extend({}, legacyOptions, {radius: options});
8614  		}
8615  		setOptions(this, options);
8616  		this._latlng = toLatLng(latlng);
8617
8618  		if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
8619
8620  		// @section
8621  		// @aka Circle options
8622  		// @option radius: Number; Radius of the circle, in meters.
8623  		this._mRadius = this.options.radius;
8624  	},
8625
8626  	// @method setRadius(radius: Number): this
8627  	// Sets the radius of a circle. Units are in meters.
8628  	setRadius: function (radius) {
8629  		this._mRadius = radius;
8630  		return this.redraw();
8631  	},
8632
8633  	// @method getRadius(): Number
8634  	// Returns the current radius of a circle. Units are in meters.
8635  	getRadius: function () {
8636  		return this._mRadius;
8637  	},
8638
8639  	// @method getBounds(): LatLngBounds
8640  	// Returns the `LatLngBounds` of the path.
8641  	getBounds: function () {
8642  		var half = [this._radius, this._radiusY || this._radius];
8643
8644  		return new LatLngBounds(
8645  			this._map.layerPointToLatLng(this._point.subtract(half)),
8646  			this._map.layerPointToLatLng(this._point.add(half)));
8647  	},
8648
8649  	setStyle: Path.prototype.setStyle,
8650
8651  	_project: function () {
8652
8653  		var lng = this._latlng.lng,
8654  		    lat = this._latlng.lat,
8655  		    map = this._map,
8656  		    crs = map.options.crs;
8657
8658  		if (crs.distance === Earth.distance) {
8659  			var d = Math.PI / 180,
8660  			    latR = (this._mRadius / Earth.R) / d,
8661  			    top = map.project([lat + latR, lng]),
8662  			    bottom = map.project([lat - latR, lng]),
8663  			    p = top.add(bottom).divideBy(2),
8664  			    lat2 = map.unproject(p).lat,
8665  			    lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
8666  			            (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
8667
8668  			if (isNaN(lngR) || lngR === 0) {
8669  				lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
8670  			}
8671
8672  			this._point = p.subtract(map.getPixelOrigin());
8673  			this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;
8674  			this._radiusY = p.y - top.y;
8675
8676  		} else {
8677  			var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
8678
8679  			this._point = map.latLngToLayerPoint(this._latlng);
8680  			this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
8681  		}
8682
8683  		this._updateBounds();
8684  	}
8685  });
8686
8687  // @factory L.circle(latlng: LatLng, options?: Circle options)
8688  // Instantiates a circle object given a geographical point, and an options object
8689  // which contains the circle radius.
8690  // @alternative
8691  // @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
8692  // Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
8693  // Do not use in new applications or plugins.
8694  function circle(latlng, options, legacyOptions) {
8695  	return new Circle(latlng, options, legacyOptions);
8696  }
8697
8698  /*
8699   * @class Polyline
8700   * @aka L.Polyline
8701   * @inherits Path
8702   *
8703   * A class for drawing polyline overlays on a map. Extends `Path`.
8704   *
8705   * @example
8706   *
8707   * ```js
8708   * // create a red polyline from an array of LatLng points
8709   * var latlngs = [
8710   * 	[45.51, -122.68],
8711   * 	[37.77, -122.43],
8712   * 	[34.04, -118.2]
8713   * ];
8714   *
8715   * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
8716   *
8717   * // zoom the map to the polyline
8718   * map.fitBounds(polyline.getBounds());
8719   * ```
8720   *
8721   * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
8722   *
8723   * ```js
8724   * // create a red polyline from an array of arrays of LatLng points
8725   * var latlngs = [
8726   * 	[[45.51, -122.68],
8727   * 	 [37.77, -122.43],
8728   * 	 [34.04, -118.2]],
8729   * 	[[40.78, -73.91],
8730   * 	 [41.83, -87.62],
8731   * 	 [32.76, -96.72]]
8732   * ];
8733   * ```
8734   */
8735
8736
8737  var Polyline = Path.extend({
8738
8739  	// @section
8740  	// @aka Polyline options
8741  	options: {
8742  		// @option smoothFactor: Number = 1.0
8743  		// How much to simplify the polyline on each zoom level. More means
8744  		// better performance and smoother look, and less means more accurate representation.
8745  		smoothFactor: 1.0,
8746
8747  		// @option noClip: Boolean = false
8748  		// Disable polyline clipping.
8749  		noClip: false
8750  	},
8751
8752  	initialize: function (latlngs, options) {
8753  		setOptions(this, options);
8754  		this._setLatLngs(latlngs);
8755  	},
8756
8757  	// @method getLatLngs(): LatLng[]
8758  	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
8759  	getLatLngs: function () {
8760  		return this._latlngs;
8761  	},
8762
8763  	// @method setLatLngs(latlngs: LatLng[]): this
8764  	// Replaces all the points in the polyline with the given array of geographical points.
8765  	setLatLngs: function (latlngs) {
8766  		this._setLatLngs(latlngs);
8767  		return this.redraw();
8768  	},
8769
8770  	// @method isEmpty(): Boolean
8771  	// Returns `true` if the Polyline has no LatLngs.
8772  	isEmpty: function () {
8773  		return !this._latlngs.length;
8774  	},
8775
8776  	// @method closestLayerPoint(p: Point): Point
8777  	// Returns the point closest to `p` on the Polyline.
8778  	closestLayerPoint: function (p) {
8779  		var minDistance = Infinity,
8780  		    minPoint = null,
8781  		    closest = _sqClosestPointOnSegment,
8782  		    p1, p2;
8783
8784  		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
8785  			var points = this._parts[j];
8786
8787  			for (var i = 1, len = points.length; i < len; i++) {
8788  				p1 = points[i - 1];
8789  				p2 = points[i];
8790
8791  				var sqDist = closest(p, p1, p2, true);
8792
8793  				if (sqDist < minDistance) {
8794  					minDistance = sqDist;
8795  					minPoint = closest(p, p1, p2);
8796  				}
8797  			}
8798  		}
8799  		if (minPoint) {
8800  			minPoint.distance = Math.sqrt(minDistance);
8801  		}
8802  		return minPoint;
8803  	},
8804
8805  	// @method getCenter(): LatLng
8806  	// Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline.
8807  	getCenter: function () {
8808  		// throws error when not yet added to map as this center calculation requires projected coordinates
8809  		if (!this._map) {
8810  			throw new Error('Must add layer to map before using getCenter()');
8811  		}
8812  		return polylineCenter(this._defaultShape(), this._map.options.crs);
8813  	},
8814
8815  	// @method getBounds(): LatLngBounds
8816  	// Returns the `LatLngBounds` of the path.
8817  	getBounds: function () {
8818  		return this._bounds;
8819  	},
8820
8821  	// @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this
8822  	// Adds a given point to the polyline. By default, adds to the first ring of
8823  	// the polyline in case of a multi-polyline, but can be overridden by passing
8824  	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
8825  	addLatLng: function (latlng, latlngs) {
8826  		latlngs = latlngs || this._defaultShape();
8827  		latlng = toLatLng(latlng);
8828  		latlngs.push(latlng);
8829  		this._bounds.extend(latlng);
8830  		return this.redraw();
8831  	},
8832
8833  	_setLatLngs: function (latlngs) {
8834  		this._bounds = new LatLngBounds();
8835  		this._latlngs = this._convertLatLngs(latlngs);
8836  	},
8837
8838  	_defaultShape: function () {
8839  		return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];
8840  	},
8841
8842  	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
8843  	_convertLatLngs: function (latlngs) {
8844  		var result = [],
8845  		    flat = isFlat(latlngs);
8846
8847  		for (var i = 0, len = latlngs.length; i < len; i++) {
8848  			if (flat) {
8849  				result[i] = toLatLng(latlngs[i]);
8850  				this._bounds.extend(result[i]);
8851  			} else {
8852  				result[i] = this._convertLatLngs(latlngs[i]);
8853  			}
8854  		}
8855
8856  		return result;
8857  	},
8858
8859  	_project: function () {
8860  		var pxBounds = new Bounds();
8861  		this._rings = [];
8862  		this._projectLatlngs(this._latlngs, this._rings, pxBounds);
8863
8864  		if (this._bounds.isValid() && pxBounds.isValid()) {
8865  			this._rawPxBounds = pxBounds;
8866  			this._updateBounds();
8867  		}
8868  	},
8869
8870  	_updateBounds: function () {
8871  		var w = this._clickTolerance(),
8872  		    p = new Point(w, w);
8873
8874  		if (!this._rawPxBounds) {
8875  			return;
8876  		}
8877
8878  		this._pxBounds = new Bounds([
8879  			this._rawPxBounds.min.subtract(p),
8880  			this._rawPxBounds.max.add(p)
8881  		]);
8882  	},
8883
8884  	// recursively turns latlngs into a set of rings with projected coordinates
8885  	_projectLatlngs: function (latlngs, result, projectedBounds) {
8886  		var flat = latlngs[0] instanceof LatLng,
8887  		    len = latlngs.length,
8888  		    i, ring;
8889
8890  		if (flat) {
8891  			ring = [];
8892  			for (i = 0; i < len; i++) {
8893  				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
8894  				projectedBounds.extend(ring[i]);
8895  			}
8896  			result.push(ring);
8897  		} else {
8898  			for (i = 0; i < len; i++) {
8899  				this._projectLatlngs(latlngs[i], result, projectedBounds);
8900  			}
8901  		}
8902  	},
8903
8904  	// clip polyline by renderer bounds so that we have less to render for performance
8905  	_clipPoints: function () {
8906  		var bounds = this._renderer._bounds;
8907
8908  		this._parts = [];
8909  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8910  			return;
8911  		}
8912
8913  		if (this.options.noClip) {
8914  			this._parts = this._rings;
8915  			return;
8916  		}
8917
8918  		var parts = this._parts,
8919  		    i, j, k, len, len2, segment, points;
8920
8921  		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
8922  			points = this._rings[i];
8923
8924  			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
8925  				segment = clipSegment(points[j], points[j + 1], bounds, j, true);
8926
8927  				if (!segment) { continue; }
8928
8929  				parts[k] = parts[k] || [];
8930  				parts[k].push(segment[0]);
8931
8932  				// if segment goes out of screen, or it's the last one, it's the end of the line part
8933  				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
8934  					parts[k].push(segment[1]);
8935  					k++;
8936  				}
8937  			}
8938  		}
8939  	},
8940
8941  	// simplify each clipped part of the polyline for performance
8942  	_simplifyPoints: function () {
8943  		var parts = this._parts,
8944  		    tolerance = this.options.smoothFactor;
8945
8946  		for (var i = 0, len = parts.length; i < len; i++) {
8947  			parts[i] = simplify(parts[i], tolerance);
8948  		}
8949  	},
8950
8951  	_update: function () {
8952  		if (!this._map) { return; }
8953
8954  		this._clipPoints();
8955  		this._simplifyPoints();
8956  		this._updatePath();
8957  	},
8958
8959  	_updatePath: function () {
8960  		this._renderer._updatePoly(this);
8961  	},
8962
8963  	// Needed by the `Canvas` renderer for interactivity
8964  	_containsPoint: function (p, closed) {
8965  		var i, j, k, len, len2, part,
8966  		    w = this._clickTolerance();
8967
8968  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
8969
8970  		// hit detection for polylines
8971  		for (i = 0, len = this._parts.length; i < len; i++) {
8972  			part = this._parts[i];
8973
8974  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
8975  				if (!closed && (j === 0)) { continue; }
8976
8977  				if (pointToSegmentDistance(p, part[k], part[j]) <= w) {
8978  					return true;
8979  				}
8980  			}
8981  		}
8982  		return false;
8983  	}
8984  });
8985
8986  // @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
8987  // Instantiates a polyline object given an array of geographical points and
8988  // optionally an options object. You can create a `Polyline` object with
8989  // multiple separate lines (`MultiPolyline`) by passing an array of arrays
8990  // of geographic points.
8991  function polyline(latlngs, options) {
8992  	return new Polyline(latlngs, options);
8993  }
8994
8995  // Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.
8996  Polyline._flat = _flat;
8997
8998  /*
8999   * @class Polygon
9000   * @aka L.Polygon
9001   * @inherits Polyline
9002   *
9003   * A class for drawing polygon overlays on a map. Extends `Polyline`.
9004   *
9005   * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.
9006   *
9007   *
9008   * @example
9009   *
9010   * ```js
9011   * // create a red polygon from an array of LatLng points
9012   * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
9013   *
9014   * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
9015   *
9016   * // zoom the map to the polygon
9017   * map.fitBounds(polygon.getBounds());
9018   * ```
9019   *
9020   * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:
9021   *
9022   * ```js
9023   * var latlngs = [
9024   *   [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
9025   *   [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
9026   * ];
9027   * ```
9028   *
9029   * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
9030   *
9031   * ```js
9032   * var latlngs = [
9033   *   [ // first polygon
9034   *     [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
9035   *     [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
9036   *   ],
9037   *   [ // second polygon
9038   *     [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]
9039   *   ]
9040   * ];
9041   * ```
9042   */
9043
9044  var Polygon = Polyline.extend({
9045
9046  	options: {
9047  		fill: true
9048  	},
9049
9050  	isEmpty: function () {
9051  		return !this._latlngs.length || !this._latlngs[0].length;
9052  	},
9053
9054  	// @method getCenter(): LatLng
9055  	// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon.
9056  	getCenter: function () {
9057  		// throws error when not yet added to map as this center calculation requires projected coordinates
9058  		if (!this._map) {
9059  			throw new Error('Must add layer to map before using getCenter()');
9060  		}
9061  		return polygonCenter(this._defaultShape(), this._map.options.crs);
9062  	},
9063
9064  	_convertLatLngs: function (latlngs) {
9065  		var result = Polyline.prototype._convertLatLngs.call(this, latlngs),
9066  		    len = result.length;
9067
9068  		// remove last point if it equals first one
9069  		if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {
9070  			result.pop();
9071  		}
9072  		return result;
9073  	},
9074
9075  	_setLatLngs: function (latlngs) {
9076  		Polyline.prototype._setLatLngs.call(this, latlngs);
9077  		if (isFlat(this._latlngs)) {
9078  			this._latlngs = [this._latlngs];
9079  		}
9080  	},
9081
9082  	_defaultShape: function () {
9083  		return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
9084  	},
9085
9086  	_clipPoints: function () {
9087  		// polygons need a different clipping algorithm so we redefine that
9088
9089  		var bounds = this._renderer._bounds,
9090  		    w = this.options.weight,
9091  		    p = new Point(w, w);
9092
9093  		// increase clip padding by stroke width to avoid stroke on clip edges
9094  		bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));
9095
9096  		this._parts = [];
9097  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
9098  			return;
9099  		}
9100
9101  		if (this.options.noClip) {
9102  			this._parts = this._rings;
9103  			return;
9104  		}
9105
9106  		for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
9107  			clipped = clipPolygon(this._rings[i], bounds, true);
9108  			if (clipped.length) {
9109  				this._parts.push(clipped);
9110  			}
9111  		}
9112  	},
9113
9114  	_updatePath: function () {
9115  		this._renderer._updatePoly(this, true);
9116  	},
9117
9118  	// Needed by the `Canvas` renderer for interactivity
9119  	_containsPoint: function (p) {
9120  		var inside = false,
9121  		    part, p1, p2, i, j, k, len, len2;
9122
9123  		if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }
9124
9125  		// ray casting algorithm for detecting if point is in polygon
9126  		for (i = 0, len = this._parts.length; i < len; i++) {
9127  			part = this._parts[i];
9128
9129  			for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
9130  				p1 = part[j];
9131  				p2 = part[k];
9132
9133  				if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
9134  					inside = !inside;
9135  				}
9136  			}
9137  		}
9138
9139  		// also check if it's on polygon stroke
9140  		return inside || Polyline.prototype._containsPoint.call(this, p, true);
9141  	}
9142
9143  });
9144
9145
9146  // @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
9147  function polygon(latlngs, options) {
9148  	return new Polygon(latlngs, options);
9149  }
9150
9151  /*
9152   * @class GeoJSON
9153   * @aka L.GeoJSON
9154   * @inherits FeatureGroup
9155   *
9156   * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
9157   * GeoJSON data and display it on the map. Extends `FeatureGroup`.
9158   *
9159   * @example
9160   *
9161   * ```js
9162   * L.geoJSON(data, {
9163   * 	style: function (feature) {
9164   * 		return {color: feature.properties.color};
9165   * 	}
9166   * }).bindPopup(function (layer) {
9167   * 	return layer.feature.properties.description;
9168   * }).addTo(map);
9169   * ```
9170   */
9171
9172  var GeoJSON = FeatureGroup.extend({
9173
9174  	/* @section
9175  	 * @aka GeoJSON options
9176  	 *
9177  	 * @option pointToLayer: Function = *
9178  	 * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
9179  	 * called when data is added, passing the GeoJSON point feature and its `LatLng`.
9180  	 * The default is to spawn a default `Marker`:
9181  	 * ```js
9182  	 * function(geoJsonPoint, latlng) {
9183  	 * 	return L.marker(latlng);
9184  	 * }
9185  	 * ```
9186  	 *
9187  	 * @option style: Function = *
9188  	 * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
9189  	 * called internally when data is added.
9190  	 * The default value is to not override any defaults:
9191  	 * ```js
9192  	 * function (geoJsonFeature) {
9193  	 * 	return {}
9194  	 * }
9195  	 * ```
9196  	 *
9197  	 * @option onEachFeature: Function = *
9198  	 * A `Function` that will be called once for each created `Feature`, after it has
9199  	 * been created and styled. Useful for attaching events and popups to features.
9200  	 * The default is to do nothing with the newly created layers:
9201  	 * ```js
9202  	 * function (feature, layer) {}
9203  	 * ```
9204  	 *
9205  	 * @option filter: Function = *
9206  	 * A `Function` that will be used to decide whether to include a feature or not.
9207  	 * The default is to include all features:
9208  	 * ```js
9209  	 * function (geoJsonFeature) {
9210  	 * 	return true;
9211  	 * }
9212  	 * ```
9213  	 * Note: dynamically changing the `filter` option will have effect only on newly
9214  	 * added data. It will _not_ re-evaluate already included features.
9215  	 *
9216  	 * @option coordsToLatLng: Function = *
9217  	 * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
9218  	 * The default is the `coordsToLatLng` static method.
9219  	 *
9220  	 * @option markersInheritOptions: Boolean = false
9221  	 * Whether default Markers for "Point" type Features inherit from group options.
9222  	 */
9223
9224  	initialize: function (geojson, options) {
9225  		setOptions(this, options);
9226
9227  		this._layers = {};
9228
9229  		if (geojson) {
9230  			this.addData(geojson);
9231  		}
9232  	},
9233
9234  	// @method addData( <GeoJSON> data ): this
9235  	// Adds a GeoJSON object to the layer.
9236  	addData: function (geojson) {
9237  		var features = isArray(geojson) ? geojson : geojson.features,
9238  		    i, len, feature;
9239
9240  		if (features) {
9241  			for (i = 0, len = features.length; i < len; i++) {
9242  				// only add this if geometry or geometries are set and not null
9243  				feature = features[i];
9244  				if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
9245  					this.addData(feature);
9246  				}
9247  			}
9248  			return this;
9249  		}
9250
9251  		var options = this.options;
9252
9253  		if (options.filter && !options.filter(geojson)) { return this; }
9254
9255  		var layer = geometryToLayer(geojson, options);
9256  		if (!layer) {
9257  			return this;
9258  		}
9259  		layer.feature = asFeature(geojson);
9260
9261  		layer.defaultOptions = layer.options;
9262  		this.resetStyle(layer);
9263
9264  		if (options.onEachFeature) {
9265  			options.onEachFeature(geojson, layer);
9266  		}
9267
9268  		return this.addLayer(layer);
9269  	},
9270
9271  	// @method resetStyle( <Path> layer? ): this
9272  	// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
9273  	// If `layer` is omitted, the style of all features in the current layer is reset.
9274  	resetStyle: function (layer) {
9275  		if (layer === undefined) {
9276  			return this.eachLayer(this.resetStyle, this);
9277  		}
9278  		// reset any custom styles
9279  		layer.options = extend({}, layer.defaultOptions);
9280  		this._setLayerStyle(layer, this.options.style);
9281  		return this;
9282  	},
9283
9284  	// @method setStyle( <Function> style ): this
9285  	// Changes styles of GeoJSON vector layers with the given style function.
9286  	setStyle: function (style) {
9287  		return this.eachLayer(function (layer) {
9288  			this._setLayerStyle(layer, style);
9289  		}, this);
9290  	},
9291
9292  	_setLayerStyle: function (layer, style) {
9293  		if (layer.setStyle) {
9294  			if (typeof style === 'function') {
9295  				style = style(layer.feature);
9296  			}
9297  			layer.setStyle(style);
9298  		}
9299  	}
9300  });
9301
9302  // @section
9303  // There are several static functions which can be called without instantiating L.GeoJSON:
9304
9305  // @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
9306  // Creates a `Layer` from a given GeoJSON feature. Can use a custom
9307  // [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
9308  // functions if provided as options.
9309  function geometryToLayer(geojson, options) {
9310
9311  	var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
9312  	    coords = geometry ? geometry.coordinates : null,
9313  	    layers = [],
9314  	    pointToLayer = options && options.pointToLayer,
9315  	    _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,
9316  	    latlng, latlngs, i, len;
9317
9318  	if (!coords && !geometry) {
9319  		return null;
9320  	}
9321
9322  	switch (geometry.type) {
9323  	case 'Point':
9324  		latlng = _coordsToLatLng(coords);
9325  		return _pointToLayer(pointToLayer, geojson, latlng, options);
9326
9327  	case 'MultiPoint':
9328  		for (i = 0, len = coords.length; i < len; i++) {
9329  			latlng = _coordsToLatLng(coords[i]);
9330  			layers.push(_pointToLayer(pointToLayer, geojson, latlng, options));
9331  		}
9332  		return new FeatureGroup(layers);
9333
9334  	case 'LineString':
9335  	case 'MultiLineString':
9336  		latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);
9337  		return new Polyline(latlngs, options);
9338
9339  	case 'Polygon':
9340  	case 'MultiPolygon':
9341  		latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);
9342  		return new Polygon(latlngs, options);
9343
9344  	case 'GeometryCollection':
9345  		for (i = 0, len = geometry.geometries.length; i < len; i++) {
9346  			var geoLayer = geometryToLayer({
9347  				geometry: geometry.geometries[i],
9348  				type: 'Feature',
9349  				properties: geojson.properties
9350  			}, options);
9351
9352  			if (geoLayer) {
9353  				layers.push(geoLayer);
9354  			}
9355  		}
9356  		return new FeatureGroup(layers);
9357
9358  	case 'FeatureCollection':
9359  		for (i = 0, len = geometry.features.length; i < len; i++) {
9360  			var featureLayer = geometryToLayer(geometry.features[i], options);
9361
9362  			if (featureLayer) {
9363  				layers.push(featureLayer);
9364  			}
9365  		}
9366  		return new FeatureGroup(layers);
9367
9368  	default:
9369  		throw new Error('Invalid GeoJSON object.');
9370  	}
9371  }
9372
9373  function _pointToLayer(pointToLayerFn, geojson, latlng, options) {
9374  	return pointToLayerFn ?
9375  		pointToLayerFn(geojson, latlng) :
9376  		new Marker(latlng, options && options.markersInheritOptions && options);
9377  }
9378
9379  // @function coordsToLatLng(coords: Array): LatLng
9380  // Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
9381  // or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
9382  function coordsToLatLng(coords) {
9383  	return new LatLng(coords[1], coords[0], coords[2]);
9384  }
9385
9386  // @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
9387  // Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
9388  // `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
9389  // Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
9390  function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {
9391  	var latlngs = [];
9392
9393  	for (var i = 0, len = coords.length, latlng; i < len; i++) {
9394  		latlng = levelsDeep ?
9395  			coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :
9396  			(_coordsToLatLng || coordsToLatLng)(coords[i]);
9397
9398  		latlngs.push(latlng);
9399  	}
9400
9401  	return latlngs;
9402  }
9403
9404  // @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array
9405  // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
9406  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
9407  function latLngToCoords(latlng, precision) {
9408  	latlng = toLatLng(latlng);
9409  	return latlng.alt !== undefined ?
9410  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :
9411  		[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];
9412  }
9413
9414  // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array
9415  // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
9416  // `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
9417  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function.
9418  function latLngsToCoords(latlngs, levelsDeep, closed, precision) {
9419  	var coords = [];
9420
9421  	for (var i = 0, len = latlngs.length; i < len; i++) {
9422  		// Check for flat arrays required to ensure unbalanced arrays are correctly converted in recursion
9423  		coords.push(levelsDeep ?
9424  			latLngsToCoords(latlngs[i], isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) :
9425  			latLngToCoords(latlngs[i], precision));
9426  	}
9427
9428  	if (!levelsDeep && closed && coords.length > 0) {
9429  		coords.push(coords[0].slice());
9430  	}
9431
9432  	return coords;
9433  }
9434
9435  function getFeature(layer, newGeometry) {
9436  	return layer.feature ?
9437  		extend({}, layer.feature, {geometry: newGeometry}) :
9438  		asFeature(newGeometry);
9439  }
9440
9441  // @function asFeature(geojson: Object): Object
9442  // Normalize GeoJSON geometries/features into GeoJSON features.
9443  function asFeature(geojson) {
9444  	if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
9445  		return geojson;
9446  	}
9447
9448  	return {
9449  		type: 'Feature',
9450  		properties: {},
9451  		geometry: geojson
9452  	};
9453  }
9454
9455  var PointToGeoJSON = {
9456  	toGeoJSON: function (precision) {
9457  		return getFeature(this, {
9458  			type: 'Point',
9459  			coordinates: latLngToCoords(this.getLatLng(), precision)
9460  		});
9461  	}
9462  };
9463
9464  // @namespace Marker
9465  // @section Other methods
9466  // @method toGeoJSON(precision?: Number|false): Object
9467  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9468  // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
9469  Marker.include(PointToGeoJSON);
9470
9471  // @namespace CircleMarker
9472  // @method toGeoJSON(precision?: Number|false): Object
9473  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9474  // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
9475  Circle.include(PointToGeoJSON);
9476  CircleMarker.include(PointToGeoJSON);
9477
9478
9479  // @namespace Polyline
9480  // @method toGeoJSON(precision?: Number|false): Object
9481  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9482  // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
9483  Polyline.include({
9484  	toGeoJSON: function (precision) {
9485  		var multi = !isFlat(this._latlngs);
9486
9487  		var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);
9488
9489  		return getFeature(this, {
9490  			type: (multi ? 'Multi' : '') + 'LineString',
9491  			coordinates: coords
9492  		});
9493  	}
9494  });
9495
9496  // @namespace Polygon
9497  // @method toGeoJSON(precision?: Number|false): Object
9498  // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9499  // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
9500  Polygon.include({
9501  	toGeoJSON: function (precision) {
9502  		var holes = !isFlat(this._latlngs),
9503  		    multi = holes && !isFlat(this._latlngs[0]);
9504
9505  		var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);
9506
9507  		if (!holes) {
9508  			coords = [coords];
9509  		}
9510
9511  		return getFeature(this, {
9512  			type: (multi ? 'Multi' : '') + 'Polygon',
9513  			coordinates: coords
9514  		});
9515  	}
9516  });
9517
9518
9519  // @namespace LayerGroup
9520  LayerGroup.include({
9521  	toMultiPoint: function (precision) {
9522  		var coords = [];
9523
9524  		this.eachLayer(function (layer) {
9525  			coords.push(layer.toGeoJSON(precision).geometry.coordinates);
9526  		});
9527
9528  		return getFeature(this, {
9529  			type: 'MultiPoint',
9530  			coordinates: coords
9531  		});
9532  	},
9533
9534  	// @method toGeoJSON(precision?: Number|false): Object
9535  	// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`.
9536  	// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).
9537  	toGeoJSON: function (precision) {
9538
9539  		var type = this.feature && this.feature.geometry && this.feature.geometry.type;
9540
9541  		if (type === 'MultiPoint') {
9542  			return this.toMultiPoint(precision);
9543  		}
9544
9545  		var isGeometryCollection = type === 'GeometryCollection',
9546  		    jsons = [];
9547
9548  		this.eachLayer(function (layer) {
9549  			if (layer.toGeoJSON) {
9550  				var json = layer.toGeoJSON(precision);
9551  				if (isGeometryCollection) {
9552  					jsons.push(json.geometry);
9553  				} else {
9554  					var feature = asFeature(json);
9555  					// Squash nested feature collections
9556  					if (feature.type === 'FeatureCollection') {
9557  						jsons.push.apply(jsons, feature.features);
9558  					} else {
9559  						jsons.push(feature);
9560  					}
9561  				}
9562  			}
9563  		});
9564
9565  		if (isGeometryCollection) {
9566  			return getFeature(this, {
9567  				geometries: jsons,
9568  				type: 'GeometryCollection'
9569  			});
9570  		}
9571
9572  		return {
9573  			type: 'FeatureCollection',
9574  			features: jsons
9575  		};
9576  	}
9577  });
9578
9579  // @namespace GeoJSON
9580  // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
9581  // Creates a GeoJSON layer. Optionally accepts an object in
9582  // [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map
9583  // (you can alternatively add it later with `addData` method) and an `options` object.
9584  function geoJSON(geojson, options) {
9585  	return new GeoJSON(geojson, options);
9586  }
9587
9588  // Backward compatibility.
9589  var geoJson = geoJSON;
9590
9591  /*
9592   * @class ImageOverlay
9593   * @aka L.ImageOverlay
9594   * @inherits Interactive layer
9595   *
9596   * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
9597   *
9598   * @example
9599   *
9600   * ```js
9601   * var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
9602   * 	imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
9603   * L.imageOverlay(imageUrl, imageBounds).addTo(map);
9604   * ```
9605   */
9606
9607  var ImageOverlay = Layer.extend({
9608
9609  	// @section
9610  	// @aka ImageOverlay options
9611  	options: {
9612  		// @option opacity: Number = 1.0
9613  		// The opacity of the image overlay.
9614  		opacity: 1,
9615
9616  		// @option alt: String = ''
9617  		// Text for the `alt` attribute of the image (useful for accessibility).
9618  		alt: '',
9619
9620  		// @option interactive: Boolean = false
9621  		// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
9622  		interactive: false,
9623
9624  		// @option crossOrigin: Boolean|String = false
9625  		// Whether the crossOrigin attribute will be added to the image.
9626  		// If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data.
9627  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
9628  		crossOrigin: false,
9629
9630  		// @option errorOverlayUrl: String = ''
9631  		// URL to the overlay image to show in place of the overlay that failed to load.
9632  		errorOverlayUrl: '',
9633
9634  		// @option zIndex: Number = 1
9635  		// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer.
9636  		zIndex: 1,
9637
9638  		// @option className: String = ''
9639  		// A custom class name to assign to the image. Empty by default.
9640  		className: ''
9641  	},
9642
9643  	initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
9644  		this._url = url;
9645  		this._bounds = toLatLngBounds(bounds);
9646
9647  		setOptions(this, options);
9648  	},
9649
9650  	onAdd: function () {
9651  		if (!this._image) {
9652  			this._initImage();
9653
9654  			if (this.options.opacity < 1) {
9655  				this._updateOpacity();
9656  			}
9657  		}
9658
9659  		if (this.options.interactive) {
9660  			addClass(this._image, 'leaflet-interactive');
9661  			this.addInteractiveTarget(this._image);
9662  		}
9663
9664  		this.getPane().appendChild(this._image);
9665  		this._reset();
9666  	},
9667
9668  	onRemove: function () {
9669  		remove(this._image);
9670  		if (this.options.interactive) {
9671  			this.removeInteractiveTarget(this._image);
9672  		}
9673  	},
9674
9675  	// @method setOpacity(opacity: Number): this
9676  	// Sets the opacity of the overlay.
9677  	setOpacity: function (opacity) {
9678  		this.options.opacity = opacity;
9679
9680  		if (this._image) {
9681  			this._updateOpacity();
9682  		}
9683  		return this;
9684  	},
9685
9686  	setStyle: function (styleOpts) {
9687  		if (styleOpts.opacity) {
9688  			this.setOpacity(styleOpts.opacity);
9689  		}
9690  		return this;
9691  	},
9692
9693  	// @method bringToFront(): this
9694  	// Brings the layer to the top of all overlays.
9695  	bringToFront: function () {
9696  		if (this._map) {
9697  			toFront(this._image);
9698  		}
9699  		return this;
9700  	},
9701
9702  	// @method bringToBack(): this
9703  	// Brings the layer to the bottom of all overlays.
9704  	bringToBack: function () {
9705  		if (this._map) {
9706  			toBack(this._image);
9707  		}
9708  		return this;
9709  	},
9710
9711  	// @method setUrl(url: String): this
9712  	// Changes the URL of the image.
9713  	setUrl: function (url) {
9714  		this._url = url;
9715
9716  		if (this._image) {
9717  			this._image.src = url;
9718  		}
9719  		return this;
9720  	},
9721
9722  	// @method setBounds(bounds: LatLngBounds): this
9723  	// Update the bounds that this ImageOverlay covers
9724  	setBounds: function (bounds) {
9725  		this._bounds = toLatLngBounds(bounds);
9726
9727  		if (this._map) {
9728  			this._reset();
9729  		}
9730  		return this;
9731  	},
9732
9733  	getEvents: function () {
9734  		var events = {
9735  			zoom: this._reset,
9736  			viewreset: this._reset
9737  		};
9738
9739  		if (this._zoomAnimated) {
9740  			events.zoomanim = this._animateZoom;
9741  		}
9742
9743  		return events;
9744  	},
9745
9746  	// @method setZIndex(value: Number): this
9747  	// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.
9748  	setZIndex: function (value) {
9749  		this.options.zIndex = value;
9750  		this._updateZIndex();
9751  		return this;
9752  	},
9753
9754  	// @method getBounds(): LatLngBounds
9755  	// Get the bounds that this ImageOverlay covers
9756  	getBounds: function () {
9757  		return this._bounds;
9758  	},
9759
9760  	// @method getElement(): HTMLElement
9761  	// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)
9762  	// used by this overlay.
9763  	getElement: function () {
9764  		return this._image;
9765  	},
9766
9767  	_initImage: function () {
9768  		var wasElementSupplied = this._url.tagName === 'IMG';
9769  		var img = this._image = wasElementSupplied ? this._url : create$1('img');
9770
9771  		addClass(img, 'leaflet-image-layer');
9772  		if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }
9773  		if (this.options.className) { addClass(img, this.options.className); }
9774
9775  		img.onselectstart = falseFn;
9776  		img.onmousemove = falseFn;
9777
9778  		// @event load: Event
9779  		// Fired when the ImageOverlay layer has loaded its image
9780  		img.onload = bind(this.fire, this, 'load');
9781  		img.onerror = bind(this._overlayOnError, this, 'error');
9782
9783  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
9784  			img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
9785  		}
9786
9787  		if (this.options.zIndex) {
9788  			this._updateZIndex();
9789  		}
9790
9791  		if (wasElementSupplied) {
9792  			this._url = img.src;
9793  			return;
9794  		}
9795
9796  		img.src = this._url;
9797  		img.alt = this.options.alt;
9798  	},
9799
9800  	_animateZoom: function (e) {
9801  		var scale = this._map.getZoomScale(e.zoom),
9802  		    offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
9803
9804  		setTransform(this._image, offset, scale);
9805  	},
9806
9807  	_reset: function () {
9808  		var image = this._image,
9809  		    bounds = new Bounds(
9810  		        this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
9811  		        this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
9812  		    size = bounds.getSize();
9813
9814  		setPosition(image, bounds.min);
9815
9816  		image.style.width  = size.x + 'px';
9817  		image.style.height = size.y + 'px';
9818  	},
9819
9820  	_updateOpacity: function () {
9821  		setOpacity(this._image, this.options.opacity);
9822  	},
9823
9824  	_updateZIndex: function () {
9825  		if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {
9826  			this._image.style.zIndex = this.options.zIndex;
9827  		}
9828  	},
9829
9830  	_overlayOnError: function () {
9831  		// @event error: Event
9832  		// Fired when the ImageOverlay layer fails to load its image
9833  		this.fire('error');
9834
9835  		var errorUrl = this.options.errorOverlayUrl;
9836  		if (errorUrl && this._url !== errorUrl) {
9837  			this._url = errorUrl;
9838  			this._image.src = errorUrl;
9839  		}
9840  	},
9841
9842  	// @method getCenter(): LatLng
9843  	// Returns the center of the ImageOverlay.
9844  	getCenter: function () {
9845  		return this._bounds.getCenter();
9846  	}
9847  });
9848
9849  // @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
9850  // Instantiates an image overlay object given the URL of the image and the
9851  // geographical bounds it is tied to.
9852  var imageOverlay = function (url, bounds, options) {
9853  	return new ImageOverlay(url, bounds, options);
9854  };
9855
9856  /*
9857   * @class VideoOverlay
9858   * @aka L.VideoOverlay
9859   * @inherits ImageOverlay
9860   *
9861   * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.
9862   *
9863   * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video)
9864   * HTML5 element.
9865   *
9866   * @example
9867   *
9868   * ```js
9869   * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',
9870   * 	videoBounds = [[ 32, -130], [ 13, -100]];
9871   * L.videoOverlay(videoUrl, videoBounds ).addTo(map);
9872   * ```
9873   */
9874
9875  var VideoOverlay = ImageOverlay.extend({
9876
9877  	// @section
9878  	// @aka VideoOverlay options
9879  	options: {
9880  		// @option autoplay: Boolean = true
9881  		// Whether the video starts playing automatically when loaded.
9882  		// On some browsers autoplay will only work with `muted: true`
9883  		autoplay: true,
9884
9885  		// @option loop: Boolean = true
9886  		// Whether the video will loop back to the beginning when played.
9887  		loop: true,
9888
9889  		// @option keepAspectRatio: Boolean = true
9890  		// Whether the video will save aspect ratio after the projection.
9891  		// Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit)
9892  		keepAspectRatio: true,
9893
9894  		// @option muted: Boolean = false
9895  		// Whether the video starts on mute when loaded.
9896  		muted: false,
9897
9898  		// @option playsInline: Boolean = true
9899  		// Mobile browsers will play the video right where it is instead of open it up in fullscreen mode.
9900  		playsInline: true
9901  	},
9902
9903  	_initImage: function () {
9904  		var wasElementSupplied = this._url.tagName === 'VIDEO';
9905  		var vid = this._image = wasElementSupplied ? this._url : create$1('video');
9906
9907  		addClass(vid, 'leaflet-image-layer');
9908  		if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }
9909  		if (this.options.className) { addClass(vid, this.options.className); }
9910
9911  		vid.onselectstart = falseFn;
9912  		vid.onmousemove = falseFn;
9913
9914  		// @event load: Event
9915  		// Fired when the video has finished loading the first frame
9916  		vid.onloadeddata = bind(this.fire, this, 'load');
9917
9918  		if (wasElementSupplied) {
9919  			var sourceElements = vid.getElementsByTagName('source');
9920  			var sources = [];
9921  			for (var j = 0; j < sourceElements.length; j++) {
9922  				sources.push(sourceElements[j].src);
9923  			}
9924
9925  			this._url = (sourceElements.length > 0) ? sources : [vid.src];
9926  			return;
9927  		}
9928
9929  		if (!isArray(this._url)) { this._url = [this._url]; }
9930
9931  		if (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) {
9932  			vid.style['objectFit'] = 'fill';
9933  		}
9934  		vid.autoplay = !!this.options.autoplay;
9935  		vid.loop = !!this.options.loop;
9936  		vid.muted = !!this.options.muted;
9937  		vid.playsInline = !!this.options.playsInline;
9938  		for (var i = 0; i < this._url.length; i++) {
9939  			var source = create$1('source');
9940  			source.src = this._url[i];
9941  			vid.appendChild(source);
9942  		}
9943  	}
9944
9945  	// @method getElement(): HTMLVideoElement
9946  	// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)
9947  	// used by this overlay.
9948  });
9949
9950
9951  // @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)
9952  // Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the
9953  // geographical bounds it is tied to.
9954
9955  function videoOverlay(video, bounds, options) {
9956  	return new VideoOverlay(video, bounds, options);
9957  }
9958
9959  /*
9960   * @class SVGOverlay
9961   * @aka L.SVGOverlay
9962   * @inherits ImageOverlay
9963   *
9964   * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`.
9965   *
9966   * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element.
9967   *
9968   * @example
9969   *
9970   * ```js
9971   * var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
9972   * svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg");
9973   * svgElement.setAttribute('viewBox', "0 0 200 200");
9974   * svgElement.innerHTML = '<rect width="200" height="200"/><rect x="75" y="23" width="50" height="50" style="fill:red"/><rect x="75" y="123" width="50" height="50" style="fill:#0013ff"/>';
9975   * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ];
9976   * L.svgOverlay(svgElement, svgElementBounds).addTo(map);
9977   * ```
9978   */
9979
9980  var SVGOverlay = ImageOverlay.extend({
9981  	_initImage: function () {
9982  		var el = this._image = this._url;
9983
9984  		addClass(el, 'leaflet-image-layer');
9985  		if (this._zoomAnimated) { addClass(el, 'leaflet-zoom-animated'); }
9986  		if (this.options.className) { addClass(el, this.options.className); }
9987
9988  		el.onselectstart = falseFn;
9989  		el.onmousemove = falseFn;
9990  	}
9991
9992  	// @method getElement(): SVGElement
9993  	// Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement)
9994  	// used by this overlay.
9995  });
9996
9997
9998  // @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options)
9999  // Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to.
10000  // A viewBox attribute is required on the SVG element to zoom in and out properly.
10001
10002  function svgOverlay(el, bounds, options) {
10003  	return new SVGOverlay(el, bounds, options);
10004  }
10005
10006  /*
10007   * @class DivOverlay
10008   * @inherits Interactive layer
10009   * @aka L.DivOverlay
10010   * Base model for L.Popup and L.Tooltip. Inherit from it for custom overlays like plugins.
10011   */
10012
10013  // @namespace DivOverlay
10014  var DivOverlay = Layer.extend({
10015
10016  	// @section
10017  	// @aka DivOverlay options
10018  	options: {
10019  		// @option interactive: Boolean = false
10020  		// If true, the popup/tooltip will listen to the mouse events.
10021  		interactive: false,
10022
10023  		// @option offset: Point = Point(0, 0)
10024  		// The offset of the overlay position.
10025  		offset: [0, 0],
10026
10027  		// @option className: String = ''
10028  		// A custom CSS class name to assign to the overlay.
10029  		className: '',
10030
10031  		// @option pane: String = undefined
10032  		// `Map pane` where the overlay will be added.
10033  		pane: undefined,
10034
10035  		// @option content: String|HTMLElement|Function = ''
10036  		// Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be
10037  		// passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay.
10038  		content: ''
10039  	},
10040
10041  	initialize: function (options, source) {
10042  		if (options && (options instanceof LatLng || isArray(options))) {
10043  			this._latlng = toLatLng(options);
10044  			setOptions(this, source);
10045  		} else {
10046  			setOptions(this, options);
10047  			this._source = source;
10048  		}
10049  		if (this.options.content) {
10050  			this._content = this.options.content;
10051  		}
10052  	},
10053
10054  	// @method openOn(map: Map): this
10055  	// Adds the overlay to the map.
10056  	// Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`.
10057  	openOn: function (map) {
10058  		map = arguments.length ? map : this._source._map; // experimental, not the part of public api
10059  		if (!map.hasLayer(this)) {
10060  			map.addLayer(this);
10061  		}
10062  		return this;
10063  	},
10064
10065  	// @method close(): this
10066  	// Closes the overlay.
10067  	// Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)`
10068  	// and `layer.closePopup()`/`.closeTooltip()`.
10069  	close: function () {
10070  		if (this._map) {
10071  			this._map.removeLayer(this);
10072  		}
10073  		return this;
10074  	},
10075
10076  	// @method toggle(layer?: Layer): this
10077  	// Opens or closes the overlay bound to layer depending on its current state.
10078  	// Argument may be omitted only for overlay bound to layer.
10079  	// Alternative to `layer.togglePopup()`/`.toggleTooltip()`.
10080  	toggle: function (layer) {
10081  		if (this._map) {
10082  			this.close();
10083  		} else {
10084  			if (arguments.length) {
10085  				this._source = layer;
10086  			} else {
10087  				layer = this._source;
10088  			}
10089  			this._prepareOpen();
10090
10091  			// open the overlay on the map
10092  			this.openOn(layer._map);
10093  		}
10094  		return this;
10095  	},
10096
10097  	onAdd: function (map) {
10098  		this._zoomAnimated = map._zoomAnimated;
10099
10100  		if (!this._container) {
10101  			this._initLayout();
10102  		}
10103
10104  		if (map._fadeAnimated) {
10105  			setOpacity(this._container, 0);
10106  		}
10107
10108  		clearTimeout(this._removeTimeout);
10109  		this.getPane().appendChild(this._container);
10110  		this.update();
10111
10112  		if (map._fadeAnimated) {
10113  			setOpacity(this._container, 1);
10114  		}
10115
10116  		this.bringToFront();
10117
10118  		if (this.options.interactive) {
10119  			addClass(this._container, 'leaflet-interactive');
10120  			this.addInteractiveTarget(this._container);
10121  		}
10122  	},
10123
10124  	onRemove: function (map) {
10125  		if (map._fadeAnimated) {
10126  			setOpacity(this._container, 0);
10127  			this._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200);
10128  		} else {
10129  			remove(this._container);
10130  		}
10131
10132  		if (this.options.interactive) {
10133  			removeClass(this._container, 'leaflet-interactive');
10134  			this.removeInteractiveTarget(this._container);
10135  		}
10136  	},
10137
10138  	// @namespace DivOverlay
10139  	// @method getLatLng: LatLng
10140  	// Returns the geographical point of the overlay.
10141  	getLatLng: function () {
10142  		return this._latlng;
10143  	},
10144
10145  	// @method setLatLng(latlng: LatLng): this
10146  	// Sets the geographical point where the overlay will open.
10147  	setLatLng: function (latlng) {
10148  		this._latlng = toLatLng(latlng);
10149  		if (this._map) {
10150  			this._updatePosition();
10151  			this._adjustPan();
10152  		}
10153  		return this;
10154  	},
10155
10156  	// @method getContent: String|HTMLElement
10157  	// Returns the content of the overlay.
10158  	getContent: function () {
10159  		return this._content;
10160  	},
10161
10162  	// @method setContent(htmlContent: String|HTMLElement|Function): this
10163  	// Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function.
10164  	// The function should return a `String` or `HTMLElement` to be used in the overlay.
10165  	setContent: function (content) {
10166  		this._content = content;
10167  		this.update();
10168  		return this;
10169  	},
10170
10171  	// @method getElement: String|HTMLElement
10172  	// Returns the HTML container of the overlay.
10173  	getElement: function () {
10174  		return this._container;
10175  	},
10176
10177  	// @method update: null
10178  	// Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded.
10179  	update: function () {
10180  		if (!this._map) { return; }
10181
10182  		this._container.style.visibility = 'hidden';
10183
10184  		this._updateContent();
10185  		this._updateLayout();
10186  		this._updatePosition();
10187
10188  		this._container.style.visibility = '';
10189
10190  		this._adjustPan();
10191  	},
10192
10193  	getEvents: function () {
10194  		var events = {
10195  			zoom: this._updatePosition,
10196  			viewreset: this._updatePosition
10197  		};
10198
10199  		if (this._zoomAnimated) {
10200  			events.zoomanim = this._animateZoom;
10201  		}
10202  		return events;
10203  	},
10204
10205  	// @method isOpen: Boolean
10206  	// Returns `true` when the overlay is visible on the map.
10207  	isOpen: function () {
10208  		return !!this._map && this._map.hasLayer(this);
10209  	},
10210
10211  	// @method bringToFront: this
10212  	// Brings this overlay in front of other overlays (in the same map pane).
10213  	bringToFront: function () {
10214  		if (this._map) {
10215  			toFront(this._container);
10216  		}
10217  		return this;
10218  	},
10219
10220  	// @method bringToBack: this
10221  	// Brings this overlay to the back of other overlays (in the same map pane).
10222  	bringToBack: function () {
10223  		if (this._map) {
10224  			toBack(this._container);
10225  		}
10226  		return this;
10227  	},
10228
10229  	// prepare bound overlay to open: update latlng pos / content source (for FeatureGroup)
10230  	_prepareOpen: function (latlng) {
10231  		var source = this._source;
10232  		if (!source._map) { return false; }
10233
10234  		if (source instanceof FeatureGroup) {
10235  			source = null;
10236  			var layers = this._source._layers;
10237  			for (var id in layers) {
10238  				if (layers[id]._map) {
10239  					source = layers[id];
10240  					break;
10241  				}
10242  			}
10243  			if (!source) { return false; } // Unable to get source layer.
10244
10245  			// set overlay source to this layer
10246  			this._source = source;
10247  		}
10248
10249  		if (!latlng) {
10250  			if (source.getCenter) {
10251  				latlng = source.getCenter();
10252  			} else if (source.getLatLng) {
10253  				latlng = source.getLatLng();
10254  			} else if (source.getBounds) {
10255  				latlng = source.getBounds().getCenter();
10256  			} else {
10257  				throw new Error('Unable to get source layer LatLng.');
10258  			}
10259  		}
10260  		this.setLatLng(latlng);
10261
10262  		if (this._map) {
10263  			// update the overlay (content, layout, etc...)
10264  			this.update();
10265  		}
10266
10267  		return true;
10268  	},
10269
10270  	_updateContent: function () {
10271  		if (!this._content) { return; }
10272
10273  		var node = this._contentNode;
10274  		var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
10275
10276  		if (typeof content === 'string') {
10277  			node.innerHTML = content;
10278  		} else {
10279  			while (node.hasChildNodes()) {
10280  				node.removeChild(node.firstChild);
10281  			}
10282  			node.appendChild(content);
10283  		}
10284
10285  		// @namespace DivOverlay
10286  		// @section DivOverlay events
10287  		// @event contentupdate: Event
10288  		// Fired when the content of the overlay is updated
10289  		this.fire('contentupdate');
10290  	},
10291
10292  	_updatePosition: function () {
10293  		if (!this._map) { return; }
10294
10295  		var pos = this._map.latLngToLayerPoint(this._latlng),
10296  		    offset = toPoint(this.options.offset),
10297  		    anchor = this._getAnchor();
10298
10299  		if (this._zoomAnimated) {
10300  			setPosition(this._container, pos.add(anchor));
10301  		} else {
10302  			offset = offset.add(pos).add(anchor);
10303  		}
10304
10305  		var bottom = this._containerBottom = -offset.y,
10306  		    left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
10307
10308  		// bottom position the overlay in case the height of the overlay changes (images loading etc)
10309  		this._container.style.bottom = bottom + 'px';
10310  		this._container.style.left = left + 'px';
10311  	},
10312
10313  	_getAnchor: function () {
10314  		return [0, 0];
10315  	}
10316
10317  });
10318
10319  Map.include({
10320  	_initOverlay: function (OverlayClass, content, latlng, options) {
10321  		var overlay = content;
10322  		if (!(overlay instanceof OverlayClass)) {
10323  			overlay = new OverlayClass(options).setContent(content);
10324  		}
10325  		if (latlng) {
10326  			overlay.setLatLng(latlng);
10327  		}
10328  		return overlay;
10329  	}
10330  });
10331
10332
10333  Layer.include({
10334  	_initOverlay: function (OverlayClass, old, content, options) {
10335  		var overlay = content;
10336  		if (overlay instanceof OverlayClass) {
10337  			setOptions(overlay, options);
10338  			overlay._source = this;
10339  		} else {
10340  			overlay = (old && !options) ? old : new OverlayClass(options, this);
10341  			overlay.setContent(content);
10342  		}
10343  		return overlay;
10344  	}
10345  });
10346
10347  /*
10348   * @class Popup
10349   * @inherits DivOverlay
10350   * @aka L.Popup
10351   * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
10352   * open popups while making sure that only one popup is open at one time
10353   * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
10354   *
10355   * @example
10356   *
10357   * If you want to just bind a popup to marker click and then open it, it's really easy:
10358   *
10359   * ```js
10360   * marker.bindPopup(popupContent).openPopup();
10361   * ```
10362   * Path overlays like polylines also have a `bindPopup` method.
10363   *
10364   * A popup can be also standalone:
10365   *
10366   * ```js
10367   * var popup = L.popup()
10368   * 	.setLatLng(latlng)
10369   * 	.setContent('<p>Hello world!<br />This is a nice popup.</p>')
10370   * 	.openOn(map);
10371   * ```
10372   * or
10373   * ```js
10374   * var popup = L.popup(latlng, {content: '<p>Hello world!<br />This is a nice popup.</p>')
10375   * 	.openOn(map);
10376   * ```
10377   */
10378
10379
10380  // @namespace Popup
10381  var Popup = DivOverlay.extend({
10382
10383  	// @section
10384  	// @aka Popup options
10385  	options: {
10386  		// @option pane: String = 'popupPane'
10387  		// `Map pane` where the popup will be added.
10388  		pane: 'popupPane',
10389
10390  		// @option offset: Point = Point(0, 7)
10391  		// The offset of the popup position.
10392  		offset: [0, 7],
10393
10394  		// @option maxWidth: Number = 300
10395  		// Max width of the popup, in pixels.
10396  		maxWidth: 300,
10397
10398  		// @option minWidth: Number = 50
10399  		// Min width of the popup, in pixels.
10400  		minWidth: 50,
10401
10402  		// @option maxHeight: Number = null
10403  		// If set, creates a scrollable container of the given height
10404  		// inside a popup if its content exceeds it.
10405  		// The scrollable container can be styled using the
10406  		// `leaflet-popup-scrolled` CSS class selector.
10407  		maxHeight: null,
10408
10409  		// @option autoPan: Boolean = true
10410  		// Set it to `false` if you don't want the map to do panning animation
10411  		// to fit the opened popup.
10412  		autoPan: true,
10413
10414  		// @option autoPanPaddingTopLeft: Point = null
10415  		// The margin between the popup and the top left corner of the map
10416  		// view after autopanning was performed.
10417  		autoPanPaddingTopLeft: null,
10418
10419  		// @option autoPanPaddingBottomRight: Point = null
10420  		// The margin between the popup and the bottom right corner of the map
10421  		// view after autopanning was performed.
10422  		autoPanPaddingBottomRight: null,
10423
10424  		// @option autoPanPadding: Point = Point(5, 5)
10425  		// Equivalent of setting both top left and bottom right autopan padding to the same value.
10426  		autoPanPadding: [5, 5],
10427
10428  		// @option keepInView: Boolean = false
10429  		// Set it to `true` if you want to prevent users from panning the popup
10430  		// off of the screen while it is open.
10431  		keepInView: false,
10432
10433  		// @option closeButton: Boolean = true
10434  		// Controls the presence of a close button in the popup.
10435  		closeButton: true,
10436
10437  		// @option autoClose: Boolean = true
10438  		// Set it to `false` if you want to override the default behavior of
10439  		// the popup closing when another popup is opened.
10440  		autoClose: true,
10441
10442  		// @option closeOnEscapeKey: Boolean = true
10443  		// Set it to `false` if you want to override the default behavior of
10444  		// the ESC key for closing of the popup.
10445  		closeOnEscapeKey: true,
10446
10447  		// @option closeOnClick: Boolean = *
10448  		// Set it if you want to override the default behavior of the popup closing when user clicks
10449  		// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.
10450
10451  		// @option className: String = ''
10452  		// A custom CSS class name to assign to the popup.
10453  		className: ''
10454  	},
10455
10456  	// @namespace Popup
10457  	// @method openOn(map: Map): this
10458  	// Alternative to `map.openPopup(popup)`.
10459  	// Adds the popup to the map and closes the previous one.
10460  	openOn: function (map) {
10461  		map = arguments.length ? map : this._source._map; // experimental, not the part of public api
10462
10463  		if (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) {
10464  			map.removeLayer(map._popup);
10465  		}
10466  		map._popup = this;
10467
10468  		return DivOverlay.prototype.openOn.call(this, map);
10469  	},
10470
10471  	onAdd: function (map) {
10472  		DivOverlay.prototype.onAdd.call(this, map);
10473
10474  		// @namespace Map
10475  		// @section Popup events
10476  		// @event popupopen: PopupEvent
10477  		// Fired when a popup is opened in the map
10478  		map.fire('popupopen', {popup: this});
10479
10480  		if (this._source) {
10481  			// @namespace Layer
10482  			// @section Popup events
10483  			// @event popupopen: PopupEvent
10484  			// Fired when a popup bound to this layer is opened
10485  			this._source.fire('popupopen', {popup: this}, true);
10486  			// For non-path layers, we toggle the popup when clicking
10487  			// again the layer, so prevent the map to reopen it.
10488  			if (!(this._source instanceof Path)) {
10489  				this._source.on('preclick', stopPropagation);
10490  			}
10491  		}
10492  	},
10493
10494  	onRemove: function (map) {
10495  		DivOverlay.prototype.onRemove.call(this, map);
10496
10497  		// @namespace Map
10498  		// @section Popup events
10499  		// @event popupclose: PopupEvent
10500  		// Fired when a popup in the map is closed
10501  		map.fire('popupclose', {popup: this});
10502
10503  		if (this._source) {
10504  			// @namespace Layer
10505  			// @section Popup events
10506  			// @event popupclose: PopupEvent
10507  			// Fired when a popup bound to this layer is closed
10508  			this._source.fire('popupclose', {popup: this}, true);
10509  			if (!(this._source instanceof Path)) {
10510  				this._source.off('preclick', stopPropagation);
10511  			}
10512  		}
10513  	},
10514
10515  	getEvents: function () {
10516  		var events = DivOverlay.prototype.getEvents.call(this);
10517
10518  		if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
10519  			events.preclick = this.close;
10520  		}
10521
10522  		if (this.options.keepInView) {
10523  			events.moveend = this._adjustPan;
10524  		}
10525
10526  		return events;
10527  	},
10528
10529  	_initLayout: function () {
10530  		var prefix = 'leaflet-popup',
10531  		    container = this._container = create$1('div',
10532  			prefix + ' ' + (this.options.className || '') +
10533  			' leaflet-zoom-animated');
10534
10535  		var wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container);
10536  		this._contentNode = create$1('div', prefix + '-content', wrapper);
10537
10538  		disableClickPropagation(container);
10539  		disableScrollPropagation(this._contentNode);
10540  		on(container, 'contextmenu', stopPropagation);
10541
10542  		this._tipContainer = create$1('div', prefix + '-tip-container', container);
10543  		this._tip = create$1('div', prefix + '-tip', this._tipContainer);
10544
10545  		if (this.options.closeButton) {
10546  			var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);
10547  			closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399
10548  			closeButton.setAttribute('aria-label', 'Close popup');
10549  			closeButton.href = '#close';
10550  			closeButton.innerHTML = '<span aria-hidden="true">&#215;</span>';
10551
10552  			on(closeButton, 'click', function (ev) {
10553  				preventDefault(ev);
10554  				this.close();
10555  			}, this);
10556  		}
10557  	},
10558
10559  	_updateLayout: function () {
10560  		var container = this._contentNode,
10561  		    style = container.style;
10562
10563  		style.width = '';
10564  		style.whiteSpace = 'nowrap';
10565
10566  		var width = container.offsetWidth;
10567  		width = Math.min(width, this.options.maxWidth);
10568  		width = Math.max(width, this.options.minWidth);
10569
10570  		style.width = (width + 1) + 'px';
10571  		style.whiteSpace = '';
10572
10573  		style.height = '';
10574
10575  		var height = container.offsetHeight,
10576  		    maxHeight = this.options.maxHeight,
10577  		    scrolledClass = 'leaflet-popup-scrolled';
10578
10579  		if (maxHeight && height > maxHeight) {
10580  			style.height = maxHeight + 'px';
10581  			addClass(container, scrolledClass);
10582  		} else {
10583  			removeClass(container, scrolledClass);
10584  		}
10585
10586  		this._containerWidth = this._container.offsetWidth;
10587  	},
10588
10589  	_animateZoom: function (e) {
10590  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
10591  		    anchor = this._getAnchor();
10592  		setPosition(this._container, pos.add(anchor));
10593  	},
10594
10595  	_adjustPan: function () {
10596  		if (!this.options.autoPan) { return; }
10597  		if (this._map._panAnim) { this._map._panAnim.stop(); }
10598
10599  		// We can endlessly recurse if keepInView is set and the view resets.
10600  		// Let's guard against that by exiting early if we're responding to our own autopan.
10601  		if (this._autopanning) {
10602  			this._autopanning = false;
10603  			return;
10604  		}
10605
10606  		var map = this._map,
10607  		    marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,
10608  		    containerHeight = this._container.offsetHeight + marginBottom,
10609  		    containerWidth = this._containerWidth,
10610  		    layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);
10611
10612  		layerPos._add(getPosition(this._container));
10613
10614  		var containerPos = map.layerPointToContainerPoint(layerPos),
10615  		    padding = toPoint(this.options.autoPanPadding),
10616  		    paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),
10617  		    paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),
10618  		    size = map.getSize(),
10619  		    dx = 0,
10620  		    dy = 0;
10621
10622  		if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
10623  			dx = containerPos.x + containerWidth - size.x + paddingBR.x;
10624  		}
10625  		if (containerPos.x - dx - paddingTL.x < 0) { // left
10626  			dx = containerPos.x - paddingTL.x;
10627  		}
10628  		if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
10629  			dy = containerPos.y + containerHeight - size.y + paddingBR.y;
10630  		}
10631  		if (containerPos.y - dy - paddingTL.y < 0) { // top
10632  			dy = containerPos.y - paddingTL.y;
10633  		}
10634
10635  		// @namespace Map
10636  		// @section Popup events
10637  		// @event autopanstart: Event
10638  		// Fired when the map starts autopanning when opening a popup.
10639  		if (dx || dy) {
10640  			// Track that we're autopanning, as this function will be re-ran on moveend
10641  			if (this.options.keepInView) {
10642  				this._autopanning = true;
10643  			}
10644
10645  			map
10646  			    .fire('autopanstart')
10647  			    .panBy([dx, dy]);
10648  		}
10649  	},
10650
10651  	_getAnchor: function () {
10652  		// Where should we anchor the popup on the source layer?
10653  		return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
10654  	}
10655
10656  });
10657
10658  // @namespace Popup
10659  // @factory L.popup(options?: Popup options, source?: Layer)
10660  // Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.
10661  // @alternative
10662  // @factory L.popup(latlng: LatLng, options?: Popup options)
10663  // Instantiates a `Popup` object given `latlng` where the popup will open and an optional `options` object that describes its appearance and location.
10664  var popup = function (options, source) {
10665  	return new Popup(options, source);
10666  };
10667
10668
10669  /* @namespace Map
10670   * @section Interaction Options
10671   * @option closePopupOnClick: Boolean = true
10672   * Set it to `false` if you don't want popups to close when user clicks the map.
10673   */
10674  Map.mergeOptions({
10675  	closePopupOnClick: true
10676  });
10677
10678
10679  // @namespace Map
10680  // @section Methods for Layers and Controls
10681  Map.include({
10682  	// @method openPopup(popup: Popup): this
10683  	// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
10684  	// @alternative
10685  	// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
10686  	// Creates a popup with the specified content and options and opens it in the given point on a map.
10687  	openPopup: function (popup, latlng, options) {
10688  		this._initOverlay(Popup, popup, latlng, options)
10689  		  .openOn(this);
10690
10691  		return this;
10692  	},
10693
10694  	// @method closePopup(popup?: Popup): this
10695  	// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
10696  	closePopup: function (popup) {
10697  		popup = arguments.length ? popup : this._popup;
10698  		if (popup) {
10699  			popup.close();
10700  		}
10701  		return this;
10702  	}
10703  });
10704
10705  /*
10706   * @namespace Layer
10707   * @section Popup methods example
10708   *
10709   * All layers share a set of methods convenient for binding popups to it.
10710   *
10711   * ```js
10712   * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
10713   * layer.openPopup();
10714   * layer.closePopup();
10715   * ```
10716   *
10717   * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.
10718   */
10719
10720  // @section Popup methods
10721  Layer.include({
10722
10723  	// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
10724  	// Binds a popup to the layer with the passed `content` and sets up the
10725  	// necessary event listeners. If a `Function` is passed it will receive
10726  	// the layer as the first argument and should return a `String` or `HTMLElement`.
10727  	bindPopup: function (content, options) {
10728  		this._popup = this._initOverlay(Popup, this._popup, content, options);
10729  		if (!this._popupHandlersAdded) {
10730  			this.on({
10731  				click: this._openPopup,
10732  				keypress: this._onKeyPress,
10733  				remove: this.closePopup,
10734  				move: this._movePopup
10735  			});
10736  			this._popupHandlersAdded = true;
10737  		}
10738
10739  		return this;
10740  	},
10741
10742  	// @method unbindPopup(): this
10743  	// Removes the popup previously bound with `bindPopup`.
10744  	unbindPopup: function () {
10745  		if (this._popup) {
10746  			this.off({
10747  				click: this._openPopup,
10748  				keypress: this._onKeyPress,
10749  				remove: this.closePopup,
10750  				move: this._movePopup
10751  			});
10752  			this._popupHandlersAdded = false;
10753  			this._popup = null;
10754  		}
10755  		return this;
10756  	},
10757
10758  	// @method openPopup(latlng?: LatLng): this
10759  	// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.
10760  	openPopup: function (latlng) {
10761  		if (this._popup) {
10762  			if (!(this instanceof FeatureGroup)) {
10763  				this._popup._source = this;
10764  			}
10765  			if (this._popup._prepareOpen(latlng || this._latlng)) {
10766  				// open the popup on the map
10767  				this._popup.openOn(this._map);
10768  			}
10769  		}
10770  		return this;
10771  	},
10772
10773  	// @method closePopup(): this
10774  	// Closes the popup bound to this layer if it is open.
10775  	closePopup: function () {
10776  		if (this._popup) {
10777  			this._popup.close();
10778  		}
10779  		return this;
10780  	},
10781
10782  	// @method togglePopup(): this
10783  	// Opens or closes the popup bound to this layer depending on its current state.
10784  	togglePopup: function () {
10785  		if (this._popup) {
10786  			this._popup.toggle(this);
10787  		}
10788  		return this;
10789  	},
10790
10791  	// @method isPopupOpen(): boolean
10792  	// Returns `true` if the popup bound to this layer is currently open.
10793  	isPopupOpen: function () {
10794  		return (this._popup ? this._popup.isOpen() : false);
10795  	},
10796
10797  	// @method setPopupContent(content: String|HTMLElement|Popup): this
10798  	// Sets the content of the popup bound to this layer.
10799  	setPopupContent: function (content) {
10800  		if (this._popup) {
10801  			this._popup.setContent(content);
10802  		}
10803  		return this;
10804  	},
10805
10806  	// @method getPopup(): Popup
10807  	// Returns the popup bound to this layer.
10808  	getPopup: function () {
10809  		return this._popup;
10810  	},
10811
10812  	_openPopup: function (e) {
10813  		if (!this._popup || !this._map) {
10814  			return;
10815  		}
10816  		// prevent map click
10817  		stop(e);
10818
10819  		var target = e.layer || e.target;
10820  		if (this._popup._source === target && !(target instanceof Path)) {
10821  			// treat it like a marker and figure out
10822  			// if we should toggle it open/closed
10823  			if (this._map.hasLayer(this._popup)) {
10824  				this.closePopup();
10825  			} else {
10826  				this.openPopup(e.latlng);
10827  			}
10828  			return;
10829  		}
10830  		this._popup._source = target;
10831  		this.openPopup(e.latlng);
10832  	},
10833
10834  	_movePopup: function (e) {
10835  		this._popup.setLatLng(e.latlng);
10836  	},
10837
10838  	_onKeyPress: function (e) {
10839  		if (e.originalEvent.keyCode === 13) {
10840  			this._openPopup(e);
10841  		}
10842  	}
10843  });
10844
10845  /*
10846   * @class Tooltip
10847   * @inherits DivOverlay
10848   * @aka L.Tooltip
10849   * Used to display small texts on top of map layers.
10850   *
10851   * @example
10852   * If you want to just bind a tooltip to marker:
10853   *
10854   * ```js
10855   * marker.bindTooltip("my tooltip text").openTooltip();
10856   * ```
10857   * Path overlays like polylines also have a `bindTooltip` method.
10858   *
10859   * A tooltip can be also standalone:
10860   *
10861   * ```js
10862   * var tooltip = L.tooltip()
10863   * 	.setLatLng(latlng)
10864   * 	.setContent('Hello world!<br />This is a nice tooltip.')
10865   * 	.addTo(map);
10866   * ```
10867   * or
10868   * ```js
10869   * var tooltip = L.tooltip(latlng, {content: 'Hello world!<br />This is a nice tooltip.'})
10870   * 	.addTo(map);
10871   * ```
10872   *
10873   *
10874   * Note about tooltip offset. Leaflet takes two options in consideration
10875   * for computing tooltip offsetting:
10876   * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
10877   *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
10878   *   move it to the bottom. Negatives will move to the left and top.
10879   * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
10880   *   should adapt this value if you use a custom icon.
10881   */
10882
10883
10884  // @namespace Tooltip
10885  var Tooltip = DivOverlay.extend({
10886
10887  	// @section
10888  	// @aka Tooltip options
10889  	options: {
10890  		// @option pane: String = 'tooltipPane'
10891  		// `Map pane` where the tooltip will be added.
10892  		pane: 'tooltipPane',
10893
10894  		// @option offset: Point = Point(0, 0)
10895  		// Optional offset of the tooltip position.
10896  		offset: [0, 0],
10897
10898  		// @option direction: String = 'auto'
10899  		// Direction where to open the tooltip. Possible values are: `right`, `left`,
10900  		// `top`, `bottom`, `center`, `auto`.
10901  		// `auto` will dynamically switch between `right` and `left` according to the tooltip
10902  		// position on the map.
10903  		direction: 'auto',
10904
10905  		// @option permanent: Boolean = false
10906  		// Whether to open the tooltip permanently or only on mouseover.
10907  		permanent: false,
10908
10909  		// @option sticky: Boolean = false
10910  		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
10911  		sticky: false,
10912
10913  		// @option opacity: Number = 0.9
10914  		// Tooltip container opacity.
10915  		opacity: 0.9
10916  	},
10917
10918  	onAdd: function (map) {
10919  		DivOverlay.prototype.onAdd.call(this, map);
10920  		this.setOpacity(this.options.opacity);
10921
10922  		// @namespace Map
10923  		// @section Tooltip events
10924  		// @event tooltipopen: TooltipEvent
10925  		// Fired when a tooltip is opened in the map.
10926  		map.fire('tooltipopen', {tooltip: this});
10927
10928  		if (this._source) {
10929  			this.addEventParent(this._source);
10930
10931  			// @namespace Layer
10932  			// @section Tooltip events
10933  			// @event tooltipopen: TooltipEvent
10934  			// Fired when a tooltip bound to this layer is opened.
10935  			this._source.fire('tooltipopen', {tooltip: this}, true);
10936  		}
10937  	},
10938
10939  	onRemove: function (map) {
10940  		DivOverlay.prototype.onRemove.call(this, map);
10941
10942  		// @namespace Map
10943  		// @section Tooltip events
10944  		// @event tooltipclose: TooltipEvent
10945  		// Fired when a tooltip in the map is closed.
10946  		map.fire('tooltipclose', {tooltip: this});
10947
10948  		if (this._source) {
10949  			this.removeEventParent(this._source);
10950
10951  			// @namespace Layer
10952  			// @section Tooltip events
10953  			// @event tooltipclose: TooltipEvent
10954  			// Fired when a tooltip bound to this layer is closed.
10955  			this._source.fire('tooltipclose', {tooltip: this}, true);
10956  		}
10957  	},
10958
10959  	getEvents: function () {
10960  		var events = DivOverlay.prototype.getEvents.call(this);
10961
10962  		if (!this.options.permanent) {
10963  			events.preclick = this.close;
10964  		}
10965
10966  		return events;
10967  	},
10968
10969  	_initLayout: function () {
10970  		var prefix = 'leaflet-tooltip',
10971  		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
10972
10973  		this._contentNode = this._container = create$1('div', className);
10974
10975  		this._container.setAttribute('role', 'tooltip');
10976  		this._container.setAttribute('id', 'leaflet-tooltip-' + stamp(this));
10977  	},
10978
10979  	_updateLayout: function () {},
10980
10981  	_adjustPan: function () {},
10982
10983  	_setPosition: function (pos) {
10984  		var subX, subY,
10985  		    map = this._map,
10986  		    container = this._container,
10987  		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
10988  		    tooltipPoint = map.layerPointToContainerPoint(pos),
10989  		    direction = this.options.direction,
10990  		    tooltipWidth = container.offsetWidth,
10991  		    tooltipHeight = container.offsetHeight,
10992  		    offset = toPoint(this.options.offset),
10993  		    anchor = this._getAnchor();
10994
10995  		if (direction === 'top') {
10996  			subX = tooltipWidth / 2;
10997  			subY = tooltipHeight;
10998  		} else if (direction === 'bottom') {
10999  			subX = tooltipWidth / 2;
11000  			subY = 0;
11001  		} else if (direction === 'center') {
11002  			subX = tooltipWidth / 2;
11003  			subY = tooltipHeight / 2;
11004  		} else if (direction === 'right') {
11005  			subX = 0;
11006  			subY = tooltipHeight / 2;
11007  		} else if (direction === 'left') {
11008  			subX = tooltipWidth;
11009  			subY = tooltipHeight / 2;
11010  		} else if (tooltipPoint.x < centerPoint.x) {
11011  			direction = 'right';
11012  			subX = 0;
11013  			subY = tooltipHeight / 2;
11014  		} else {
11015  			direction = 'left';
11016  			subX = tooltipWidth + (offset.x + anchor.x) * 2;
11017  			subY = tooltipHeight / 2;
11018  		}
11019
11020  		pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);
11021
11022  		removeClass(container, 'leaflet-tooltip-right');
11023  		removeClass(container, 'leaflet-tooltip-left');
11024  		removeClass(container, 'leaflet-tooltip-top');
11025  		removeClass(container, 'leaflet-tooltip-bottom');
11026  		addClass(container, 'leaflet-tooltip-' + direction);
11027  		setPosition(container, pos);
11028  	},
11029
11030  	_updatePosition: function () {
11031  		var pos = this._map.latLngToLayerPoint(this._latlng);
11032  		this._setPosition(pos);
11033  	},
11034
11035  	setOpacity: function (opacity) {
11036  		this.options.opacity = opacity;
11037
11038  		if (this._container) {
11039  			setOpacity(this._container, opacity);
11040  		}
11041  	},
11042
11043  	_animateZoom: function (e) {
11044  		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
11045  		this._setPosition(pos);
11046  	},
11047
11048  	_getAnchor: function () {
11049  		// Where should we anchor the tooltip on the source layer?
11050  		return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
11051  	}
11052
11053  });
11054
11055  // @namespace Tooltip
11056  // @factory L.tooltip(options?: Tooltip options, source?: Layer)
11057  // Instantiates a `Tooltip` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
11058  // @alternative
11059  // @factory L.tooltip(latlng: LatLng, options?: Tooltip options)
11060  // Instantiates a `Tooltip` object given `latlng` where the tooltip will open and an optional `options` object that describes its appearance and location.
11061  var tooltip = function (options, source) {
11062  	return new Tooltip(options, source);
11063  };
11064
11065  // @namespace Map
11066  // @section Methods for Layers and Controls
11067  Map.include({
11068
11069  	// @method openTooltip(tooltip: Tooltip): this
11070  	// Opens the specified tooltip.
11071  	// @alternative
11072  	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
11073  	// Creates a tooltip with the specified content and options and open it.
11074  	openTooltip: function (tooltip, latlng, options) {
11075  		this._initOverlay(Tooltip, tooltip, latlng, options)
11076  		  .openOn(this);
11077
11078  		return this;
11079  	},
11080
11081  	// @method closeTooltip(tooltip: Tooltip): this
11082  	// Closes the tooltip given as parameter.
11083  	closeTooltip: function (tooltip) {
11084  		tooltip.close();
11085  		return this;
11086  	}
11087
11088  });
11089
11090  /*
11091   * @namespace Layer
11092   * @section Tooltip methods example
11093   *
11094   * All layers share a set of methods convenient for binding tooltips to it.
11095   *
11096   * ```js
11097   * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
11098   * layer.openTooltip();
11099   * layer.closeTooltip();
11100   * ```
11101   */
11102
11103  // @section Tooltip methods
11104  Layer.include({
11105
11106  	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
11107  	// Binds a tooltip to the layer with the passed `content` and sets up the
11108  	// necessary event listeners. If a `Function` is passed it will receive
11109  	// the layer as the first argument and should return a `String` or `HTMLElement`.
11110  	bindTooltip: function (content, options) {
11111
11112  		if (this._tooltip && this.isTooltipOpen()) {
11113  			this.unbindTooltip();
11114  		}
11115
11116  		this._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options);
11117  		this._initTooltipInteractions();
11118
11119  		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
11120  			this.openTooltip();
11121  		}
11122
11123  		return this;
11124  	},
11125
11126  	// @method unbindTooltip(): this
11127  	// Removes the tooltip previously bound with `bindTooltip`.
11128  	unbindTooltip: function () {
11129  		if (this._tooltip) {
11130  			this._initTooltipInteractions(true);
11131  			this.closeTooltip();
11132  			this._tooltip = null;
11133  		}
11134  		return this;
11135  	},
11136
11137  	_initTooltipInteractions: function (remove) {
11138  		if (!remove && this._tooltipHandlersAdded) { return; }
11139  		var onOff = remove ? 'off' : 'on',
11140  		    events = {
11141  			remove: this.closeTooltip,
11142  			move: this._moveTooltip
11143  		    };
11144  		if (!this._tooltip.options.permanent) {
11145  			events.mouseover = this._openTooltip;
11146  			events.mouseout = this.closeTooltip;
11147  			events.click = this._openTooltip;
11148  			if (this._map) {
11149  				this._addFocusListeners();
11150  			} else {
11151  				events.add = this._addFocusListeners;
11152  			}
11153  		} else {
11154  			events.add = this._openTooltip;
11155  		}
11156  		if (this._tooltip.options.sticky) {
11157  			events.mousemove = this._moveTooltip;
11158  		}
11159  		this[onOff](events);
11160  		this._tooltipHandlersAdded = !remove;
11161  	},
11162
11163  	// @method openTooltip(latlng?: LatLng): this
11164  	// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
11165  	openTooltip: function (latlng) {
11166  		if (this._tooltip) {
11167  			if (!(this instanceof FeatureGroup)) {
11168  				this._tooltip._source = this;
11169  			}
11170  			if (this._tooltip._prepareOpen(latlng)) {
11171  				// open the tooltip on the map
11172  				this._tooltip.openOn(this._map);
11173
11174  				if (this.getElement) {
11175  					this._setAriaDescribedByOnLayer(this);
11176  				} else if (this.eachLayer) {
11177  					this.eachLayer(this._setAriaDescribedByOnLayer, this);
11178  				}
11179  			}
11180  		}
11181  		return this;
11182  	},
11183
11184  	// @method closeTooltip(): this
11185  	// Closes the tooltip bound to this layer if it is open.
11186  	closeTooltip: function () {
11187  		if (this._tooltip) {
11188  			return this._tooltip.close();
11189  		}
11190  	},
11191
11192  	// @method toggleTooltip(): this
11193  	// Opens or closes the tooltip bound to this layer depending on its current state.
11194  	toggleTooltip: function () {
11195  		if (this._tooltip) {
11196  			this._tooltip.toggle(this);
11197  		}
11198  		return this;
11199  	},
11200
11201  	// @method isTooltipOpen(): boolean
11202  	// Returns `true` if the tooltip bound to this layer is currently open.
11203  	isTooltipOpen: function () {
11204  		return this._tooltip.isOpen();
11205  	},
11206
11207  	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
11208  	// Sets the content of the tooltip bound to this layer.
11209  	setTooltipContent: function (content) {
11210  		if (this._tooltip) {
11211  			this._tooltip.setContent(content);
11212  		}
11213  		return this;
11214  	},
11215
11216  	// @method getTooltip(): Tooltip
11217  	// Returns the tooltip bound to this layer.
11218  	getTooltip: function () {
11219  		return this._tooltip;
11220  	},
11221
11222  	_addFocusListeners: function () {
11223  		if (this.getElement) {
11224  			this._addFocusListenersOnLayer(this);
11225  		} else if (this.eachLayer) {
11226  			this.eachLayer(this._addFocusListenersOnLayer, this);
11227  		}
11228  	},
11229
11230  	_addFocusListenersOnLayer: function (layer) {
11231  		var el = typeof layer.getElement === 'function' && layer.getElement();
11232  		if (el) {
11233  			on(el, 'focus', function () {
11234  				this._tooltip._source = layer;
11235  				this.openTooltip();
11236  			}, this);
11237  			on(el, 'blur', this.closeTooltip, this);
11238  		}
11239  	},
11240
11241  	_setAriaDescribedByOnLayer: function (layer) {
11242  		var el = typeof layer.getElement === 'function' && layer.getElement();
11243  		if (el) {
11244  			el.setAttribute('aria-describedby', this._tooltip._container.id);
11245  		}
11246  	},
11247
11248
11249  	_openTooltip: function (e) {
11250  		if (!this._tooltip || !this._map) {
11251  			return;
11252  		}
11253
11254  		// If the map is moving, we will show the tooltip after it's done.
11255  		if (this._map.dragging && this._map.dragging.moving() && !this._openOnceFlag) {
11256  			this._openOnceFlag = true;
11257  			var that = this;
11258  			this._map.once('moveend', function () {
11259  				that._openOnceFlag = false;
11260  				that._openTooltip(e);
11261  			});
11262  			return;
11263  		}
11264
11265  		this._tooltip._source = e.layer || e.target;
11266
11267  		this.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined);
11268  	},
11269
11270  	_moveTooltip: function (e) {
11271  		var latlng = e.latlng, containerPoint, layerPoint;
11272  		if (this._tooltip.options.sticky && e.originalEvent) {
11273  			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
11274  			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
11275  			latlng = this._map.layerPointToLatLng(layerPoint);
11276  		}
11277  		this._tooltip.setLatLng(latlng);
11278  	}
11279  });
11280
11281  /*
11282   * @class DivIcon
11283   * @aka L.DivIcon
11284   * @inherits Icon
11285   *
11286   * Represents a lightweight icon for markers that uses a simple `<div>`
11287   * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
11288   *
11289   * @example
11290   * ```js
11291   * var myIcon = L.divIcon({className: 'my-div-icon'});
11292   * // you can set .my-div-icon styles in CSS
11293   *
11294   * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
11295   * ```
11296   *
11297   * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
11298   */
11299
11300  var DivIcon = Icon.extend({
11301  	options: {
11302  		// @section
11303  		// @aka DivIcon options
11304  		iconSize: [12, 12], // also can be set through CSS
11305
11306  		// iconAnchor: (Point),
11307  		// popupAnchor: (Point),
11308
11309  		// @option html: String|HTMLElement = ''
11310  		// Custom HTML code to put inside the div element, empty by default. Alternatively,
11311  		// an instance of `HTMLElement`.
11312  		html: false,
11313
11314  		// @option bgPos: Point = [0, 0]
11315  		// Optional relative position of the background, in pixels
11316  		bgPos: null,
11317
11318  		className: 'leaflet-div-icon'
11319  	},
11320
11321  	createIcon: function (oldIcon) {
11322  		var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
11323  		    options = this.options;
11324
11325  		if (options.html instanceof Element) {
11326  			empty(div);
11327  			div.appendChild(options.html);
11328  		} else {
11329  			div.innerHTML = options.html !== false ? options.html : '';
11330  		}
11331
11332  		if (options.bgPos) {
11333  			var bgPos = toPoint(options.bgPos);
11334  			div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
11335  		}
11336  		this._setIconStyles(div, 'icon');
11337
11338  		return div;
11339  	},
11340
11341  	createShadow: function () {
11342  		return null;
11343  	}
11344  });
11345
11346  // @factory L.divIcon(options: DivIcon options)
11347  // Creates a `DivIcon` instance with the given options.
11348  function divIcon(options) {
11349  	return new DivIcon(options);
11350  }
11351
11352  Icon.Default = IconDefault;
11353
11354  /*
11355   * @class GridLayer
11356   * @inherits Layer
11357   * @aka L.GridLayer
11358   *
11359   * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
11360   * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.
11361   *
11362   *
11363   * @section Synchronous usage
11364   * @example
11365   *
11366   * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.
11367   *
11368   * ```js
11369   * var CanvasLayer = L.GridLayer.extend({
11370   *     createTile: function(coords){
11371   *         // create a <canvas> element for drawing
11372   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
11373   *
11374   *         // setup tile width and height according to the options
11375   *         var size = this.getTileSize();
11376   *         tile.width = size.x;
11377   *         tile.height = size.y;
11378   *
11379   *         // get a canvas context and draw something on it using coords.x, coords.y and coords.z
11380   *         var ctx = tile.getContext('2d');
11381   *
11382   *         // return the tile so it can be rendered on screen
11383   *         return tile;
11384   *     }
11385   * });
11386   * ```
11387   *
11388   * @section Asynchronous usage
11389   * @example
11390   *
11391   * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.
11392   *
11393   * ```js
11394   * var CanvasLayer = L.GridLayer.extend({
11395   *     createTile: function(coords, done){
11396   *         var error;
11397   *
11398   *         // create a <canvas> element for drawing
11399   *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
11400   *
11401   *         // setup tile width and height according to the options
11402   *         var size = this.getTileSize();
11403   *         tile.width = size.x;
11404   *         tile.height = size.y;
11405   *
11406   *         // draw something asynchronously and pass the tile to the done() callback
11407   *         setTimeout(function() {
11408   *             done(error, tile);
11409   *         }, 1000);
11410   *
11411   *         return tile;
11412   *     }
11413   * });
11414   * ```
11415   *
11416   * @section
11417   */
11418
11419
11420  var GridLayer = Layer.extend({
11421
11422  	// @section
11423  	// @aka GridLayer options
11424  	options: {
11425  		// @option tileSize: Number|Point = 256
11426  		// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
11427  		tileSize: 256,
11428
11429  		// @option opacity: Number = 1.0
11430  		// Opacity of the tiles. Can be used in the `createTile()` function.
11431  		opacity: 1,
11432
11433  		// @option updateWhenIdle: Boolean = (depends)
11434  		// Load new tiles only when panning ends.
11435  		// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.
11436  		// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the
11437  		// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.
11438  		updateWhenIdle: Browser.mobile,
11439
11440  		// @option updateWhenZooming: Boolean = true
11441  		// By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.
11442  		updateWhenZooming: true,
11443
11444  		// @option updateInterval: Number = 200
11445  		// Tiles will not update more than once every `updateInterval` milliseconds when panning.
11446  		updateInterval: 200,
11447
11448  		// @option zIndex: Number = 1
11449  		// The explicit zIndex of the tile layer.
11450  		zIndex: 1,
11451
11452  		// @option bounds: LatLngBounds = undefined
11453  		// If set, tiles will only be loaded inside the set `LatLngBounds`.
11454  		bounds: null,
11455
11456  		// @option minZoom: Number = 0
11457  		// The minimum zoom level down to which this layer will be displayed (inclusive).
11458  		minZoom: 0,
11459
11460  		// @option maxZoom: Number = undefined
11461  		// The maximum zoom level up to which this layer will be displayed (inclusive).
11462  		maxZoom: undefined,
11463
11464  		// @option maxNativeZoom: Number = undefined
11465  		// Maximum zoom number the tile source has available. If it is specified,
11466  		// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
11467  		// from `maxNativeZoom` level and auto-scaled.
11468  		maxNativeZoom: undefined,
11469
11470  		// @option minNativeZoom: Number = undefined
11471  		// Minimum zoom number the tile source has available. If it is specified,
11472  		// the tiles on all zoom levels lower than `minNativeZoom` will be loaded
11473  		// from `minNativeZoom` level and auto-scaled.
11474  		minNativeZoom: undefined,
11475
11476  		// @option noWrap: Boolean = false
11477  		// Whether the layer is wrapped around the antimeridian. If `true`, the
11478  		// GridLayer will only be displayed once at low zoom levels. Has no
11479  		// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
11480  		// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
11481  		// tiles outside the CRS limits.
11482  		noWrap: false,
11483
11484  		// @option pane: String = 'tilePane'
11485  		// `Map pane` where the grid layer will be added.
11486  		pane: 'tilePane',
11487
11488  		// @option className: String = ''
11489  		// A custom class name to assign to the tile layer. Empty by default.
11490  		className: '',
11491
11492  		// @option keepBuffer: Number = 2
11493  		// When panning the map, keep this many rows and columns of tiles before unloading them.
11494  		keepBuffer: 2
11495  	},
11496
11497  	initialize: function (options) {
11498  		setOptions(this, options);
11499  	},
11500
11501  	onAdd: function () {
11502  		this._initContainer();
11503
11504  		this._levels = {};
11505  		this._tiles = {};
11506
11507  		this._resetView(); // implicit _update() call
11508  	},
11509
11510  	beforeAdd: function (map) {
11511  		map._addZoomLimit(this);
11512  	},
11513
11514  	onRemove: function (map) {
11515  		this._removeAllTiles();
11516  		remove(this._container);
11517  		map._removeZoomLimit(this);
11518  		this._container = null;
11519  		this._tileZoom = undefined;
11520  	},
11521
11522  	// @method bringToFront: this
11523  	// Brings the tile layer to the top of all tile layers.
11524  	bringToFront: function () {
11525  		if (this._map) {
11526  			toFront(this._container);
11527  			this._setAutoZIndex(Math.max);
11528  		}
11529  		return this;
11530  	},
11531
11532  	// @method bringToBack: this
11533  	// Brings the tile layer to the bottom of all tile layers.
11534  	bringToBack: function () {
11535  		if (this._map) {
11536  			toBack(this._container);
11537  			this._setAutoZIndex(Math.min);
11538  		}
11539  		return this;
11540  	},
11541
11542  	// @method getContainer: HTMLElement
11543  	// Returns the HTML element that contains the tiles for this layer.
11544  	getContainer: function () {
11545  		return this._container;
11546  	},
11547
11548  	// @method setOpacity(opacity: Number): this
11549  	// Changes the [opacity](#gridlayer-opacity) of the grid layer.
11550  	setOpacity: function (opacity) {
11551  		this.options.opacity = opacity;
11552  		this._updateOpacity();
11553  		return this;
11554  	},
11555
11556  	// @method setZIndex(zIndex: Number): this
11557  	// Changes the [zIndex](#gridlayer-zindex) of the grid layer.
11558  	setZIndex: function (zIndex) {
11559  		this.options.zIndex = zIndex;
11560  		this._updateZIndex();
11561
11562  		return this;
11563  	},
11564
11565  	// @method isLoading: Boolean
11566  	// Returns `true` if any tile in the grid layer has not finished loading.
11567  	isLoading: function () {
11568  		return this._loading;
11569  	},
11570
11571  	// @method redraw: this
11572  	// Causes the layer to clear all the tiles and request them again.
11573  	redraw: function () {
11574  		if (this._map) {
11575  			this._removeAllTiles();
11576  			var tileZoom = this._clampZoom(this._map.getZoom());
11577  			if (tileZoom !== this._tileZoom) {
11578  				this._tileZoom = tileZoom;
11579  				this._updateLevels();
11580  			}
11581  			this._update();
11582  		}
11583  		return this;
11584  	},
11585
11586  	getEvents: function () {
11587  		var events = {
11588  			viewprereset: this._invalidateAll,
11589  			viewreset: this._resetView,
11590  			zoom: this._resetView,
11591  			moveend: this._onMoveEnd
11592  		};
11593
11594  		if (!this.options.updateWhenIdle) {
11595  			// update tiles on move, but not more often than once per given interval
11596  			if (!this._onMove) {
11597  				this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);
11598  			}
11599
11600  			events.move = this._onMove;
11601  		}
11602
11603  		if (this._zoomAnimated) {
11604  			events.zoomanim = this._animateZoom;
11605  		}
11606
11607  		return events;
11608  	},
11609
11610  	// @section Extension methods
11611  	// Layers extending `GridLayer` shall reimplement the following method.
11612  	// @method createTile(coords: Object, done?: Function): HTMLElement
11613  	// Called only internally, must be overridden by classes extending `GridLayer`.
11614  	// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
11615  	// is specified, it must be called when the tile has finished loading and drawing.
11616  	createTile: function () {
11617  		return document.createElement('div');
11618  	},
11619
11620  	// @section
11621  	// @method getTileSize: Point
11622  	// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
11623  	getTileSize: function () {
11624  		var s = this.options.tileSize;
11625  		return s instanceof Point ? s : new Point(s, s);
11626  	},
11627
11628  	_updateZIndex: function () {
11629  		if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
11630  			this._container.style.zIndex = this.options.zIndex;
11631  		}
11632  	},
11633
11634  	_setAutoZIndex: function (compare) {
11635  		// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
11636
11637  		var layers = this.getPane().children,
11638  		    edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
11639
11640  		for (var i = 0, len = layers.length, zIndex; i < len; i++) {
11641
11642  			zIndex = layers[i].style.zIndex;
11643
11644  			if (layers[i] !== this._container && zIndex) {
11645  				edgeZIndex = compare(edgeZIndex, +zIndex);
11646  			}
11647  		}
11648
11649  		if (isFinite(edgeZIndex)) {
11650  			this.options.zIndex = edgeZIndex + compare(-1, 1);
11651  			this._updateZIndex();
11652  		}
11653  	},
11654
11655  	_updateOpacity: function () {
11656  		if (!this._map) { return; }
11657
11658  		// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
11659  		if (Browser.ielt9) { return; }
11660
11661  		setOpacity(this._container, this.options.opacity);
11662
11663  		var now = +new Date(),
11664  		    nextFrame = false,
11665  		    willPrune = false;
11666
11667  		for (var key in this._tiles) {
11668  			var tile = this._tiles[key];
11669  			if (!tile.current || !tile.loaded) { continue; }
11670
11671  			var fade = Math.min(1, (now - tile.loaded) / 200);
11672
11673  			setOpacity(tile.el, fade);
11674  			if (fade < 1) {
11675  				nextFrame = true;
11676  			} else {
11677  				if (tile.active) {
11678  					willPrune = true;
11679  				} else {
11680  					this._onOpaqueTile(tile);
11681  				}
11682  				tile.active = true;
11683  			}
11684  		}
11685
11686  		if (willPrune && !this._noPrune) { this._pruneTiles(); }
11687
11688  		if (nextFrame) {
11689  			cancelAnimFrame(this._fadeFrame);
11690  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
11691  		}
11692  	},
11693
11694  	_onOpaqueTile: falseFn,
11695
11696  	_initContainer: function () {
11697  		if (this._container) { return; }
11698
11699  		this._container = create$1('div', 'leaflet-layer ' + (this.options.className || ''));
11700  		this._updateZIndex();
11701
11702  		if (this.options.opacity < 1) {
11703  			this._updateOpacity();
11704  		}
11705
11706  		this.getPane().appendChild(this._container);
11707  	},
11708
11709  	_updateLevels: function () {
11710
11711  		var zoom = this._tileZoom,
11712  		    maxZoom = this.options.maxZoom;
11713
11714  		if (zoom === undefined) { return undefined; }
11715
11716  		for (var z in this._levels) {
11717  			z = Number(z);
11718  			if (this._levels[z].el.children.length || z === zoom) {
11719  				this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
11720  				this._onUpdateLevel(z);
11721  			} else {
11722  				remove(this._levels[z].el);
11723  				this._removeTilesAtZoom(z);
11724  				this._onRemoveLevel(z);
11725  				delete this._levels[z];
11726  			}
11727  		}
11728
11729  		var level = this._levels[zoom],
11730  		    map = this._map;
11731
11732  		if (!level) {
11733  			level = this._levels[zoom] = {};
11734
11735  			level.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
11736  			level.el.style.zIndex = maxZoom;
11737
11738  			level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
11739  			level.zoom = zoom;
11740
11741  			this._setZoomTransform(level, map.getCenter(), map.getZoom());
11742
11743  			// force the browser to consider the newly added element for transition
11744  			falseFn(level.el.offsetWidth);
11745
11746  			this._onCreateLevel(level);
11747  		}
11748
11749  		this._level = level;
11750
11751  		return level;
11752  	},
11753
11754  	_onUpdateLevel: falseFn,
11755
11756  	_onRemoveLevel: falseFn,
11757
11758  	_onCreateLevel: falseFn,
11759
11760  	_pruneTiles: function () {
11761  		if (!this._map) {
11762  			return;
11763  		}
11764
11765  		var key, tile;
11766
11767  		var zoom = this._map.getZoom();
11768  		if (zoom > this.options.maxZoom ||
11769  			zoom < this.options.minZoom) {
11770  			this._removeAllTiles();
11771  			return;
11772  		}
11773
11774  		for (key in this._tiles) {
11775  			tile = this._tiles[key];
11776  			tile.retain = tile.current;
11777  		}
11778
11779  		for (key in this._tiles) {
11780  			tile = this._tiles[key];
11781  			if (tile.current && !tile.active) {
11782  				var coords = tile.coords;
11783  				if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
11784  					this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
11785  				}
11786  			}
11787  		}
11788
11789  		for (key in this._tiles) {
11790  			if (!this._tiles[key].retain) {
11791  				this._removeTile(key);
11792  			}
11793  		}
11794  	},
11795
11796  	_removeTilesAtZoom: function (zoom) {
11797  		for (var key in this._tiles) {
11798  			if (this._tiles[key].coords.z !== zoom) {
11799  				continue;
11800  			}
11801  			this._removeTile(key);
11802  		}
11803  	},
11804
11805  	_removeAllTiles: function () {
11806  		for (var key in this._tiles) {
11807  			this._removeTile(key);
11808  		}
11809  	},
11810
11811  	_invalidateAll: function () {
11812  		for (var z in this._levels) {
11813  			remove(this._levels[z].el);
11814  			this._onRemoveLevel(Number(z));
11815  			delete this._levels[z];
11816  		}
11817  		this._removeAllTiles();
11818
11819  		this._tileZoom = undefined;
11820  	},
11821
11822  	_retainParent: function (x, y, z, minZoom) {
11823  		var x2 = Math.floor(x / 2),
11824  		    y2 = Math.floor(y / 2),
11825  		    z2 = z - 1,
11826  		    coords2 = new Point(+x2, +y2);
11827  		coords2.z = +z2;
11828
11829  		var key = this._tileCoordsToKey(coords2),
11830  		    tile = this._tiles[key];
11831
11832  		if (tile && tile.active) {
11833  			tile.retain = true;
11834  			return true;
11835
11836  		} else if (tile && tile.loaded) {
11837  			tile.retain = true;
11838  		}
11839
11840  		if (z2 > minZoom) {
11841  			return this._retainParent(x2, y2, z2, minZoom);
11842  		}
11843
11844  		return false;
11845  	},
11846
11847  	_retainChildren: function (x, y, z, maxZoom) {
11848
11849  		for (var i = 2 * x; i < 2 * x + 2; i++) {
11850  			for (var j = 2 * y; j < 2 * y + 2; j++) {
11851
11852  				var coords = new Point(i, j);
11853  				coords.z = z + 1;
11854
11855  				var key = this._tileCoordsToKey(coords),
11856  				    tile = this._tiles[key];
11857
11858  				if (tile && tile.active) {
11859  					tile.retain = true;
11860  					continue;
11861
11862  				} else if (tile && tile.loaded) {
11863  					tile.retain = true;
11864  				}
11865
11866  				if (z + 1 < maxZoom) {
11867  					this._retainChildren(i, j, z + 1, maxZoom);
11868  				}
11869  			}
11870  		}
11871  	},
11872
11873  	_resetView: function (e) {
11874  		var animating = e && (e.pinch || e.flyTo);
11875  		this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
11876  	},
11877
11878  	_animateZoom: function (e) {
11879  		this._setView(e.center, e.zoom, true, e.noUpdate);
11880  	},
11881
11882  	_clampZoom: function (zoom) {
11883  		var options = this.options;
11884
11885  		if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {
11886  			return options.minNativeZoom;
11887  		}
11888
11889  		if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {
11890  			return options.maxNativeZoom;
11891  		}
11892
11893  		return zoom;
11894  	},
11895
11896  	_setView: function (center, zoom, noPrune, noUpdate) {
11897  		var tileZoom = Math.round(zoom);
11898  		if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
11899  		    (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
11900  			tileZoom = undefined;
11901  		} else {
11902  			tileZoom = this._clampZoom(tileZoom);
11903  		}
11904
11905  		var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
11906
11907  		if (!noUpdate || tileZoomChanged) {
11908
11909  			this._tileZoom = tileZoom;
11910
11911  			if (this._abortLoading) {
11912  				this._abortLoading();
11913  			}
11914
11915  			this._updateLevels();
11916  			this._resetGrid();
11917
11918  			if (tileZoom !== undefined) {
11919  				this._update(center);
11920  			}
11921
11922  			if (!noPrune) {
11923  				this._pruneTiles();
11924  			}
11925
11926  			// Flag to prevent _updateOpacity from pruning tiles during
11927  			// a zoom anim or a pinch gesture
11928  			this._noPrune = !!noPrune;
11929  		}
11930
11931  		this._setZoomTransforms(center, zoom);
11932  	},
11933
11934  	_setZoomTransforms: function (center, zoom) {
11935  		for (var i in this._levels) {
11936  			this._setZoomTransform(this._levels[i], center, zoom);
11937  		}
11938  	},
11939
11940  	_setZoomTransform: function (level, center, zoom) {
11941  		var scale = this._map.getZoomScale(zoom, level.zoom),
11942  		    translate = level.origin.multiplyBy(scale)
11943  		        .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
11944
11945  		if (Browser.any3d) {
11946  			setTransform(level.el, translate, scale);
11947  		} else {
11948  			setPosition(level.el, translate);
11949  		}
11950  	},
11951
11952  	_resetGrid: function () {
11953  		var map = this._map,
11954  		    crs = map.options.crs,
11955  		    tileSize = this._tileSize = this.getTileSize(),
11956  		    tileZoom = this._tileZoom;
11957
11958  		var bounds = this._map.getPixelWorldBounds(this._tileZoom);
11959  		if (bounds) {
11960  			this._globalTileRange = this._pxBoundsToTileRange(bounds);
11961  		}
11962
11963  		this._wrapX = crs.wrapLng && !this.options.noWrap && [
11964  			Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
11965  			Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
11966  		];
11967  		this._wrapY = crs.wrapLat && !this.options.noWrap && [
11968  			Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
11969  			Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
11970  		];
11971  	},
11972
11973  	_onMoveEnd: function () {
11974  		if (!this._map || this._map._animatingZoom) { return; }
11975
11976  		this._update();
11977  	},
11978
11979  	_getTiledPixelBounds: function (center) {
11980  		var map = this._map,
11981  		    mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
11982  		    scale = map.getZoomScale(mapZoom, this._tileZoom),
11983  		    pixelCenter = map.project(center, this._tileZoom).floor(),
11984  		    halfSize = map.getSize().divideBy(scale * 2);
11985
11986  		return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
11987  	},
11988
11989  	// Private method to load tiles in the grid's active zoom level according to map bounds
11990  	_update: function (center) {
11991  		var map = this._map;
11992  		if (!map) { return; }
11993  		var zoom = this._clampZoom(map.getZoom());
11994
11995  		if (center === undefined) { center = map.getCenter(); }
11996  		if (this._tileZoom === undefined) { return; }	// if out of minzoom/maxzoom
11997
11998  		var pixelBounds = this._getTiledPixelBounds(center),
11999  		    tileRange = this._pxBoundsToTileRange(pixelBounds),
12000  		    tileCenter = tileRange.getCenter(),
12001  		    queue = [],
12002  		    margin = this.options.keepBuffer,
12003  		    noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
12004  		                              tileRange.getTopRight().add([margin, -margin]));
12005
12006  		// Sanity check: panic if the tile range contains Infinity somewhere.
12007  		if (!(isFinite(tileRange.min.x) &&
12008  		      isFinite(tileRange.min.y) &&
12009  		      isFinite(tileRange.max.x) &&
12010  		      isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }
12011
12012  		for (var key in this._tiles) {
12013  			var c = this._tiles[key].coords;
12014  			if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {
12015  				this._tiles[key].current = false;
12016  			}
12017  		}
12018
12019  		// _update just loads more tiles. If the tile zoom level differs too much
12020  		// from the map's, let _setView reset levels and prune old tiles.
12021  		if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
12022
12023  		// create a queue of coordinates to load tiles from
12024  		for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
12025  			for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
12026  				var coords = new Point(i, j);
12027  				coords.z = this._tileZoom;
12028
12029  				if (!this._isValidTile(coords)) { continue; }
12030
12031  				var tile = this._tiles[this._tileCoordsToKey(coords)];
12032  				if (tile) {
12033  					tile.current = true;
12034  				} else {
12035  					queue.push(coords);
12036  				}
12037  			}
12038  		}
12039
12040  		// sort tile queue to load tiles in order of their distance to center
12041  		queue.sort(function (a, b) {
12042  			return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
12043  		});
12044
12045  		if (queue.length !== 0) {
12046  			// if it's the first batch of tiles to load
12047  			if (!this._loading) {
12048  				this._loading = true;
12049  				// @event loading: Event
12050  				// Fired when the grid layer starts loading tiles.
12051  				this.fire('loading');
12052  			}
12053
12054  			// create DOM fragment to append tiles in one batch
12055  			var fragment = document.createDocumentFragment();
12056
12057  			for (i = 0; i < queue.length; i++) {
12058  				this._addTile(queue[i], fragment);
12059  			}
12060
12061  			this._level.el.appendChild(fragment);
12062  		}
12063  	},
12064
12065  	_isValidTile: function (coords) {
12066  		var crs = this._map.options.crs;
12067
12068  		if (!crs.infinite) {
12069  			// don't load tile if it's out of bounds and not wrapped
12070  			var bounds = this._globalTileRange;
12071  			if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
12072  			    (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
12073  		}
12074
12075  		if (!this.options.bounds) { return true; }
12076
12077  		// don't load tile if it doesn't intersect the bounds in options
12078  		var tileBounds = this._tileCoordsToBounds(coords);
12079  		return toLatLngBounds(this.options.bounds).overlaps(tileBounds);
12080  	},
12081
12082  	_keyToBounds: function (key) {
12083  		return this._tileCoordsToBounds(this._keyToTileCoords(key));
12084  	},
12085
12086  	_tileCoordsToNwSe: function (coords) {
12087  		var map = this._map,
12088  		    tileSize = this.getTileSize(),
12089  		    nwPoint = coords.scaleBy(tileSize),
12090  		    sePoint = nwPoint.add(tileSize),
12091  		    nw = map.unproject(nwPoint, coords.z),
12092  		    se = map.unproject(sePoint, coords.z);
12093  		return [nw, se];
12094  	},
12095
12096  	// converts tile coordinates to its geographical bounds
12097  	_tileCoordsToBounds: function (coords) {
12098  		var bp = this._tileCoordsToNwSe(coords),
12099  		    bounds = new LatLngBounds(bp[0], bp[1]);
12100
12101  		if (!this.options.noWrap) {
12102  			bounds = this._map.wrapLatLngBounds(bounds);
12103  		}
12104  		return bounds;
12105  	},
12106  	// converts tile coordinates to key for the tile cache
12107  	_tileCoordsToKey: function (coords) {
12108  		return coords.x + ':' + coords.y + ':' + coords.z;
12109  	},
12110
12111  	// converts tile cache key to coordinates
12112  	_keyToTileCoords: function (key) {
12113  		var k = key.split(':'),
12114  		    coords = new Point(+k[0], +k[1]);
12115  		coords.z = +k[2];
12116  		return coords;
12117  	},
12118
12119  	_removeTile: function (key) {
12120  		var tile = this._tiles[key];
12121  		if (!tile) { return; }
12122
12123  		remove(tile.el);
12124
12125  		delete this._tiles[key];
12126
12127  		// @event tileunload: TileEvent
12128  		// Fired when a tile is removed (e.g. when a tile goes off the screen).
12129  		this.fire('tileunload', {
12130  			tile: tile.el,
12131  			coords: this._keyToTileCoords(key)
12132  		});
12133  	},
12134
12135  	_initTile: function (tile) {
12136  		addClass(tile, 'leaflet-tile');
12137
12138  		var tileSize = this.getTileSize();
12139  		tile.style.width = tileSize.x + 'px';
12140  		tile.style.height = tileSize.y + 'px';
12141
12142  		tile.onselectstart = falseFn;
12143  		tile.onmousemove = falseFn;
12144
12145  		// update opacity on tiles in IE7-8 because of filter inheritance problems
12146  		if (Browser.ielt9 && this.options.opacity < 1) {
12147  			setOpacity(tile, this.options.opacity);
12148  		}
12149  	},
12150
12151  	_addTile: function (coords, container) {
12152  		var tilePos = this._getTilePos(coords),
12153  		    key = this._tileCoordsToKey(coords);
12154
12155  		var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));
12156
12157  		this._initTile(tile);
12158
12159  		// if createTile is defined with a second argument ("done" callback),
12160  		// we know that tile is async and will be ready later; otherwise
12161  		if (this.createTile.length < 2) {
12162  			// mark tile as ready, but delay one frame for opacity animation to happen
12163  			requestAnimFrame(bind(this._tileReady, this, coords, null, tile));
12164  		}
12165
12166  		setPosition(tile, tilePos);
12167
12168  		// save tile in cache
12169  		this._tiles[key] = {
12170  			el: tile,
12171  			coords: coords,
12172  			current: true
12173  		};
12174
12175  		container.appendChild(tile);
12176  		// @event tileloadstart: TileEvent
12177  		// Fired when a tile is requested and starts loading.
12178  		this.fire('tileloadstart', {
12179  			tile: tile,
12180  			coords: coords
12181  		});
12182  	},
12183
12184  	_tileReady: function (coords, err, tile) {
12185  		if (err) {
12186  			// @event tileerror: TileErrorEvent
12187  			// Fired when there is an error loading a tile.
12188  			this.fire('tileerror', {
12189  				error: err,
12190  				tile: tile,
12191  				coords: coords
12192  			});
12193  		}
12194
12195  		var key = this._tileCoordsToKey(coords);
12196
12197  		tile = this._tiles[key];
12198  		if (!tile) { return; }
12199
12200  		tile.loaded = +new Date();
12201  		if (this._map._fadeAnimated) {
12202  			setOpacity(tile.el, 0);
12203  			cancelAnimFrame(this._fadeFrame);
12204  			this._fadeFrame = requestAnimFrame(this._updateOpacity, this);
12205  		} else {
12206  			tile.active = true;
12207  			this._pruneTiles();
12208  		}
12209
12210  		if (!err) {
12211  			addClass(tile.el, 'leaflet-tile-loaded');
12212
12213  			// @event tileload: TileEvent
12214  			// Fired when a tile loads.
12215  			this.fire('tileload', {
12216  				tile: tile.el,
12217  				coords: coords
12218  			});
12219  		}
12220
12221  		if (this._noTilesToLoad()) {
12222  			this._loading = false;
12223  			// @event load: Event
12224  			// Fired when the grid layer loaded all visible tiles.
12225  			this.fire('load');
12226
12227  			if (Browser.ielt9 || !this._map._fadeAnimated) {
12228  				requestAnimFrame(this._pruneTiles, this);
12229  			} else {
12230  				// Wait a bit more than 0.2 secs (the duration of the tile fade-in)
12231  				// to trigger a pruning.
12232  				setTimeout(bind(this._pruneTiles, this), 250);
12233  			}
12234  		}
12235  	},
12236
12237  	_getTilePos: function (coords) {
12238  		return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
12239  	},
12240
12241  	_wrapCoords: function (coords) {
12242  		var newCoords = new Point(
12243  			this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,
12244  			this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y);
12245  		newCoords.z = coords.z;
12246  		return newCoords;
12247  	},
12248
12249  	_pxBoundsToTileRange: function (bounds) {
12250  		var tileSize = this.getTileSize();
12251  		return new Bounds(
12252  			bounds.min.unscaleBy(tileSize).floor(),
12253  			bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
12254  	},
12255
12256  	_noTilesToLoad: function () {
12257  		for (var key in this._tiles) {
12258  			if (!this._tiles[key].loaded) { return false; }
12259  		}
12260  		return true;
12261  	}
12262  });
12263
12264  // @factory L.gridLayer(options?: GridLayer options)
12265  // Creates a new instance of GridLayer with the supplied options.
12266  function gridLayer(options) {
12267  	return new GridLayer(options);
12268  }
12269
12270  /*
12271   * @class TileLayer
12272   * @inherits GridLayer
12273   * @aka L.TileLayer
12274   * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`.
12275   *
12276   * @example
12277   *
12278   * ```js
12279   * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map);
12280   * ```
12281   *
12282   * @section URL template
12283   * @example
12284   *
12285   * A string of the following form:
12286   *
12287   * ```
12288   * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
12289   * ```
12290   *
12291   * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "&commat;2x" to the URL to load retina tiles.
12292   *
12293   * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
12294   *
12295   * ```
12296   * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
12297   * ```
12298   */
12299
12300
12301  var TileLayer = GridLayer.extend({
12302
12303  	// @section
12304  	// @aka TileLayer options
12305  	options: {
12306  		// @option minZoom: Number = 0
12307  		// The minimum zoom level down to which this layer will be displayed (inclusive).
12308  		minZoom: 0,
12309
12310  		// @option maxZoom: Number = 18
12311  		// The maximum zoom level up to which this layer will be displayed (inclusive).
12312  		maxZoom: 18,
12313
12314  		// @option subdomains: String|String[] = 'abc'
12315  		// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.
12316  		subdomains: 'abc',
12317
12318  		// @option errorTileUrl: String = ''
12319  		// URL to the tile image to show in place of the tile that failed to load.
12320  		errorTileUrl: '',
12321
12322  		// @option zoomOffset: Number = 0
12323  		// The zoom number used in tile URLs will be offset with this value.
12324  		zoomOffset: 0,
12325
12326  		// @option tms: Boolean = false
12327  		// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
12328  		tms: false,
12329
12330  		// @option zoomReverse: Boolean = false
12331  		// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
12332  		zoomReverse: false,
12333
12334  		// @option detectRetina: Boolean = false
12335  		// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
12336  		detectRetina: false,
12337
12338  		// @option crossOrigin: Boolean|String = false
12339  		// Whether the crossOrigin attribute will be added to the tiles.
12340  		// If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data.
12341  		// Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values.
12342  		crossOrigin: false,
12343
12344  		// @option referrerPolicy: Boolean|String = false
12345  		// Whether the referrerPolicy attribute will be added to the tiles.
12346  		// If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided.
12347  		// This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer
12348  		// (e.g. to validate an API token).
12349  		// Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values.
12350  		referrerPolicy: false
12351  	},
12352
12353  	initialize: function (url, options) {
12354
12355  		this._url = url;
12356
12357  		options = setOptions(this, options);
12358
12359  		// detecting retina displays, adjusting tileSize and zoom levels
12360  		if (options.detectRetina && Browser.retina && options.maxZoom > 0) {
12361
12362  			options.tileSize = Math.floor(options.tileSize / 2);
12363
12364  			if (!options.zoomReverse) {
12365  				options.zoomOffset++;
12366  				options.maxZoom = Math.max(options.minZoom, options.maxZoom - 1);
12367  			} else {
12368  				options.zoomOffset--;
12369  				options.minZoom = Math.min(options.maxZoom, options.minZoom + 1);
12370  			}
12371
12372  			options.minZoom = Math.max(0, options.minZoom);
12373  		} else if (!options.zoomReverse) {
12374  			// make sure maxZoom is gte minZoom
12375  			options.maxZoom = Math.max(options.minZoom, options.maxZoom);
12376  		} else {
12377  			// make sure minZoom is lte maxZoom
12378  			options.minZoom = Math.min(options.maxZoom, options.minZoom);
12379  		}
12380
12381  		if (typeof options.subdomains === 'string') {
12382  			options.subdomains = options.subdomains.split('');
12383  		}
12384
12385  		this.on('tileunload', this._onTileRemove);
12386  	},
12387
12388  	// @method setUrl(url: String, noRedraw?: Boolean): this
12389  	// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
12390  	// If the URL does not change, the layer will not be redrawn unless
12391  	// the noRedraw parameter is set to false.
12392  	setUrl: function (url, noRedraw) {
12393  		if (this._url === url && noRedraw === undefined) {
12394  			noRedraw = true;
12395  		}
12396
12397  		this._url = url;
12398
12399  		if (!noRedraw) {
12400  			this.redraw();
12401  		}
12402  		return this;
12403  	},
12404
12405  	// @method createTile(coords: Object, done?: Function): HTMLElement
12406  	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
12407  	// to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done`
12408  	// callback is called when the tile has been loaded.
12409  	createTile: function (coords, done) {
12410  		var tile = document.createElement('img');
12411
12412  		on(tile, 'load', bind(this._tileOnLoad, this, done, tile));
12413  		on(tile, 'error', bind(this._tileOnError, this, done, tile));
12414
12415  		if (this.options.crossOrigin || this.options.crossOrigin === '') {
12416  			tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin;
12417  		}
12418
12419  		// for this new option we follow the documented behavior
12420  		// more closely by only setting the property when string
12421  		if (typeof this.options.referrerPolicy === 'string') {
12422  			tile.referrerPolicy = this.options.referrerPolicy;
12423  		}
12424
12425  		// The alt attribute is set to the empty string,
12426  		// allowing screen readers to ignore the decorative image tiles.
12427  		// https://www.w3.org/WAI/tutorials/images/decorative/
12428  		// https://www.w3.org/TR/html-aria/#el-img-empty-alt
12429  		tile.alt = '';
12430
12431  		tile.src = this.getTileUrl(coords);
12432
12433  		return tile;
12434  	},
12435
12436  	// @section Extension methods
12437  	// @uninheritable
12438  	// Layers extending `TileLayer` might reimplement the following method.
12439  	// @method getTileUrl(coords: Object): String
12440  	// Called only internally, returns the URL for a tile given its coordinates.
12441  	// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
12442  	getTileUrl: function (coords) {
12443  		var data = {
12444  			r: Browser.retina ? '@2x' : '',
12445  			s: this._getSubdomain(coords),
12446  			x: coords.x,
12447  			y: coords.y,
12448  			z: this._getZoomForUrl()
12449  		};
12450  		if (this._map && !this._map.options.crs.infinite) {
12451  			var invertedY = this._globalTileRange.max.y - coords.y;
12452  			if (this.options.tms) {
12453  				data['y'] = invertedY;
12454  			}
12455  			data['-y'] = invertedY;
12456  		}
12457
12458  		return template(this._url, extend(data, this.options));
12459  	},
12460
12461  	_tileOnLoad: function (done, tile) {
12462  		// For https://github.com/Leaflet/Leaflet/issues/3332
12463  		if (Browser.ielt9) {
12464  			setTimeout(bind(done, this, null, tile), 0);
12465  		} else {
12466  			done(null, tile);
12467  		}
12468  	},
12469
12470  	_tileOnError: function (done, tile, e) {
12471  		var errorUrl = this.options.errorTileUrl;
12472  		if (errorUrl && tile.getAttribute('src') !== errorUrl) {
12473  			tile.src = errorUrl;
12474  		}
12475  		done(e, tile);
12476  	},
12477
12478  	_onTileRemove: function (e) {
12479  		e.tile.onload = null;
12480  	},
12481
12482  	_getZoomForUrl: function () {
12483  		var zoom = this._tileZoom,
12484  		maxZoom = this.options.maxZoom,
12485  		zoomReverse = this.options.zoomReverse,
12486  		zoomOffset = this.options.zoomOffset;
12487
12488  		if (zoomReverse) {
12489  			zoom = maxZoom - zoom;
12490  		}
12491
12492  		return zoom + zoomOffset;
12493  	},
12494
12495  	_getSubdomain: function (tilePoint) {
12496  		var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
12497  		return this.options.subdomains[index];
12498  	},
12499
12500  	// stops loading all tiles in the background layer
12501  	_abortLoading: function () {
12502  		var i, tile;
12503  		for (i in this._tiles) {
12504  			if (this._tiles[i].coords.z !== this._tileZoom) {
12505  				tile = this._tiles[i].el;
12506
12507  				tile.onload = falseFn;
12508  				tile.onerror = falseFn;
12509
12510  				if (!tile.complete) {
12511  					tile.src = emptyImageUrl;
12512  					var coords = this._tiles[i].coords;
12513  					remove(tile);
12514  					delete this._tiles[i];
12515  					// @event tileabort: TileEvent
12516  					// Fired when a tile was loading but is now not wanted.
12517  					this.fire('tileabort', {
12518  						tile: tile,
12519  						coords: coords
12520  					});
12521  				}
12522  			}
12523  		}
12524  	},
12525
12526  	_removeTile: function (key) {
12527  		var tile = this._tiles[key];
12528  		if (!tile) { return; }
12529
12530  		// Cancels any pending http requests associated with the tile
12531  		tile.el.setAttribute('src', emptyImageUrl);
12532
12533  		return GridLayer.prototype._removeTile.call(this, key);
12534  	},
12535
12536  	_tileReady: function (coords, err, tile) {
12537  		if (!this._map || (tile && tile.getAttribute('src') === emptyImageUrl)) {
12538  			return;
12539  		}
12540
12541  		return GridLayer.prototype._tileReady.call(this, coords, err, tile);
12542  	}
12543  });
12544
12545
12546  // @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
12547  // Instantiates a tile layer object given a `URL template` and optionally an options object.
12548
12549  function tileLayer(url, options) {
12550  	return new TileLayer(url, options);
12551  }
12552
12553  /*
12554   * @class TileLayer.WMS
12555   * @inherits TileLayer
12556   * @aka L.TileLayer.WMS
12557   * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
12558   *
12559   * @example
12560   *
12561   * ```js
12562   * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
12563   * 	layers: 'nexrad-n0r-900913',
12564   * 	format: 'image/png',
12565   * 	transparent: true,
12566   * 	attribution: "Weather data © 2012 IEM Nexrad"
12567   * });
12568   * ```
12569   */
12570
12571  var TileLayerWMS = TileLayer.extend({
12572
12573  	// @section
12574  	// @aka TileLayer.WMS options
12575  	// If any custom options not documented here are used, they will be sent to the
12576  	// WMS server as extra parameters in each request URL. This can be useful for
12577  	// [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
12578  	defaultWmsParams: {
12579  		service: 'WMS',
12580  		request: 'GetMap',
12581
12582  		// @option layers: String = ''
12583  		// **(required)** Comma-separated list of WMS layers to show.
12584  		layers: '',
12585
12586  		// @option styles: String = ''
12587  		// Comma-separated list of WMS styles.
12588  		styles: '',
12589
12590  		// @option format: String = 'image/jpeg'
12591  		// WMS image format (use `'image/png'` for layers with transparency).
12592  		format: 'image/jpeg',
12593
12594  		// @option transparent: Boolean = false
12595  		// If `true`, the WMS service will return images with transparency.
12596  		transparent: false,
12597
12598  		// @option version: String = '1.1.1'
12599  		// Version of the WMS service to use
12600  		version: '1.1.1'
12601  	},
12602
12603  	options: {
12604  		// @option crs: CRS = null
12605  		// Coordinate Reference System to use for the WMS requests, defaults to
12606  		// map CRS. Don't change this if you're not sure what it means.
12607  		crs: null,
12608
12609  		// @option uppercase: Boolean = false
12610  		// If `true`, WMS request parameter keys will be uppercase.
12611  		uppercase: false
12612  	},
12613
12614  	initialize: function (url, options) {
12615
12616  		this._url = url;
12617
12618  		var wmsParams = extend({}, this.defaultWmsParams);
12619
12620  		// all keys that are not TileLayer options go to WMS params
12621  		for (var i in options) {
12622  			if (!(i in this.options)) {
12623  				wmsParams[i] = options[i];
12624  			}
12625  		}
12626
12627  		options = setOptions(this, options);
12628
12629  		var realRetina = options.detectRetina && Browser.retina ? 2 : 1;
12630  		var tileSize = this.getTileSize();
12631  		wmsParams.width = tileSize.x * realRetina;
12632  		wmsParams.height = tileSize.y * realRetina;
12633
12634  		this.wmsParams = wmsParams;
12635  	},
12636
12637  	onAdd: function (map) {
12638
12639  		this._crs = this.options.crs || map.options.crs;
12640  		this._wmsVersion = parseFloat(this.wmsParams.version);
12641
12642  		var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
12643  		this.wmsParams[projectionKey] = this._crs.code;
12644
12645  		TileLayer.prototype.onAdd.call(this, map);
12646  	},
12647
12648  	getTileUrl: function (coords) {
12649
12650  		var tileBounds = this._tileCoordsToNwSe(coords),
12651  		    crs = this._crs,
12652  		    bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),
12653  		    min = bounds.min,
12654  		    max = bounds.max,
12655  		    bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?
12656  		    [min.y, min.x, max.y, max.x] :
12657  		    [min.x, min.y, max.x, max.y]).join(','),
12658  		    url = TileLayer.prototype.getTileUrl.call(this, coords);
12659  		return url +
12660  			getParamString(this.wmsParams, url, this.options.uppercase) +
12661  			(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
12662  	},
12663
12664  	// @method setParams(params: Object, noRedraw?: Boolean): this
12665  	// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
12666  	setParams: function (params, noRedraw) {
12667
12668  		extend(this.wmsParams, params);
12669
12670  		if (!noRedraw) {
12671  			this.redraw();
12672  		}
12673
12674  		return this;
12675  	}
12676  });
12677
12678
12679  // @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
12680  // Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
12681  function tileLayerWMS(url, options) {
12682  	return new TileLayerWMS(url, options);
12683  }
12684
12685  TileLayer.WMS = TileLayerWMS;
12686  tileLayer.wms = tileLayerWMS;
12687
12688  /*
12689   * @class Renderer
12690   * @inherits Layer
12691   * @aka L.Renderer
12692   *
12693   * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
12694   * DOM container of the renderer, its bounds, and its zoom animation.
12695   *
12696   * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
12697   * itself can be added or removed to the map. All paths use a renderer, which can
12698   * be implicit (the map will decide the type of renderer and use it automatically)
12699   * or explicit (using the [`renderer`](#path-renderer) option of the path).
12700   *
12701   * Do not use this class directly, use `SVG` and `Canvas` instead.
12702   *
12703   * @event update: Event
12704   * Fired when the renderer updates its bounds, center and zoom, for example when
12705   * its map has moved
12706   */
12707
12708  var Renderer = Layer.extend({
12709
12710  	// @section
12711  	// @aka Renderer options
12712  	options: {
12713  		// @option padding: Number = 0.1
12714  		// How much to extend the clip area around the map view (relative to its size)
12715  		// e.g. 0.1 would be 10% of map view in each direction
12716  		padding: 0.1
12717  	},
12718
12719  	initialize: function (options) {
12720  		setOptions(this, options);
12721  		stamp(this);
12722  		this._layers = this._layers || {};
12723  	},
12724
12725  	onAdd: function () {
12726  		if (!this._container) {
12727  			this._initContainer(); // defined by renderer implementations
12728
12729  			// always keep transform-origin as 0 0
12730  			addClass(this._container, 'leaflet-zoom-animated');
12731  		}
12732
12733  		this.getPane().appendChild(this._container);
12734  		this._update();
12735  		this.on('update', this._updatePaths, this);
12736  	},
12737
12738  	onRemove: function () {
12739  		this.off('update', this._updatePaths, this);
12740  		this._destroyContainer();
12741  	},
12742
12743  	getEvents: function () {
12744  		var events = {
12745  			viewreset: this._reset,
12746  			zoom: this._onZoom,
12747  			moveend: this._update,
12748  			zoomend: this._onZoomEnd
12749  		};
12750  		if (this._zoomAnimated) {
12751  			events.zoomanim = this._onAnimZoom;
12752  		}
12753  		return events;
12754  	},
12755
12756  	_onAnimZoom: function (ev) {
12757  		this._updateTransform(ev.center, ev.zoom);
12758  	},
12759
12760  	_onZoom: function () {
12761  		this._updateTransform(this._map.getCenter(), this._map.getZoom());
12762  	},
12763
12764  	_updateTransform: function (center, zoom) {
12765  		var scale = this._map.getZoomScale(zoom, this._zoom),
12766  		    viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
12767  		    currentCenterPoint = this._map.project(this._center, zoom),
12768
12769  		    topLeftOffset = viewHalf.multiplyBy(-scale).add(currentCenterPoint)
12770  				  .subtract(this._map._getNewPixelOrigin(center, zoom));
12771
12772  		if (Browser.any3d) {
12773  			setTransform(this._container, topLeftOffset, scale);
12774  		} else {
12775  			setPosition(this._container, topLeftOffset);
12776  		}
12777  	},
12778
12779  	_reset: function () {
12780  		this._update();
12781  		this._updateTransform(this._center, this._zoom);
12782
12783  		for (var id in this._layers) {
12784  			this._layers[id]._reset();
12785  		}
12786  	},
12787
12788  	_onZoomEnd: function () {
12789  		for (var id in this._layers) {
12790  			this._layers[id]._project();
12791  		}
12792  	},
12793
12794  	_updatePaths: function () {
12795  		for (var id in this._layers) {
12796  			this._layers[id]._update();
12797  		}
12798  	},
12799
12800  	_update: function () {
12801  		// Update pixel bounds of renderer container (for positioning/sizing/clipping later)
12802  		// Subclasses are responsible of firing the 'update' event.
12803  		var p = this.options.padding,
12804  		    size = this._map.getSize(),
12805  		    min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
12806
12807  		this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
12808
12809  		this._center = this._map.getCenter();
12810  		this._zoom = this._map.getZoom();
12811  	}
12812  });
12813
12814  /*
12815   * @class Canvas
12816   * @inherits Renderer
12817   * @aka L.Canvas
12818   *
12819   * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
12820   * Inherits `Renderer`.
12821   *
12822   * Due to [technical limitations](https://caniuse.com/canvas), Canvas is not
12823   * available in all web browsers, notably IE8, and overlapping geometries might
12824   * not display properly in some edge cases.
12825   *
12826   * @example
12827   *
12828   * Use Canvas by default for all paths in the map:
12829   *
12830   * ```js
12831   * var map = L.map('map', {
12832   * 	renderer: L.canvas()
12833   * });
12834   * ```
12835   *
12836   * Use a Canvas renderer with extra padding for specific vector geometries:
12837   *
12838   * ```js
12839   * var map = L.map('map');
12840   * var myRenderer = L.canvas({ padding: 0.5 });
12841   * var line = L.polyline( coordinates, { renderer: myRenderer } );
12842   * var circle = L.circle( center, { renderer: myRenderer } );
12843   * ```
12844   */
12845
12846  var Canvas = Renderer.extend({
12847
12848  	// @section
12849  	// @aka Canvas options
12850  	options: {
12851  		// @option tolerance: Number = 0
12852  		// How much to extend the click tolerance around a path/object on the map.
12853  		tolerance: 0
12854  	},
12855
12856  	getEvents: function () {
12857  		var events = Renderer.prototype.getEvents.call(this);
12858  		events.viewprereset = this._onViewPreReset;
12859  		return events;
12860  	},
12861
12862  	_onViewPreReset: function () {
12863  		// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
12864  		this._postponeUpdatePaths = true;
12865  	},
12866
12867  	onAdd: function () {
12868  		Renderer.prototype.onAdd.call(this);
12869
12870  		// Redraw vectors since canvas is cleared upon removal,
12871  		// in case of removing the renderer itself from the map.
12872  		this._draw();
12873  	},
12874
12875  	_initContainer: function () {
12876  		var container = this._container = document.createElement('canvas');
12877
12878  		on(container, 'mousemove', this._onMouseMove, this);
12879  		on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);
12880  		on(container, 'mouseout', this._handleMouseOut, this);
12881  		container['_leaflet_disable_events'] = true;
12882
12883  		this._ctx = container.getContext('2d');
12884  	},
12885
12886  	_destroyContainer: function () {
12887  		cancelAnimFrame(this._redrawRequest);
12888  		delete this._ctx;
12889  		remove(this._container);
12890  		off(this._container);
12891  		delete this._container;
12892  	},
12893
12894  	_updatePaths: function () {
12895  		if (this._postponeUpdatePaths) { return; }
12896
12897  		var layer;
12898  		this._redrawBounds = null;
12899  		for (var id in this._layers) {
12900  			layer = this._layers[id];
12901  			layer._update();
12902  		}
12903  		this._redraw();
12904  	},
12905
12906  	_update: function () {
12907  		if (this._map._animatingZoom && this._bounds) { return; }
12908
12909  		Renderer.prototype._update.call(this);
12910
12911  		var b = this._bounds,
12912  		    container = this._container,
12913  		    size = b.getSize(),
12914  		    m = Browser.retina ? 2 : 1;
12915
12916  		setPosition(container, b.min);
12917
12918  		// set canvas size (also clearing it); use double size on retina
12919  		container.width = m * size.x;
12920  		container.height = m * size.y;
12921  		container.style.width = size.x + 'px';
12922  		container.style.height = size.y + 'px';
12923
12924  		if (Browser.retina) {
12925  			this._ctx.scale(2, 2);
12926  		}
12927
12928  		// translate so we use the same path coordinates after canvas element moves
12929  		this._ctx.translate(-b.min.x, -b.min.y);
12930
12931  		// Tell paths to redraw themselves
12932  		this.fire('update');
12933  	},
12934
12935  	_reset: function () {
12936  		Renderer.prototype._reset.call(this);
12937
12938  		if (this._postponeUpdatePaths) {
12939  			this._postponeUpdatePaths = false;
12940  			this._updatePaths();
12941  		}
12942  	},
12943
12944  	_initPath: function (layer) {
12945  		this._updateDashArray(layer);
12946  		this._layers[stamp(layer)] = layer;
12947
12948  		var order = layer._order = {
12949  			layer: layer,
12950  			prev: this._drawLast,
12951  			next: null
12952  		};
12953  		if (this._drawLast) { this._drawLast.next = order; }
12954  		this._drawLast = order;
12955  		this._drawFirst = this._drawFirst || this._drawLast;
12956  	},
12957
12958  	_addPath: function (layer) {
12959  		this._requestRedraw(layer);
12960  	},
12961
12962  	_removePath: function (layer) {
12963  		var order = layer._order;
12964  		var next = order.next;
12965  		var prev = order.prev;
12966
12967  		if (next) {
12968  			next.prev = prev;
12969  		} else {
12970  			this._drawLast = prev;
12971  		}
12972  		if (prev) {
12973  			prev.next = next;
12974  		} else {
12975  			this._drawFirst = next;
12976  		}
12977
12978  		delete layer._order;
12979
12980  		delete this._layers[stamp(layer)];
12981
12982  		this._requestRedraw(layer);
12983  	},
12984
12985  	_updatePath: function (layer) {
12986  		// Redraw the union of the layer's old pixel
12987  		// bounds and the new pixel bounds.
12988  		this._extendRedrawBounds(layer);
12989  		layer._project();
12990  		layer._update();
12991  		// The redraw will extend the redraw bounds
12992  		// with the new pixel bounds.
12993  		this._requestRedraw(layer);
12994  	},
12995
12996  	_updateStyle: function (layer) {
12997  		this._updateDashArray(layer);
12998  		this._requestRedraw(layer);
12999  	},
13000
13001  	_updateDashArray: function (layer) {
13002  		if (typeof layer.options.dashArray === 'string') {
13003  			var parts = layer.options.dashArray.split(/[, ]+/),
13004  			    dashArray = [],
13005  			    dashValue,
13006  			    i;
13007  			for (i = 0; i < parts.length; i++) {
13008  				dashValue = Number(parts[i]);
13009  				// Ignore dash array containing invalid lengths
13010  				if (isNaN(dashValue)) { return; }
13011  				dashArray.push(dashValue);
13012  			}
13013  			layer.options._dashArray = dashArray;
13014  		} else {
13015  			layer.options._dashArray = layer.options.dashArray;
13016  		}
13017  	},
13018
13019  	_requestRedraw: function (layer) {
13020  		if (!this._map) { return; }
13021
13022  		this._extendRedrawBounds(layer);
13023  		this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);
13024  	},
13025
13026  	_extendRedrawBounds: function (layer) {
13027  		if (layer._pxBounds) {
13028  			var padding = (layer.options.weight || 0) + 1;
13029  			this._redrawBounds = this._redrawBounds || new Bounds();
13030  			this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
13031  			this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
13032  		}
13033  	},
13034
13035  	_redraw: function () {
13036  		this._redrawRequest = null;
13037
13038  		if (this._redrawBounds) {
13039  			this._redrawBounds.min._floor();
13040  			this._redrawBounds.max._ceil();
13041  		}
13042
13043  		this._clear(); // clear layers in redraw bounds
13044  		this._draw(); // draw layers
13045
13046  		this._redrawBounds = null;
13047  	},
13048
13049  	_clear: function () {
13050  		var bounds = this._redrawBounds;
13051  		if (bounds) {
13052  			var size = bounds.getSize();
13053  			this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
13054  		} else {
13055  			this._ctx.save();
13056  			this._ctx.setTransform(1, 0, 0, 1, 0, 0);
13057  			this._ctx.clearRect(0, 0, this._container.width, this._container.height);
13058  			this._ctx.restore();
13059  		}
13060  	},
13061
13062  	_draw: function () {
13063  		var layer, bounds = this._redrawBounds;
13064  		this._ctx.save();
13065  		if (bounds) {
13066  			var size = bounds.getSize();
13067  			this._ctx.beginPath();
13068  			this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
13069  			this._ctx.clip();
13070  		}
13071
13072  		this._drawing = true;
13073
13074  		for (var order = this._drawFirst; order; order = order.next) {
13075  			layer = order.layer;
13076  			if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
13077  				layer._updatePath();
13078  			}
13079  		}
13080
13081  		this._drawing = false;
13082
13083  		this._ctx.restore();  // Restore state before clipping.
13084  	},
13085
13086  	_updatePoly: function (layer, closed) {
13087  		if (!this._drawing) { return; }
13088
13089  		var i, j, len2, p,
13090  		    parts = layer._parts,
13091  		    len = parts.length,
13092  		    ctx = this._ctx;
13093
13094  		if (!len) { return; }
13095
13096  		ctx.beginPath();
13097
13098  		for (i = 0; i < len; i++) {
13099  			for (j = 0, len2 = parts[i].length; j < len2; j++) {
13100  				p = parts[i][j];
13101  				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
13102  			}
13103  			if (closed) {
13104  				ctx.closePath();
13105  			}
13106  		}
13107
13108  		this._fillStroke(ctx, layer);
13109
13110  		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
13111  	},
13112
13113  	_updateCircle: function (layer) {
13114
13115  		if (!this._drawing || layer._empty()) { return; }
13116
13117  		var p = layer._point,
13118  		    ctx = this._ctx,
13119  		    r = Math.max(Math.round(layer._radius), 1),
13120  		    s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;
13121
13122  		if (s !== 1) {
13123  			ctx.save();
13124  			ctx.scale(1, s);
13125  		}
13126
13127  		ctx.beginPath();
13128  		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
13129
13130  		if (s !== 1) {
13131  			ctx.restore();
13132  		}
13133
13134  		this._fillStroke(ctx, layer);
13135  	},
13136
13137  	_fillStroke: function (ctx, layer) {
13138  		var options = layer.options;
13139
13140  		if (options.fill) {
13141  			ctx.globalAlpha = options.fillOpacity;
13142  			ctx.fillStyle = options.fillColor || options.color;
13143  			ctx.fill(options.fillRule || 'evenodd');
13144  		}
13145
13146  		if (options.stroke && options.weight !== 0) {
13147  			if (ctx.setLineDash) {
13148  				ctx.setLineDash(layer.options && layer.options._dashArray || []);
13149  			}
13150  			ctx.globalAlpha = options.opacity;
13151  			ctx.lineWidth = options.weight;
13152  			ctx.strokeStyle = options.color;
13153  			ctx.lineCap = options.lineCap;
13154  			ctx.lineJoin = options.lineJoin;
13155  			ctx.stroke();
13156  		}
13157  	},
13158
13159  	// Canvas obviously doesn't have mouse events for individual drawn objects,
13160  	// so we emulate that by calculating what's under the mouse on mousemove/click manually
13161
13162  	_onClick: function (e) {
13163  		var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
13164
13165  		for (var order = this._drawFirst; order; order = order.next) {
13166  			layer = order.layer;
13167  			if (layer.options.interactive && layer._containsPoint(point)) {
13168  				if (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) {
13169  					clickedLayer = layer;
13170  				}
13171  			}
13172  		}
13173  		this._fireEvent(clickedLayer ? [clickedLayer] : false, e);
13174  	},
13175
13176  	_onMouseMove: function (e) {
13177  		if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
13178
13179  		var point = this._map.mouseEventToLayerPoint(e);
13180  		this._handleMouseHover(e, point);
13181  	},
13182
13183
13184  	_handleMouseOut: function (e) {
13185  		var layer = this._hoveredLayer;
13186  		if (layer) {
13187  			// if we're leaving the layer, fire mouseout
13188  			removeClass(this._container, 'leaflet-interactive');
13189  			this._fireEvent([layer], e, 'mouseout');
13190  			this._hoveredLayer = null;
13191  			this._mouseHoverThrottled = false;
13192  		}
13193  	},
13194
13195  	_handleMouseHover: function (e, point) {
13196  		if (this._mouseHoverThrottled) {
13197  			return;
13198  		}
13199
13200  		var layer, candidateHoveredLayer;
13201
13202  		for (var order = this._drawFirst; order; order = order.next) {
13203  			layer = order.layer;
13204  			if (layer.options.interactive && layer._containsPoint(point)) {
13205  				candidateHoveredLayer = layer;
13206  			}
13207  		}
13208
13209  		if (candidateHoveredLayer !== this._hoveredLayer) {
13210  			this._handleMouseOut(e);
13211
13212  			if (candidateHoveredLayer) {
13213  				addClass(this._container, 'leaflet-interactive'); // change cursor
13214  				this._fireEvent([candidateHoveredLayer], e, 'mouseover');
13215  				this._hoveredLayer = candidateHoveredLayer;
13216  			}
13217  		}
13218
13219  		this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e);
13220
13221  		this._mouseHoverThrottled = true;
13222  		setTimeout(bind(function () {
13223  			this._mouseHoverThrottled = false;
13224  		}, this), 32);
13225  	},
13226
13227  	_fireEvent: function (layers, e, type) {
13228  		this._map._fireDOMEvent(e, type || e.type, layers);
13229  	},
13230
13231  	_bringToFront: function (layer) {
13232  		var order = layer._order;
13233
13234  		if (!order) { return; }
13235
13236  		var next = order.next;
13237  		var prev = order.prev;
13238
13239  		if (next) {
13240  			next.prev = prev;
13241  		} else {
13242  			// Already last
13243  			return;
13244  		}
13245  		if (prev) {
13246  			prev.next = next;
13247  		} else if (next) {
13248  			// Update first entry unless this is the
13249  			// single entry
13250  			this._drawFirst = next;
13251  		}
13252
13253  		order.prev = this._drawLast;
13254  		this._drawLast.next = order;
13255
13256  		order.next = null;
13257  		this._drawLast = order;
13258
13259  		this._requestRedraw(layer);
13260  	},
13261
13262  	_bringToBack: function (layer) {
13263  		var order = layer._order;
13264
13265  		if (!order) { return; }
13266
13267  		var next = order.next;
13268  		var prev = order.prev;
13269
13270  		if (prev) {
13271  			prev.next = next;
13272  		} else {
13273  			// Already first
13274  			return;
13275  		}
13276  		if (next) {
13277  			next.prev = prev;
13278  		} else if (prev) {
13279  			// Update last entry unless this is the
13280  			// single entry
13281  			this._drawLast = prev;
13282  		}
13283
13284  		order.prev = null;
13285
13286  		order.next = this._drawFirst;
13287  		this._drawFirst.prev = order;
13288  		this._drawFirst = order;
13289
13290  		this._requestRedraw(layer);
13291  	}
13292  });
13293
13294  // @factory L.canvas(options?: Renderer options)
13295  // Creates a Canvas renderer with the given options.
13296  function canvas(options) {
13297  	return Browser.canvas ? new Canvas(options) : null;
13298  }
13299
13300  /*
13301   * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
13302   */
13303
13304
13305  var vmlCreate = (function () {
13306  	try {
13307  		document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
13308  		return function (name) {
13309  			return document.createElement('<lvml:' + name + ' class="lvml">');
13310  		};
13311  	} catch (e) {
13312  		// Do not return fn from catch block so `e` can be garbage collected
13313  		// See https://github.com/Leaflet/Leaflet/pull/7279
13314  	}
13315  	return function (name) {
13316  		return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
13317  	};
13318  })();
13319
13320
13321  /*
13322   * @class SVG
13323   *
13324   *
13325   * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
13326   * with old versions of Internet Explorer.
13327   */
13328
13329  // mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences
13330  var vmlMixin = {
13331
13332  	_initContainer: function () {
13333  		this._container = create$1('div', 'leaflet-vml-container');
13334  	},
13335
13336  	_update: function () {
13337  		if (this._map._animatingZoom) { return; }
13338  		Renderer.prototype._update.call(this);
13339  		this.fire('update');
13340  	},
13341
13342  	_initPath: function (layer) {
13343  		var container = layer._container = vmlCreate('shape');
13344
13345  		addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
13346
13347  		container.coordsize = '1 1';
13348
13349  		layer._path = vmlCreate('path');
13350  		container.appendChild(layer._path);
13351
13352  		this._updateStyle(layer);
13353  		this._layers[stamp(layer)] = layer;
13354  	},
13355
13356  	_addPath: function (layer) {
13357  		var container = layer._container;
13358  		this._container.appendChild(container);
13359
13360  		if (layer.options.interactive) {
13361  			layer.addInteractiveTarget(container);
13362  		}
13363  	},
13364
13365  	_removePath: function (layer) {
13366  		var container = layer._container;
13367  		remove(container);
13368  		layer.removeInteractiveTarget(container);
13369  		delete this._layers[stamp(layer)];
13370  	},
13371
13372  	_updateStyle: function (layer) {
13373  		var stroke = layer._stroke,
13374  		    fill = layer._fill,
13375  		    options = layer.options,
13376  		    container = layer._container;
13377
13378  		container.stroked = !!options.stroke;
13379  		container.filled = !!options.fill;
13380
13381  		if (options.stroke) {
13382  			if (!stroke) {
13383  				stroke = layer._stroke = vmlCreate('stroke');
13384  			}
13385  			container.appendChild(stroke);
13386  			stroke.weight = options.weight + 'px';
13387  			stroke.color = options.color;
13388  			stroke.opacity = options.opacity;
13389
13390  			if (options.dashArray) {
13391  				stroke.dashStyle = isArray(options.dashArray) ?
13392  				    options.dashArray.join(' ') :
13393  				    options.dashArray.replace(/( *, *)/g, ' ');
13394  			} else {
13395  				stroke.dashStyle = '';
13396  			}
13397  			stroke.endcap = options.lineCap.replace('butt', 'flat');
13398  			stroke.joinstyle = options.lineJoin;
13399
13400  		} else if (stroke) {
13401  			container.removeChild(stroke);
13402  			layer._stroke = null;
13403  		}
13404
13405  		if (options.fill) {
13406  			if (!fill) {
13407  				fill = layer._fill = vmlCreate('fill');
13408  			}
13409  			container.appendChild(fill);
13410  			fill.color = options.fillColor || options.color;
13411  			fill.opacity = options.fillOpacity;
13412
13413  		} else if (fill) {
13414  			container.removeChild(fill);
13415  			layer._fill = null;
13416  		}
13417  	},
13418
13419  	_updateCircle: function (layer) {
13420  		var p = layer._point.round(),
13421  		    r = Math.round(layer._radius),
13422  		    r2 = Math.round(layer._radiusY || r);
13423
13424  		this._setPath(layer, layer._empty() ? 'M0 0' :
13425  			'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
13426  	},
13427
13428  	_setPath: function (layer, path) {
13429  		layer._path.v = path;
13430  	},
13431
13432  	_bringToFront: function (layer) {
13433  		toFront(layer._container);
13434  	},
13435
13436  	_bringToBack: function (layer) {
13437  		toBack(layer._container);
13438  	}
13439  };
13440
13441  var create = Browser.vml ? vmlCreate : svgCreate;
13442
13443  /*
13444   * @class SVG
13445   * @inherits Renderer
13446   * @aka L.SVG
13447   *
13448   * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
13449   * Inherits `Renderer`.
13450   *
13451   * Due to [technical limitations](https://caniuse.com/svg), SVG is not
13452   * available in all web browsers, notably Android 2.x and 3.x.
13453   *
13454   * Although SVG is not available on IE7 and IE8, these browsers support
13455   * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
13456   * (a now deprecated technology), and the SVG renderer will fall back to VML in
13457   * this case.
13458   *
13459   * @example
13460   *
13461   * Use SVG by default for all paths in the map:
13462   *
13463   * ```js
13464   * var map = L.map('map', {
13465   * 	renderer: L.svg()
13466   * });
13467   * ```
13468   *
13469   * Use a SVG renderer with extra padding for specific vector geometries:
13470   *
13471   * ```js
13472   * var map = L.map('map');
13473   * var myRenderer = L.svg({ padding: 0.5 });
13474   * var line = L.polyline( coordinates, { renderer: myRenderer } );
13475   * var circle = L.circle( center, { renderer: myRenderer } );
13476   * ```
13477   */
13478
13479  var SVG = Renderer.extend({
13480
13481  	_initContainer: function () {
13482  		this._container = create('svg');
13483
13484  		// makes it possible to click through svg root; we'll reset it back in individual paths
13485  		this._container.setAttribute('pointer-events', 'none');
13486
13487  		this._rootGroup = create('g');
13488  		this._container.appendChild(this._rootGroup);
13489  	},
13490
13491  	_destroyContainer: function () {
13492  		remove(this._container);
13493  		off(this._container);
13494  		delete this._container;
13495  		delete this._rootGroup;
13496  		delete this._svgSize;
13497  	},
13498
13499  	_update: function () {
13500  		if (this._map._animatingZoom && this._bounds) { return; }
13501
13502  		Renderer.prototype._update.call(this);
13503
13504  		var b = this._bounds,
13505  		    size = b.getSize(),
13506  		    container = this._container;
13507
13508  		// set size of svg-container if changed
13509  		if (!this._svgSize || !this._svgSize.equals(size)) {
13510  			this._svgSize = size;
13511  			container.setAttribute('width', size.x);
13512  			container.setAttribute('height', size.y);
13513  		}
13514
13515  		// movement: update container viewBox so that we don't have to change coordinates of individual layers
13516  		setPosition(container, b.min);
13517  		container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
13518
13519  		this.fire('update');
13520  	},
13521
13522  	// methods below are called by vector layers implementations
13523
13524  	_initPath: function (layer) {
13525  		var path = layer._path = create('path');
13526
13527  		// @namespace Path
13528  		// @option className: String = null
13529  		// Custom class name set on an element. Only for SVG renderer.
13530  		if (layer.options.className) {
13531  			addClass(path, layer.options.className);
13532  		}
13533
13534  		if (layer.options.interactive) {
13535  			addClass(path, 'leaflet-interactive');
13536  		}
13537
13538  		this._updateStyle(layer);
13539  		this._layers[stamp(layer)] = layer;
13540  	},
13541
13542  	_addPath: function (layer) {
13543  		if (!this._rootGroup) { this._initContainer(); }
13544  		this._rootGroup.appendChild(layer._path);
13545  		layer.addInteractiveTarget(layer._path);
13546  	},
13547
13548  	_removePath: function (layer) {
13549  		remove(layer._path);
13550  		layer.removeInteractiveTarget(layer._path);
13551  		delete this._layers[stamp(layer)];
13552  	},
13553
13554  	_updatePath: function (layer) {
13555  		layer._project();
13556  		layer._update();
13557  	},
13558
13559  	_updateStyle: function (layer) {
13560  		var path = layer._path,
13561  		    options = layer.options;
13562
13563  		if (!path) { return; }
13564
13565  		if (options.stroke) {
13566  			path.setAttribute('stroke', options.color);
13567  			path.setAttribute('stroke-opacity', options.opacity);
13568  			path.setAttribute('stroke-width', options.weight);
13569  			path.setAttribute('stroke-linecap', options.lineCap);
13570  			path.setAttribute('stroke-linejoin', options.lineJoin);
13571
13572  			if (options.dashArray) {
13573  				path.setAttribute('stroke-dasharray', options.dashArray);
13574  			} else {
13575  				path.removeAttribute('stroke-dasharray');
13576  			}
13577
13578  			if (options.dashOffset) {
13579  				path.setAttribute('stroke-dashoffset', options.dashOffset);
13580  			} else {
13581  				path.removeAttribute('stroke-dashoffset');
13582  			}
13583  		} else {
13584  			path.setAttribute('stroke', 'none');
13585  		}
13586
13587  		if (options.fill) {
13588  			path.setAttribute('fill', options.fillColor || options.color);
13589  			path.setAttribute('fill-opacity', options.fillOpacity);
13590  			path.setAttribute('fill-rule', options.fillRule || 'evenodd');
13591  		} else {
13592  			path.setAttribute('fill', 'none');
13593  		}
13594  	},
13595
13596  	_updatePoly: function (layer, closed) {
13597  		this._setPath(layer, pointsToPath(layer._parts, closed));
13598  	},
13599
13600  	_updateCircle: function (layer) {
13601  		var p = layer._point,
13602  		    r = Math.max(Math.round(layer._radius), 1),
13603  		    r2 = Math.max(Math.round(layer._radiusY), 1) || r,
13604  		    arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
13605
13606  		// drawing a circle with two half-arcs
13607  		var d = layer._empty() ? 'M0 0' :
13608  			'M' + (p.x - r) + ',' + p.y +
13609  			arc + (r * 2) + ',0 ' +
13610  			arc + (-r * 2) + ',0 ';
13611
13612  		this._setPath(layer, d);
13613  	},
13614
13615  	_setPath: function (layer, path) {
13616  		layer._path.setAttribute('d', path);
13617  	},
13618
13619  	// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
13620  	_bringToFront: function (layer) {
13621  		toFront(layer._path);
13622  	},
13623
13624  	_bringToBack: function (layer) {
13625  		toBack(layer._path);
13626  	}
13627  });
13628
13629  if (Browser.vml) {
13630  	SVG.include(vmlMixin);
13631  }
13632
13633  // @namespace SVG
13634  // @factory L.svg(options?: Renderer options)
13635  // Creates a SVG renderer with the given options.
13636  function svg(options) {
13637  	return Browser.svg || Browser.vml ? new SVG(options) : null;
13638  }
13639
13640  Map.include({
13641  	// @namespace Map; @method getRenderer(layer: Path): Renderer
13642  	// Returns the instance of `Renderer` that should be used to render the given
13643  	// `Path`. It will ensure that the `renderer` options of the map and paths
13644  	// are respected, and that the renderers do exist on the map.
13645  	getRenderer: function (layer) {
13646  		// @namespace Path; @option renderer: Renderer
13647  		// Use this specific instance of `Renderer` for this path. Takes
13648  		// precedence over the map's [default renderer](#map-renderer).
13649  		var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
13650
13651  		if (!renderer) {
13652  			renderer = this._renderer = this._createRenderer();
13653  		}
13654
13655  		if (!this.hasLayer(renderer)) {
13656  			this.addLayer(renderer);
13657  		}
13658  		return renderer;
13659  	},
13660
13661  	_getPaneRenderer: function (name) {
13662  		if (name === 'overlayPane' || name === undefined) {
13663  			return false;
13664  		}
13665
13666  		var renderer = this._paneRenderers[name];
13667  		if (renderer === undefined) {
13668  			renderer = this._createRenderer({pane: name});
13669  			this._paneRenderers[name] = renderer;
13670  		}
13671  		return renderer;
13672  	},
13673
13674  	_createRenderer: function (options) {
13675  		// @namespace Map; @option preferCanvas: Boolean = false
13676  		// Whether `Path`s should be rendered on a `Canvas` renderer.
13677  		// By default, all `Path`s are rendered in a `SVG` renderer.
13678  		return (this.options.preferCanvas && canvas(options)) || svg(options);
13679  	}
13680  });
13681
13682  /*
13683   * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
13684   */
13685
13686  /*
13687   * @class Rectangle
13688   * @aka L.Rectangle
13689   * @inherits Polygon
13690   *
13691   * A class for drawing rectangle overlays on a map. Extends `Polygon`.
13692   *
13693   * @example
13694   *
13695   * ```js
13696   * // define rectangle geographical bounds
13697   * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
13698   *
13699   * // create an orange rectangle
13700   * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
13701   *
13702   * // zoom the map to the rectangle bounds
13703   * map.fitBounds(bounds);
13704   * ```
13705   *
13706   */
13707
13708
13709  var Rectangle = Polygon.extend({
13710  	initialize: function (latLngBounds, options) {
13711  		Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
13712  	},
13713
13714  	// @method setBounds(latLngBounds: LatLngBounds): this
13715  	// Redraws the rectangle with the passed bounds.
13716  	setBounds: function (latLngBounds) {
13717  		return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
13718  	},
13719
13720  	_boundsToLatLngs: function (latLngBounds) {
13721  		latLngBounds = toLatLngBounds(latLngBounds);
13722  		return [
13723  			latLngBounds.getSouthWest(),
13724  			latLngBounds.getNorthWest(),
13725  			latLngBounds.getNorthEast(),
13726  			latLngBounds.getSouthEast()
13727  		];
13728  	}
13729  });
13730
13731
13732  // @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
13733  function rectangle(latLngBounds, options) {
13734  	return new Rectangle(latLngBounds, options);
13735  }
13736
13737  SVG.create = create;
13738  SVG.pointsToPath = pointsToPath;
13739
13740  GeoJSON.geometryToLayer = geometryToLayer;
13741  GeoJSON.coordsToLatLng = coordsToLatLng;
13742  GeoJSON.coordsToLatLngs = coordsToLatLngs;
13743  GeoJSON.latLngToCoords = latLngToCoords;
13744  GeoJSON.latLngsToCoords = latLngsToCoords;
13745  GeoJSON.getFeature = getFeature;
13746  GeoJSON.asFeature = asFeature;
13747
13748  /*
13749   * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
13750   * (zoom to a selected bounding box), enabled by default.
13751   */
13752
13753  // @namespace Map
13754  // @section Interaction Options
13755  Map.mergeOptions({
13756  	// @option boxZoom: Boolean = true
13757  	// Whether the map can be zoomed to a rectangular area specified by
13758  	// dragging the mouse while pressing the shift key.
13759  	boxZoom: true
13760  });
13761
13762  var BoxZoom = Handler.extend({
13763  	initialize: function (map) {
13764  		this._map = map;
13765  		this._container = map._container;
13766  		this._pane = map._panes.overlayPane;
13767  		this._resetStateTimeout = 0;
13768  		map.on('unload', this._destroy, this);
13769  	},
13770
13771  	addHooks: function () {
13772  		on(this._container, 'mousedown', this._onMouseDown, this);
13773  	},
13774
13775  	removeHooks: function () {
13776  		off(this._container, 'mousedown', this._onMouseDown, this);
13777  	},
13778
13779  	moved: function () {
13780  		return this._moved;
13781  	},
13782
13783  	_destroy: function () {
13784  		remove(this._pane);
13785  		delete this._pane;
13786  	},
13787
13788  	_resetState: function () {
13789  		this._resetStateTimeout = 0;
13790  		this._moved = false;
13791  	},
13792
13793  	_clearDeferredResetState: function () {
13794  		if (this._resetStateTimeout !== 0) {
13795  			clearTimeout(this._resetStateTimeout);
13796  			this._resetStateTimeout = 0;
13797  		}
13798  	},
13799
13800  	_onMouseDown: function (e) {
13801  		if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
13802
13803  		// Clear the deferred resetState if it hasn't executed yet, otherwise it
13804  		// will interrupt the interaction and orphan a box element in the container.
13805  		this._clearDeferredResetState();
13806  		this._resetState();
13807
13808  		disableTextSelection();
13809  		disableImageDrag();
13810
13811  		this._startPoint = this._map.mouseEventToContainerPoint(e);
13812
13813  		on(document, {
13814  			contextmenu: stop,
13815  			mousemove: this._onMouseMove,
13816  			mouseup: this._onMouseUp,
13817  			keydown: this._onKeyDown
13818  		}, this);
13819  	},
13820
13821  	_onMouseMove: function (e) {
13822  		if (!this._moved) {
13823  			this._moved = true;
13824
13825  			this._box = create$1('div', 'leaflet-zoom-box', this._container);
13826  			addClass(this._container, 'leaflet-crosshair');
13827
13828  			this._map.fire('boxzoomstart');
13829  		}
13830
13831  		this._point = this._map.mouseEventToContainerPoint(e);
13832
13833  		var bounds = new Bounds(this._point, this._startPoint),
13834  		    size = bounds.getSize();
13835
13836  		setPosition(this._box, bounds.min);
13837
13838  		this._box.style.width  = size.x + 'px';
13839  		this._box.style.height = size.y + 'px';
13840  	},
13841
13842  	_finish: function () {
13843  		if (this._moved) {
13844  			remove(this._box);
13845  			removeClass(this._container, 'leaflet-crosshair');
13846  		}
13847
13848  		enableTextSelection();
13849  		enableImageDrag();
13850
13851  		off(document, {
13852  			contextmenu: stop,
13853  			mousemove: this._onMouseMove,
13854  			mouseup: this._onMouseUp,
13855  			keydown: this._onKeyDown
13856  		}, this);
13857  	},
13858
13859  	_onMouseUp: function (e) {
13860  		if ((e.which !== 1) && (e.button !== 1)) { return; }
13861
13862  		this._finish();
13863
13864  		if (!this._moved) { return; }
13865  		// Postpone to next JS tick so internal click event handling
13866  		// still see it as "moved".
13867  		this._clearDeferredResetState();
13868  		this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);
13869
13870  		var bounds = new LatLngBounds(
13871  		        this._map.containerPointToLatLng(this._startPoint),
13872  		        this._map.containerPointToLatLng(this._point));
13873
13874  		this._map
13875  			.fitBounds(bounds)
13876  			.fire('boxzoomend', {boxZoomBounds: bounds});
13877  	},
13878
13879  	_onKeyDown: function (e) {
13880  		if (e.keyCode === 27) {
13881  			this._finish();
13882  			this._clearDeferredResetState();
13883  			this._resetState();
13884  		}
13885  	}
13886  });
13887
13888  // @section Handlers
13889  // @property boxZoom: Handler
13890  // Box (shift-drag with mouse) zoom handler.
13891  Map.addInitHook('addHandler', 'boxZoom', BoxZoom);
13892
13893  /*
13894   * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
13895   */
13896
13897  // @namespace Map
13898  // @section Interaction Options
13899
13900  Map.mergeOptions({
13901  	// @option doubleClickZoom: Boolean|String = true
13902  	// Whether the map can be zoomed in by double clicking on it and
13903  	// zoomed out by double clicking while holding shift. If passed
13904  	// `'center'`, double-click zoom will zoom to the center of the
13905  	//  view regardless of where the mouse was.
13906  	doubleClickZoom: true
13907  });
13908
13909  var DoubleClickZoom = Handler.extend({
13910  	addHooks: function () {
13911  		this._map.on('dblclick', this._onDoubleClick, this);
13912  	},
13913
13914  	removeHooks: function () {
13915  		this._map.off('dblclick', this._onDoubleClick, this);
13916  	},
13917
13918  	_onDoubleClick: function (e) {
13919  		var map = this._map,
13920  		    oldZoom = map.getZoom(),
13921  		    delta = map.options.zoomDelta,
13922  		    zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
13923
13924  		if (map.options.doubleClickZoom === 'center') {
13925  			map.setZoom(zoom);
13926  		} else {
13927  			map.setZoomAround(e.containerPoint, zoom);
13928  		}
13929  	}
13930  });
13931
13932  // @section Handlers
13933  //
13934  // Map properties include interaction handlers that allow you to control
13935  // interaction behavior in runtime, enabling or disabling certain features such
13936  // as dragging or touch zoom (see `Handler` methods). For example:
13937  //
13938  // ```js
13939  // map.doubleClickZoom.disable();
13940  // ```
13941  //
13942  // @property doubleClickZoom: Handler
13943  // Double click zoom handler.
13944  Map.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);
13945
13946  /*
13947   * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
13948   */
13949
13950  // @namespace Map
13951  // @section Interaction Options
13952  Map.mergeOptions({
13953  	// @option dragging: Boolean = true
13954  	// Whether the map is draggable with mouse/touch or not.
13955  	dragging: true,
13956
13957  	// @section Panning Inertia Options
13958  	// @option inertia: Boolean = *
13959  	// If enabled, panning of the map will have an inertia effect where
13960  	// the map builds momentum while dragging and continues moving in
13961  	// the same direction for some time. Feels especially nice on touch
13962  	// devices. Enabled by default.
13963  	inertia: true,
13964
13965  	// @option inertiaDeceleration: Number = 3000
13966  	// The rate with which the inertial movement slows down, in pixels/second².
13967  	inertiaDeceleration: 3400, // px/s^2
13968
13969  	// @option inertiaMaxSpeed: Number = Infinity
13970  	// Max speed of the inertial movement, in pixels/second.
13971  	inertiaMaxSpeed: Infinity, // px/s
13972
13973  	// @option easeLinearity: Number = 0.2
13974  	easeLinearity: 0.2,
13975
13976  	// TODO refactor, move to CRS
13977  	// @option worldCopyJump: Boolean = false
13978  	// With this option enabled, the map tracks when you pan to another "copy"
13979  	// of the world and seamlessly jumps to the original one so that all overlays
13980  	// like markers and vector layers are still visible.
13981  	worldCopyJump: false,
13982
13983  	// @option maxBoundsViscosity: Number = 0.0
13984  	// If `maxBounds` is set, this option will control how solid the bounds
13985  	// are when dragging the map around. The default value of `0.0` allows the
13986  	// user to drag outside the bounds at normal speed, higher values will
13987  	// slow down map dragging outside bounds, and `1.0` makes the bounds fully
13988  	// solid, preventing the user from dragging outside the bounds.
13989  	maxBoundsViscosity: 0.0
13990  });
13991
13992  var Drag = Handler.extend({
13993  	addHooks: function () {
13994  		if (!this._draggable) {
13995  			var map = this._map;
13996
13997  			this._draggable = new Draggable(map._mapPane, map._container);
13998
13999  			this._draggable.on({
14000  				dragstart: this._onDragStart,
14001  				drag: this._onDrag,
14002  				dragend: this._onDragEnd
14003  			}, this);
14004
14005  			this._draggable.on('predrag', this._onPreDragLimit, this);
14006  			if (map.options.worldCopyJump) {
14007  				this._draggable.on('predrag', this._onPreDragWrap, this);
14008  				map.on('zoomend', this._onZoomEnd, this);
14009
14010  				map.whenReady(this._onZoomEnd, this);
14011  			}
14012  		}
14013  		addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
14014  		this._draggable.enable();
14015  		this._positions = [];
14016  		this._times = [];
14017  	},
14018
14019  	removeHooks: function () {
14020  		removeClass(this._map._container, 'leaflet-grab');
14021  		removeClass(this._map._container, 'leaflet-touch-drag');
14022  		this._draggable.disable();
14023  	},
14024
14025  	moved: function () {
14026  		return this._draggable && this._draggable._moved;
14027  	},
14028
14029  	moving: function () {
14030  		return this._draggable && this._draggable._moving;
14031  	},
14032
14033  	_onDragStart: function () {
14034  		var map = this._map;
14035
14036  		map._stop();
14037  		if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
14038  			var bounds = toLatLngBounds(this._map.options.maxBounds);
14039
14040  			this._offsetLimit = toBounds(
14041  				this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
14042  				this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
14043  					.add(this._map.getSize()));
14044
14045  			this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
14046  		} else {
14047  			this._offsetLimit = null;
14048  		}
14049
14050  		map
14051  		    .fire('movestart')
14052  		    .fire('dragstart');
14053
14054  		if (map.options.inertia) {
14055  			this._positions = [];
14056  			this._times = [];
14057  		}
14058  	},
14059
14060  	_onDrag: function (e) {
14061  		if (this._map.options.inertia) {
14062  			var time = this._lastTime = +new Date(),
14063  			    pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
14064
14065  			this._positions.push(pos);
14066  			this._times.push(time);
14067
14068  			this._prunePositions(time);
14069  		}
14070
14071  		this._map
14072  		    .fire('move', e)
14073  		    .fire('drag', e);
14074  	},
14075
14076  	_prunePositions: function (time) {
14077  		while (this._positions.length > 1 && time - this._times[0] > 50) {
14078  			this._positions.shift();
14079  			this._times.shift();
14080  		}
14081  	},
14082
14083  	_onZoomEnd: function () {
14084  		var pxCenter = this._map.getSize().divideBy(2),
14085  		    pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
14086
14087  		this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
14088  		this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
14089  	},
14090
14091  	_viscousLimit: function (value, threshold) {
14092  		return value - (value - threshold) * this._viscosity;
14093  	},
14094
14095  	_onPreDragLimit: function () {
14096  		if (!this._viscosity || !this._offsetLimit) { return; }
14097
14098  		var offset = this._draggable._newPos.subtract(this._draggable._startPos);
14099
14100  		var limit = this._offsetLimit;
14101  		if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
14102  		if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
14103  		if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
14104  		if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
14105
14106  		this._draggable._newPos = this._draggable._startPos.add(offset);
14107  	},
14108
14109  	_onPreDragWrap: function () {
14110  		// TODO refactor to be able to adjust map pane position after zoom
14111  		var worldWidth = this._worldWidth,
14112  		    halfWidth = Math.round(worldWidth / 2),
14113  		    dx = this._initialWorldOffset,
14114  		    x = this._draggable._newPos.x,
14115  		    newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
14116  		    newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
14117  		    newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
14118
14119  		this._draggable._absPos = this._draggable._newPos.clone();
14120  		this._draggable._newPos.x = newX;
14121  	},
14122
14123  	_onDragEnd: function (e) {
14124  		var map = this._map,
14125  		    options = map.options,
14126
14127  		    noInertia = !options.inertia || e.noInertia || this._times.length < 2;
14128
14129  		map.fire('dragend', e);
14130
14131  		if (noInertia) {
14132  			map.fire('moveend');
14133
14134  		} else {
14135  			this._prunePositions(+new Date());
14136
14137  			var direction = this._lastPos.subtract(this._positions[0]),
14138  			    duration = (this._lastTime - this._times[0]) / 1000,
14139  			    ease = options.easeLinearity,
14140
14141  			    speedVector = direction.multiplyBy(ease / duration),
14142  			    speed = speedVector.distanceTo([0, 0]),
14143
14144  			    limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
14145  			    limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
14146
14147  			    decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
14148  			    offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
14149
14150  			if (!offset.x && !offset.y) {
14151  				map.fire('moveend');
14152
14153  			} else {
14154  				offset = map._limitOffset(offset, map.options.maxBounds);
14155
14156  				requestAnimFrame(function () {
14157  					map.panBy(offset, {
14158  						duration: decelerationDuration,
14159  						easeLinearity: ease,
14160  						noMoveStart: true,
14161  						animate: true
14162  					});
14163  				});
14164  			}
14165  		}
14166  	}
14167  });
14168
14169  // @section Handlers
14170  // @property dragging: Handler
14171  // Map dragging handler (by both mouse and touch).
14172  Map.addInitHook('addHandler', 'dragging', Drag);
14173
14174  /*
14175   * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
14176   */
14177
14178  // @namespace Map
14179  // @section Keyboard Navigation Options
14180  Map.mergeOptions({
14181  	// @option keyboard: Boolean = true
14182  	// Makes the map focusable and allows users to navigate the map with keyboard
14183  	// arrows and `+`/`-` keys.
14184  	keyboard: true,
14185
14186  	// @option keyboardPanDelta: Number = 80
14187  	// Amount of pixels to pan when pressing an arrow key.
14188  	keyboardPanDelta: 80
14189  });
14190
14191  var Keyboard = Handler.extend({
14192
14193  	keyCodes: {
14194  		left:    [37],
14195  		right:   [39],
14196  		down:    [40],
14197  		up:      [38],
14198  		zoomIn:  [187, 107, 61, 171],
14199  		zoomOut: [189, 109, 54, 173]
14200  	},
14201
14202  	initialize: function (map) {
14203  		this._map = map;
14204
14205  		this._setPanDelta(map.options.keyboardPanDelta);
14206  		this._setZoomDelta(map.options.zoomDelta);
14207  	},
14208
14209  	addHooks: function () {
14210  		var container = this._map._container;
14211
14212  		// make the container focusable by tabbing
14213  		if (container.tabIndex <= 0) {
14214  			container.tabIndex = '0';
14215  		}
14216
14217  		on(container, {
14218  			focus: this._onFocus,
14219  			blur: this._onBlur,
14220  			mousedown: this._onMouseDown
14221  		}, this);
14222
14223  		this._map.on({
14224  			focus: this._addHooks,
14225  			blur: this._removeHooks
14226  		}, this);
14227  	},
14228
14229  	removeHooks: function () {
14230  		this._removeHooks();
14231
14232  		off(this._map._container, {
14233  			focus: this._onFocus,
14234  			blur: this._onBlur,
14235  			mousedown: this._onMouseDown
14236  		}, this);
14237
14238  		this._map.off({
14239  			focus: this._addHooks,
14240  			blur: this._removeHooks
14241  		}, this);
14242  	},
14243
14244  	_onMouseDown: function () {
14245  		if (this._focused) { return; }
14246
14247  		var body = document.body,
14248  		    docEl = document.documentElement,
14249  		    top = body.scrollTop || docEl.scrollTop,
14250  		    left = body.scrollLeft || docEl.scrollLeft;
14251
14252  		this._map._container.focus();
14253
14254  		window.scrollTo(left, top);
14255  	},
14256
14257  	_onFocus: function () {
14258  		this._focused = true;
14259  		this._map.fire('focus');
14260  	},
14261
14262  	_onBlur: function () {
14263  		this._focused = false;
14264  		this._map.fire('blur');
14265  	},
14266
14267  	_setPanDelta: function (panDelta) {
14268  		var keys = this._panKeys = {},
14269  		    codes = this.keyCodes,
14270  		    i, len;
14271
14272  		for (i = 0, len = codes.left.length; i < len; i++) {
14273  			keys[codes.left[i]] = [-1 * panDelta, 0];
14274  		}
14275  		for (i = 0, len = codes.right.length; i < len; i++) {
14276  			keys[codes.right[i]] = [panDelta, 0];
14277  		}
14278  		for (i = 0, len = codes.down.length; i < len; i++) {
14279  			keys[codes.down[i]] = [0, panDelta];
14280  		}
14281  		for (i = 0, len = codes.up.length; i < len; i++) {
14282  			keys[codes.up[i]] = [0, -1 * panDelta];
14283  		}
14284  	},
14285
14286  	_setZoomDelta: function (zoomDelta) {
14287  		var keys = this._zoomKeys = {},
14288  		    codes = this.keyCodes,
14289  		    i, len;
14290
14291  		for (i = 0, len = codes.zoomIn.length; i < len; i++) {
14292  			keys[codes.zoomIn[i]] = zoomDelta;
14293  		}
14294  		for (i = 0, len = codes.zoomOut.length; i < len; i++) {
14295  			keys[codes.zoomOut[i]] = -zoomDelta;
14296  		}
14297  	},
14298
14299  	_addHooks: function () {
14300  		on(document, 'keydown', this._onKeyDown, this);
14301  	},
14302
14303  	_removeHooks: function () {
14304  		off(document, 'keydown', this._onKeyDown, this);
14305  	},
14306
14307  	_onKeyDown: function (e) {
14308  		if (e.altKey || e.ctrlKey || e.metaKey) { return; }
14309
14310  		var key = e.keyCode,
14311  		    map = this._map,
14312  		    offset;
14313
14314  		if (key in this._panKeys) {
14315  			if (!map._panAnim || !map._panAnim._inProgress) {
14316  				offset = this._panKeys[key];
14317  				if (e.shiftKey) {
14318  					offset = toPoint(offset).multiplyBy(3);
14319  				}
14320
14321  				if (map.options.maxBounds) {
14322  					offset = map._limitOffset(toPoint(offset), map.options.maxBounds);
14323  				}
14324
14325  				if (map.options.worldCopyJump) {
14326  					var newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset)));
14327  					map.panTo(newLatLng);
14328  				} else {
14329  					map.panBy(offset);
14330  				}
14331  			}
14332  		} else if (key in this._zoomKeys) {
14333  			map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
14334
14335  		} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {
14336  			map.closePopup();
14337
14338  		} else {
14339  			return;
14340  		}
14341
14342  		stop(e);
14343  	}
14344  });
14345
14346  // @section Handlers
14347  // @section Handlers
14348  // @property keyboard: Handler
14349  // Keyboard navigation handler.
14350  Map.addInitHook('addHandler', 'keyboard', Keyboard);
14351
14352  /*
14353   * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
14354   */
14355
14356  // @namespace Map
14357  // @section Interaction Options
14358  Map.mergeOptions({
14359  	// @section Mouse wheel options
14360  	// @option scrollWheelZoom: Boolean|String = true
14361  	// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
14362  	// it will zoom to the center of the view regardless of where the mouse was.
14363  	scrollWheelZoom: true,
14364
14365  	// @option wheelDebounceTime: Number = 40
14366  	// Limits the rate at which a wheel can fire (in milliseconds). By default
14367  	// user can't zoom via wheel more often than once per 40 ms.
14368  	wheelDebounceTime: 40,
14369
14370  	// @option wheelPxPerZoomLevel: Number = 60
14371  	// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
14372  	// mean a change of one full zoom level. Smaller values will make wheel-zooming
14373  	// faster (and vice versa).
14374  	wheelPxPerZoomLevel: 60
14375  });
14376
14377  var ScrollWheelZoom = Handler.extend({
14378  	addHooks: function () {
14379  		on(this._map._container, 'wheel', this._onWheelScroll, this);
14380
14381  		this._delta = 0;
14382  	},
14383
14384  	removeHooks: function () {
14385  		off(this._map._container, 'wheel', this._onWheelScroll, this);
14386  	},
14387
14388  	_onWheelScroll: function (e) {
14389  		var delta = getWheelDelta(e);
14390
14391  		var debounce = this._map.options.wheelDebounceTime;
14392
14393  		this._delta += delta;
14394  		this._lastMousePos = this._map.mouseEventToContainerPoint(e);
14395
14396  		if (!this._startTime) {
14397  			this._startTime = +new Date();
14398  		}
14399
14400  		var left = Math.max(debounce - (+new Date() - this._startTime), 0);
14401
14402  		clearTimeout(this._timer);
14403  		this._timer = setTimeout(bind(this._performZoom, this), left);
14404
14405  		stop(e);
14406  	},
14407
14408  	_performZoom: function () {
14409  		var map = this._map,
14410  		    zoom = map.getZoom(),
14411  		    snap = this._map.options.zoomSnap || 0;
14412
14413  		map._stop(); // stop panning and fly animations if any
14414
14415  		// map the delta with a sigmoid function to -4..4 range leaning on -1..1
14416  		var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
14417  		    d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
14418  		    d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
14419  		    delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
14420
14421  		this._delta = 0;
14422  		this._startTime = null;
14423
14424  		if (!delta) { return; }
14425
14426  		if (map.options.scrollWheelZoom === 'center') {
14427  			map.setZoom(zoom + delta);
14428  		} else {
14429  			map.setZoomAround(this._lastMousePos, zoom + delta);
14430  		}
14431  	}
14432  });
14433
14434  // @section Handlers
14435  // @property scrollWheelZoom: Handler
14436  // Scroll wheel zoom handler.
14437  Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);
14438
14439  /*
14440   * L.Map.TapHold is used to simulate `contextmenu` event on long hold,
14441   * which otherwise is not fired by mobile Safari.
14442   */
14443
14444  var tapHoldDelay = 600;
14445
14446  // @namespace Map
14447  // @section Interaction Options
14448  Map.mergeOptions({
14449  	// @section Touch interaction options
14450  	// @option tapHold: Boolean
14451  	// Enables simulation of `contextmenu` event, default is `true` for mobile Safari.
14452  	tapHold: Browser.touchNative && Browser.safari && Browser.mobile,
14453
14454  	// @option tapTolerance: Number = 15
14455  	// The max number of pixels a user can shift his finger during touch
14456  	// for it to be considered a valid tap.
14457  	tapTolerance: 15
14458  });
14459
14460  var TapHold = Handler.extend({
14461  	addHooks: function () {
14462  		on(this._map._container, 'touchstart', this._onDown, this);
14463  	},
14464
14465  	removeHooks: function () {
14466  		off(this._map._container, 'touchstart', this._onDown, this);
14467  	},
14468
14469  	_onDown: function (e) {
14470  		clearTimeout(this._holdTimeout);
14471  		if (e.touches.length !== 1) { return; }
14472
14473  		var first = e.touches[0];
14474  		this._startPos = this._newPos = new Point(first.clientX, first.clientY);
14475
14476  		this._holdTimeout = setTimeout(bind(function () {
14477  			this._cancel();
14478  			if (!this._isTapValid()) { return; }
14479
14480  			// prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events
14481  			on(document, 'touchend', preventDefault);
14482  			on(document, 'touchend touchcancel', this._cancelClickPrevent);
14483  			this._simulateEvent('contextmenu', first);
14484  		}, this), tapHoldDelay);
14485
14486  		on(document, 'touchend touchcancel contextmenu', this._cancel, this);
14487  		on(document, 'touchmove', this._onMove, this);
14488  	},
14489
14490  	_cancelClickPrevent: function cancelClickPrevent() {
14491  		off(document, 'touchend', preventDefault);
14492  		off(document, 'touchend touchcancel', cancelClickPrevent);
14493  	},
14494
14495  	_cancel: function () {
14496  		clearTimeout(this._holdTimeout);
14497  		off(document, 'touchend touchcancel contextmenu', this._cancel, this);
14498  		off(document, 'touchmove', this._onMove, this);
14499  	},
14500
14501  	_onMove: function (e) {
14502  		var first = e.touches[0];
14503  		this._newPos = new Point(first.clientX, first.clientY);
14504  	},
14505
14506  	_isTapValid: function () {
14507  		return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
14508  	},
14509
14510  	_simulateEvent: function (type, e) {
14511  		var simulatedEvent = new MouseEvent(type, {
14512  			bubbles: true,
14513  			cancelable: true,
14514  			view: window,
14515  			// detail: 1,
14516  			screenX: e.screenX,
14517  			screenY: e.screenY,
14518  			clientX: e.clientX,
14519  			clientY: e.clientY,
14520  			// button: 2,
14521  			// buttons: 2
14522  		});
14523
14524  		simulatedEvent._simulated = true;
14525
14526  		e.target.dispatchEvent(simulatedEvent);
14527  	}
14528  });
14529
14530  // @section Handlers
14531  // @property tapHold: Handler
14532  // Long tap handler to simulate `contextmenu` event (useful in mobile Safari).
14533  Map.addInitHook('addHandler', 'tapHold', TapHold);
14534
14535  /*
14536   * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
14537   */
14538
14539  // @namespace Map
14540  // @section Interaction Options
14541  Map.mergeOptions({
14542  	// @section Touch interaction options
14543  	// @option touchZoom: Boolean|String = *
14544  	// Whether the map can be zoomed by touch-dragging with two fingers. If
14545  	// passed `'center'`, it will zoom to the center of the view regardless of
14546  	// where the touch events (fingers) were. Enabled for touch-capable web
14547  	// browsers.
14548  	touchZoom: Browser.touch,
14549
14550  	// @option bounceAtZoomLimits: Boolean = true
14551  	// Set it to false if you don't want the map to zoom beyond min/max zoom
14552  	// and then bounce back when pinch-zooming.
14553  	bounceAtZoomLimits: true
14554  });
14555
14556  var TouchZoom = Handler.extend({
14557  	addHooks: function () {
14558  		addClass(this._map._container, 'leaflet-touch-zoom');
14559  		on(this._map._container, 'touchstart', this._onTouchStart, this);
14560  	},
14561
14562  	removeHooks: function () {
14563  		removeClass(this._map._container, 'leaflet-touch-zoom');
14564  		off(this._map._container, 'touchstart', this._onTouchStart, this);
14565  	},
14566
14567  	_onTouchStart: function (e) {
14568  		var map = this._map;
14569  		if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
14570
14571  		var p1 = map.mouseEventToContainerPoint(e.touches[0]),
14572  		    p2 = map.mouseEventToContainerPoint(e.touches[1]);
14573
14574  		this._centerPoint = map.getSize()._divideBy(2);
14575  		this._startLatLng = map.containerPointToLatLng(this._centerPoint);
14576  		if (map.options.touchZoom !== 'center') {
14577  			this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
14578  		}
14579
14580  		this._startDist = p1.distanceTo(p2);
14581  		this._startZoom = map.getZoom();
14582
14583  		this._moved = false;
14584  		this._zooming = true;
14585
14586  		map._stop();
14587
14588  		on(document, 'touchmove', this._onTouchMove, this);
14589  		on(document, 'touchend touchcancel', this._onTouchEnd, this);
14590
14591  		preventDefault(e);
14592  	},
14593
14594  	_onTouchMove: function (e) {
14595  		if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
14596
14597  		var map = this._map,
14598  		    p1 = map.mouseEventToContainerPoint(e.touches[0]),
14599  		    p2 = map.mouseEventToContainerPoint(e.touches[1]),
14600  		    scale = p1.distanceTo(p2) / this._startDist;
14601
14602  		this._zoom = map.getScaleZoom(scale, this._startZoom);
14603
14604  		if (!map.options.bounceAtZoomLimits && (
14605  			(this._zoom < map.getMinZoom() && scale < 1) ||
14606  			(this._zoom > map.getMaxZoom() && scale > 1))) {
14607  			this._zoom = map._limitZoom(this._zoom);
14608  		}
14609
14610  		if (map.options.touchZoom === 'center') {
14611  			this._center = this._startLatLng;
14612  			if (scale === 1) { return; }
14613  		} else {
14614  			// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
14615  			var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
14616  			if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
14617  			this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
14618  		}
14619
14620  		if (!this._moved) {
14621  			map._moveStart(true, false);
14622  			this._moved = true;
14623  		}
14624
14625  		cancelAnimFrame(this._animRequest);
14626
14627  		var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}, undefined);
14628  		this._animRequest = requestAnimFrame(moveFn, this, true);
14629
14630  		preventDefault(e);
14631  	},
14632
14633  	_onTouchEnd: function () {
14634  		if (!this._moved || !this._zooming) {
14635  			this._zooming = false;
14636  			return;
14637  		}
14638
14639  		this._zooming = false;
14640  		cancelAnimFrame(this._animRequest);
14641
14642  		off(document, 'touchmove', this._onTouchMove, this);
14643  		off(document, 'touchend touchcancel', this._onTouchEnd, this);
14644
14645  		// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
14646  		if (this._map.options.zoomAnimation) {
14647  			this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
14648  		} else {
14649  			this._map._resetView(this._center, this._map._limitZoom(this._zoom));
14650  		}
14651  	}
14652  });
14653
14654  // @section Handlers
14655  // @property touchZoom: Handler
14656  // Touch zoom handler.
14657  Map.addInitHook('addHandler', 'touchZoom', TouchZoom);
14658
14659  Map.BoxZoom = BoxZoom;
14660  Map.DoubleClickZoom = DoubleClickZoom;
14661  Map.Drag = Drag;
14662  Map.Keyboard = Keyboard;
14663  Map.ScrollWheelZoom = ScrollWheelZoom;
14664  Map.TapHold = TapHold;
14665  Map.TouchZoom = TouchZoom;
14666
14667  exports.Bounds = Bounds;
14668  exports.Browser = Browser;
14669  exports.CRS = CRS;
14670  exports.Canvas = Canvas;
14671  exports.Circle = Circle;
14672  exports.CircleMarker = CircleMarker;
14673  exports.Class = Class;
14674  exports.Control = Control;
14675  exports.DivIcon = DivIcon;
14676  exports.DivOverlay = DivOverlay;
14677  exports.DomEvent = DomEvent;
14678  exports.DomUtil = DomUtil;
14679  exports.Draggable = Draggable;
14680  exports.Evented = Evented;
14681  exports.FeatureGroup = FeatureGroup;
14682  exports.GeoJSON = GeoJSON;
14683  exports.GridLayer = GridLayer;
14684  exports.Handler = Handler;
14685  exports.Icon = Icon;
14686  exports.ImageOverlay = ImageOverlay;
14687  exports.LatLng = LatLng;
14688  exports.LatLngBounds = LatLngBounds;
14689  exports.Layer = Layer;
14690  exports.LayerGroup = LayerGroup;
14691  exports.LineUtil = LineUtil;
14692  exports.Map = Map;
14693  exports.Marker = Marker;
14694  exports.Mixin = Mixin;
14695  exports.Path = Path;
14696  exports.Point = Point;
14697  exports.PolyUtil = PolyUtil;
14698  exports.Polygon = Polygon;
14699  exports.Polyline = Polyline;
14700  exports.Popup = Popup;
14701  exports.PosAnimation = PosAnimation;
14702  exports.Projection = index;
14703  exports.Rectangle = Rectangle;
14704  exports.Renderer = Renderer;
14705  exports.SVG = SVG;
14706  exports.SVGOverlay = SVGOverlay;
14707  exports.TileLayer = TileLayer;
14708  exports.Tooltip = Tooltip;
14709  exports.Transformation = Transformation;
14710  exports.Util = Util;
14711  exports.VideoOverlay = VideoOverlay;
14712  exports.bind = bind;
14713  exports.bounds = toBounds;
14714  exports.canvas = canvas;
14715  exports.circle = circle;
14716  exports.circleMarker = circleMarker;
14717  exports.control = control;
14718  exports.divIcon = divIcon;
14719  exports.extend = extend;
14720  exports.featureGroup = featureGroup;
14721  exports.geoJSON = geoJSON;
14722  exports.geoJson = geoJson;
14723  exports.gridLayer = gridLayer;
14724  exports.icon = icon;
14725  exports.imageOverlay = imageOverlay;
14726  exports.latLng = toLatLng;
14727  exports.latLngBounds = toLatLngBounds;
14728  exports.layerGroup = layerGroup;
14729  exports.map = createMap;
14730  exports.marker = marker;
14731  exports.point = toPoint;
14732  exports.polygon = polygon;
14733  exports.polyline = polyline;
14734  exports.popup = popup;
14735  exports.rectangle = rectangle;
14736  exports.setOptions = setOptions;
14737  exports.stamp = stamp;
14738  exports.svg = svg;
14739  exports.svgOverlay = svgOverlay;
14740  exports.tileLayer = tileLayer;
14741  exports.tooltip = tooltip;
14742  exports.transformation = toTransformation;
14743  exports.version = version;
14744  exports.videoOverlay = videoOverlay;
14745
14746  var oldL = window.L;
14747  exports.noConflict = function() {
14748  	window.L = oldL;
14749  	return this;
14750  }
14751  // Always export us to window global (see #2364)
14752  window.L = exports;
14753
14754}));
14755//# sourceMappingURL=leaflet-src.js.map
14756
14757
14758/***/ }),
14759
14760/***/ "./resources/css/app.css":
14761/*!*******************************!*\
14762  !*** ./resources/css/app.css ***!
14763  \*******************************/
14764/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
14765
14766"use strict";
14767__webpack_require__.r(__webpack_exports__);
14768// extracted by mini-css-extract-plugin
14769
14770
14771/***/ }),
14772
14773/***/ "./resources/css/editor-style.css":
14774/*!****************************************!*\
14775  !*** ./resources/css/editor-style.css ***!
14776  \****************************************/
14777/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
14778
14779"use strict";
14780__webpack_require__.r(__webpack_exports__);
14781// extracted by mini-css-extract-plugin
14782
14783
14784/***/ }),
14785
vendor: 2,242 bytes, lines 14786-14815
14786/***/ "./node_modules/leaflet/dist/leaflet.css":
14787/*!***********************************************!*\
14788  !*** ./node_modules/leaflet/dist/leaflet.css ***!
14789  \***********************************************/
14790/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
14791
14792"use strict";
14793__webpack_require__.r(__webpack_exports__);
14794/* harmony export */ __webpack_require__.d(__webpack_exports__, {
14795/* harmony export */   "default": () => (__WEBPACK_DEFAULT_EXPORT__)
14796/* harmony export */ });
14797/* harmony import */ var _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !../../style-loader/dist/runtime/injectStylesIntoStyleTag.js */ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js");
14798/* harmony import */ var _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0__);
14799/* harmony import */ var _css_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_1_postcss_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_2_leaflet_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! !!../../css-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[1]!../../postcss-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[2]!./leaflet.css */ "./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[7].oneOf[1].use[2]!./node_modules/leaflet/dist/leaflet.css");
14800
14801            
14802
14803var options = {};
14804
14805options.insert = "head";
14806options.singleton = false;
14807
14808var update = _style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()(_css_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_1_postcss_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_2_leaflet_css__WEBPACK_IMPORTED_MODULE_1__["default"], options);
14809
14810
14811
14812/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_css_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_1_postcss_loader_dist_cjs_js_ruleSet_1_rules_7_oneOf_1_use_2_leaflet_css__WEBPACK_IMPORTED_MODULE_1__["default"].locals || {});
14813
14814/***/ }),
14815
vendor: 7,479 bytes, lines 14816-15094
14816/***/ "./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js":
14817/*!****************************************************************************!*\
14818  !*** ./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js ***!
14819  \****************************************************************************/
14820/***/ ((module, __unused_webpack_exports, __webpack_require__) => {
14821
14822"use strict";
14823
14824
14825var isOldIE = function isOldIE() {
14826  var memo;
14827  return function memorize() {
14828    if (typeof memo === 'undefined') {
14829      // Test for IE <= 9 as proposed by Browserhacks
14830      // @see http://browserhacks.com/#hack-e71d8692f65334173fee715c222cb805
14831      // Tests for existence of standard globals is to allow style-loader
14832      // to operate correctly into non-standard environments
14833      // @see https://github.com/webpack-contrib/style-loader/issues/177
14834      memo = Boolean(window && document && document.all && !window.atob);
14835    }
14836
14837    return memo;
14838  };
14839}();
14840
14841var getTarget = function getTarget() {
14842  var memo = {};
14843  return function memorize(target) {
14844    if (typeof memo[target] === 'undefined') {
14845      var styleTarget = document.querySelector(target); // Special case to return head of iframe instead of iframe itself
14846
14847      if (window.HTMLIFrameElement && styleTarget instanceof window.HTMLIFrameElement) {
14848        try {
14849          // This will throw an exception if access to iframe is blocked
14850          // due to cross-origin restrictions
14851          styleTarget = styleTarget.contentDocument.head;
14852        } catch (e) {
14853          // istanbul ignore next
14854          styleTarget = null;
14855        }
14856      }
14857
14858      memo[target] = styleTarget;
14859    }
14860
14861    return memo[target];
14862  };
14863}();
14864
14865var stylesInDom = [];
14866
14867function getIndexByIdentifier(identifier) {
14868  var result = -1;
14869
14870  for (var i = 0; i < stylesInDom.length; i++) {
14871    if (stylesInDom[i].identifier === identifier) {
14872      result = i;
14873      break;
14874    }
14875  }
14876
14877  return result;
14878}
14879
14880function modulesToDom(list, options) {
14881  var idCountMap = {};
14882  var identifiers = [];
14883
14884  for (var i = 0; i < list.length; i++) {
14885    var item = list[i];
14886    var id = options.base ? item[0] + options.base : item[0];
14887    var count = idCountMap[id] || 0;
14888    var identifier = "".concat(id, " ").concat(count);
14889    idCountMap[id] = count + 1;
14890    var index = getIndexByIdentifier(identifier);
14891    var obj = {
14892      css: item[1],
14893      media: item[2],
14894      sourceMap: item[3]
14895    };
14896
14897    if (index !== -1) {
14898      stylesInDom[index].references++;
14899      stylesInDom[index].updater(obj);
14900    } else {
14901      stylesInDom.push({
14902        identifier: identifier,
14903        updater: addStyle(obj, options),
14904        references: 1
14905      });
14906    }
14907
14908    identifiers.push(identifier);
14909  }
14910
14911  return identifiers;
14912}
14913
14914function insertStyleElement(options) {
14915  var style = document.createElement('style');
14916  var attributes = options.attributes || {};
14917
14918  if (typeof attributes.nonce === 'undefined') {
14919    var nonce =  true ? __webpack_require__.nc : 0;
14920
14921    if (nonce) {
14922      attributes.nonce = nonce;
14923    }
14924  }
14925
14926  Object.keys(attributes).forEach(function (key) {
14927    style.setAttribute(key, attributes[key]);
14928  });
14929
14930  if (typeof options.insert === 'function') {
14931    options.insert(style);
14932  } else {
14933    var target = getTarget(options.insert || 'head');
14934
14935    if (!target) {
14936      throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
14937    }
14938
14939    target.appendChild(style);
14940  }
14941
14942  return style;
14943}
14944
14945function removeStyleElement(style) {
14946  // istanbul ignore if
14947  if (style.parentNode === null) {
14948    return false;
14949  }
14950
14951  style.parentNode.removeChild(style);
14952}
14953/* istanbul ignore next  */
14954
14955
14956var replaceText = function replaceText() {
14957  var textStore = [];
14958  return function replace(index, replacement) {
14959    textStore[index] = replacement;
14960    return textStore.filter(Boolean).join('\n');
14961  };
14962}();
14963
14964function applyToSingletonTag(style, index, remove, obj) {
14965  var css = remove ? '' : obj.media ? "@media ".concat(obj.media, " {").concat(obj.css, "}") : obj.css; // For old IE
14966
14967  /* istanbul ignore if  */
14968
14969  if (style.styleSheet) {
14970    style.styleSheet.cssText = replaceText(index, css);
14971  } else {
14972    var cssNode = document.createTextNode(css);
14973    var childNodes = style.childNodes;
14974
14975    if (childNodes[index]) {
14976      style.removeChild(childNodes[index]);
14977    }
14978
14979    if (childNodes.length) {
14980      style.insertBefore(cssNode, childNodes[index]);
14981    } else {
14982      style.appendChild(cssNode);
14983    }
14984  }
14985}
14986
14987function applyToTag(style, options, obj) {
14988  var css = obj.css;
14989  var media = obj.media;
14990  var sourceMap = obj.sourceMap;
14991
14992  if (media) {
14993    style.setAttribute('media', media);
14994  } else {
14995    style.removeAttribute('media');
14996  }
14997
14998  if (sourceMap && typeof btoa !== 'undefined') {
14999    css += "\n/*# sourceMappingURL=data:application/json;base64,".concat(btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))), " */");
15000  } // For old IE
15001
15002  /* istanbul ignore if  */
15003
15004
15005  if (style.styleSheet) {
15006    style.styleSheet.cssText = css;
15007  } else {
15008    while (style.firstChild) {
15009      style.removeChild(style.firstChild);
15010    }
15011
15012    style.appendChild(document.createTextNode(css));
15013  }
15014}
15015
15016var singleton = null;
15017var singletonCounter = 0;
15018
15019function addStyle(obj, options) {
15020  var style;
15021  var update;
15022  var remove;
15023
15024  if (options.singleton) {
15025    var styleIndex = singletonCounter++;
15026    style = singleton || (singleton = insertStyleElement(options));
15027    update = applyToSingletonTag.bind(null, style, styleIndex, false);
15028    remove = applyToSingletonTag.bind(null, style, styleIndex, true);
15029  } else {
15030    style = insertStyleElement(options);
15031    update = applyToTag.bind(null, style, options);
15032
15033    remove = function remove() {
15034      removeStyleElement(style);
15035    };
15036  }
15037
15038  update(obj);
15039  return function updateStyle(newObj) {
15040    if (newObj) {
15041      if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) {
15042        return;
15043      }
15044
15045      update(obj = newObj);
15046    } else {
15047      remove();
15048    }
15049  };
15050}
15051
15052module.exports = function (list, options) {
15053  options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style>
15054  // tags it will allow on a page
15055
15056  if (!options.singleton && typeof options.singleton !== 'boolean') {
15057    options.singleton = isOldIE();
15058  }
15059
15060  list = list || [];
15061  var lastIdentifiers = modulesToDom(list, options);
15062  return function update(newList) {
15063    newList = newList || [];
15064
15065    if (Object.prototype.toString.call(newList) !== '[object Array]') {
15066      return;
15067    }
15068
15069    for (var i = 0; i < lastIdentifiers.length; i++) {
15070      var identifier = lastIdentifiers[i];
15071      var index = getIndexByIdentifier(identifier);
15072      stylesInDom[index].references--;
15073    }
15074
15075    var newLastIdentifiers = modulesToDom(newList, options);
15076
15077    for (var _i = 0; _i < lastIdentifiers.length; _i++) {
15078      var _identifier = lastIdentifiers[_i];
15079
15080      var _index = getIndexByIdentifier(_identifier);
15081
15082      if (stylesInDom[_index].references === 0) {
15083        stylesInDom[_index].updater();
15084
15085        stylesInDom.splice(_index, 1);
15086      }
15087    }
15088
15089    lastIdentifiers = newLastIdentifiers;
15090  };
15091};
15092
15093/***/ }),
15094
vendor: 8,158 bytes, lines 15095-15382
15095/***/ "./node_modules/superfish/dist/js/superfish.js":
15096/*!*****************************************************!*\
15097  !*** ./node_modules/superfish/dist/js/superfish.js ***!
15098  \*****************************************************/
15099/***/ (() => {
15100
15101/*
15102 * jQuery Superfish Menu Plugin - v1.7.10
15103 * Copyright (c) 2018 Joel Birch
15104 *
15105 * Dual licensed under the MIT and GPL licenses:
15106 *	http://www.opensource.org/licenses/mit-license.php
15107 *	http://www.gnu.org/licenses/gpl.html
15108 */
15109
15110;(function ($, w) {
15111	"use strict";
15112
15113	var methods = (function () {
15114		// private properties and methods go here
15115		var c = {
15116				bcClass: 'sf-breadcrumb',
15117				menuClass: 'sf-js-enabled',
15118				anchorClass: 'sf-with-ul',
15119				menuArrowClass: 'sf-arrows'
15120			},
15121			ios = (function () {
15122				var ios = /^(?![\w\W]*Windows Phone)[\w\W]*(iPhone|iPad|iPod)/i.test(navigator.userAgent);
15123				if (ios) {
15124					// tap anywhere on iOS to unfocus a submenu
15125					$('html').css('cursor', 'pointer').on('click', $.noop);
15126				}
15127				return ios;
15128			})(),
15129			wp7 = (function () {
15130				var style = document.documentElement.style;
15131				return ('behavior' in style && 'fill' in style && /iemobile/i.test(navigator.userAgent));
15132			})(),
15133			unprefixedPointerEvents = (function () {
15134				return (!!w.PointerEvent);
15135			})(),
15136			toggleMenuClasses = function ($menu, o, add) {
15137				var classes = c.menuClass,
15138					method;
15139				if (o.cssArrows) {
15140					classes += ' ' + c.menuArrowClass;
15141				}
15142				method = (add) ? 'addClass' : 'removeClass';
15143				$menu[method](classes);
15144			},
15145			setPathToCurrent = function ($menu, o) {
15146				return $menu.find('li.' + o.pathClass).slice(0, o.pathLevels)
15147					.addClass(o.hoverClass + ' ' + c.bcClass)
15148						.filter(function () {
15149							return ($(this).children(o.popUpSelector).hide().show().length);
15150						}).removeClass(o.pathClass);
15151			},
15152			toggleAnchorClass = function ($li, add) {
15153				var method = (add) ? 'addClass' : 'removeClass';
15154				$li.children('a')[method](c.anchorClass);
15155			},
15156			toggleTouchAction = function ($menu) {
15157				var msTouchAction = $menu.css('ms-touch-action');
15158				var touchAction = $menu.css('touch-action');
15159				touchAction = touchAction || msTouchAction;
15160				touchAction = (touchAction === 'pan-y') ? 'auto' : 'pan-y';
15161				$menu.css({
15162					'ms-touch-action': touchAction,
15163					'touch-action': touchAction
15164				});
15165			},
15166			getMenu = function ($el) {
15167				return $el.closest('.' + c.menuClass);
15168			},
15169			getOptions = function ($el) {
15170				return getMenu($el).data('sfOptions');
15171			},
15172			over = function () {
15173				var $this = $(this),
15174					o = getOptions($this);
15175				clearTimeout(o.sfTimer);
15176				$this.siblings().superfish('hide').end().superfish('show');
15177			},
15178			close = function (o) {
15179				o.retainPath = ($.inArray(this[0], o.$path) > -1);
15180				this.superfish('hide');
15181
15182				if (!this.parents('.' + o.hoverClass).length) {
15183					o.onIdle.call(getMenu(this));
15184					if (o.$path.length) {
15185						$.proxy(over, o.$path)();
15186					}
15187				}
15188			},
15189			out = function () {
15190				var $this = $(this),
15191					o = getOptions($this);
15192				if (ios) {
15193					$.proxy(close, $this, o)();
15194				}
15195				else {
15196					clearTimeout(o.sfTimer);
15197					o.sfTimer = setTimeout($.proxy(close, $this, o), o.delay);
15198				}
15199			},
15200			touchHandler = function (e) {
15201				var $this = $(this),
15202					o = getOptions($this),
15203					$ul = $this.siblings(e.data.popUpSelector);
15204
15205				if (o.onHandleTouch.call($ul) === false) {
15206					return this;
15207				}
15208
15209				if ($ul.length > 0 && $ul.is(':hidden')) {
15210					$this.one('click.superfish', false);
15211					if (e.type === 'MSPointerDown' || e.type === 'pointerdown') {
15212						$this.trigger('focus');
15213					} else {
15214						$.proxy(over, $this.parent('li'))();
15215					}
15216				}
15217			},
15218			applyHandlers = function ($menu, o) {
15219				var targets = 'li:has(' + o.popUpSelector + ')';
15220				if ($.fn.hoverIntent && !o.disableHI) {
15221					$menu.hoverIntent(over, out, targets);
15222				}
15223				else {
15224					$menu
15225						.on('mouseenter.superfish', targets, over)
15226						.on('mouseleave.superfish', targets, out);
15227				}
15228				var touchevent = 'MSPointerDown.superfish';
15229				if (unprefixedPointerEvents) {
15230					touchevent = 'pointerdown.superfish';
15231				}
15232				if (!ios) {
15233					touchevent += ' touchend.superfish';
15234				}
15235				if (wp7) {
15236					touchevent += ' mousedown.superfish';
15237				}
15238				$menu
15239					.on('focusin.superfish', 'li', over)
15240					.on('focusout.superfish', 'li', out)
15241					.on(touchevent, 'a', o, touchHandler);
15242			};
15243
15244		return {
15245			// public methods
15246			hide: function (instant) {
15247				if (this.length) {
15248					var $this = this,
15249						o = getOptions($this);
15250					if (!o) {
15251						return this;
15252					}
15253					var not = (o.retainPath === true) ? o.$path : '',
15254						$ul = $this.find('li.' + o.hoverClass).add(this).not(not).removeClass(o.hoverClass).children(o.popUpSelector),
15255						speed = o.speedOut;
15256
15257					if (instant) {
15258						$ul.show();
15259						speed = 0;
15260					}
15261					o.retainPath = false;
15262
15263					if (o.onBeforeHide.call($ul) === false) {
15264						return this;
15265					}
15266
15267					$ul.stop(true, true).animate(o.animationOut, speed, function () {
15268						var $this = $(this);
15269						o.onHide.call($this);
15270					});
15271				}
15272				return this;
15273			},
15274			show: function () {
15275				var o = getOptions(this);
15276				if (!o) {
15277					return this;
15278				}
15279				var $this = this.addClass(o.hoverClass),
15280					$ul = $this.children(o.popUpSelector);
15281
15282				if (o.onBeforeShow.call($ul) === false) {
15283					return this;
15284				}
15285
15286				$ul.stop(true, true).animate(o.animation, o.speed, function () {
15287					o.onShow.call($ul);
15288				});
15289				return this;
15290			},
15291			destroy: function () {
15292				return this.each(function () {
15293					var $this = $(this),
15294						o = $this.data('sfOptions'),
15295						$hasPopUp;
15296					if (!o) {
15297						return false;
15298					}
15299					$hasPopUp = $this.find(o.popUpSelector).parent('li');
15300					clearTimeout(o.sfTimer);
15301					toggleMenuClasses($this, o);
15302					toggleAnchorClass($hasPopUp);
15303					toggleTouchAction($this);
15304					// remove event handlers
15305					$this.off('.superfish').off('.hoverIntent');
15306					// clear animation's inline display style
15307					$hasPopUp.children(o.popUpSelector).attr('style', function (i, style) {
15308						if (typeof style !== 'undefined') {
15309							return style.replace(/display[^;]+;?/g, '');
15310						}
15311					});
15312					// reset 'current' path classes
15313					o.$path.removeClass(o.hoverClass + ' ' + c.bcClass).addClass(o.pathClass);
15314					$this.find('.' + o.hoverClass).removeClass(o.hoverClass);
15315					o.onDestroy.call($this);
15316					$this.removeData('sfOptions');
15317				});
15318			},
15319			init: function (op) {
15320				return this.each(function () {
15321					var $this = $(this);
15322					if ($this.data('sfOptions')) {
15323						return false;
15324					}
15325					var o = $.extend({}, $.fn.superfish.defaults, op),
15326						$hasPopUp = $this.find(o.popUpSelector).parent('li');
15327					o.$path = setPathToCurrent($this, o);
15328
15329					$this.data('sfOptions', o);
15330
15331					toggleMenuClasses($this, o, true);
15332					toggleAnchorClass($hasPopUp, true);
15333					toggleTouchAction($this);
15334					applyHandlers($this, o);
15335
15336					$hasPopUp.not('.' + c.bcClass).superfish('hide', true);
15337
15338					o.onInit.call(this);
15339				});
15340			}
15341		};
15342	})();
15343
15344	$.fn.superfish = function (method, args) {
15345		if (methods[method]) {
15346			return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
15347		}
15348		else if (typeof method === 'object' || ! method) {
15349			return methods.init.apply(this, arguments);
15350		}
15351		else {
15352			return $.error('Method ' +  method + ' does not exist on jQuery.fn.superfish');
15353		}
15354	};
15355
15356	$.fn.superfish.defaults = {
15357		popUpSelector: 'ul,.sf-mega', // within menu context
15358		hoverClass: 'sfHover',
15359		pathClass: 'overrideThisToUse',
15360		pathLevels: 1,
15361		delay: 800,
15362		animation: {opacity: 'show'},
15363		animationOut: {opacity: 'hide'},
15364		speed: 'normal',
15365		speedOut: 'fast',
15366		cssArrows: true,
15367		disableHI: false,
15368		onInit: $.noop,
15369		onBeforeShow: $.noop,
15370		onShow: $.noop,
15371		onBeforeHide: $.noop,
15372		onHide: $.noop,
15373		onIdle: $.noop,
15374		onDestroy: $.noop,
15375		onHandleTouch: $.noop
15376	};
15377
15378})(jQuery, window);
15379
15380
15381/***/ }),
15382
vendor: 94,925 bytes, lines 15383-19288
15383/***/ "./node_modules/@glidejs/glide/dist/glide.esm.js":
15384/*!*******************************************************!*\
15385  !*** ./node_modules/@glidejs/glide/dist/glide.esm.js ***!
15386  \*******************************************************/
15387/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
15388
15389"use strict";
15390__webpack_require__.r(__webpack_exports__);
15391/* harmony export */ __webpack_require__.d(__webpack_exports__, {
15392/* harmony export */   "default": () => (/* binding */ Glide)
15393/* harmony export */ });
15394/*!
15395 * Glide.js v3.6.2
15396 * (c) 2013-2024 Jędrzej Chałubek (https://github.com/jedrzejchalubek/)
15397 * Released under the MIT License.
15398 */
15399
15400function ownKeys(object, enumerableOnly) {
15401  var keys = Object.keys(object);
15402
15403  if (Object.getOwnPropertySymbols) {
15404    var symbols = Object.getOwnPropertySymbols(object);
15405
15406    if (enumerableOnly) {
15407      symbols = symbols.filter(function (sym) {
15408        return Object.getOwnPropertyDescriptor(object, sym).enumerable;
15409      });
15410    }
15411
15412    keys.push.apply(keys, symbols);
15413  }
15414
15415  return keys;
15416}
15417
15418function _objectSpread2(target) {
15419  for (var i = 1; i < arguments.length; i++) {
15420    var source = arguments[i] != null ? arguments[i] : {};
15421
15422    if (i % 2) {
15423      ownKeys(Object(source), true).forEach(function (key) {
15424        _defineProperty(target, key, source[key]);
15425      });
15426    } else if (Object.getOwnPropertyDescriptors) {
15427      Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
15428    } else {
15429      ownKeys(Object(source)).forEach(function (key) {
15430        Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
15431      });
15432    }
15433  }
15434
15435  return target;
15436}
15437
15438function _typeof(obj) {
15439  "@babel/helpers - typeof";
15440
15441  if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") {
15442    _typeof = function (obj) {
15443      return typeof obj;
15444    };
15445  } else {
15446    _typeof = function (obj) {
15447      return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
15448    };
15449  }
15450
15451  return _typeof(obj);
15452}
15453
15454function _classCallCheck(instance, Constructor) {
15455  if (!(instance instanceof Constructor)) {
15456    throw new TypeError("Cannot call a class as a function");
15457  }
15458}
15459
15460function _defineProperties(target, props) {
15461  for (var i = 0; i < props.length; i++) {
15462    var descriptor = props[i];
15463    descriptor.enumerable = descriptor.enumerable || false;
15464    descriptor.configurable = true;
15465    if ("value" in descriptor) descriptor.writable = true;
15466    Object.defineProperty(target, descriptor.key, descriptor);
15467  }
15468}
15469
15470function _createClass(Constructor, protoProps, staticProps) {
15471  if (protoProps) _defineProperties(Constructor.prototype, protoProps);
15472  if (staticProps) _defineProperties(Constructor, staticProps);
15473  return Constructor;
15474}
15475
15476function _defineProperty(obj, key, value) {
15477  if (key in obj) {
15478    Object.defineProperty(obj, key, {
15479      value: value,
15480      enumerable: true,
15481      configurable: true,
15482      writable: true
15483    });
15484  } else {
15485    obj[key] = value;
15486  }
15487
15488  return obj;
15489}
15490
15491function _inherits(subClass, superClass) {
15492  if (typeof superClass !== "function" && superClass !== null) {
15493    throw new TypeError("Super expression must either be null or a function");
15494  }
15495
15496  subClass.prototype = Object.create(superClass && superClass.prototype, {
15497    constructor: {
15498      value: subClass,
15499      writable: true,
15500      configurable: true
15501    }
15502  });
15503  if (superClass) _setPrototypeOf(subClass, superClass);
15504}
15505
15506function _getPrototypeOf(o) {
15507  _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {
15508    return o.__proto__ || Object.getPrototypeOf(o);
15509  };
15510  return _getPrototypeOf(o);
15511}
15512
15513function _setPrototypeOf(o, p) {
15514  _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {
15515    o.__proto__ = p;
15516    return o;
15517  };
15518
15519  return _setPrototypeOf(o, p);
15520}
15521
15522function _isNativeReflectConstruct() {
15523  if (typeof Reflect === "undefined" || !Reflect.construct) return false;
15524  if (Reflect.construct.sham) return false;
15525  if (typeof Proxy === "function") return true;
15526
15527  try {
15528    Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
15529    return true;
15530  } catch (e) {
15531    return false;
15532  }
15533}
15534
15535function _assertThisInitialized(self) {
15536  if (self === void 0) {
15537    throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
15538  }
15539
15540  return self;
15541}
15542
15543function _possibleConstructorReturn(self, call) {
15544  if (call && (typeof call === "object" || typeof call === "function")) {
15545    return call;
15546  } else if (call !== void 0) {
15547    throw new TypeError("Derived constructors may only return object or undefined");
15548  }
15549
15550  return _assertThisInitialized(self);
15551}
15552
15553function _createSuper(Derived) {
15554  var hasNativeReflectConstruct = _isNativeReflectConstruct();
15555
15556  return function _createSuperInternal() {
15557    var Super = _getPrototypeOf(Derived),
15558        result;
15559
15560    if (hasNativeReflectConstruct) {
15561      var NewTarget = _getPrototypeOf(this).constructor;
15562
15563      result = Reflect.construct(Super, arguments, NewTarget);
15564    } else {
15565      result = Super.apply(this, arguments);
15566    }
15567
15568    return _possibleConstructorReturn(this, result);
15569  };
15570}
15571
15572function _superPropBase(object, property) {
15573  while (!Object.prototype.hasOwnProperty.call(object, property)) {
15574    object = _getPrototypeOf(object);
15575    if (object === null) break;
15576  }
15577
15578  return object;
15579}
15580
15581function _get() {
15582  if (typeof Reflect !== "undefined" && Reflect.get) {
15583    _get = Reflect.get;
15584  } else {
15585    _get = function _get(target, property, receiver) {
15586      var base = _superPropBase(target, property);
15587
15588      if (!base) return;
15589      var desc = Object.getOwnPropertyDescriptor(base, property);
15590
15591      if (desc.get) {
15592        return desc.get.call(arguments.length < 3 ? target : receiver);
15593      }
15594
15595      return desc.value;
15596    };
15597  }
15598
15599  return _get.apply(this, arguments);
15600}
15601
15602var defaults = {
15603  /**
15604   * Type of the movement.
15605   *
15606   * Available types:
15607   * `slider` - Rewinds slider to the start/end when it reaches the first or last slide.
15608   * `carousel` - Changes slides without starting over when it reaches the first or last slide.
15609   *
15610   * @type {String}
15611   */
15612  type: 'slider',
15613
15614  /**
15615   * Start at specific slide number defined with zero-based index.
15616   *
15617   * @type {Number}
15618   */
15619  startAt: 0,
15620
15621  /**
15622   * A number of slides visible on the single viewport.
15623   *
15624   * @type {Number}
15625   */
15626  perView: 1,
15627
15628  /**
15629   * Focus currently active slide at a specified position in the track.
15630   *
15631   * Available inputs:
15632   * `center` - Current slide will be always focused at the center of a track.
15633   * `0,1,2,3...` - Current slide will be focused on the specified zero-based index.
15634   *
15635   * @type {String|Number}
15636   */
15637  focusAt: 0,
15638
15639  /**
15640   * A size of the gap added between slides.
15641   *
15642   * @type {Number}
15643   */
15644  gap: 10,
15645
15646  /**
15647   * Change slides after a specified interval. Use `false` for turning off autoplay.
15648   *
15649   * @type {Number|Boolean}
15650   */
15651  autoplay: false,
15652
15653  /**
15654   * Stop autoplay on mouseover event.
15655   *
15656   * @type {Boolean}
15657   */
15658  hoverpause: true,
15659
15660  /**
15661   * Allow for changing slides with left and right keyboard arrows.
15662   *
15663   * @type {Boolean}
15664   */
15665  keyboard: true,
15666
15667  /**
15668   * Stop running `perView` number of slides from the end. Use this
15669   * option if you don't want to have an empty space after
15670   * a slider. Works only with `slider` type and a
15671   * non-centered `focusAt` setting.
15672   *
15673   * @type {Boolean}
15674   */
15675  bound: false,
15676
15677  /**
15678   * Minimal swipe distance needed to change the slide. Use `false` for turning off a swiping.
15679   *
15680   * @type {Number|Boolean}
15681   */
15682  swipeThreshold: 80,
15683
15684  /**
15685   * Minimal mouse drag distance needed to change the slide. Use `false` for turning off a dragging.
15686   *
15687   * @type {Number|Boolean}
15688   */
15689  dragThreshold: 120,
15690
15691  /**
15692   * A number of slides moved on single swipe.
15693   *
15694   * Available types:
15695   * `` - Moves slider by one slide per swipe
15696   * `|` - Moves slider between views per swipe (number of slides defined in `perView` options)
15697   *
15698   * @type {String}
15699   */
15700  perSwipe: '',
15701
15702  /**
15703   * Moving distance ratio of the slides on a swiping and dragging.
15704   *
15705   * @type {Number}
15706   */
15707  touchRatio: 0.5,
15708
15709  /**
15710   * Angle required to activate slides moving on swiping or dragging.
15711   *
15712   * @type {Number}
15713   */
15714  touchAngle: 45,
15715
15716  /**
15717   * Duration of the animation in milliseconds.
15718   *
15719   * @type {Number}
15720   */
15721  animationDuration: 400,
15722
15723  /**
15724   * Allows looping the `slider` type. Slider will rewind to the first/last slide when it's at the start/end.
15725   *
15726   * @type {Boolean}
15727   */
15728  rewind: true,
15729
15730  /**
15731   * Duration of the rewinding animation of the `slider` type in milliseconds.
15732   *
15733   * @type {Number}
15734   */
15735  rewindDuration: 800,
15736
15737  /**
15738   * Easing function for the animation.
15739   *
15740   * @type {String}
15741   */
15742  animationTimingFunc: 'cubic-bezier(.165, .840, .440, 1)',
15743
15744  /**
15745   * Wait for the animation to finish until the next user input can be processed
15746   *
15747   * @type {boolean}
15748   */
15749  waitForTransition: true,
15750
15751  /**
15752   * Throttle costly events at most once per every wait milliseconds.
15753   *
15754   * @type {Number}
15755   */
15756  throttle: 10,
15757
15758  /**
15759   * Moving direction mode.
15760   *
15761   * Available inputs:
15762   * - 'ltr' - left to right movement,
15763   * - 'rtl' - right to left movement.
15764   *
15765   * @type {String}
15766   */
15767  direction: 'ltr',
15768
15769  /**
15770   * The distance value of the next and previous viewports which
15771   * have to peek in the current view. Accepts number and
15772   * pixels as a string. Left and right peeking can be
15773   * set up separately with a directions object.
15774   *
15775   * For example:
15776   * `100` - Peek 100px on the both sides.
15777   * { before: 100, after: 50 }` - Peek 100px on the left side and 50px on the right side.
15778   *
15779   * @type {Number|String|Object}
15780   */
15781  peek: 0,
15782
15783  /**
15784   * Defines how many clones of current viewport will be generated.
15785   *
15786   * @type {Number}
15787   */
15788  cloningRatio: 1,
15789
15790  /**
15791   * Collection of options applied at specified media breakpoints.
15792   * For example: display two slides per view under 800px.
15793   * `{
15794   *   '800px': {
15795   *     perView: 2
15796   *   }
15797   * }`
15798   */
15799  breakpoints: {},
15800
15801  /**
15802   * Collection of internally used HTML classes.
15803   *
15804   * @todo Refactor `slider` and `carousel` properties to single `type: { slider: '', carousel: '' }` object
15805   * @type {Object}
15806   */
15807  classes: {
15808    swipeable: 'glide--swipeable',
15809    dragging: 'glide--dragging',
15810    direction: {
15811      ltr: 'glide--ltr',
15812      rtl: 'glide--rtl'
15813    },
15814    type: {
15815      slider: 'glide--slider',
15816      carousel: 'glide--carousel'
15817    },
15818    slide: {
15819      clone: 'glide__slide--clone',
15820      active: 'glide__slide--active'
15821    },
15822    arrow: {
15823      disabled: 'glide__arrow--disabled'
15824    },
15825    nav: {
15826      active: 'glide__bullet--active'
15827    }
15828  }
15829};
15830
15831/**
15832 * Outputs warning message to the bowser console.
15833 *
15834 * @param  {String} msg
15835 * @return {Void}
15836 */
15837function warn(msg) {
15838  console.error("[Glide warn]: ".concat(msg));
15839}
15840
15841/**
15842 * Converts value entered as number
15843 * or string to integer value.
15844 *
15845 * @param {String} value
15846 * @returns {Number}
15847 */
15848function toInt(value) {
15849  return parseInt(value);
15850}
15851/**
15852 * Converts value entered as number
15853 * or string to flat value.
15854 *
15855 * @param {String} value
15856 * @returns {Number}
15857 */
15858
15859function toFloat(value) {
15860  return parseFloat(value);
15861}
15862/**
15863 * Indicates whether the specified value is a string.
15864 *
15865 * @param  {*}   value
15866 * @return {Boolean}
15867 */
15868
15869function isString(value) {
15870  return typeof value === 'string';
15871}
15872/**
15873 * Indicates whether the specified value is an object.
15874 *
15875 * @param  {*} value
15876 * @return {Boolean}
15877 *
15878 * @see https://github.com/jashkenas/underscore
15879 */
15880
15881function isObject(value) {
15882  var type = _typeof(value);
15883
15884  return type === 'function' || type === 'object' && !!value; // eslint-disable-line no-mixed-operators
15885}
15886/**
15887 * Indicates whether the specified value is a function.
15888 *
15889 * @param  {*} value
15890 * @return {Boolean}
15891 */
15892
15893function isFunction(value) {
15894  return typeof value === 'function';
15895}
15896/**
15897 * Indicates whether the specified value is undefined.
15898 *
15899 * @param  {*} value
15900 * @return {Boolean}
15901 */
15902
15903function isUndefined(value) {
15904  return typeof value === 'undefined';
15905}
15906/**
15907 * Indicates whether the specified value is an array.
15908 *
15909 * @param  {*} value
15910 * @return {Boolean}
15911 */
15912
15913function isArray(value) {
15914  return value.constructor === Array;
15915}
15916
15917/**
15918 * Creates and initializes specified collection of extensions.
15919 * Each extension receives access to instance of glide and rest of components.
15920 *
15921 * @param {Object} glide
15922 * @param {Object} extensions
15923 *
15924 * @returns {Object}
15925 */
15926
15927function mount(glide, extensions, events) {
15928  var components = {};
15929
15930  for (var name in extensions) {
15931    if (isFunction(extensions[name])) {
15932      components[name] = extensions[name](glide, components, events);
15933    } else {
15934      warn('Extension must be a function');
15935    }
15936  }
15937
15938  for (var _name in components) {
15939    if (isFunction(components[_name].mount)) {
15940      components[_name].mount();
15941    }
15942  }
15943
15944  return components;
15945}
15946
15947/**
15948 * Defines getter and setter property on the specified object.
15949 *
15950 * @param  {Object} obj         Object where property has to be defined.
15951 * @param  {String} prop        Name of the defined property.
15952 * @param  {Object} definition  Get and set definitions for the property.
15953 * @return {Void}
15954 */
15955function define(obj, prop, definition) {
15956  Object.defineProperty(obj, prop, definition);
15957}
15958/**
15959 * Sorts aphabetically object keys.
15960 *
15961 * @param  {Object} obj
15962 * @return {Object}
15963 */
15964
15965function sortKeys(obj) {
15966  return Object.keys(obj).sort().reduce(function (r, k) {
15967    r[k] = obj[k];
15968    return r[k], r;
15969  }, {});
15970}
15971/**
15972 * Merges passed settings object with default options.
15973 *
15974 * @param  {Object} defaults
15975 * @param  {Object} settings
15976 * @return {Object}
15977 */
15978
15979function mergeOptions(defaults, settings) {
15980  var options = Object.assign({}, defaults, settings); // `Object.assign` do not deeply merge objects, so we
15981  // have to do it manually for every nested object
15982  // in options. Although it does not look smart,
15983  // it's smaller and faster than some fancy
15984  // merging deep-merge algorithm script.
15985
15986  if (settings.hasOwnProperty('classes')) {
15987    options.classes = Object.assign({}, defaults.classes, settings.classes);
15988    var properties = ['direction', 'type', 'slide', 'arrow', 'nav'];
15989    properties.forEach(function (property) {
15990      if (settings.classes.hasOwnProperty(property)) {
15991        options.classes[property] = _objectSpread2(_objectSpread2({}, defaults.classes[property]), settings.classes[property]);
15992      }
15993    });
15994  }
15995
15996  if (settings.hasOwnProperty('breakpoints')) {
15997    options.breakpoints = Object.assign({}, defaults.breakpoints, settings.breakpoints);
15998  }
15999
16000  return options;
16001}
16002
16003var EventsBus = /*#__PURE__*/function () {
16004  /**
16005   * Construct a EventBus instance.
16006   *
16007   * @param {Object} events
16008   */
16009  function EventsBus() {
16010    var events = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
16011
16012    _classCallCheck(this, EventsBus);
16013
16014    this.events = events;
16015    this.hop = events.hasOwnProperty;
16016  }
16017  /**
16018   * Adds listener to the specifed event.
16019   *
16020   * @param {String|Array} event
16021   * @param {Function} handler
16022   */
16023
16024
16025  _createClass(EventsBus, [{
16026    key: "on",
16027    value: function on(event, handler) {
16028      if (isArray(event)) {
16029        for (var i = 0; i < event.length; i++) {
16030          this.on(event[i], handler);
16031        }
16032
16033        return;
16034      } // Create the event's object if not yet created
16035
16036
16037      if (!this.hop.call(this.events, event)) {
16038        this.events[event] = [];
16039      } // Add the handler to queue
16040
16041
16042      var index = this.events[event].push(handler) - 1; // Provide handle back for removal of event
16043
16044      return {
16045        remove: function remove() {
16046          delete this.events[event][index];
16047        }
16048      };
16049    }
16050    /**
16051     * Runs registered handlers for specified event.
16052     *
16053     * @param {String|Array} event
16054     * @param {Object=} context
16055     */
16056
16057  }, {
16058    key: "emit",
16059    value: function emit(event, context) {
16060      if (isArray(event)) {
16061        for (var i = 0; i < event.length; i++) {
16062          this.emit(event[i], context);
16063        }
16064
16065        return;
16066      } // If the event doesn't exist, or there's no handlers in queue, just leave
16067
16068
16069      if (!this.hop.call(this.events, event)) {
16070        return;
16071      } // Cycle through events queue, fire!
16072
16073
16074      this.events[event].forEach(function (item) {
16075        item(context || {});
16076      });
16077    }
16078  }]);
16079
16080  return EventsBus;
16081}();
16082
16083var Glide$1 = /*#__PURE__*/function () {
16084  /**
16085   * Construct glide.
16086   *
16087   * @param  {String} selector
16088   * @param  {Object} options
16089   */
16090  function Glide(selector) {
16091    var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
16092
16093    _classCallCheck(this, Glide);
16094
16095    this._c = {};
16096    this._t = [];
16097    this._e = new EventsBus();
16098    this.disabled = false;
16099    this.selector = selector;
16100    this.settings = mergeOptions(defaults, options);
16101    this.index = this.settings.startAt;
16102  }
16103  /**
16104   * Initializes glide.
16105   *
16106   * @param {Object} extensions Collection of extensions to initialize.
16107   * @return {Glide}
16108   */
16109
16110
16111  _createClass(Glide, [{
16112    key: "mount",
16113    value: function mount$1() {
16114      var extensions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
16115
16116      this._e.emit('mount.before');
16117
16118      if (isObject(extensions)) {
16119        this._c = mount(this, extensions, this._e);
16120      } else {
16121        warn('You need to provide a object on `mount()`');
16122      }
16123
16124      this._e.emit('mount.after');
16125
16126      return this;
16127    }
16128    /**
16129     * Collects an instance `translate` transformers.
16130     *
16131     * @param  {Array} transformers Collection of transformers.
16132     * @return {Void}
16133     */
16134
16135  }, {
16136    key: "mutate",
16137    value: function mutate() {
16138      var transformers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
16139
16140      if (isArray(transformers)) {
16141        this._t = transformers;
16142      } else {
16143        warn('You need to provide a array on `mutate()`');
16144      }
16145
16146      return this;
16147    }
16148    /**
16149     * Updates glide with specified settings.
16150     *
16151     * @param {Object} settings
16152     * @return {Glide}
16153     */
16154
16155  }, {
16156    key: "update",
16157    value: function update() {
16158      var settings = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
16159      this.settings = mergeOptions(this.settings, settings);
16160
16161      if (settings.hasOwnProperty('startAt')) {
16162        this.index = settings.startAt;
16163      }
16164
16165      this._e.emit('update');
16166
16167      return this;
16168    }
16169    /**
16170     * Change slide with specified pattern. A pattern must be in the special format:
16171     * `>` - Move one forward
16172     * `<` - Move one backward
16173     * `={i}` - Go to {i} zero-based slide (eq. '=1', will go to second slide)
16174     * `>>` - Rewinds to end (last slide)
16175     * `<<` - Rewinds to start (first slide)
16176     * `|>` - Move one viewport forward
16177     * `|<` - Move one viewport backward
16178     *
16179     * @param {String} pattern
16180     * @return {Glide}
16181     */
16182
16183  }, {
16184    key: "go",
16185    value: function go(pattern) {
16186      this._c.Run.make(pattern);
16187
16188      return this;
16189    }
16190    /**
16191     * Move track by specified distance.
16192     *
16193     * @param {String} distance
16194     * @return {Glide}
16195     */
16196
16197  }, {
16198    key: "move",
16199    value: function move(distance) {
16200      this._c.Transition.disable();
16201
16202      this._c.Move.make(distance);
16203
16204      return this;
16205    }
16206    /**
16207     * Destroy instance and revert all changes done by this._c.
16208     *
16209     * @return {Glide}
16210     */
16211
16212  }, {
16213    key: "destroy",
16214    value: function destroy() {
16215      this._e.emit('destroy');
16216
16217      return this;
16218    }
16219    /**
16220     * Start instance autoplaying.
16221     *
16222     * @param {Boolean|Number} interval Run autoplaying with passed interval regardless of `autoplay` settings
16223     * @return {Glide}
16224     */
16225
16226  }, {
16227    key: "play",
16228    value: function play() {
16229      var interval = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
16230
16231      if (interval) {
16232        this.settings.autoplay = interval;
16233      }
16234
16235      this._e.emit('play');
16236
16237      return this;
16238    }
16239    /**
16240     * Stop instance autoplaying.
16241     *
16242     * @return {Glide}
16243     */
16244
16245  }, {
16246    key: "pause",
16247    value: function pause() {
16248      this._e.emit('pause');
16249
16250      return this;
16251    }
16252    /**
16253     * Sets glide into a idle status.
16254     *
16255     * @return {Glide}
16256     */
16257
16258  }, {
16259    key: "disable",
16260    value: function disable() {
16261      this.disabled = true;
16262      return this;
16263    }
16264    /**
16265     * Sets glide into a active status.
16266     *
16267     * @return {Glide}
16268     */
16269
16270  }, {
16271    key: "enable",
16272    value: function enable() {
16273      this.disabled = false;
16274      return this;
16275    }
16276    /**
16277     * Adds cuutom event listener with handler.
16278     *
16279     * @param  {String|Array} event
16280     * @param  {Function} handler
16281     * @return {Glide}
16282     */
16283
16284  }, {
16285    key: "on",
16286    value: function on(event, handler) {
16287      this._e.on(event, handler);
16288
16289      return this;
16290    }
16291    /**
16292     * Checks if glide is a precised type.
16293     *
16294     * @param  {String} name
16295     * @return {Boolean}
16296     */
16297
16298  }, {
16299    key: "isType",
16300    value: function isType(name) {
16301      return this.settings.type === name;
16302    }
16303    /**
16304     * Gets value of the core options.
16305     *
16306     * @return {Object}
16307     */
16308
16309  }, {
16310    key: "settings",
16311    get: function get() {
16312      return this._o;
16313    }
16314    /**
16315     * Sets value of the core options.
16316     *
16317     * @param  {Object} o
16318     * @return {Void}
16319     */
16320    ,
16321    set: function set(o) {
16322      if (isObject(o)) {
16323        this._o = o;
16324      } else {
16325        warn('Options must be an `object` instance.');
16326      }
16327    }
16328    /**
16329     * Gets current index of the slider.
16330     *
16331     * @return {Object}
16332     */
16333
16334  }, {
16335    key: "index",
16336    get: function get() {
16337      return this._i;
16338    }
16339    /**
16340     * Sets current index a slider.
16341     *
16342     * @return {Object}
16343     */
16344    ,
16345    set: function set(i) {
16346      this._i = toInt(i);
16347    }
16348    /**
16349     * Gets type name of the slider.
16350     *
16351     * @return {String}
16352     */
16353
16354  }, {
16355    key: "type",
16356    get: function get() {
16357      return this.settings.type;
16358    }
16359    /**
16360     * Gets value of the idle status.
16361     *
16362     * @return {Boolean}
16363     */
16364
16365  }, {
16366    key: "disabled",
16367    get: function get() {
16368      return this._d;
16369    }
16370    /**
16371     * Sets value of the idle status.
16372     *
16373     * @return {Boolean}
16374     */
16375    ,
16376    set: function set(status) {
16377      this._d = !!status;
16378    }
16379  }]);
16380
16381  return Glide;
16382}();
16383
16384function Run (Glide, Components, Events) {
16385  var Run = {
16386    /**
16387     * Initializes autorunning of the glide.
16388     *
16389     * @return {Void}
16390     */
16391    mount: function mount() {
16392      this._o = false;
16393    },
16394
16395    /**
16396     * Makes glides running based on the passed moving schema.
16397     *
16398     * @param {String} move
16399     */
16400    make: function make(move) {
16401      var _this = this;
16402
16403      if (!Glide.disabled) {
16404        !Glide.settings.waitForTransition || Glide.disable();
16405        this.move = move;
16406        Events.emit('run.before', this.move);
16407        this.calculate();
16408        Events.emit('run', this.move);
16409        Components.Transition.after(function () {
16410          if (_this.isStart()) {
16411            Events.emit('run.start', _this.move);
16412          }
16413
16414          if (_this.isEnd()) {
16415            Events.emit('run.end', _this.move);
16416          }
16417
16418          if (_this.isOffset()) {
16419            _this._o = false;
16420            Events.emit('run.offset', _this.move);
16421          }
16422
16423          Events.emit('run.after', _this.move);
16424          Glide.enable();
16425        });
16426      }
16427    },
16428
16429    /**
16430     * Calculates current index based on defined move.
16431     *
16432     * @return {Number|Undefined}
16433     */
16434    calculate: function calculate() {
16435      var move = this.move,
16436          length = this.length;
16437      var steps = move.steps,
16438          direction = move.direction; // By default assume that size of view is equal to one slide
16439
16440      var viewSize = 1; // While direction is `=` we want jump to
16441      // a specified index described in steps.
16442
16443      if (direction === '=') {
16444        // Check if bound is true, 
16445        // as we want to avoid whitespaces.
16446        if (Glide.settings.bound && toInt(steps) > length) {
16447          Glide.index = length;
16448          return;
16449        }
16450
16451        Glide.index = steps;
16452        return;
16453      } // When pattern is equal to `>>` we want
16454      // fast forward to the last slide.
16455
16456
16457      if (direction === '>' && steps === '>') {
16458        Glide.index = length;
16459        return;
16460      } // When pattern is equal to `<<` we want
16461      // fast forward to the first slide.
16462
16463
16464      if (direction === '<' && steps === '<') {
16465        Glide.index = 0;
16466        return;
16467      } // pagination movement
16468
16469
16470      if (direction === '|') {
16471        viewSize = Glide.settings.perView || 1;
16472      } // we are moving forward
16473
16474
16475      if (direction === '>' || direction === '|' && steps === '>') {
16476        var index = calculateForwardIndex(viewSize);
16477
16478        if (index > length) {
16479          this._o = true;
16480        }
16481
16482        Glide.index = normalizeForwardIndex(index, viewSize);
16483        return;
16484      } // we are moving backward
16485
16486
16487      if (direction === '<' || direction === '|' && steps === '<') {
16488        var _index = calculateBackwardIndex(viewSize);
16489
16490        if (_index < 0) {
16491          this._o = true;
16492        }
16493
16494        Glide.index = normalizeBackwardIndex(_index, viewSize);
16495        return;
16496      }
16497
16498      warn("Invalid direction pattern [".concat(direction).concat(steps, "] has been used"));
16499    },
16500
16501    /**
16502     * Checks if we are on the first slide.
16503     *
16504     * @return {Boolean}
16505     */
16506    isStart: function isStart() {
16507      return Glide.index <= 0;
16508    },
16509
16510    /**
16511     * Checks if we are on the last slide.
16512     *
16513     * @return {Boolean}
16514     */
16515    isEnd: function isEnd() {
16516      return Glide.index >= this.length;
16517    },
16518
16519    /**
16520     * Checks if we are making a offset run.
16521     *
16522     * @param {String} direction
16523     * @return {Boolean}
16524     */
16525    isOffset: function isOffset() {
16526      var direction = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : undefined;
16527
16528      if (!direction) {
16529        return this._o;
16530      }
16531
16532      if (!this._o) {
16533        return false;
16534      } // did we view to the right?
16535
16536
16537      if (direction === '|>') {
16538        return this.move.direction === '|' && this.move.steps === '>';
16539      } // did we view to the left?
16540
16541
16542      if (direction === '|<') {
16543        return this.move.direction === '|' && this.move.steps === '<';
16544      }
16545
16546      return this.move.direction === direction;
16547    },
16548
16549    /**
16550     * Checks if bound mode is active
16551     *
16552     * @return {Boolean}
16553     */
16554    isBound: function isBound() {
16555      return Glide.isType('slider') && Glide.settings.focusAt !== 'center' && Glide.settings.bound;
16556    }
16557  };
16558  /**
16559   * Returns index value to move forward/to the right
16560   *
16561   * @param viewSize
16562   * @returns {Number}
16563   */
16564
16565  function calculateForwardIndex(viewSize) {
16566    var index = Glide.index;
16567
16568    if (Glide.isType('carousel')) {
16569      return index + viewSize;
16570    }
16571
16572    return index + (viewSize - index % viewSize);
16573  }
16574  /**
16575   * Normalizes the given forward index based on glide settings, preventing it to exceed certain boundaries
16576   *
16577   * @param index
16578   * @param length
16579   * @param viewSize
16580   * @returns {Number}
16581   */
16582
16583
16584  function normalizeForwardIndex(index, viewSize) {
16585    var length = Run.length;
16586
16587    if (index <= length) {
16588      return index;
16589    }
16590
16591    if (Glide.isType('carousel')) {
16592      return index - (length + 1);
16593    }
16594
16595    if (Glide.settings.rewind) {
16596      // bound does funny things with the length, therefor we have to be certain
16597      // that we are on the last possible index value given by bound
16598      if (Run.isBound() && !Run.isEnd()) {
16599        return length;
16600      }
16601
16602      return 0;
16603    }
16604
16605    if (Run.isBound()) {
16606      return length;
16607    }
16608
16609    return Math.floor(length / viewSize) * viewSize;
16610  }
16611  /**
16612   * Calculates index value to move backward/to the left
16613   *
16614   * @param viewSize
16615   * @returns {Number}
16616   */
16617
16618
16619  function calculateBackwardIndex(viewSize) {
16620    var index = Glide.index;
16621
16622    if (Glide.isType('carousel')) {
16623      return index - viewSize;
16624    } // ensure our back navigation results in the same index as a forward navigation
16625    // to experience a homogeneous paging
16626
16627
16628    var view = Math.ceil(index / viewSize);
16629    return (view - 1) * viewSize;
16630  }
16631  /**
16632   * Normalizes the given backward index based on glide settings, preventing it to exceed certain boundaries
16633   *
16634   * @param index
16635   * @param length
16636   * @param viewSize
16637   * @returns {*}
16638   */
16639
16640
16641  function normalizeBackwardIndex(index, viewSize) {
16642    var length = Run.length;
16643
16644    if (index >= 0) {
16645      return index;
16646    }
16647
16648    if (Glide.isType('carousel')) {
16649      return index + (length + 1);
16650    }
16651
16652    if (Glide.settings.rewind) {
16653      // bound does funny things with the length, therefor we have to be certain
16654      // that we are on first possible index value before we to rewind to the length given by bound
16655      if (Run.isBound() && Run.isStart()) {
16656        return length;
16657      }
16658
16659      return Math.floor(length / viewSize) * viewSize;
16660    }
16661
16662    return 0;
16663  }
16664
16665  define(Run, 'move', {
16666    /**
16667     * Gets value of the move schema.
16668     *
16669     * @returns {Object}
16670     */
16671    get: function get() {
16672      return this._m;
16673    },
16674
16675    /**
16676     * Sets value of the move schema.
16677     *
16678     * @returns {Object}
16679     */
16680    set: function set(value) {
16681      var step = value.substr(1);
16682      this._m = {
16683        direction: value.substr(0, 1),
16684        steps: step ? toInt(step) ? toInt(step) : step : 0
16685      };
16686    }
16687  });
16688  define(Run, 'length', {
16689    /**
16690     * Gets value of the running distance based
16691     * on zero-indexing number of slides.
16692     *
16693     * @return {Number}
16694     */
16695    get: function get() {
16696      var settings = Glide.settings;
16697      var length = Components.Html.slides.length; // If the `bound` option is active, a maximum running distance should be
16698      // reduced by `perView` and `focusAt` settings. Running distance
16699      // should end before creating an empty space after instance.
16700
16701      if (this.isBound()) {
16702        return length - 1 - (toInt(settings.perView) - 1) + toInt(settings.focusAt);
16703      }
16704
16705      return length - 1;
16706    }
16707  });
16708  define(Run, 'offset', {
16709    /**
16710     * Gets status of the offsetting flag.
16711     *
16712     * @return {Boolean}
16713     */
16714    get: function get() {
16715      return this._o;
16716    }
16717  });
16718  return Run;
16719}
16720
16721/**
16722 * Returns a current time.
16723 *
16724 * @return {Number}
16725 */
16726function now() {
16727  return new Date().getTime();
16728}
16729
16730/**
16731 * Returns a function, that, when invoked, will only be triggered
16732 * at most once during a given window of time.
16733 *
16734 * @param {Function} func
16735 * @param {Number} wait
16736 * @param {Object=} options
16737 * @return {Function}
16738 *
16739 * @see https://github.com/jashkenas/underscore
16740 */
16741
16742function throttle(func, wait) {
16743  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
16744  var timeout, context, args, result;
16745  var previous = 0;
16746
16747  var later = function later() {
16748    previous = options.leading === false ? 0 : now();
16749    timeout = null;
16750    result = func.apply(context, args);
16751    if (!timeout) context = args = null;
16752  };
16753
16754  var throttled = function throttled() {
16755    var at = now();
16756    if (!previous && options.leading === false) previous = at;
16757    var remaining = wait - (at - previous);
16758    context = this;
16759    args = arguments;
16760
16761    if (remaining <= 0 || remaining > wait) {
16762      if (timeout) {
16763        clearTimeout(timeout);
16764        timeout = null;
16765      }
16766
16767      previous = at;
16768      result = func.apply(context, args);
16769      if (!timeout) context = args = null;
16770    } else if (!timeout && options.trailing !== false) {
16771      timeout = setTimeout(later, remaining);
16772    }
16773
16774    return result;
16775  };
16776
16777  throttled.cancel = function () {
16778    clearTimeout(timeout);
16779    previous = 0;
16780    timeout = context = args = null;
16781  };
16782
16783  return throttled;
16784}
16785
16786var MARGIN_TYPE = {
16787  ltr: ['marginLeft', 'marginRight'],
16788  rtl: ['marginRight', 'marginLeft']
16789};
16790function Gaps (Glide, Components, Events) {
16791  var Gaps = {
16792    /**
16793     * Applies gaps between slides. First and last
16794     * slides do not receive it's edge margins.
16795     *
16796     * @param {HTMLCollection} slides
16797     * @return {Void}
16798     */
16799    apply: function apply(slides) {
16800      for (var i = 0, len = slides.length; i < len; i++) {
16801        var style = slides[i].style;
16802        var direction = Components.Direction.value;
16803
16804        if (i !== 0) {
16805          style[MARGIN_TYPE[direction][0]] = "".concat(this.value / 2, "px");
16806        } else {
16807          style[MARGIN_TYPE[direction][0]] = '';
16808        }
16809
16810        if (i !== slides.length - 1) {
16811          style[MARGIN_TYPE[direction][1]] = "".concat(this.value / 2, "px");
16812        } else {
16813          style[MARGIN_TYPE[direction][1]] = '';
16814        }
16815      }
16816    },
16817
16818    /**
16819     * Removes gaps from the slides.
16820     *
16821     * @param {HTMLCollection} slides
16822     * @returns {Void}
16823    */
16824    remove: function remove(slides) {
16825      for (var i = 0, len = slides.length; i < len; i++) {
16826        var style = slides[i].style;
16827        style.marginLeft = '';
16828        style.marginRight = '';
16829      }
16830    }
16831  };
16832  define(Gaps, 'value', {
16833    /**
16834     * Gets value of the gap.
16835     *
16836     * @returns {Number}
16837     */
16838    get: function get() {
16839      return toInt(Glide.settings.gap);
16840    }
16841  });
16842  define(Gaps, 'grow', {
16843    /**
16844     * Gets additional dimensions value caused by gaps.
16845     * Used to increase width of the slides wrapper.
16846     *
16847     * @returns {Number}
16848     */
16849    get: function get() {
16850      return Gaps.value * Components.Sizes.length;
16851    }
16852  });
16853  define(Gaps, 'reductor', {
16854    /**
16855     * Gets reduction value caused by gaps.
16856     * Used to subtract width of the slides.
16857     *
16858     * @returns {Number}
16859     */
16860    get: function get() {
16861      var perView = Glide.settings.perView;
16862      return Gaps.value * (perView - 1) / perView;
16863    }
16864  });
16865  /**
16866   * Apply calculated gaps:
16867   * - after building, so slides (including clones) will receive proper margins
16868   * - on updating via API, to recalculate gaps with new options
16869   */
16870
16871  Events.on(['build.after', 'update'], throttle(function () {
16872    Gaps.apply(Components.Html.wrapper.children);
16873  }, 30));
16874  /**
16875   * Remove gaps:
16876   * - on destroying to bring markup to its inital state
16877   */
16878
16879  Events.on('destroy', function () {
16880    Gaps.remove(Components.Html.wrapper.children);
16881  });
16882  return Gaps;
16883}
16884
16885/**
16886 * Finds siblings nodes of the passed node.
16887 *
16888 * @param  {Element} node
16889 * @return {Array}
16890 */
16891function siblings(node) {
16892  if (node && node.parentNode) {
16893    var n = node.parentNode.firstChild;
16894    var matched = [];
16895
16896    for (; n; n = n.nextSibling) {
16897      if (n.nodeType === 1 && n !== node) {
16898        matched.push(n);
16899      }
16900    }
16901
16902    return matched;
16903  }
16904
16905  return [];
16906}
16907/**
16908 * Coerces a NodeList to an Array.
16909 *
16910 * @param  {NodeList} nodeList
16911 * @return {Array}
16912 */
16913
16914function toArray(nodeList) {
16915  return Array.prototype.slice.call(nodeList);
16916}
16917
16918var TRACK_SELECTOR = '[data-glide-el="track"]';
16919function Html (Glide, Components, Events) {
16920  var Html = {
16921    /**
16922     * Setup slider HTML nodes.
16923     *
16924     * @param {Glide} glide
16925     */
16926    mount: function mount() {
16927      this.root = Glide.selector;
16928      this.track = this.root.querySelector(TRACK_SELECTOR);
16929      this.collectSlides();
16930    },
16931
16932    /**
16933     * Collect slides
16934     */
16935    collectSlides: function collectSlides() {
16936      this.slides = toArray(this.wrapper.children).filter(function (slide) {
16937        return !slide.classList.contains(Glide.settings.classes.slide.clone);
16938      });
16939    }
16940  };
16941  define(Html, 'root', {
16942    /**
16943     * Gets node of the glide main element.
16944     *
16945     * @return {Object}
16946     */
16947    get: function get() {
16948      return Html._r;
16949    },
16950
16951    /**
16952     * Sets node of the glide main element.
16953     *
16954     * @return {Object}
16955     */
16956    set: function set(r) {
16957      if (isString(r)) {
16958        r = document.querySelector(r);
16959      }
16960
16961      if (r !== null) {
16962        Html._r = r;
16963      } else {
16964        warn('Root element must be a existing Html node');
16965      }
16966    }
16967  });
16968  define(Html, 'track', {
16969    /**
16970     * Gets node of the glide track with slides.
16971     *
16972     * @return {Object}
16973     */
16974    get: function get() {
16975      return Html._t;
16976    },
16977
16978    /**
16979     * Sets node of the glide track with slides.
16980     *
16981     * @return {Object}
16982     */
16983    set: function set(t) {
16984      Html._t = t;
16985    }
16986  });
16987  define(Html, 'wrapper', {
16988    /**
16989     * Gets node of the slides wrapper.
16990     *
16991     * @return {Object}
16992     */
16993    get: function get() {
16994      return Html.track.children[0];
16995    }
16996  });
16997  /**
16998   * Add/remove/reorder dynamic slides
16999   */
17000
17001  Events.on('update', function () {
17002    Html.collectSlides();
17003  });
17004  return Html;
17005}
17006
17007function Peek (Glide, Components, Events) {
17008  var Peek = {
17009    /**
17010     * Setups how much to peek based on settings.
17011     *
17012     * @return {Void}
17013     */
17014    mount: function mount() {
17015      this.value = Glide.settings.peek;
17016    }
17017  };
17018  define(Peek, 'value', {
17019    /**
17020     * Gets value of the peek.
17021     *
17022     * @returns {Number|Object}
17023     */
17024    get: function get() {
17025      return Peek._v;
17026    },
17027
17028    /**
17029     * Sets value of the peek.
17030     *
17031     * @param {Number|Object} value
17032     * @return {Void}
17033     */
17034    set: function set(value) {
17035      if (isObject(value)) {
17036        value.before = toInt(value.before);
17037        value.after = toInt(value.after);
17038      } else {
17039        value = toInt(value);
17040      }
17041
17042      Peek._v = value;
17043    }
17044  });
17045  define(Peek, 'reductor', {
17046    /**
17047     * Gets reduction value caused by peek.
17048     *
17049     * @returns {Number}
17050     */
17051    get: function get() {
17052      var value = Peek.value;
17053      var perView = Glide.settings.perView;
17054
17055      if (isObject(value)) {
17056        return value.before / perView + value.after / perView;
17057      }
17058
17059      return value * 2 / perView;
17060    }
17061  });
17062  /**
17063   * Recalculate peeking sizes on:
17064   * - when resizing window to update to proper percents
17065   */
17066
17067  Events.on(['resize', 'update'], function () {
17068    Peek.mount();
17069  });
17070  return Peek;
17071}
17072
17073function Move (Glide, Components, Events) {
17074  var Move = {
17075    /**
17076     * Constructs move component.
17077     *
17078     * @returns {Void}
17079     */
17080    mount: function mount() {
17081      this._o = 0;
17082    },
17083
17084    /**
17085     * Calculates a movement value based on passed offset and currently active index.
17086     *
17087     * @param  {Number} offset
17088     * @return {Void}
17089     */
17090    make: function make() {
17091      var _this = this;
17092
17093      var offset = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
17094      this.offset = offset;
17095      Events.emit('move', {
17096        movement: this.value
17097      });
17098      Components.Transition.after(function () {
17099        Events.emit('move.after', {
17100          movement: _this.value
17101        });
17102      });
17103    }
17104  };
17105  define(Move, 'offset', {
17106    /**
17107     * Gets an offset value used to modify current translate.
17108     *
17109     * @return {Object}
17110     */
17111    get: function get() {
17112      return Move._o;
17113    },
17114
17115    /**
17116     * Sets an offset value used to modify current translate.
17117     *
17118     * @return {Object}
17119     */
17120    set: function set(value) {
17121      Move._o = !isUndefined(value) ? toInt(value) : 0;
17122    }
17123  });
17124  define(Move, 'translate', {
17125    /**
17126     * Gets a raw movement value.
17127     *
17128     * @return {Number}
17129     */
17130    get: function get() {
17131      return Components.Sizes.slideWidth * Glide.index;
17132    }
17133  });
17134  define(Move, 'value', {
17135    /**
17136     * Gets an actual movement value corrected by offset.
17137     *
17138     * @return {Number}
17139     */
17140    get: function get() {
17141      var offset = this.offset;
17142      var translate = this.translate;
17143
17144      if (Components.Direction.is('rtl')) {
17145        return translate + offset;
17146      }
17147
17148      return translate - offset;
17149    }
17150  });
17151  /**
17152   * Make movement to proper slide on:
17153   * - before build, so glide will start at `startAt` index
17154   * - on each standard run to move to newly calculated index
17155   */
17156
17157  Events.on(['build.before', 'run'], function () {
17158    Move.make();
17159  });
17160  return Move;
17161}
17162
17163function Sizes (Glide, Components, Events) {
17164  var Sizes = {
17165    /**
17166     * Setups dimensions of slides.
17167     *
17168     * @return {Void}
17169     */
17170    setupSlides: function setupSlides() {
17171      var width = "".concat(this.slideWidth, "px");
17172      var slides = Components.Html.slides;
17173
17174      for (var i = 0; i < slides.length; i++) {
17175        slides[i].style.width = width;
17176      }
17177    },
17178
17179    /**
17180     * Setups dimensions of slides wrapper.
17181     *
17182     * @return {Void}
17183     */
17184    setupWrapper: function setupWrapper() {
17185      Components.Html.wrapper.style.width = "".concat(this.wrapperSize, "px");
17186    },
17187
17188    /**
17189     * Removes applied styles from HTML elements.
17190     *
17191     * @returns {Void}
17192     */
17193    remove: function remove() {
17194      var slides = Components.Html.slides;
17195
17196      for (var i = 0; i < slides.length; i++) {
17197        slides[i].style.width = '';
17198      }
17199
17200      Components.Html.wrapper.style.width = '';
17201    }
17202  };
17203  define(Sizes, 'length', {
17204    /**
17205     * Gets count number of the slides.
17206     *
17207     * @return {Number}
17208     */
17209    get: function get() {
17210      return Components.Html.slides.length;
17211    }
17212  });
17213  define(Sizes, 'width', {
17214    /**
17215     * Gets width value of the slider (visible area).
17216     *
17217     * @return {Number}
17218     */
17219    get: function get() {
17220      return Components.Html.track.offsetWidth;
17221    }
17222  });
17223  define(Sizes, 'wrapperSize', {
17224    /**
17225     * Gets size of the slides wrapper.
17226     *
17227     * @return {Number}
17228     */
17229    get: function get() {
17230      return Sizes.slideWidth * Sizes.length + Components.Gaps.grow + Components.Clones.grow;
17231    }
17232  });
17233  define(Sizes, 'slideWidth', {
17234    /**
17235     * Gets width value of a single slide.
17236     *
17237     * @return {Number}
17238     */
17239    get: function get() {
17240      return Sizes.width / Glide.settings.perView - Components.Peek.reductor - Components.Gaps.reductor;
17241    }
17242  });
17243  /**
17244   * Apply calculated glide's dimensions:
17245   * - before building, so other dimensions (e.g. translate) will be calculated propertly
17246   * - when resizing window to recalculate sildes dimensions
17247   * - on updating via API, to calculate dimensions based on new options
17248   */
17249
17250  Events.on(['build.before', 'resize', 'update'], function () {
17251    Sizes.setupSlides();
17252    Sizes.setupWrapper();
17253  });
17254  /**
17255   * Remove calculated glide's dimensions:
17256   * - on destoting to bring markup to its inital state
17257   */
17258
17259  Events.on('destroy', function () {
17260    Sizes.remove();
17261  });
17262  return Sizes;
17263}
17264
17265function Build (Glide, Components, Events) {
17266  var Build = {
17267    /**
17268     * Init glide building. Adds classes, sets
17269     * dimensions and setups initial state.
17270     *
17271     * @return {Void}
17272     */
17273    mount: function mount() {
17274      Events.emit('build.before');
17275      this.typeClass();
17276      this.activeClass();
17277      Events.emit('build.after');
17278    },
17279
17280    /**
17281     * Adds `type` class to the glide element.
17282     *
17283     * @return {Void}
17284     */
17285    typeClass: function typeClass() {
17286      Components.Html.root.classList.add(Glide.settings.classes.type[Glide.settings.type]);
17287    },
17288
17289    /**
17290     * Sets active class to current slide.
17291     *
17292     * @return {Void}
17293     */
17294    activeClass: function activeClass() {
17295      var classes = Glide.settings.classes;
17296      var slide = Components.Html.slides[Glide.index];
17297
17298      if (slide) {
17299        slide.classList.add(classes.slide.active);
17300        siblings(slide).forEach(function (sibling) {
17301          sibling.classList.remove(classes.slide.active);
17302        });
17303      }
17304    },
17305
17306    /**
17307     * Removes HTML classes applied at building.
17308     *
17309     * @return {Void}
17310     */
17311    removeClasses: function removeClasses() {
17312      var _Glide$settings$class = Glide.settings.classes,
17313          type = _Glide$settings$class.type,
17314          slide = _Glide$settings$class.slide;
17315      Components.Html.root.classList.remove(type[Glide.settings.type]);
17316      Components.Html.slides.forEach(function (sibling) {
17317        sibling.classList.remove(slide.active);
17318      });
17319    }
17320  };
17321  /**
17322   * Clear building classes:
17323   * - on destroying to bring HTML to its initial state
17324   * - on updating to remove classes before remounting component
17325   */
17326
17327  Events.on(['destroy', 'update'], function () {
17328    Build.removeClasses();
17329  });
17330  /**
17331   * Remount component:
17332   * - on resizing of the window to calculate new dimensions
17333   * - on updating settings via API
17334   */
17335
17336  Events.on(['resize', 'update'], function () {
17337    Build.mount();
17338  });
17339  /**
17340   * Swap active class of current slide:
17341   * - after each move to the new index
17342   */
17343
17344  Events.on('move.after', function () {
17345    Build.activeClass();
17346  });
17347  return Build;
17348}
17349
17350function Clones (Glide, Components, Events) {
17351  var Clones = {
17352    /**
17353     * Create pattern map and collect slides to be cloned.
17354     */
17355    mount: function mount() {
17356      this.items = [];
17357
17358      if (Glide.isType('carousel')) {
17359        this.items = this.collect();
17360      }
17361    },
17362
17363    /**
17364     * Collect clones with pattern.
17365     *
17366     * @return {[]}
17367     */
17368    collect: function collect() {
17369      var items = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
17370      var slides = Components.Html.slides;
17371      var _Glide$settings = Glide.settings,
17372          perView = _Glide$settings.perView,
17373          classes = _Glide$settings.classes,
17374          cloningRatio = _Glide$settings.cloningRatio;
17375
17376      if (slides.length > 0) {
17377        var peekIncrementer = +!!Glide.settings.peek;
17378        var cloneCount = perView + peekIncrementer + Math.round(perView / 2);
17379        var append = slides.slice(0, cloneCount).reverse();
17380        var prepend = slides.slice(cloneCount * -1);
17381
17382        for (var r = 0; r < Math.max(cloningRatio, Math.floor(perView / slides.length)); r++) {
17383          for (var i = 0; i < append.length; i++) {
17384            var clone = append[i].cloneNode(true);
17385            clone.classList.add(classes.slide.clone);
17386            items.push(clone);
17387          }
17388
17389          for (var _i = 0; _i < prepend.length; _i++) {
17390            var _clone = prepend[_i].cloneNode(true);
17391
17392            _clone.classList.add(classes.slide.clone);
17393
17394            items.unshift(_clone);
17395          }
17396        }
17397      }
17398
17399      return items;
17400    },
17401
17402    /**
17403     * Append cloned slides with generated pattern.
17404     *
17405     * @return {Void}
17406     */
17407    append: function append() {
17408      var items = this.items;
17409      var _Components$Html = Components.Html,
17410          wrapper = _Components$Html.wrapper,
17411          slides = _Components$Html.slides;
17412      var half = Math.floor(items.length / 2);
17413      var prepend = items.slice(0, half).reverse();
17414      var append = items.slice(half * -1).reverse();
17415      var width = "".concat(Components.Sizes.slideWidth, "px");
17416
17417      for (var i = 0; i < append.length; i++) {
17418        wrapper.appendChild(append[i]);
17419      }
17420
17421      for (var _i2 = 0; _i2 < prepend.length; _i2++) {
17422        wrapper.insertBefore(prepend[_i2], slides[0]);
17423      }
17424
17425      for (var _i3 = 0; _i3 < items.length; _i3++) {
17426        items[_i3].style.width = width;
17427      }
17428    },
17429
17430    /**
17431     * Remove all cloned slides.
17432     *
17433     * @return {Void}
17434     */
17435    remove: function remove() {
17436      var items = this.items;
17437
17438      for (var i = 0; i < items.length; i++) {
17439        Components.Html.wrapper.removeChild(items[i]);
17440      }
17441    }
17442  };
17443  define(Clones, 'grow', {
17444    /**
17445     * Gets additional dimensions value caused by clones.
17446     *
17447     * @return {Number}
17448     */
17449    get: function get() {
17450      return (Components.Sizes.slideWidth + Components.Gaps.value) * Clones.items.length;
17451    }
17452  });
17453  /**
17454   * Append additional slide's clones:
17455   * - while glide's type is `carousel`
17456   */
17457
17458  Events.on('update', function () {
17459    Clones.remove();
17460    Clones.mount();
17461    Clones.append();
17462  });
17463  /**
17464   * Append additional slide's clones:
17465   * - while glide's type is `carousel`
17466   */
17467
17468  Events.on('build.before', function () {
17469    if (Glide.isType('carousel')) {
17470      Clones.append();
17471    }
17472  });
17473  /**
17474   * Remove clones HTMLElements:
17475   * - on destroying, to bring HTML to its initial state
17476   */
17477
17478  Events.on('destroy', function () {
17479    Clones.remove();
17480  });
17481  return Clones;
17482}
17483
17484var EventsBinder = /*#__PURE__*/function () {
17485  /**
17486   * Construct a EventsBinder instance.
17487   */
17488  function EventsBinder() {
17489    var listeners = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
17490
17491    _classCallCheck(this, EventsBinder);
17492
17493    this.listeners = listeners;
17494  }
17495  /**
17496   * Adds events listeners to arrows HTML elements.
17497   *
17498   * @param  {String|Array} events
17499   * @param  {Element|Window|Document} el
17500   * @param  {Function} closure
17501   * @param  {Boolean|Object} capture
17502   * @return {Void}
17503   */
17504
17505
17506  _createClass(EventsBinder, [{
17507    key: "on",
17508    value: function on(events, el, closure) {
17509      var capture = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : false;
17510
17511      if (isString(events)) {
17512        events = [events];
17513      }
17514
17515      for (var i = 0; i < events.length; i++) {
17516        this.listeners[events[i]] = closure;
17517        el.addEventListener(events[i], this.listeners[events[i]], capture);
17518      }
17519    }
17520    /**
17521     * Removes event listeners from arrows HTML elements.
17522     *
17523     * @param  {String|Array} events
17524     * @param  {Element|Window|Document} el
17525     * @param  {Boolean|Object} capture
17526     * @return {Void}
17527     */
17528
17529  }, {
17530    key: "off",
17531    value: function off(events, el) {
17532      var capture = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
17533
17534      if (isString(events)) {
17535        events = [events];
17536      }
17537
17538      for (var i = 0; i < events.length; i++) {
17539        el.removeEventListener(events[i], this.listeners[events[i]], capture);
17540      }
17541    }
17542    /**
17543     * Destroy collected listeners.
17544     *
17545     * @returns {Void}
17546     */
17547
17548  }, {
17549    key: "destroy",
17550    value: function destroy() {
17551      delete this.listeners;
17552    }
17553  }]);
17554
17555  return EventsBinder;
17556}();
17557
17558function Resize (Glide, Components, Events) {
17559  /**
17560   * Instance of the binder for DOM Events.
17561   *
17562   * @type {EventsBinder}
17563   */
17564  var Binder = new EventsBinder();
17565  var Resize = {
17566    /**
17567     * Initializes window bindings.
17568     */
17569    mount: function mount() {
17570      this.bind();
17571    },
17572
17573    /**
17574     * Binds `rezsize` listener to the window.
17575     * It's a costly event, so we are debouncing it.
17576     *
17577     * @return {Void}
17578     */
17579    bind: function bind() {
17580      Binder.on('resize', window, throttle(function () {
17581        Events.emit('resize');
17582      }, Glide.settings.throttle));
17583    },
17584
17585    /**
17586     * Unbinds listeners from the window.
17587     *
17588     * @return {Void}
17589     */
17590    unbind: function unbind() {
17591      Binder.off('resize', window);
17592    }
17593  };
17594  /**
17595   * Remove bindings from window:
17596   * - on destroying, to remove added EventListener
17597   */
17598
17599  Events.on('destroy', function () {
17600    Resize.unbind();
17601    Binder.destroy();
17602  });
17603  return Resize;
17604}
17605
17606var VALID_DIRECTIONS = ['ltr', 'rtl'];
17607var FLIPED_MOVEMENTS = {
17608  '>': '<',
17609  '<': '>',
17610  '=': '='
17611};
17612function Direction (Glide, Components, Events) {
17613  var Direction = {
17614    /**
17615     * Setups gap value based on settings.
17616     *
17617     * @return {Void}
17618     */
17619    mount: function mount() {
17620      this.value = Glide.settings.direction;
17621    },
17622
17623    /**
17624     * Resolves pattern based on direction value
17625     *
17626     * @param {String} pattern
17627     * @returns {String}
17628     */
17629    resolve: function resolve(pattern) {
17630      var token = pattern.slice(0, 1);
17631
17632      if (this.is('rtl')) {
17633        return pattern.split(token).join(FLIPED_MOVEMENTS[token]);
17634      }
17635
17636      return pattern;
17637    },
17638
17639    /**
17640     * Checks value of direction mode.
17641     *
17642     * @param {String} direction
17643     * @returns {Boolean}
17644     */
17645    is: function is(direction) {
17646      return this.value === direction;
17647    },
17648
17649    /**
17650     * Applies direction class to the root HTML element.
17651     *
17652     * @return {Void}
17653     */
17654    addClass: function addClass() {
17655      Components.Html.root.classList.add(Glide.settings.classes.direction[this.value]);
17656    },
17657
17658    /**
17659     * Removes direction class from the root HTML element.
17660     *
17661     * @return {Void}
17662     */
17663    removeClass: function removeClass() {
17664      Components.Html.root.classList.remove(Glide.settings.classes.direction[this.value]);
17665    }
17666  };
17667  define(Direction, 'value', {
17668    /**
17669     * Gets value of the direction.
17670     *
17671     * @returns {Number}
17672     */
17673    get: function get() {
17674      return Direction._v;
17675    },
17676
17677    /**
17678     * Sets value of the direction.
17679     *
17680     * @param {String} value
17681     * @return {Void}
17682     */
17683    set: function set(value) {
17684      if (VALID_DIRECTIONS.indexOf(value) > -1) {
17685        Direction._v = value;
17686      } else {
17687        warn('Direction value must be `ltr` or `rtl`');
17688      }
17689    }
17690  });
17691  /**
17692   * Clear direction class:
17693   * - on destroy to bring HTML to its initial state
17694   * - on update to remove class before reappling bellow
17695   */
17696
17697  Events.on(['destroy', 'update'], function () {
17698    Direction.removeClass();
17699  });
17700  /**
17701   * Remount component:
17702   * - on update to reflect changes in direction value
17703   */
17704
17705  Events.on('update', function () {
17706    Direction.mount();
17707  });
17708  /**
17709   * Apply direction class:
17710   * - before building to apply class for the first time
17711   * - on updating to reapply direction class that may changed
17712   */
17713
17714  Events.on(['build.before', 'update'], function () {
17715    Direction.addClass();
17716  });
17717  return Direction;
17718}
17719
17720/**
17721 * Reflects value of glide movement.
17722 *
17723 * @param  {Object} Glide
17724 * @param  {Object} Components
17725 * @return {Object}
17726 */
17727function Rtl (Glide, Components) {
17728  return {
17729    /**
17730     * Negates the passed translate if glide is in RTL option.
17731     *
17732     * @param  {Number} translate
17733     * @return {Number}
17734     */
17735    modify: function modify(translate) {
17736      if (Components.Direction.is('rtl')) {
17737        return -translate;
17738      }
17739
17740      return translate;
17741    }
17742  };
17743}
17744
17745/**
17746 * Updates glide movement with a `gap` settings.
17747 *
17748 * @param  {Object} Glide
17749 * @param  {Object} Components
17750 * @return {Object}
17751 */
17752function Gap (Glide, Components) {
17753  return {
17754    /**
17755     * Modifies passed translate value with number in the `gap` settings.
17756     *
17757     * @param  {Number} translate
17758     * @return {Number}
17759     */
17760    modify: function modify(translate) {
17761      var multiplier = Math.floor(translate / Components.Sizes.slideWidth);
17762      return translate + Components.Gaps.value * multiplier;
17763    }
17764  };
17765}
17766
17767/**
17768 * Updates glide movement with width of additional clones width.
17769 *
17770 * @param  {Object} Glide
17771 * @param  {Object} Components
17772 * @return {Object}
17773 */
17774function Grow (Glide, Components) {
17775  return {
17776    /**
17777     * Adds to the passed translate width of the half of clones.
17778     *
17779     * @param  {Number} translate
17780     * @return {Number}
17781     */
17782    modify: function modify(translate) {
17783      return translate + Components.Clones.grow / 2;
17784    }
17785  };
17786}
17787
17788/**
17789 * Updates glide movement with a `peek` settings.
17790 *
17791 * @param  {Object} Glide
17792 * @param  {Object} Components
17793 * @return {Object}
17794 */
17795
17796function Peeking (Glide, Components) {
17797  return {
17798    /**
17799     * Modifies passed translate value with a `peek` setting.
17800     *
17801     * @param  {Number} translate
17802     * @return {Number}
17803     */
17804    modify: function modify(translate) {
17805      if (Glide.settings.focusAt >= 0) {
17806        var peek = Components.Peek.value;
17807
17808        if (isObject(peek)) {
17809          return translate - peek.before;
17810        }
17811
17812        return translate - peek;
17813      }
17814
17815      return translate;
17816    }
17817  };
17818}
17819
17820/**
17821 * Updates glide movement with a `focusAt` settings.
17822 *
17823 * @param  {Object} Glide
17824 * @param  {Object} Components
17825 * @return {Object}
17826 */
17827function Focusing (Glide, Components) {
17828  return {
17829    /**
17830     * Modifies passed translate value with index in the `focusAt` setting.
17831     *
17832     * @param  {Number} translate
17833     * @return {Number}
17834     */
17835    modify: function modify(translate) {
17836      var gap = Components.Gaps.value;
17837      var width = Components.Sizes.width;
17838      var focusAt = Glide.settings.focusAt;
17839      var slideWidth = Components.Sizes.slideWidth;
17840
17841      if (focusAt === 'center') {
17842        return translate - (width / 2 - slideWidth / 2);
17843      }
17844
17845      return translate - slideWidth * focusAt - gap * focusAt;
17846    }
17847  };
17848}
17849
17850/**
17851 * Applies diffrent transformers on translate value.
17852 *
17853 * @param  {Object} Glide
17854 * @param  {Object} Components
17855 * @return {Object}
17856 */
17857
17858function mutator (Glide, Components, Events) {
17859  /**
17860   * Merge instance transformers with collection of default transformers.
17861   * It's important that the Rtl component be last on the list,
17862   * so it reflects all previous transformations.
17863   *
17864   * @type {Array}
17865   */
17866  var TRANSFORMERS = [Gap, Grow, Peeking, Focusing].concat(Glide._t, [Rtl]);
17867  return {
17868    /**
17869     * Piplines translate value with registered transformers.
17870     *
17871     * @param  {Number} translate
17872     * @return {Number}
17873     */
17874    mutate: function mutate(translate) {
17875      for (var i = 0; i < TRANSFORMERS.length; i++) {
17876        var transformer = TRANSFORMERS[i];
17877
17878        if (isFunction(transformer) && isFunction(transformer().modify)) {
17879          translate = transformer(Glide, Components, Events).modify(translate);
17880        } else {
17881          warn('Transformer should be a function that returns an object with `modify()` method');
17882        }
17883      }
17884
17885      return translate;
17886    }
17887  };
17888}
17889
17890function Translate (Glide, Components, Events) {
17891  var Translate = {
17892    /**
17893     * Sets value of translate on HTML element.
17894     *
17895     * @param {Number} value
17896     * @return {Void}
17897     */
17898    set: function set(value) {
17899      var transform = mutator(Glide, Components).mutate(value);
17900      var translate3d = "translate3d(".concat(-1 * transform, "px, 0px, 0px)");
17901      Components.Html.wrapper.style.mozTransform = translate3d; // needed for supported Firefox 10-15
17902
17903      Components.Html.wrapper.style.webkitTransform = translate3d; // needed for supported Chrome 10-35, Safari 5.1-8, and Opera 15-22
17904
17905      Components.Html.wrapper.style.transform = translate3d;
17906    },
17907
17908    /**
17909     * Removes value of translate from HTML element.
17910     *
17911     * @return {Void}
17912     */
17913    remove: function remove() {
17914      Components.Html.wrapper.style.transform = '';
17915    },
17916
17917    /**
17918     * @return {number}
17919     */
17920    getStartIndex: function getStartIndex() {
17921      var length = Components.Sizes.length;
17922      var index = Glide.index;
17923      var perView = Glide.settings.perView;
17924
17925      if (Components.Run.isOffset('>') || Components.Run.isOffset('|>')) {
17926        return length + (index - perView);
17927      } // "modulo length" converts an index that equals length to zero
17928
17929
17930      return (index + perView) % length;
17931    },
17932
17933    /**
17934     * @return {number}
17935     */
17936    getTravelDistance: function getTravelDistance() {
17937      var travelDistance = Components.Sizes.slideWidth * Glide.settings.perView;
17938
17939      if (Components.Run.isOffset('>') || Components.Run.isOffset('|>')) {
17940        // reverse travel distance so that we don't have to change subtract operations
17941        return travelDistance * -1;
17942      }
17943
17944      return travelDistance;
17945    }
17946  };
17947  /**
17948   * Set new translate value:
17949   * - on move to reflect index change
17950   * - on updating via API to reflect possible changes in options
17951   */
17952
17953  Events.on('move', function (context) {
17954    if (!Glide.isType('carousel') || !Components.Run.isOffset()) {
17955      return Translate.set(context.movement);
17956    }
17957
17958    Components.Transition.after(function () {
17959      Events.emit('translate.jump');
17960      Translate.set(Components.Sizes.slideWidth * Glide.index);
17961    });
17962    var startWidth = Components.Sizes.slideWidth * Components.Translate.getStartIndex();
17963    return Translate.set(startWidth - Components.Translate.getTravelDistance());
17964  });
17965  /**
17966   * Remove translate:
17967   * - on destroying to bring markup to its inital state
17968   */
17969
17970  Events.on('destroy', function () {
17971    Translate.remove();
17972  });
17973  return Translate;
17974}
17975
17976function Transition (Glide, Components, Events) {
17977  /**
17978   * Holds inactivity status of transition.
17979   * When true transition is not applied.
17980   *
17981   * @type {Boolean}
17982   */
17983  var disabled = false;
17984  var Transition = {
17985    /**
17986     * Composes string of the CSS transition.
17987     *
17988     * @param {String} property
17989     * @return {String}
17990     */
17991    compose: function compose(property) {
17992      var settings = Glide.settings;
17993
17994      if (disabled) {
17995        return "".concat(property, " 0ms ").concat(settings.animationTimingFunc);
17996      }
17997
17998      return "".concat(property, " ").concat(this.duration, "ms ").concat(settings.animationTimingFunc);
17999    },
18000
18001    /**
18002     * Sets value of transition on HTML element.
18003     *
18004     * @param {String=} property
18005     * @return {Void}
18006     */
18007    set: function set() {
18008      var property = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'transform';
18009      Components.Html.wrapper.style.transition = this.compose(property);
18010    },
18011
18012    /**
18013     * Removes value of transition from HTML element.
18014     *
18015     * @return {Void}
18016     */
18017    remove: function remove() {
18018      Components.Html.wrapper.style.transition = '';
18019    },
18020
18021    /**
18022     * Runs callback after animation.
18023     *
18024     * @param  {Function} callback
18025     * @return {Void}
18026     */
18027    after: function after(callback) {
18028      setTimeout(function () {
18029        callback();
18030      }, this.duration);
18031    },
18032
18033    /**
18034     * Enable transition.
18035     *
18036     * @return {Void}
18037     */
18038    enable: function enable() {
18039      disabled = false;
18040      this.set();
18041    },
18042
18043    /**
18044     * Disable transition.
18045     *
18046     * @return {Void}
18047     */
18048    disable: function disable() {
18049      disabled = true;
18050      this.set();
18051    }
18052  };
18053  define(Transition, 'duration', {
18054    /**
18055     * Gets duration of the transition based
18056     * on currently running animation type.
18057     *
18058     * @return {Number}
18059     */
18060    get: function get() {
18061      var settings = Glide.settings;
18062
18063      if (Glide.isType('slider') && Components.Run.offset) {
18064        return settings.rewindDuration;
18065      }
18066
18067      return settings.animationDuration;
18068    }
18069  });
18070  /**
18071   * Set transition `style` value:
18072   * - on each moving, because it may be cleared by offset move
18073   */
18074
18075  Events.on('move', function () {
18076    Transition.set();
18077  });
18078  /**
18079   * Disable transition:
18080   * - before initial build to avoid transitioning from `0` to `startAt` index
18081   * - while resizing window and recalculating dimensions
18082   * - on jumping from offset transition at start and end edges in `carousel` type
18083   */
18084
18085  Events.on(['build.before', 'resize', 'translate.jump'], function () {
18086    Transition.disable();
18087  });
18088  /**
18089   * Enable transition:
18090   * - on each running, because it may be disabled by offset move
18091   */
18092
18093  Events.on('run', function () {
18094    Transition.enable();
18095  });
18096  /**
18097   * Remove transition:
18098   * - on destroying to bring markup to its inital state
18099   */
18100
18101  Events.on('destroy', function () {
18102    Transition.remove();
18103  });
18104  return Transition;
18105}
18106
18107/**
18108 * Test via a getter in the options object to see
18109 * if the passive property is accessed.
18110 *
18111 * @see https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection
18112 */
18113var supportsPassive = false;
18114
18115try {
18116  var opts = Object.defineProperty({}, 'passive', {
18117    get: function get() {
18118      supportsPassive = true;
18119    }
18120  });
18121  window.addEventListener('testPassive', null, opts);
18122  window.removeEventListener('testPassive', null, opts);
18123} catch (e) {}
18124
18125var supportsPassive$1 = supportsPassive;
18126
18127var START_EVENTS = ['touchstart', 'mousedown'];
18128var MOVE_EVENTS = ['touchmove', 'mousemove'];
18129var END_EVENTS = ['touchend', 'touchcancel', 'mouseup', 'mouseleave'];
18130var MOUSE_EVENTS = ['mousedown', 'mousemove', 'mouseup', 'mouseleave'];
18131function Swipe (Glide, Components, Events) {
18132  /**
18133   * Instance of the binder for DOM Events.
18134   *
18135   * @type {EventsBinder}
18136   */
18137  var Binder = new EventsBinder();
18138  var swipeSin = 0;
18139  var swipeStartX = 0;
18140  var swipeStartY = 0;
18141  var disabled = false;
18142  var capture = supportsPassive$1 ? {
18143    passive: true
18144  } : false;
18145  var Swipe = {
18146    /**
18147     * Initializes swipe bindings.
18148     *
18149     * @return {Void}
18150     */
18151    mount: function mount() {
18152      this.bindSwipeStart();
18153    },
18154
18155    /**
18156     * Handler for `swipestart` event. Calculates entry points of the user's tap.
18157     *
18158     * @param {Object} event
18159     * @return {Void}
18160     */
18161    start: function start(event) {
18162      if (!disabled && !Glide.disabled) {
18163        this.disable();
18164        var swipe = this.touches(event);
18165        swipeSin = null;
18166        swipeStartX = toInt(swipe.pageX);
18167        swipeStartY = toInt(swipe.pageY);
18168        this.bindSwipeMove();
18169        this.bindSwipeEnd();
18170        Events.emit('swipe.start');
18171      }
18172    },
18173
18174    /**
18175     * Handler for `swipemove` event. Calculates user's tap angle and distance.
18176     *
18177     * @param {Object} event
18178     */
18179    move: function move(event) {
18180      if (!Glide.disabled) {
18181        var _Glide$settings = Glide.settings,
18182            touchAngle = _Glide$settings.touchAngle,
18183            touchRatio = _Glide$settings.touchRatio,
18184            classes = _Glide$settings.classes;
18185        var swipe = this.touches(event);
18186        var subExSx = toInt(swipe.pageX) - swipeStartX;
18187        var subEySy = toInt(swipe.pageY) - swipeStartY;
18188        var powEX = Math.abs(subExSx << 2);
18189        var powEY = Math.abs(subEySy << 2);
18190        var swipeHypotenuse = Math.sqrt(powEX + powEY);
18191        var swipeCathetus = Math.sqrt(powEY);
18192        swipeSin = Math.asin(swipeCathetus / swipeHypotenuse);
18193
18194        if (swipeSin * 180 / Math.PI < touchAngle) {
18195          event.stopPropagation();
18196          Components.Move.make(subExSx * toFloat(touchRatio));
18197          Components.Html.root.classList.add(classes.dragging);
18198          Events.emit('swipe.move');
18199        } else {
18200          return false;
18201        }
18202      }
18203    },
18204
18205    /**
18206     * Handler for `swipeend` event. Finitializes user's tap and decides about glide move.
18207     *
18208     * @param {Object} event
18209     * @return {Void}
18210     */
18211    end: function end(event) {
18212      if (!Glide.disabled) {
18213        var _Glide$settings2 = Glide.settings,
18214            perSwipe = _Glide$settings2.perSwipe,
18215            touchAngle = _Glide$settings2.touchAngle,
18216            classes = _Glide$settings2.classes;
18217        var swipe = this.touches(event);
18218        var threshold = this.threshold(event);
18219        var swipeDistance = swipe.pageX - swipeStartX;
18220        var swipeDeg = swipeSin * 180 / Math.PI;
18221        this.enable();
18222
18223        if (swipeDistance > threshold && swipeDeg < touchAngle) {
18224          Components.Run.make(Components.Direction.resolve("".concat(perSwipe, "<")));
18225        } else if (swipeDistance < -threshold && swipeDeg < touchAngle) {
18226          Components.Run.make(Components.Direction.resolve("".concat(perSwipe, ">")));
18227        } else {
18228          // While swipe don't reach distance apply previous transform.
18229          Components.Move.make();
18230        }
18231
18232        Components.Html.root.classList.remove(classes.dragging);
18233        this.unbindSwipeMove();
18234        this.unbindSwipeEnd();
18235        Events.emit('swipe.end');
18236      }
18237    },
18238
18239    /**
18240     * Binds swipe's starting event.
18241     *
18242     * @return {Void}
18243     */
18244    bindSwipeStart: function bindSwipeStart() {
18245      var _this = this;
18246
18247      var _Glide$settings3 = Glide.settings,
18248          swipeThreshold = _Glide$settings3.swipeThreshold,
18249          dragThreshold = _Glide$settings3.dragThreshold;
18250
18251      if (swipeThreshold) {
18252        Binder.on(START_EVENTS[0], Components.Html.wrapper, function (event) {
18253          _this.start(event);
18254        }, capture);
18255      }
18256
18257      if (dragThreshold) {
18258        Binder.on(START_EVENTS[1], Components.Html.wrapper, function (event) {
18259          _this.start(event);
18260        }, capture);
18261      }
18262    },
18263
18264    /**
18265     * Unbinds swipe's starting event.
18266     *
18267     * @return {Void}
18268     */
18269    unbindSwipeStart: function unbindSwipeStart() {
18270      Binder.off(START_EVENTS[0], Components.Html.wrapper, capture);
18271      Binder.off(START_EVENTS[1], Components.Html.wrapper, capture);
18272    },
18273
18274    /**
18275     * Binds swipe's moving event.
18276     *
18277     * @return {Void}
18278     */
18279    bindSwipeMove: function bindSwipeMove() {
18280      var _this2 = this;
18281
18282      Binder.on(MOVE_EVENTS, Components.Html.wrapper, throttle(function (event) {
18283        _this2.move(event);
18284      }, Glide.settings.throttle), capture);
18285    },
18286
18287    /**
18288     * Unbinds swipe's moving event.
18289     *
18290     * @return {Void}
18291     */
18292    unbindSwipeMove: function unbindSwipeMove() {
18293      Binder.off(MOVE_EVENTS, Components.Html.wrapper, capture);
18294    },
18295
18296    /**
18297     * Binds swipe's ending event.
18298     *
18299     * @return {Void}
18300     */
18301    bindSwipeEnd: function bindSwipeEnd() {
18302      var _this3 = this;
18303
18304      Binder.on(END_EVENTS, Components.Html.wrapper, function (event) {
18305        _this3.end(event);
18306      });
18307    },
18308
18309    /**
18310     * Unbinds swipe's ending event.
18311     *
18312     * @return {Void}
18313     */
18314    unbindSwipeEnd: function unbindSwipeEnd() {
18315      Binder.off(END_EVENTS, Components.Html.wrapper);
18316    },
18317
18318    /**
18319     * Normalizes event touches points accorting to different types.
18320     *
18321     * @param {Object} event
18322     */
18323    touches: function touches(event) {
18324      if (MOUSE_EVENTS.indexOf(event.type) > -1) {
18325        return event;
18326      }
18327
18328      return event.touches[0] || event.changedTouches[0];
18329    },
18330
18331    /**
18332     * Gets value of minimum swipe distance settings based on event type.
18333     *
18334     * @return {Number}
18335     */
18336    threshold: function threshold(event) {
18337      var settings = Glide.settings;
18338
18339      if (MOUSE_EVENTS.indexOf(event.type) > -1) {
18340        return settings.dragThreshold;
18341      }
18342
18343      return settings.swipeThreshold;
18344    },
18345
18346    /**
18347     * Enables swipe event.
18348     *
18349     * @return {self}
18350     */
18351    enable: function enable() {
18352      disabled = false;
18353      Components.Transition.enable();
18354      return this;
18355    },
18356
18357    /**
18358     * Disables swipe event.
18359     *
18360     * @return {self}
18361     */
18362    disable: function disable() {
18363      disabled = true;
18364      Components.Transition.disable();
18365      return this;
18366    }
18367  };
18368  /**
18369   * Add component class:
18370   * - after initial building
18371   */
18372
18373  Events.on('build.after', function () {
18374    Components.Html.root.classList.add(Glide.settings.classes.swipeable);
18375  });
18376  /**
18377   * Remove swiping bindings:
18378   * - on destroying, to remove added EventListeners
18379   */
18380
18381  Events.on('destroy', function () {
18382    Swipe.unbindSwipeStart();
18383    Swipe.unbindSwipeMove();
18384    Swipe.unbindSwipeEnd();
18385    Binder.destroy();
18386  });
18387  return Swipe;
18388}
18389
18390function Images (Glide, Components, Events) {
18391  /**
18392   * Instance of the binder for DOM Events.
18393   *
18394   * @type {EventsBinder}
18395   */
18396  var Binder = new EventsBinder();
18397  var Images = {
18398    /**
18399     * Binds listener to glide wrapper.
18400     *
18401     * @return {Void}
18402     */
18403    mount: function mount() {
18404      this.bind();
18405    },
18406
18407    /**
18408     * Binds `dragstart` event on wrapper to prevent dragging images.
18409     *
18410     * @return {Void}
18411     */
18412    bind: function bind() {
18413      Binder.on('dragstart', Components.Html.wrapper, this.dragstart);
18414    },
18415
18416    /**
18417     * Unbinds `dragstart` event on wrapper.
18418     *
18419     * @return {Void}
18420     */
18421    unbind: function unbind() {
18422      Binder.off('dragstart', Components.Html.wrapper);
18423    },
18424
18425    /**
18426     * Event handler. Prevents dragging.
18427     *
18428     * @return {Void}
18429     */
18430    dragstart: function dragstart(event) {
18431      event.preventDefault();
18432    }
18433  };
18434  /**
18435   * Remove bindings from images:
18436   * - on destroying, to remove added EventListeners
18437   */
18438
18439  Events.on('destroy', function () {
18440    Images.unbind();
18441    Binder.destroy();
18442  });
18443  return Images;
18444}
18445
18446function Anchors (Glide, Components, Events) {
18447  /**
18448   * Instance of the binder for DOM Events.
18449   *
18450   * @type {EventsBinder}
18451   */
18452  var Binder = new EventsBinder();
18453  /**
18454   * Holds detaching status of anchors.
18455   * Prevents detaching of already detached anchors.
18456   *
18457   * @private
18458   * @type {Boolean}
18459   */
18460
18461  var detached = false;
18462  /**
18463   * Holds preventing status of anchors.
18464   * If `true` redirection after click will be disabled.
18465   *
18466   * @private
18467   * @type {Boolean}
18468   */
18469
18470  var prevented = false;
18471  var Anchors = {
18472    /**
18473     * Setups a initial state of anchors component.
18474     *
18475     * @returns {Void}
18476     */
18477    mount: function mount() {
18478      /**
18479       * Holds collection of anchors elements.
18480       *
18481       * @private
18482       * @type {HTMLCollection}
18483       */
18484      this._a = Components.Html.wrapper.querySelectorAll('a');
18485      this.bind();
18486    },
18487
18488    /**
18489     * Binds events to anchors inside a track.
18490     *
18491     * @return {Void}
18492     */
18493    bind: function bind() {
18494      Binder.on('click', Components.Html.wrapper, this.click);
18495    },
18496
18497    /**
18498     * Unbinds events attached to anchors inside a track.
18499     *
18500     * @return {Void}
18501     */
18502    unbind: function unbind() {
18503      Binder.off('click', Components.Html.wrapper);
18504    },
18505
18506    /**
18507     * Handler for click event. Prevents clicks when glide is in `prevent` status.
18508     *
18509     * @param  {Object} event
18510     * @return {Void}
18511     */
18512    click: function click(event) {
18513      if (prevented) {
18514        event.stopPropagation();
18515        event.preventDefault();
18516      }
18517    },
18518
18519    /**
18520     * Detaches anchors click event inside glide.
18521     *
18522     * @return {self}
18523     */
18524    detach: function detach() {
18525      prevented = true;
18526
18527      if (!detached) {
18528        for (var i = 0; i < this.items.length; i++) {
18529          this.items[i].draggable = false;
18530        }
18531
18532        detached = true;
18533      }
18534
18535      return this;
18536    },
18537
18538    /**
18539     * Attaches anchors click events inside glide.
18540     *
18541     * @return {self}
18542     */
18543    attach: function attach() {
18544      prevented = false;
18545
18546      if (detached) {
18547        for (var i = 0; i < this.items.length; i++) {
18548          this.items[i].draggable = true;
18549        }
18550
18551        detached = false;
18552      }
18553
18554      return this;
18555    }
18556  };
18557  define(Anchors, 'items', {
18558    /**
18559     * Gets collection of the arrows HTML elements.
18560     *
18561     * @return {HTMLElement[]}
18562     */
18563    get: function get() {
18564      return Anchors._a;
18565    }
18566  });
18567  /**
18568   * Detach anchors inside slides:
18569   * - on swiping, so they won't redirect to its `href` attributes
18570   */
18571
18572  Events.on('swipe.move', function () {
18573    Anchors.detach();
18574  });
18575  /**
18576   * Attach anchors inside slides:
18577   * - after swiping and transitions ends, so they can redirect after click again
18578   */
18579
18580  Events.on('swipe.end', function () {
18581    Components.Transition.after(function () {
18582      Anchors.attach();
18583    });
18584  });
18585  /**
18586   * Unbind anchors inside slides:
18587   * - on destroying, to bring anchors to its initial state
18588   */
18589
18590  Events.on('destroy', function () {
18591    Anchors.attach();
18592    Anchors.unbind();
18593    Binder.destroy();
18594  });
18595  return Anchors;
18596}
18597
18598var NAV_SELECTOR = '[data-glide-el="controls[nav]"]';
18599var CONTROLS_SELECTOR = '[data-glide-el^="controls"]';
18600var PREVIOUS_CONTROLS_SELECTOR = "".concat(CONTROLS_SELECTOR, " [data-glide-dir*=\"<\"]");
18601var NEXT_CONTROLS_SELECTOR = "".concat(CONTROLS_SELECTOR, " [data-glide-dir*=\">\"]");
18602function Controls (Glide, Components, Events) {
18603  /**
18604   * Instance of the binder for DOM Events.
18605   *
18606   * @type {EventsBinder}
18607   */
18608  var Binder = new EventsBinder();
18609  var capture = supportsPassive$1 ? {
18610    passive: true
18611  } : false;
18612  var Controls = {
18613    /**
18614     * Inits arrows. Binds events listeners
18615     * to the arrows HTML elements.
18616     *
18617     * @return {Void}
18618     */
18619    mount: function mount() {
18620      /**
18621       * Collection of navigation HTML elements.
18622       *
18623       * @private
18624       * @type {HTMLCollection}
18625       */
18626      this._n = Components.Html.root.querySelectorAll(NAV_SELECTOR);
18627      /**
18628       * Collection of controls HTML elements.
18629       *
18630       * @private
18631       * @type {HTMLCollection}
18632       */
18633
18634      this._c = Components.Html.root.querySelectorAll(CONTROLS_SELECTOR);
18635      /**
18636       * Collection of arrow control HTML elements.
18637       *
18638       * @private
18639       * @type {Object}
18640       */
18641
18642      this._arrowControls = {
18643        previous: Components.Html.root.querySelectorAll(PREVIOUS_CONTROLS_SELECTOR),
18644        next: Components.Html.root.querySelectorAll(NEXT_CONTROLS_SELECTOR)
18645      };
18646      this.addBindings();
18647    },
18648
18649    /**
18650     * Sets active class to current slide.
18651     *
18652     * @return {Void}
18653     */
18654    setActive: function setActive() {
18655      for (var i = 0; i < this._n.length; i++) {
18656        this.addClass(this._n[i].children);
18657      }
18658    },
18659
18660    /**
18661     * Removes active class to current slide.
18662     *
18663     * @return {Void}
18664     */
18665    removeActive: function removeActive() {
18666      for (var i = 0; i < this._n.length; i++) {
18667        this.removeClass(this._n[i].children);
18668      }
18669    },
18670
18671    /**
18672     * Toggles active class on items inside navigation.
18673     *
18674     * @param  {HTMLElement} controls
18675     * @return {Void}
18676     */
18677    addClass: function addClass(controls) {
18678      var settings = Glide.settings;
18679      var item = controls[Glide.index];
18680
18681      if (!item) {
18682        return;
18683      }
18684
18685      item.classList.add(settings.classes.nav.active);
18686      siblings(item).forEach(function (sibling) {
18687        sibling.classList.remove(settings.classes.nav.active);
18688      });
18689    },
18690
18691    /**
18692     * Removes active class from active control.
18693     *
18694     * @param  {HTMLElement} controls
18695     * @return {Void}
18696     */
18697    removeClass: function removeClass(controls) {
18698      var item = controls[Glide.index];
18699      item === null || item === void 0 ? void 0 : item.classList.remove(Glide.settings.classes.nav.active);
18700    },
18701
18702    /**
18703     * Calculates, removes or adds `Glide.settings.classes.disabledArrow` class on the control arrows
18704     */
18705    setArrowState: function setArrowState() {
18706      if (Glide.settings.rewind) {
18707        return;
18708      }
18709
18710      var next = Controls._arrowControls.next;
18711      var previous = Controls._arrowControls.previous;
18712      this.resetArrowState(next, previous);
18713
18714      if (Glide.index === 0) {
18715        this.disableArrow(previous);
18716      }
18717
18718      if (Glide.index === Components.Run.length) {
18719        this.disableArrow(next);
18720      }
18721    },
18722
18723    /**
18724     * Removes `Glide.settings.classes.disabledArrow` from given NodeList elements
18725     *
18726     * @param {NodeList[]} lists
18727     */
18728    resetArrowState: function resetArrowState() {
18729      var settings = Glide.settings;
18730
18731      for (var _len = arguments.length, lists = new Array(_len), _key = 0; _key < _len; _key++) {
18732        lists[_key] = arguments[_key];
18733      }
18734
18735      lists.forEach(function (list) {
18736        toArray(list).forEach(function (element) {
18737          element.classList.remove(settings.classes.arrow.disabled);
18738        });
18739      });
18740    },
18741
18742    /**
18743     * Adds `Glide.settings.classes.disabledArrow` to given NodeList elements
18744     *
18745     * @param {NodeList[]} lists
18746     */
18747    disableArrow: function disableArrow() {
18748      var settings = Glide.settings;
18749
18750      for (var _len2 = arguments.length, lists = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
18751        lists[_key2] = arguments[_key2];
18752      }
18753
18754      lists.forEach(function (list) {
18755        toArray(list).forEach(function (element) {
18756          element.classList.add(settings.classes.arrow.disabled);
18757        });
18758      });
18759    },
18760
18761    /**
18762     * Adds handles to the each group of controls.
18763     *
18764     * @return {Void}
18765     */
18766    addBindings: function addBindings() {
18767      for (var i = 0; i < this._c.length; i++) {
18768        this.bind(this._c[i].children);
18769      }
18770    },
18771
18772    /**
18773     * Removes handles from the each group of controls.
18774     *
18775     * @return {Void}
18776     */
18777    removeBindings: function removeBindings() {
18778      for (var i = 0; i < this._c.length; i++) {
18779        this.unbind(this._c[i].children);
18780      }
18781    },
18782
18783    /**
18784     * Binds events to arrows HTML elements.
18785     *
18786     * @param {HTMLCollection} elements
18787     * @return {Void}
18788     */
18789    bind: function bind(elements) {
18790      for (var i = 0; i < elements.length; i++) {
18791        Binder.on('click', elements[i], this.click);
18792        Binder.on('touchstart', elements[i], this.click, capture);
18793      }
18794    },
18795
18796    /**
18797     * Unbinds events binded to the arrows HTML elements.
18798     *
18799     * @param {HTMLCollection} elements
18800     * @return {Void}
18801     */
18802    unbind: function unbind(elements) {
18803      for (var i = 0; i < elements.length; i++) {
18804        Binder.off(['click', 'touchstart'], elements[i]);
18805      }
18806    },
18807
18808    /**
18809     * Handles `click` event on the arrows HTML elements.
18810     * Moves slider in direction given via the
18811     * `data-glide-dir` attribute.
18812     *
18813     * @param {Object} event
18814     * @return {void}
18815     */
18816    click: function click(event) {
18817      if (!supportsPassive$1 && event.type === 'touchstart') {
18818        event.preventDefault();
18819      }
18820
18821      var direction = event.currentTarget.getAttribute('data-glide-dir');
18822      Components.Run.make(Components.Direction.resolve(direction));
18823    }
18824  };
18825  define(Controls, 'items', {
18826    /**
18827     * Gets collection of the controls HTML elements.
18828     *
18829     * @return {HTMLElement[]}
18830     */
18831    get: function get() {
18832      return Controls._c;
18833    }
18834  });
18835  /**
18836   * Swap active class of current navigation item:
18837   * - after mounting to set it to initial index
18838   * - after each move to the new index
18839   */
18840
18841  Events.on(['mount.after', 'move.after'], function () {
18842    Controls.setActive();
18843  });
18844  /**
18845   * Add or remove disabled class of arrow elements
18846   */
18847
18848  Events.on(['mount.after', 'run'], function () {
18849    Controls.setArrowState();
18850  });
18851  /**
18852   * Remove bindings and HTML Classes:
18853   * - on destroying, to bring markup to its initial state
18854   */
18855
18856  Events.on('destroy', function () {
18857    Controls.removeBindings();
18858    Controls.removeActive();
18859    Binder.destroy();
18860  });
18861  return Controls;
18862}
18863
18864function Keyboard (Glide, Components, Events) {
18865  /**
18866   * Instance of the binder for DOM Events.
18867   *
18868   * @type {EventsBinder}
18869   */
18870  var Binder = new EventsBinder();
18871  var Keyboard = {
18872    /**
18873     * Binds keyboard events on component mount.
18874     *
18875     * @return {Void}
18876     */
18877    mount: function mount() {
18878      if (Glide.settings.keyboard) {
18879        this.bind();
18880      }
18881    },
18882
18883    /**
18884     * Adds keyboard press events.
18885     *
18886     * @return {Void}
18887     */
18888    bind: function bind() {
18889      Binder.on('keyup', document, this.press);
18890    },
18891
18892    /**
18893     * Removes keyboard press events.
18894     *
18895     * @return {Void}
18896     */
18897    unbind: function unbind() {
18898      Binder.off('keyup', document);
18899    },
18900
18901    /**
18902     * Handles keyboard's arrows press and moving glide foward and backward.
18903     *
18904     * @param  {Object} event
18905     * @return {Void}
18906     */
18907    press: function press(event) {
18908      var perSwipe = Glide.settings.perSwipe;
18909      var arrowSymbols = {
18910        ArrowRight: '>',
18911        ArrowLeft: '<'
18912      };
18913
18914      if (['ArrowRight', 'ArrowLeft'].includes(event.code)) {
18915        Components.Run.make(Components.Direction.resolve("".concat(perSwipe).concat(arrowSymbols[event.code])));
18916      }
18917    }
18918  };
18919  /**
18920   * Remove bindings from keyboard:
18921   * - on destroying to remove added events
18922   * - on updating to remove events before remounting
18923   */
18924
18925  Events.on(['destroy', 'update'], function () {
18926    Keyboard.unbind();
18927  });
18928  /**
18929   * Remount component
18930   * - on updating to reflect potential changes in settings
18931   */
18932
18933  Events.on('update', function () {
18934    Keyboard.mount();
18935  });
18936  /**
18937   * Destroy binder:
18938   * - on destroying to remove listeners
18939   */
18940
18941  Events.on('destroy', function () {
18942    Binder.destroy();
18943  });
18944  return Keyboard;
18945}
18946
18947function Autoplay (Glide, Components, Events) {
18948  /**
18949   * Instance of the binder for DOM Events.
18950   *
18951   * @type {EventsBinder}
18952   */
18953  var Binder = new EventsBinder();
18954  var Autoplay = {
18955    /**
18956     * Initializes autoplaying and events.
18957     *
18958     * @return {Void}
18959     */
18960    mount: function mount() {
18961      this.enable();
18962      this.start();
18963
18964      if (Glide.settings.hoverpause) {
18965        this.bind();
18966      }
18967    },
18968
18969    /**
18970     * Enables autoplaying
18971     *
18972     * @returns {Void}
18973     */
18974    enable: function enable() {
18975      this._e = true;
18976    },
18977
18978    /**
18979     * Disables autoplaying.
18980     *
18981     * @returns {Void}
18982     */
18983    disable: function disable() {
18984      this._e = false;
18985    },
18986
18987    /**
18988     * Starts autoplaying in configured interval.
18989     *
18990     * @param {Boolean|Number} force Run autoplaying with passed interval regardless of `autoplay` settings
18991     * @return {Void}
18992     */
18993    start: function start() {
18994      var _this = this;
18995
18996      if (!this._e) {
18997        return;
18998      }
18999
19000      this.enable();
19001
19002      if (Glide.settings.autoplay) {
19003        if (isUndefined(this._i)) {
19004          this._i = setInterval(function () {
19005            _this.stop();
19006
19007            Components.Run.make('>');
19008
19009            _this.start();
19010
19011            Events.emit('autoplay');
19012          }, this.time);
19013        }
19014      }
19015    },
19016
19017    /**
19018     * Stops autorunning of the glide.
19019     *
19020     * @return {Void}
19021     */
19022    stop: function stop() {
19023      this._i = clearInterval(this._i);
19024    },
19025
19026    /**
19027     * Stops autoplaying while mouse is over glide's area.
19028     *
19029     * @return {Void}
19030     */
19031    bind: function bind() {
19032      var _this2 = this;
19033
19034      Binder.on('mouseover', Components.Html.root, function () {
19035        if (_this2._e) {
19036          _this2.stop();
19037        }
19038      });
19039      Binder.on('mouseout', Components.Html.root, function () {
19040        if (_this2._e) {
19041          _this2.start();
19042        }
19043      });
19044    },
19045
19046    /**
19047     * Unbind mouseover events.
19048     *
19049     * @returns {Void}
19050     */
19051    unbind: function unbind() {
19052      Binder.off(['mouseover', 'mouseout'], Components.Html.root);
19053    }
19054  };
19055  define(Autoplay, 'time', {
19056    /**
19057     * Gets time period value for the autoplay interval. Prioritizes
19058     * times in `data-glide-autoplay` attrubutes over options.
19059     *
19060     * @return {Number}
19061     */
19062    get: function get() {
19063      var autoplay = Components.Html.slides[Glide.index].getAttribute('data-glide-autoplay');
19064
19065      if (autoplay) {
19066        return toInt(autoplay);
19067      }
19068
19069      return toInt(Glide.settings.autoplay);
19070    }
19071  });
19072  /**
19073   * Stop autoplaying and unbind events:
19074   * - on destroying, to clear defined interval
19075   * - on updating via API to reset interval that may changed
19076   */
19077
19078  Events.on(['destroy', 'update'], function () {
19079    Autoplay.unbind();
19080  });
19081  /**
19082   * Stop autoplaying:
19083   * - before each run, to restart autoplaying
19084   * - on pausing via API
19085   * - on destroying, to clear defined interval
19086   * - while starting a swipe
19087   * - on updating via API to reset interval that may changed
19088   */
19089
19090  Events.on(['run.before', 'swipe.start', 'update'], function () {
19091    Autoplay.stop();
19092  });
19093  Events.on(['pause', 'destroy'], function () {
19094    Autoplay.disable();
19095    Autoplay.stop();
19096  });
19097  /**
19098   * Start autoplaying:
19099   * - after each run, to restart autoplaying
19100   * - on playing via API
19101   * - while ending a swipe
19102   */
19103
19104  Events.on(['run.after', 'swipe.end'], function () {
19105    Autoplay.start();
19106  });
19107  /**
19108   * Start autoplaying:
19109   * - after each run, to restart autoplaying
19110   * - on playing via API
19111   * - while ending a swipe
19112   */
19113
19114  Events.on(['play'], function () {
19115    Autoplay.enable();
19116    Autoplay.start();
19117  });
19118  /**
19119   * Remount autoplaying:
19120   * - on updating via API to reset interval that may changed
19121   */
19122
19123  Events.on('update', function () {
19124    Autoplay.mount();
19125  });
19126  /**
19127   * Destroy a binder:
19128   * - on destroying glide instance to clearup listeners
19129   */
19130
19131  Events.on('destroy', function () {
19132    Binder.destroy();
19133  });
19134  return Autoplay;
19135}
19136
19137/**
19138 * Sorts keys of breakpoint object so they will be ordered from lower to bigger.
19139 *
19140 * @param {Object} points
19141 * @returns {Object}
19142 */
19143
19144function sortBreakpoints(points) {
19145  if (isObject(points)) {
19146    return sortKeys(points);
19147  } else {
19148    warn("Breakpoints option must be an object");
19149  }
19150
19151  return {};
19152}
19153
19154function Breakpoints (Glide, Components, Events) {
19155  /**
19156   * Instance of the binder for DOM Events.
19157   *
19158   * @type {EventsBinder}
19159   */
19160  var Binder = new EventsBinder();
19161  /**
19162   * Holds reference to settings.
19163   *
19164   * @type {Object}
19165   */
19166
19167  var settings = Glide.settings;
19168  /**
19169   * Holds reference to breakpoints object in settings. Sorts breakpoints
19170   * from smaller to larger. It is required in order to proper
19171   * matching currently active breakpoint settings.
19172   *
19173   * @type {Object}
19174   */
19175
19176  var points = sortBreakpoints(settings.breakpoints);
19177  /**
19178   * Cache initial settings before overwritting.
19179   *
19180   * @type {Object}
19181   */
19182
19183  var defaults = Object.assign({}, settings);
19184  var Breakpoints = {
19185    /**
19186     * Matches settings for currectly matching media breakpoint.
19187     *
19188     * @param {Object} points
19189     * @returns {Object}
19190     */
19191    match: function match(points) {
19192      if (typeof window.matchMedia !== 'undefined') {
19193        for (var point in points) {
19194          if (points.hasOwnProperty(point)) {
19195            if (window.matchMedia("(max-width: ".concat(point, "px)")).matches) {
19196              return points[point];
19197            }
19198          }
19199        }
19200      }
19201
19202      return defaults;
19203    }
19204  };
19205  /**
19206   * Overwrite instance settings with currently matching breakpoint settings.
19207   * This happens right after component initialization.
19208   */
19209
19210  Object.assign(settings, Breakpoints.match(points));
19211  /**
19212   * Update glide with settings of matched brekpoint:
19213   * - window resize to update slider
19214   */
19215
19216  Binder.on('resize', window, throttle(function () {
19217    Glide.settings = mergeOptions(settings, Breakpoints.match(points));
19218  }, Glide.settings.throttle));
19219  /**
19220   * Resort and update default settings:
19221   * - on reinit via API, so breakpoint matching will be performed with options
19222   */
19223
19224  Events.on('update', function () {
19225    points = sortBreakpoints(points);
19226    defaults = Object.assign({}, settings);
19227  });
19228  /**
19229   * Unbind resize listener:
19230   * - on destroying, to bring markup to its initial state
19231   */
19232
19233  Events.on('destroy', function () {
19234    Binder.off('resize', window);
19235  });
19236  return Breakpoints;
19237}
19238
19239var COMPONENTS = {
19240  // Required
19241  Html: Html,
19242  Translate: Translate,
19243  Transition: Transition,
19244  Direction: Direction,
19245  Peek: Peek,
19246  Sizes: Sizes,
19247  Gaps: Gaps,
19248  Move: Move,
19249  Clones: Clones,
19250  Resize: Resize,
19251  Build: Build,
19252  Run: Run,
19253  // Optional
19254  Swipe: Swipe,
19255  Images: Images,
19256  Anchors: Anchors,
19257  Controls: Controls,
19258  Keyboard: Keyboard,
19259  Autoplay: Autoplay,
19260  Breakpoints: Breakpoints
19261};
19262
19263var Glide = /*#__PURE__*/function (_Core) {
19264  _inherits(Glide, _Core);
19265
19266  var _super = _createSuper(Glide);
19267
19268  function Glide() {
19269    _classCallCheck(this, Glide);
19270
19271    return _super.apply(this, arguments);
19272  }
19273
19274  _createClass(Glide, [{
19275    key: "mount",
19276    value: function mount() {
19277      var extensions = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
19278      return _get(_getPrototypeOf(Glide.prototype), "mount", this).call(this, Object.assign({}, COMPONENTS, extensions));
19279    }
19280  }]);
19281
19282  return Glide;
19283}(Glide$1);
19284
19285
19286
19287
19288/***/ })
vendor: 4,135 bytes, lines 19288-19388
19288
19289
19290/******/ 	});
19291/************************************************************************/
19292/******/ 	// The module cache
19293/******/ 	var __webpack_module_cache__ = {};
19294/******/ 	
19295/******/ 	// The require function
19296/******/ 	function __webpack_require__(moduleId) {
19297/******/ 		// Check if module is in cache
19298/******/ 		var cachedModule = __webpack_module_cache__[moduleId];
19299/******/ 		if (cachedModule !== undefined) {
19300/******/ 			return cachedModule.exports;
19301/******/ 		}
19302/******/ 		// Create a new module (and put it into the cache)
19303/******/ 		var module = __webpack_module_cache__[moduleId] = {
19304/******/ 			id: moduleId,
19305/******/ 			// no module.loaded needed
19306/******/ 			exports: {}
19307/******/ 		};
19308/******/ 	
19309/******/ 		// Execute the module function
19310/******/ 		__webpack_modules__[moduleId].call(module.exports, module, module.exports, __webpack_require__);
19311/******/ 	
19312/******/ 		// Return the exports of the module
19313/******/ 		return module.exports;
19314/******/ 	}
19315/******/ 	
19316/******/ 	// expose the modules object (__webpack_modules__)
19317/******/ 	__webpack_require__.m = __webpack_modules__;
19318/******/ 	
19319/************************************************************************/
19320/******/ 	/* webpack/runtime/chunk loaded */
19321/******/ 	(() => {
19322/******/ 		var deferred = [];
19323/******/ 		__webpack_require__.O = (result, chunkIds, fn, priority) => {
19324/******/ 			if(chunkIds) {
19325/******/ 				priority = priority || 0;
19326/******/ 				for(var i = deferred.length; i > 0 && deferred[i - 1][2] > priority; i--) deferred[i] = deferred[i - 1];
19327/******/ 				deferred[i] = [chunkIds, fn, priority];
19328/******/ 				return;
19329/******/ 			}
19330/******/ 			var notFulfilled = Infinity;
19331/******/ 			for (var i = 0; i < deferred.length; i++) {
19332/******/ 				var [chunkIds, fn, priority] = deferred[i];
19333/******/ 				var fulfilled = true;
19334/******/ 				for (var j = 0; j < chunkIds.length; j++) {
19335/******/ 					if ((priority & 1 === 0 || notFulfilled >= priority) && Object.keys(__webpack_require__.O).every((key) => (__webpack_require__.O[key](chunkIds[j])))) {
19336/******/ 						chunkIds.splice(j--, 1);
19337/******/ 					} else {
19338/******/ 						fulfilled = false;
19339/******/ 						if(priority < notFulfilled) notFulfilled = priority;
19340/******/ 					}
19341/******/ 				}
19342/******/ 				if(fulfilled) {
19343/******/ 					deferred.splice(i--, 1)
19344/******/ 					var r = fn();
19345/******/ 					if (r !== undefined) result = r;
19346/******/ 				}
19347/******/ 			}
19348/******/ 			return result;
19349/******/ 		};
19350/******/ 	})();
19351/******/ 	
19352/******/ 	/* webpack/runtime/compat get default export */
19353/******/ 	(() => {
19354/******/ 		// getDefaultExport function for compatibility with non-harmony modules
19355/******/ 		__webpack_require__.n = (module) => {
19356/******/ 			var getter = module && module.__esModule ?
19357/******/ 				() => (module['default']) :
19358/******/ 				() => (module);
19359/******/ 			__webpack_require__.d(getter, { a: getter });
19360/******/ 			return getter;
19361/******/ 		};
19362/******/ 	})();
19363/******/ 	
19364/******/ 	/* webpack/runtime/define property getters */
19365/******/ 	(() => {
19366/******/ 		// define getter functions for harmony exports
19367/******/ 		__webpack_require__.d = (exports, definition) => {
19368/******/ 			for(var key in definition) {
19369/******/ 				if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
19370/******/ 					Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
19371/******/ 				}
19372/******/ 			}
19373/******/ 		};
19374/******/ 	})();
19375/******/ 	
19376/******/ 	/* webpack/runtime/hasOwnProperty shorthand */
19377/******/ 	(() => {
19378/******/ 		__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
19379/******/ 	})();
19380/******/ 	
19381/******/ 	/* webpack/runtime/make namespace object */
19382/******/ 	(() => {
19383/******/ 		// define __esModule on exports
19384/******/ 		__webpack_require__.r = (exports) => {
19385/******/ 			if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
19386/******/ 				Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
19387/******/ 			}
19388/******/ 			Object.defineProperty(exports, '__esModule', { value: true });
19389/******/ 		};
19390/******/ 	})();
19391/******/ 	
19392/******/ 	/* webpack/runtime/jsonp chunk loading */
19393/******/ 	(() => {
19394/******/ 		// no baseURI
19395/******/ 		
19396/******/ 		// object to store loaded and loading chunks
19397/******/ 		// undefined = chunk not loaded, null = chunk preloaded/prefetched
19398/******/ 		// [resolve, reject, Promise] = chunk loading, 0 = chunk loaded
19399/******/ 		var installedChunks = {
19400/******/ 			"/js/app": 0,
19401/******/ 			"editor-style": 0,
19402/******/ 			"css/app": 0
19403/******/ 		};
19404/******/ 		
19405/******/ 		// no chunk on demand loading
19406/******/ 		
19407/******/ 		// no prefetching
19408/******/ 		
19409/******/ 		// no preloaded
19410/******/ 		
19411/******/ 		// no HMR
19412/******/ 		
19413/******/ 		// no HMR manifest
19414/******/ 		
19415/******/ 		__webpack_require__.O.j = (chunkId) => (installedChunks[chunkId] === 0);
19416/******/ 		
19417/******/ 		// install a JSONP callback for chunk loading
19418/******/ 		var webpackJsonpCallback = (parentChunkLoadingFunction, data) => {
19419/******/ 			var [chunkIds, moreModules, runtime] = data;
19420/******/ 			// add "moreModules" to the modules object,
19421/******/ 			// then flag all "chunkIds" as loaded and fire callback
19422/******/ 			var moduleId, chunkId, i = 0;
19423/******/ 			if(chunkIds.some((id) => (installedChunks[id] !== 0))) {
19424/******/ 				for(moduleId in moreModules) {
19425/******/ 					if(__webpack_require__.o(moreModules, moduleId)) {
19426/******/ 						__webpack_require__.m[moduleId] = moreModules[moduleId];
19427/******/ 					}
19428/******/ 				}
19429/******/ 				if(runtime) var result = runtime(__webpack_require__);
19430/******/ 			}
19431/******/ 			if(parentChunkLoadingFunction) parentChunkLoadingFunction(data);
19432/******/ 			for(;i < chunkIds.length; i++) {
19433/******/ 				chunkId = chunkIds[i];
19434/******/ 				if(__webpack_require__.o(installedChunks, chunkId) && installedChunks[chunkId]) {
19435/******/ 					installedChunks[chunkId][0]();
19436/******/ 				}
19437/******/ 				installedChunks[chunkId] = 0;
19438/******/ 			}
19439/******/ 			return __webpack_require__.O(result);
19440/******/ 		}
19441/******/ 		
19442/******/ 		var chunkLoadingGlobal = self["webpackChunktailpress"] = self["webpackChunktailpress"] || [];
19443/******/ 		chunkLoadingGlobal.forEach(webpackJsonpCallback.bind(null, 0));
19444/******/ 		chunkLoadingGlobal.push = webpackJsonpCallback.bind(null, chunkLoadingGlobal.push.bind(chunkLoadingGlobal));
19445/******/ 	})();
19446/******/ 	
19447/******/ 	/* webpack/runtime/nonce */
19448/******/ 	(() => {
19449/******/ 		__webpack_require__.nc = undefined;
19450/******/ 	})();
19451/******/ 	
19452/************************************************************************/
19453/******/ 	
19454/******/ 	// startup
19455/******/ 	// Load entry module and return exports
19456/******/ 	// This entry module depends on other loaded chunks and execution need to be delayed
19457/******/ 	__webpack_require__.O(undefined, ["editor-style","css/app"], () => (__webpack_require__("./resources/js/app.js")))
19458/******/ 	__webpack_require__.O(undefined, ["editor-style","css/app"], () => (__webpack_require__("./resources/css/app.css")))
19459/******/ 	var __webpack_exports__ = __webpack_require__.O(undefined, ["editor-style","css/app"], () => (__webpack_require__("./resources/css/editor-style.css")))
19460/******/ 	__webpack_exports__ = __webpack_require__.O(__webpack_exports__);
19461/******/ 	
19462/******/ })()
19463;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.