View | Details | Raw Unified | Return to bug 18066
Collapse All | Expand All

(-)a/koha-tmpl/intranet-tmpl/lib/leaflet/leaflet-src.js (+13251 lines)
Line 0 Link Here
1
/*
2
 Leaflet 1.0.3+ed36a04, a JS library for interactive maps. http://leafletjs.com
3
 (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4
*/
5
(function (window, document, undefined) {
6
var L = {
7
	version: "1.0.3+ed36a04"
8
};
9
10
function expose() {
11
	var oldL = window.L;
12
13
	L.noConflict = function () {
14
		window.L = oldL;
15
		return this;
16
	};
17
18
	window.L = L;
19
}
20
21
// define Leaflet for Node module pattern loaders, including Browserify
22
if (typeof module === 'object' && typeof module.exports === 'object') {
23
	module.exports = L;
24
25
// define Leaflet as an AMD module
26
} else if (typeof define === 'function' && define.amd) {
27
	define(L);
28
}
29
30
// define Leaflet as a global L variable, saving the original L to restore later if needed
31
if (typeof window !== 'undefined') {
32
	expose();
33
}
34
35
36
37
/*
38
 * @namespace Util
39
 *
40
 * Various utility functions, used by Leaflet internally.
41
 */
42
43
L.Util = {
44
45
	// @function extend(dest: Object, src?: Object): Object
46
	// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
47
	extend: function (dest) {
48
		var i, j, len, src;
49
50
		for (j = 1, len = arguments.length; j < len; j++) {
51
			src = arguments[j];
52
			for (i in src) {
53
				dest[i] = src[i];
54
			}
55
		}
56
		return dest;
57
	},
58
59
	// @function create(proto: Object, properties?: Object): Object
60
	// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
61
	create: Object.create || (function () {
62
		function F() {}
63
		return function (proto) {
64
			F.prototype = proto;
65
			return new F();
66
		};
67
	})(),
68
69
	// @function bind(fn: Function, …): Function
70
	// 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).
71
	// Has a `L.bind()` shortcut.
72
	bind: function (fn, obj) {
73
		var slice = Array.prototype.slice;
74
75
		if (fn.bind) {
76
			return fn.bind.apply(fn, slice.call(arguments, 1));
77
		}
78
79
		var args = slice.call(arguments, 2);
80
81
		return function () {
82
			return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
83
		};
84
	},
85
86
	// @function stamp(obj: Object): Number
87
	// Returns the unique ID of an object, assiging it one if it doesn't have it.
88
	stamp: function (obj) {
89
		/*eslint-disable */
90
		obj._leaflet_id = obj._leaflet_id || ++L.Util.lastId;
91
		return obj._leaflet_id;
92
		/*eslint-enable */
93
	},
94
95
	// @property lastId: Number
96
	// Last unique ID used by [`stamp()`](#util-stamp)
97
	lastId: 0,
98
99
	// @function throttle(fn: Function, time: Number, context: Object): Function
100
	// Returns a function which executes function `fn` with the given scope `context`
101
	// (so that the `this` keyword refers to `context` inside `fn`'s code). The function
102
	// `fn` will be called no more than one time per given amount of `time`. The arguments
103
	// received by the bound function will be any arguments passed when binding the
104
	// function, followed by any arguments passed when invoking the bound function.
105
	// Has an `L.bind` shortcut.
106
	throttle: function (fn, time, context) {
107
		var lock, args, wrapperFn, later;
108
109
		later = function () {
110
			// reset lock and call if queued
111
			lock = false;
112
			if (args) {
113
				wrapperFn.apply(context, args);
114
				args = false;
115
			}
116
		};
117
118
		wrapperFn = function () {
119
			if (lock) {
120
				// called too soon, queue to call later
121
				args = arguments;
122
123
			} else {
124
				// call and lock until later
125
				fn.apply(context, arguments);
126
				setTimeout(later, time);
127
				lock = true;
128
			}
129
		};
130
131
		return wrapperFn;
132
	},
133
134
	// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
135
	// Returns the number `num` modulo `range` in such a way so it lies within
136
	// `range[0]` and `range[1]`. The returned value will be always smaller than
137
	// `range[1]` unless `includeMax` is set to `true`.
138
	wrapNum: function (x, range, includeMax) {
139
		var max = range[1],
140
		    min = range[0],
141
		    d = max - min;
142
		return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
143
	},
144
145
	// @function falseFn(): Function
146
	// Returns a function which always returns `false`.
147
	falseFn: function () { return false; },
148
149
	// @function formatNum(num: Number, digits?: Number): Number
150
	// Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.
151
	formatNum: function (num, digits) {
152
		var pow = Math.pow(10, digits || 5);
153
		return Math.round(num * pow) / pow;
154
	},
155
156
	// @function trim(str: String): String
157
	// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
158
	trim: function (str) {
159
		return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
160
	},
161
162
	// @function splitWords(str: String): String[]
163
	// Trims and splits the string on whitespace and returns the array of parts.
164
	splitWords: function (str) {
165
		return L.Util.trim(str).split(/\s+/);
166
	},
167
168
	// @function setOptions(obj: Object, options: Object): Object
169
	// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
170
	setOptions: function (obj, options) {
171
		if (!obj.hasOwnProperty('options')) {
172
			obj.options = obj.options ? L.Util.create(obj.options) : {};
173
		}
174
		for (var i in options) {
175
			obj.options[i] = options[i];
176
		}
177
		return obj.options;
178
	},
179
180
	// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
181
	// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
182
	// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
183
	// be appended at the end. If `uppercase` is `true`, the parameter names will
184
	// be uppercased (e.g. `'?A=foo&B=bar'`)
185
	getParamString: function (obj, existingUrl, uppercase) {
186
		var params = [];
187
		for (var i in obj) {
188
			params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
189
		}
190
		return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
191
	},
192
193
	// @function template(str: String, data: Object): String
194
	// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
195
	// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
196
	// `('Hello foo, bar')`. You can also specify functions instead of strings for
197
	// data values — they will be evaluated passing `data` as an argument.
198
	template: function (str, data) {
199
		return str.replace(L.Util.templateRe, function (str, key) {
200
			var value = data[key];
201
202
			if (value === undefined) {
203
				throw new Error('No value provided for variable ' + str);
204
205
			} else if (typeof value === 'function') {
206
				value = value(data);
207
			}
208
			return value;
209
		});
210
	},
211
212
	templateRe: /\{ *([\w_\-]+) *\}/g,
213
214
	// @function isArray(obj): Boolean
215
	// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
216
	isArray: Array.isArray || function (obj) {
217
		return (Object.prototype.toString.call(obj) === '[object Array]');
218
	},
219
220
	// @function indexOf(array: Array, el: Object): Number
221
	// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
222
	indexOf: function (array, el) {
223
		for (var i = 0; i < array.length; i++) {
224
			if (array[i] === el) { return i; }
225
		}
226
		return -1;
227
	},
228
229
	// @property emptyImageUrl: String
230
	// Data URI string containing a base64-encoded empty GIF image.
231
	// Used as a hack to free memory from unused images on WebKit-powered
232
	// mobile devices (by setting image `src` to this string).
233
	emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
234
};
235
236
(function () {
237
	// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
238
239
	function getPrefixed(name) {
240
		return window['webkit' + name] || window['moz' + name] || window['ms' + name];
241
	}
242
243
	var lastTime = 0;
244
245
	// fallback for IE 7-8
246
	function timeoutDefer(fn) {
247
		var time = +new Date(),
248
		    timeToCall = Math.max(0, 16 - (time - lastTime));
249
250
		lastTime = time + timeToCall;
251
		return window.setTimeout(fn, timeToCall);
252
	}
253
254
	var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer,
255
	    cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
256
	               getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
257
258
259
	// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
260
	// Schedules `fn` to be executed when the browser repaints. `fn` is bound to
261
	// `context` if given. When `immediate` is set, `fn` is called immediately if
262
	// the browser doesn't have native support for
263
	// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
264
	// otherwise it's delayed. Returns a request ID that can be used to cancel the request.
265
	L.Util.requestAnimFrame = function (fn, context, immediate) {
266
		if (immediate && requestFn === timeoutDefer) {
267
			fn.call(context);
268
		} else {
269
			return requestFn.call(window, L.bind(fn, context));
270
		}
271
	};
272
273
	// @function cancelAnimFrame(id: Number): undefined
274
	// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
275
	L.Util.cancelAnimFrame = function (id) {
276
		if (id) {
277
			cancelFn.call(window, id);
278
		}
279
	};
280
})();
281
282
// shortcuts for most used utility functions
283
L.extend = L.Util.extend;
284
L.bind = L.Util.bind;
285
L.stamp = L.Util.stamp;
286
L.setOptions = L.Util.setOptions;
287
288
289
290
291
// @class Class
292
// @aka L.Class
293
294
// @section
295
// @uninheritable
296
297
// Thanks to John Resig and Dean Edwards for inspiration!
298
299
L.Class = function () {};
300
301
L.Class.extend = function (props) {
302
303
	// @function extend(props: Object): Function
304
	// [Extends the current class](#class-inheritance) given the properties to be included.
305
	// Returns a Javascript function that is a class constructor (to be called with `new`).
306
	var NewClass = function () {
307
308
		// call the constructor
309
		if (this.initialize) {
310
			this.initialize.apply(this, arguments);
311
		}
312
313
		// call all constructor hooks
314
		this.callInitHooks();
315
	};
316
317
	var parentProto = NewClass.__super__ = this.prototype;
318
319
	var proto = L.Util.create(parentProto);
320
	proto.constructor = NewClass;
321
322
	NewClass.prototype = proto;
323
324
	// inherit parent's statics
325
	for (var i in this) {
326
		if (this.hasOwnProperty(i) && i !== 'prototype') {
327
			NewClass[i] = this[i];
328
		}
329
	}
330
331
	// mix static properties into the class
332
	if (props.statics) {
333
		L.extend(NewClass, props.statics);
334
		delete props.statics;
335
	}
336
337
	// mix includes into the prototype
338
	if (props.includes) {
339
		L.Util.extend.apply(null, [proto].concat(props.includes));
340
		delete props.includes;
341
	}
342
343
	// merge options
344
	if (proto.options) {
345
		props.options = L.Util.extend(L.Util.create(proto.options), props.options);
346
	}
347
348
	// mix given properties into the prototype
349
	L.extend(proto, props);
350
351
	proto._initHooks = [];
352
353
	// add method for calling all hooks
354
	proto.callInitHooks = function () {
355
356
		if (this._initHooksCalled) { return; }
357
358
		if (parentProto.callInitHooks) {
359
			parentProto.callInitHooks.call(this);
360
		}
361
362
		this._initHooksCalled = true;
363
364
		for (var i = 0, len = proto._initHooks.length; i < len; i++) {
365
			proto._initHooks[i].call(this);
366
		}
367
	};
368
369
	return NewClass;
370
};
371
372
373
// @function include(properties: Object): this
374
// [Includes a mixin](#class-includes) into the current class.
375
L.Class.include = function (props) {
376
	L.extend(this.prototype, props);
377
	return this;
378
};
379
380
// @function mergeOptions(options: Object): this
381
// [Merges `options`](#class-options) into the defaults of the class.
382
L.Class.mergeOptions = function (options) {
383
	L.extend(this.prototype.options, options);
384
	return this;
385
};
386
387
// @function addInitHook(fn: Function): this
388
// Adds a [constructor hook](#class-constructor-hooks) to the class.
389
L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
390
	var args = Array.prototype.slice.call(arguments, 1);
391
392
	var init = typeof fn === 'function' ? fn : function () {
393
		this[fn].apply(this, args);
394
	};
395
396
	this.prototype._initHooks = this.prototype._initHooks || [];
397
	this.prototype._initHooks.push(init);
398
	return this;
399
};
400
401
402
403
/*
404
 * @class Evented
405
 * @aka L.Evented
406
 * @inherits Class
407
 *
408
 * 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).
409
 *
410
 * @example
411
 *
412
 * ```js
413
 * map.on('click', function(e) {
414
 * 	alert(e.latlng);
415
 * } );
416
 * ```
417
 *
418
 * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
419
 *
420
 * ```js
421
 * function onClick(e) { ... }
422
 *
423
 * map.on('click', onClick);
424
 * map.off('click', onClick);
425
 * ```
426
 */
427
428
429
L.Evented = L.Class.extend({
430
431
	/* @method on(type: String, fn: Function, context?: Object): this
432
	 * 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'`).
433
	 *
434
	 * @alternative
435
	 * @method on(eventMap: Object): this
436
	 * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
437
	 */
438
	on: function (types, fn, context) {
439
440
		// types can be a map of types/handlers
441
		if (typeof types === 'object') {
442
			for (var type in types) {
443
				// we don't process space-separated events here for performance;
444
				// it's a hot path since Layer uses the on(obj) syntax
445
				this._on(type, types[type], fn);
446
			}
447
448
		} else {
449
			// types can be a string of space-separated words
450
			types = L.Util.splitWords(types);
451
452
			for (var i = 0, len = types.length; i < len; i++) {
453
				this._on(types[i], fn, context);
454
			}
455
		}
456
457
		return this;
458
	},
459
460
	/* @method off(type: String, fn?: Function, context?: Object): this
461
	 * 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.
462
	 *
463
	 * @alternative
464
	 * @method off(eventMap: Object): this
465
	 * Removes a set of type/listener pairs.
466
	 *
467
	 * @alternative
468
	 * @method off: this
469
	 * Removes all listeners to all events on the object.
470
	 */
471
	off: function (types, fn, context) {
472
473
		if (!types) {
474
			// clear all listeners if called without arguments
475
			delete this._events;
476
477
		} else if (typeof types === 'object') {
478
			for (var type in types) {
479
				this._off(type, types[type], fn);
480
			}
481
482
		} else {
483
			types = L.Util.splitWords(types);
484
485
			for (var i = 0, len = types.length; i < len; i++) {
486
				this._off(types[i], fn, context);
487
			}
488
		}
489
490
		return this;
491
	},
492
493
	// attach listener (without syntactic sugar now)
494
	_on: function (type, fn, context) {
495
		this._events = this._events || {};
496
497
		/* get/init listeners for type */
498
		var typeListeners = this._events[type];
499
		if (!typeListeners) {
500
			typeListeners = [];
501
			this._events[type] = typeListeners;
502
		}
503
504
		if (context === this) {
505
			// Less memory footprint.
506
			context = undefined;
507
		}
508
		var newListener = {fn: fn, ctx: context},
509
		    listeners = typeListeners;
510
511
		// check if fn already there
512
		for (var i = 0, len = listeners.length; i < len; i++) {
513
			if (listeners[i].fn === fn && listeners[i].ctx === context) {
514
				return;
515
			}
516
		}
517
518
		listeners.push(newListener);
519
	},
520
521
	_off: function (type, fn, context) {
522
		var listeners,
523
		    i,
524
		    len;
525
526
		if (!this._events) { return; }
527
528
		listeners = this._events[type];
529
530
		if (!listeners) {
531
			return;
532
		}
533
534
		if (!fn) {
535
			// Set all removed listeners to noop so they are not called if remove happens in fire
536
			for (i = 0, len = listeners.length; i < len; i++) {
537
				listeners[i].fn = L.Util.falseFn;
538
			}
539
			// clear all listeners for a type if function isn't specified
540
			delete this._events[type];
541
			return;
542
		}
543
544
		if (context === this) {
545
			context = undefined;
546
		}
547
548
		if (listeners) {
549
550
			// find fn and remove it
551
			for (i = 0, len = listeners.length; i < len; i++) {
552
				var l = listeners[i];
553
				if (l.ctx !== context) { continue; }
554
				if (l.fn === fn) {
555
556
					// set the removed listener to noop so that's not called if remove happens in fire
557
					l.fn = L.Util.falseFn;
558
559
					if (this._firingCount) {
560
						/* copy array in case events are being fired */
561
						this._events[type] = listeners = listeners.slice();
562
					}
563
					listeners.splice(i, 1);
564
565
					return;
566
				}
567
			}
568
		}
569
	},
570
571
	// @method fire(type: String, data?: Object, propagate?: Boolean): this
572
	// Fires an event of the specified type. You can optionally provide an data
573
	// object — the first argument of the listener function will contain its
574
	// properties. The event can optionally be propagated to event parents.
575
	fire: function (type, data, propagate) {
576
		if (!this.listens(type, propagate)) { return this; }
577
578
		var event = L.Util.extend({}, data, {type: type, target: this});
579
580
		if (this._events) {
581
			var listeners = this._events[type];
582
583
			if (listeners) {
584
				this._firingCount = (this._firingCount + 1) || 1;
585
				for (var i = 0, len = listeners.length; i < len; i++) {
586
					var l = listeners[i];
587
					l.fn.call(l.ctx || this, event);
588
				}
589
590
				this._firingCount--;
591
			}
592
		}
593
594
		if (propagate) {
595
			// propagate the event to parents (set with addEventParent)
596
			this._propagateEvent(event);
597
		}
598
599
		return this;
600
	},
601
602
	// @method listens(type: String): Boolean
603
	// Returns `true` if a particular event type has any listeners attached to it.
604
	listens: function (type, propagate) {
605
		var listeners = this._events && this._events[type];
606
		if (listeners && listeners.length) { return true; }
607
608
		if (propagate) {
609
			// also check parents for listeners if event propagates
610
			for (var id in this._eventParents) {
611
				if (this._eventParents[id].listens(type, propagate)) { return true; }
612
			}
613
		}
614
		return false;
615
	},
616
617
	// @method once(…): this
618
	// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
619
	once: function (types, fn, context) {
620
621
		if (typeof types === 'object') {
622
			for (var type in types) {
623
				this.once(type, types[type], fn);
624
			}
625
			return this;
626
		}
627
628
		var handler = L.bind(function () {
629
			this
630
			    .off(types, fn, context)
631
			    .off(types, handler, context);
632
		}, this);
633
634
		// add a listener that's executed once and removed after that
635
		return this
636
		    .on(types, fn, context)
637
		    .on(types, handler, context);
638
	},
639
640
	// @method addEventParent(obj: Evented): this
641
	// Adds an event parent - an `Evented` that will receive propagated events
642
	addEventParent: function (obj) {
643
		this._eventParents = this._eventParents || {};
644
		this._eventParents[L.stamp(obj)] = obj;
645
		return this;
646
	},
647
648
	// @method removeEventParent(obj: Evented): this
649
	// Removes an event parent, so it will stop receiving propagated events
650
	removeEventParent: function (obj) {
651
		if (this._eventParents) {
652
			delete this._eventParents[L.stamp(obj)];
653
		}
654
		return this;
655
	},
656
657
	_propagateEvent: function (e) {
658
		for (var id in this._eventParents) {
659
			this._eventParents[id].fire(e.type, L.extend({layer: e.target}, e), true);
660
		}
661
	}
662
});
663
664
var proto = L.Evented.prototype;
665
666
// aliases; we should ditch those eventually
667
668
// @method addEventListener(…): this
669
// Alias to [`on(…)`](#evented-on)
670
proto.addEventListener = proto.on;
671
672
// @method removeEventListener(…): this
673
// Alias to [`off(…)`](#evented-off)
674
675
// @method clearAllEventListeners(…): this
676
// Alias to [`off()`](#evented-off)
677
proto.removeEventListener = proto.clearAllEventListeners = proto.off;
678
679
// @method addOneTimeEventListener(…): this
680
// Alias to [`once(…)`](#evented-once)
681
proto.addOneTimeEventListener = proto.once;
682
683
// @method fireEvent(…): this
684
// Alias to [`fire(…)`](#evented-fire)
685
proto.fireEvent = proto.fire;
686
687
// @method hasEventListeners(…): Boolean
688
// Alias to [`listens(…)`](#evented-listens)
689
proto.hasEventListeners = proto.listens;
690
691
L.Mixin = {Events: proto};
692
693
694
695
/*
696
 * @namespace Browser
697
 * @aka L.Browser
698
 *
699
 * A namespace with static properties for browser/feature detection used by Leaflet internally.
700
 *
701
 * @example
702
 *
703
 * ```js
704
 * if (L.Browser.ielt9) {
705
 *   alert('Upgrade your browser, dude!');
706
 * }
707
 * ```
708
 */
709
710
(function () {
711
712
	var ua = navigator.userAgent.toLowerCase(),
713
	    doc = document.documentElement,
714
715
	    ie = 'ActiveXObject' in window,
716
717
	    webkit    = ua.indexOf('webkit') !== -1,
718
	    phantomjs = ua.indexOf('phantom') !== -1,
719
	    android23 = ua.search('android [23]') !== -1,
720
	    chrome    = ua.indexOf('chrome') !== -1,
721
	    gecko     = ua.indexOf('gecko') !== -1  && !webkit && !window.opera && !ie,
722
723
	    win = navigator.platform.indexOf('Win') === 0,
724
725
	    mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1,
726
	    msPointer = !window.PointerEvent && window.MSPointerEvent,
727
	    pointer = window.PointerEvent || msPointer,
728
729
	    ie3d = ie && ('transition' in doc.style),
730
	    webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,
731
	    gecko3d = 'MozPerspective' in doc.style,
732
	    opera12 = 'OTransition' in doc.style;
733
734
735
	var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
736
			(window.DocumentTouch && document instanceof window.DocumentTouch));
737
738
	L.Browser = {
739
740
		// @property ie: Boolean
741
		// `true` for all Internet Explorer versions (not Edge).
742
		ie: ie,
743
744
		// @property ielt9: Boolean
745
		// `true` for Internet Explorer versions less than 9.
746
		ielt9: ie && !document.addEventListener,
747
748
		// @property edge: Boolean
749
		// `true` for the Edge web browser.
750
		edge: 'msLaunchUri' in navigator && !('documentMode' in document),
751
752
		// @property webkit: Boolean
753
		// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
754
		webkit: webkit,
755
756
		// @property gecko: Boolean
757
		// `true` for gecko-based browsers like Firefox.
758
		gecko: gecko,
759
760
		// @property android: Boolean
761
		// `true` for any browser running on an Android platform.
762
		android: ua.indexOf('android') !== -1,
763
764
		// @property android23: Boolean
765
		// `true` for browsers running on Android 2 or Android 3.
766
		android23: android23,
767
768
		// @property chrome: Boolean
769
		// `true` for the Chrome browser.
770
		chrome: chrome,
771
772
		// @property safari: Boolean
773
		// `true` for the Safari browser.
774
		safari: !chrome && ua.indexOf('safari') !== -1,
775
776
777
		// @property win: Boolean
778
		// `true` when the browser is running in a Windows platform
779
		win: win,
780
781
782
		// @property ie3d: Boolean
783
		// `true` for all Internet Explorer versions supporting CSS transforms.
784
		ie3d: ie3d,
785
786
		// @property webkit3d: Boolean
787
		// `true` for webkit-based browsers supporting CSS transforms.
788
		webkit3d: webkit3d,
789
790
		// @property gecko3d: Boolean
791
		// `true` for gecko-based browsers supporting CSS transforms.
792
		gecko3d: gecko3d,
793
794
		// @property opera12: Boolean
795
		// `true` for the Opera browser supporting CSS transforms (version 12 or later).
796
		opera12: opera12,
797
798
		// @property any3d: Boolean
799
		// `true` for all browsers supporting CSS transforms.
800
		any3d: !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantomjs,
801
802
803
		// @property mobile: Boolean
804
		// `true` for all browsers running in a mobile device.
805
		mobile: mobile,
806
807
		// @property mobileWebkit: Boolean
808
		// `true` for all webkit-based browsers in a mobile device.
809
		mobileWebkit: mobile && webkit,
810
811
		// @property mobileWebkit3d: Boolean
812
		// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
813
		mobileWebkit3d: mobile && webkit3d,
814
815
		// @property mobileOpera: Boolean
816
		// `true` for the Opera browser in a mobile device.
817
		mobileOpera: mobile && window.opera,
818
819
		// @property mobileGecko: Boolean
820
		// `true` for gecko-based browsers running in a mobile device.
821
		mobileGecko: mobile && gecko,
822
823
824
		// @property touch: Boolean
825
		// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
826
		// This does not necessarily mean that the browser is running in a computer with
827
		// a touchscreen, it only means that the browser is capable of understanding
828
		// touch events.
829
		touch: !!touch,
830
831
		// @property msPointer: Boolean
832
		// `true` for browsers implementing the Microsoft touch events model (notably IE10).
833
		msPointer: !!msPointer,
834
835
		// @property pointer: Boolean
836
		// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
837
		pointer: !!pointer,
838
839
840
		// @property retina: Boolean
841
		// `true` for browsers on a high-resolution "retina" screen.
842
		retina: (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1
843
	};
844
845
}());
846
847
848
849
/*
850
 * @class Point
851
 * @aka L.Point
852
 *
853
 * Represents a point with `x` and `y` coordinates in pixels.
854
 *
855
 * @example
856
 *
857
 * ```js
858
 * var point = L.point(200, 300);
859
 * ```
860
 *
861
 * 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:
862
 *
863
 * ```js
864
 * map.panBy([200, 300]);
865
 * map.panBy(L.point(200, 300));
866
 * ```
867
 */
868
869
L.Point = function (x, y, round) {
870
	// @property x: Number; The `x` coordinate of the point
871
	this.x = (round ? Math.round(x) : x);
872
	// @property y: Number; The `y` coordinate of the point
873
	this.y = (round ? Math.round(y) : y);
874
};
875
876
L.Point.prototype = {
877
878
	// @method clone(): Point
879
	// Returns a copy of the current point.
880
	clone: function () {
881
		return new L.Point(this.x, this.y);
882
	},
883
884
	// @method add(otherPoint: Point): Point
885
	// Returns the result of addition of the current and the given points.
886
	add: function (point) {
887
		// non-destructive, returns a new point
888
		return this.clone()._add(L.point(point));
889
	},
890
891
	_add: function (point) {
892
		// destructive, used directly for performance in situations where it's safe to modify existing point
893
		this.x += point.x;
894
		this.y += point.y;
895
		return this;
896
	},
897
898
	// @method subtract(otherPoint: Point): Point
899
	// Returns the result of subtraction of the given point from the current.
900
	subtract: function (point) {
901
		return this.clone()._subtract(L.point(point));
902
	},
903
904
	_subtract: function (point) {
905
		this.x -= point.x;
906
		this.y -= point.y;
907
		return this;
908
	},
909
910
	// @method divideBy(num: Number): Point
911
	// Returns the result of division of the current point by the given number.
912
	divideBy: function (num) {
913
		return this.clone()._divideBy(num);
914
	},
915
916
	_divideBy: function (num) {
917
		this.x /= num;
918
		this.y /= num;
919
		return this;
920
	},
921
922
	// @method multiplyBy(num: Number): Point
923
	// Returns the result of multiplication of the current point by the given number.
924
	multiplyBy: function (num) {
925
		return this.clone()._multiplyBy(num);
926
	},
927
928
	_multiplyBy: function (num) {
929
		this.x *= num;
930
		this.y *= num;
931
		return this;
932
	},
933
934
	// @method scaleBy(scale: Point): Point
935
	// Multiply each coordinate of the current point by each coordinate of
936
	// `scale`. In linear algebra terms, multiply the point by the
937
	// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
938
	// defined by `scale`.
939
	scaleBy: function (point) {
940
		return new L.Point(this.x * point.x, this.y * point.y);
941
	},
942
943
	// @method unscaleBy(scale: Point): Point
944
	// Inverse of `scaleBy`. Divide each coordinate of the current point by
945
	// each coordinate of `scale`.
946
	unscaleBy: function (point) {
947
		return new L.Point(this.x / point.x, this.y / point.y);
948
	},
949
950
	// @method round(): Point
951
	// Returns a copy of the current point with rounded coordinates.
952
	round: function () {
953
		return this.clone()._round();
954
	},
955
956
	_round: function () {
957
		this.x = Math.round(this.x);
958
		this.y = Math.round(this.y);
959
		return this;
960
	},
961
962
	// @method floor(): Point
963
	// Returns a copy of the current point with floored coordinates (rounded down).
964
	floor: function () {
965
		return this.clone()._floor();
966
	},
967
968
	_floor: function () {
969
		this.x = Math.floor(this.x);
970
		this.y = Math.floor(this.y);
971
		return this;
972
	},
973
974
	// @method ceil(): Point
975
	// Returns a copy of the current point with ceiled coordinates (rounded up).
976
	ceil: function () {
977
		return this.clone()._ceil();
978
	},
979
980
	_ceil: function () {
981
		this.x = Math.ceil(this.x);
982
		this.y = Math.ceil(this.y);
983
		return this;
984
	},
985
986
	// @method distanceTo(otherPoint: Point): Number
987
	// Returns the cartesian distance between the current and the given points.
988
	distanceTo: function (point) {
989
		point = L.point(point);
990
991
		var x = point.x - this.x,
992
		    y = point.y - this.y;
993
994
		return Math.sqrt(x * x + y * y);
995
	},
996
997
	// @method equals(otherPoint: Point): Boolean
998
	// Returns `true` if the given point has the same coordinates.
999
	equals: function (point) {
1000
		point = L.point(point);
1001
1002
		return point.x === this.x &&
1003
		       point.y === this.y;
1004
	},
1005
1006
	// @method contains(otherPoint: Point): Boolean
1007
	// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
1008
	contains: function (point) {
1009
		point = L.point(point);
1010
1011
		return Math.abs(point.x) <= Math.abs(this.x) &&
1012
		       Math.abs(point.y) <= Math.abs(this.y);
1013
	},
1014
1015
	// @method toString(): String
1016
	// Returns a string representation of the point for debugging purposes.
1017
	toString: function () {
1018
		return 'Point(' +
1019
		        L.Util.formatNum(this.x) + ', ' +
1020
		        L.Util.formatNum(this.y) + ')';
1021
	}
1022
};
1023
1024
// @factory L.point(x: Number, y: Number, round?: Boolean)
1025
// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.
1026
1027
// @alternative
1028
// @factory L.point(coords: Number[])
1029
// Expects an array of the form `[x, y]` instead.
1030
1031
// @alternative
1032
// @factory L.point(coords: Object)
1033
// Expects a plain object of the form `{x: Number, y: Number}` instead.
1034
L.point = function (x, y, round) {
1035
	if (x instanceof L.Point) {
1036
		return x;
1037
	}
1038
	if (L.Util.isArray(x)) {
1039
		return new L.Point(x[0], x[1]);
1040
	}
1041
	if (x === undefined || x === null) {
1042
		return x;
1043
	}
1044
	if (typeof x === 'object' && 'x' in x && 'y' in x) {
1045
		return new L.Point(x.x, x.y);
1046
	}
1047
	return new L.Point(x, y, round);
1048
};
1049
1050
1051
1052
/*
1053
 * @class Bounds
1054
 * @aka L.Bounds
1055
 *
1056
 * Represents a rectangular area in pixel coordinates.
1057
 *
1058
 * @example
1059
 *
1060
 * ```js
1061
 * var p1 = L.point(10, 10),
1062
 * p2 = L.point(40, 60),
1063
 * bounds = L.bounds(p1, p2);
1064
 * ```
1065
 *
1066
 * 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:
1067
 *
1068
 * ```js
1069
 * otherBounds.intersects([[10, 10], [40, 60]]);
1070
 * ```
1071
 */
1072
1073
L.Bounds = function (a, b) {
1074
	if (!a) { return; }
1075
1076
	var points = b ? [a, b] : a;
1077
1078
	for (var i = 0, len = points.length; i < len; i++) {
1079
		this.extend(points[i]);
1080
	}
1081
};
1082
1083
L.Bounds.prototype = {
1084
	// @method extend(point: Point): this
1085
	// Extends the bounds to contain the given point.
1086
	extend: function (point) { // (Point)
1087
		point = L.point(point);
1088
1089
		// @property min: Point
1090
		// The top left corner of the rectangle.
1091
		// @property max: Point
1092
		// The bottom right corner of the rectangle.
1093
		if (!this.min && !this.max) {
1094
			this.min = point.clone();
1095
			this.max = point.clone();
1096
		} else {
1097
			this.min.x = Math.min(point.x, this.min.x);
1098
			this.max.x = Math.max(point.x, this.max.x);
1099
			this.min.y = Math.min(point.y, this.min.y);
1100
			this.max.y = Math.max(point.y, this.max.y);
1101
		}
1102
		return this;
1103
	},
1104
1105
	// @method getCenter(round?: Boolean): Point
1106
	// Returns the center point of the bounds.
1107
	getCenter: function (round) {
1108
		return new L.Point(
1109
		        (this.min.x + this.max.x) / 2,
1110
		        (this.min.y + this.max.y) / 2, round);
1111
	},
1112
1113
	// @method getBottomLeft(): Point
1114
	// Returns the bottom-left point of the bounds.
1115
	getBottomLeft: function () {
1116
		return new L.Point(this.min.x, this.max.y);
1117
	},
1118
1119
	// @method getTopRight(): Point
1120
	// Returns the top-right point of the bounds.
1121
	getTopRight: function () { // -> Point
1122
		return new L.Point(this.max.x, this.min.y);
1123
	},
1124
1125
	// @method getSize(): Point
1126
	// Returns the size of the given bounds
1127
	getSize: function () {
1128
		return this.max.subtract(this.min);
1129
	},
1130
1131
	// @method contains(otherBounds: Bounds): Boolean
1132
	// Returns `true` if the rectangle contains the given one.
1133
	// @alternative
1134
	// @method contains(point: Point): Boolean
1135
	// Returns `true` if the rectangle contains the given point.
1136
	contains: function (obj) {
1137
		var min, max;
1138
1139
		if (typeof obj[0] === 'number' || obj instanceof L.Point) {
1140
			obj = L.point(obj);
1141
		} else {
1142
			obj = L.bounds(obj);
1143
		}
1144
1145
		if (obj instanceof L.Bounds) {
1146
			min = obj.min;
1147
			max = obj.max;
1148
		} else {
1149
			min = max = obj;
1150
		}
1151
1152
		return (min.x >= this.min.x) &&
1153
		       (max.x <= this.max.x) &&
1154
		       (min.y >= this.min.y) &&
1155
		       (max.y <= this.max.y);
1156
	},
1157
1158
	// @method intersects(otherBounds: Bounds): Boolean
1159
	// Returns `true` if the rectangle intersects the given bounds. Two bounds
1160
	// intersect if they have at least one point in common.
1161
	intersects: function (bounds) { // (Bounds) -> Boolean
1162
		bounds = L.bounds(bounds);
1163
1164
		var min = this.min,
1165
		    max = this.max,
1166
		    min2 = bounds.min,
1167
		    max2 = bounds.max,
1168
		    xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
1169
		    yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
1170
1171
		return xIntersects && yIntersects;
1172
	},
1173
1174
	// @method overlaps(otherBounds: Bounds): Boolean
1175
	// Returns `true` if the rectangle overlaps the given bounds. Two bounds
1176
	// overlap if their intersection is an area.
1177
	overlaps: function (bounds) { // (Bounds) -> Boolean
1178
		bounds = L.bounds(bounds);
1179
1180
		var min = this.min,
1181
		    max = this.max,
1182
		    min2 = bounds.min,
1183
		    max2 = bounds.max,
1184
		    xOverlaps = (max2.x > min.x) && (min2.x < max.x),
1185
		    yOverlaps = (max2.y > min.y) && (min2.y < max.y);
1186
1187
		return xOverlaps && yOverlaps;
1188
	},
1189
1190
	isValid: function () {
1191
		return !!(this.min && this.max);
1192
	}
1193
};
1194
1195
1196
// @factory L.bounds(topLeft: Point, bottomRight: Point)
1197
// Creates a Bounds object from two coordinates (usually top-left and bottom-right corners).
1198
// @alternative
1199
// @factory L.bounds(points: Point[])
1200
// Creates a Bounds object from the points it contains
1201
L.bounds = function (a, b) {
1202
	if (!a || a instanceof L.Bounds) {
1203
		return a;
1204
	}
1205
	return new L.Bounds(a, b);
1206
};
1207
1208
1209
1210
/*
1211
 * @class Transformation
1212
 * @aka L.Transformation
1213
 *
1214
 * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
1215
 * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
1216
 * the reverse. Used by Leaflet in its projections code.
1217
 *
1218
 * @example
1219
 *
1220
 * ```js
1221
 * var transformation = new L.Transformation(2, 5, -1, 10),
1222
 * 	p = L.point(1, 2),
1223
 * 	p2 = transformation.transform(p), //  L.point(7, 8)
1224
 * 	p3 = transformation.untransform(p2); //  L.point(1, 2)
1225
 * ```
1226
 */
1227
1228
1229
// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
1230
// Creates a `Transformation` object with the given coefficients.
1231
L.Transformation = function (a, b, c, d) {
1232
	this._a = a;
1233
	this._b = b;
1234
	this._c = c;
1235
	this._d = d;
1236
};
1237
1238
L.Transformation.prototype = {
1239
	// @method transform(point: Point, scale?: Number): Point
1240
	// Returns a transformed point, optionally multiplied by the given scale.
1241
	// Only accepts actual `L.Point` instances, not arrays.
1242
	transform: function (point, scale) { // (Point, Number) -> Point
1243
		return this._transform(point.clone(), scale);
1244
	},
1245
1246
	// destructive transform (faster)
1247
	_transform: function (point, scale) {
1248
		scale = scale || 1;
1249
		point.x = scale * (this._a * point.x + this._b);
1250
		point.y = scale * (this._c * point.y + this._d);
1251
		return point;
1252
	},
1253
1254
	// @method untransform(point: Point, scale?: Number): Point
1255
	// Returns the reverse transformation of the given point, optionally divided
1256
	// by the given scale. Only accepts actual `L.Point` instances, not arrays.
1257
	untransform: function (point, scale) {
1258
		scale = scale || 1;
1259
		return new L.Point(
1260
		        (point.x / scale - this._b) / this._a,
1261
		        (point.y / scale - this._d) / this._c);
1262
	}
1263
};
1264
1265
1266
1267
/*
1268
 * @namespace DomUtil
1269
 *
1270
 * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
1271
 * tree, used by Leaflet internally.
1272
 *
1273
 * Most functions expecting or returning a `HTMLElement` also work for
1274
 * SVG elements. The only difference is that classes refer to CSS classes
1275
 * in HTML and SVG classes in SVG.
1276
 */
1277
1278
L.DomUtil = {
1279
1280
	// @function get(id: String|HTMLElement): HTMLElement
1281
	// Returns an element given its DOM id, or returns the element itself
1282
	// if it was passed directly.
1283
	get: function (id) {
1284
		return typeof id === 'string' ? document.getElementById(id) : id;
1285
	},
1286
1287
	// @function getStyle(el: HTMLElement, styleAttrib: String): String
1288
	// Returns the value for a certain style attribute on an element,
1289
	// including computed values or values set through CSS.
1290
	getStyle: function (el, style) {
1291
1292
		var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
1293
1294
		if ((!value || value === 'auto') && document.defaultView) {
1295
			var css = document.defaultView.getComputedStyle(el, null);
1296
			value = css ? css[style] : null;
1297
		}
1298
1299
		return value === 'auto' ? null : value;
1300
	},
1301
1302
	// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
1303
	// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
1304
	create: function (tagName, className, container) {
1305
1306
		var el = document.createElement(tagName);
1307
		el.className = className || '';
1308
1309
		if (container) {
1310
			container.appendChild(el);
1311
		}
1312
1313
		return el;
1314
	},
1315
1316
	// @function remove(el: HTMLElement)
1317
	// Removes `el` from its parent element
1318
	remove: function (el) {
1319
		var parent = el.parentNode;
1320
		if (parent) {
1321
			parent.removeChild(el);
1322
		}
1323
	},
1324
1325
	// @function empty(el: HTMLElement)
1326
	// Removes all of `el`'s children elements from `el`
1327
	empty: function (el) {
1328
		while (el.firstChild) {
1329
			el.removeChild(el.firstChild);
1330
		}
1331
	},
1332
1333
	// @function toFront(el: HTMLElement)
1334
	// Makes `el` the last children of its parent, so it renders in front of the other children.
1335
	toFront: function (el) {
1336
		el.parentNode.appendChild(el);
1337
	},
1338
1339
	// @function toBack(el: HTMLElement)
1340
	// Makes `el` the first children of its parent, so it renders back from the other children.
1341
	toBack: function (el) {
1342
		var parent = el.parentNode;
1343
		parent.insertBefore(el, parent.firstChild);
1344
	},
1345
1346
	// @function hasClass(el: HTMLElement, name: String): Boolean
1347
	// Returns `true` if the element's class attribute contains `name`.
1348
	hasClass: function (el, name) {
1349
		if (el.classList !== undefined) {
1350
			return el.classList.contains(name);
1351
		}
1352
		var className = L.DomUtil.getClass(el);
1353
		return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
1354
	},
1355
1356
	// @function addClass(el: HTMLElement, name: String)
1357
	// Adds `name` to the element's class attribute.
1358
	addClass: function (el, name) {
1359
		if (el.classList !== undefined) {
1360
			var classes = L.Util.splitWords(name);
1361
			for (var i = 0, len = classes.length; i < len; i++) {
1362
				el.classList.add(classes[i]);
1363
			}
1364
		} else if (!L.DomUtil.hasClass(el, name)) {
1365
			var className = L.DomUtil.getClass(el);
1366
			L.DomUtil.setClass(el, (className ? className + ' ' : '') + name);
1367
		}
1368
	},
1369
1370
	// @function removeClass(el: HTMLElement, name: String)
1371
	// Removes `name` from the element's class attribute.
1372
	removeClass: function (el, name) {
1373
		if (el.classList !== undefined) {
1374
			el.classList.remove(name);
1375
		} else {
1376
			L.DomUtil.setClass(el, L.Util.trim((' ' + L.DomUtil.getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
1377
		}
1378
	},
1379
1380
	// @function setClass(el: HTMLElement, name: String)
1381
	// Sets the element's class.
1382
	setClass: function (el, name) {
1383
		if (el.className.baseVal === undefined) {
1384
			el.className = name;
1385
		} else {
1386
			// in case of SVG element
1387
			el.className.baseVal = name;
1388
		}
1389
	},
1390
1391
	// @function getClass(el: HTMLElement): String
1392
	// Returns the element's class.
1393
	getClass: function (el) {
1394
		return el.className.baseVal === undefined ? el.className : el.className.baseVal;
1395
	},
1396
1397
	// @function setOpacity(el: HTMLElement, opacity: Number)
1398
	// Set the opacity of an element (including old IE support).
1399
	// `opacity` must be a number from `0` to `1`.
1400
	setOpacity: function (el, value) {
1401
1402
		if ('opacity' in el.style) {
1403
			el.style.opacity = value;
1404
1405
		} else if ('filter' in el.style) {
1406
			L.DomUtil._setOpacityIE(el, value);
1407
		}
1408
	},
1409
1410
	_setOpacityIE: function (el, value) {
1411
		var filter = false,
1412
		    filterName = 'DXImageTransform.Microsoft.Alpha';
1413
1414
		// filters collection throws an error if we try to retrieve a filter that doesn't exist
1415
		try {
1416
			filter = el.filters.item(filterName);
1417
		} catch (e) {
1418
			// don't set opacity to 1 if we haven't already set an opacity,
1419
			// it isn't needed and breaks transparent pngs.
1420
			if (value === 1) { return; }
1421
		}
1422
1423
		value = Math.round(value * 100);
1424
1425
		if (filter) {
1426
			filter.Enabled = (value !== 100);
1427
			filter.Opacity = value;
1428
		} else {
1429
			el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
1430
		}
1431
	},
1432
1433
	// @function testProp(props: String[]): String|false
1434
	// Goes through the array of style names and returns the first name
1435
	// that is a valid style name for an element. If no such name is found,
1436
	// it returns false. Useful for vendor-prefixed styles like `transform`.
1437
	testProp: function (props) {
1438
1439
		var style = document.documentElement.style;
1440
1441
		for (var i = 0; i < props.length; i++) {
1442
			if (props[i] in style) {
1443
				return props[i];
1444
			}
1445
		}
1446
		return false;
1447
	},
1448
1449
	// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
1450
	// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
1451
	// and optionally scaled by `scale`. Does not have an effect if the
1452
	// browser doesn't support 3D CSS transforms.
1453
	setTransform: function (el, offset, scale) {
1454
		var pos = offset || new L.Point(0, 0);
1455
1456
		el.style[L.DomUtil.TRANSFORM] =
1457
			(L.Browser.ie3d ?
1458
				'translate(' + pos.x + 'px,' + pos.y + 'px)' :
1459
				'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
1460
			(scale ? ' scale(' + scale + ')' : '');
1461
	},
1462
1463
	// @function setPosition(el: HTMLElement, position: Point)
1464
	// Sets the position of `el` to coordinates specified by `position`,
1465
	// using CSS translate or top/left positioning depending on the browser
1466
	// (used by Leaflet internally to position its layers).
1467
	setPosition: function (el, point) { // (HTMLElement, Point[, Boolean])
1468
1469
		/*eslint-disable */
1470
		el._leaflet_pos = point;
1471
		/*eslint-enable */
1472
1473
		if (L.Browser.any3d) {
1474
			L.DomUtil.setTransform(el, point);
1475
		} else {
1476
			el.style.left = point.x + 'px';
1477
			el.style.top = point.y + 'px';
1478
		}
1479
	},
1480
1481
	// @function getPosition(el: HTMLElement): Point
1482
	// Returns the coordinates of an element previously positioned with setPosition.
1483
	getPosition: function (el) {
1484
		// this method is only used for elements previously positioned using setPosition,
1485
		// so it's safe to cache the position for performance
1486
1487
		return el._leaflet_pos || new L.Point(0, 0);
1488
	}
1489
};
1490
1491
1492
(function () {
1493
	// prefix style property names
1494
1495
	// @property TRANSFORM: String
1496
	// Vendor-prefixed fransform style name (e.g. `'webkitTransform'` for WebKit).
1497
	L.DomUtil.TRANSFORM = L.DomUtil.testProp(
1498
			['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
1499
1500
1501
	// webkitTransition comes first because some browser versions that drop vendor prefix don't do
1502
	// the same for the transitionend event, in particular the Android 4.1 stock browser
1503
1504
	// @property TRANSITION: String
1505
	// Vendor-prefixed transform style name.
1506
	var transition = L.DomUtil.TRANSITION = L.DomUtil.testProp(
1507
			['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
1508
1509
	L.DomUtil.TRANSITION_END =
1510
			transition === 'webkitTransition' || transition === 'OTransition' ? transition + 'End' : 'transitionend';
1511
1512
	// @function disableTextSelection()
1513
	// Prevents the user from generating `selectstart` DOM events, usually generated
1514
	// when the user drags the mouse through a page with text. Used internally
1515
	// by Leaflet to override the behaviour of any click-and-drag interaction on
1516
	// the map. Affects drag interactions on the whole document.
1517
1518
	// @function enableTextSelection()
1519
	// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
1520
	if ('onselectstart' in document) {
1521
		L.DomUtil.disableTextSelection = function () {
1522
			L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
1523
		};
1524
		L.DomUtil.enableTextSelection = function () {
1525
			L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
1526
		};
1527
1528
	} else {
1529
		var userSelectProperty = L.DomUtil.testProp(
1530
			['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
1531
1532
		L.DomUtil.disableTextSelection = function () {
1533
			if (userSelectProperty) {
1534
				var style = document.documentElement.style;
1535
				this._userSelect = style[userSelectProperty];
1536
				style[userSelectProperty] = 'none';
1537
			}
1538
		};
1539
		L.DomUtil.enableTextSelection = function () {
1540
			if (userSelectProperty) {
1541
				document.documentElement.style[userSelectProperty] = this._userSelect;
1542
				delete this._userSelect;
1543
			}
1544
		};
1545
	}
1546
1547
	// @function disableImageDrag()
1548
	// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
1549
	// for `dragstart` DOM events, usually generated when the user drags an image.
1550
	L.DomUtil.disableImageDrag = function () {
1551
		L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
1552
	};
1553
1554
	// @function enableImageDrag()
1555
	// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
1556
	L.DomUtil.enableImageDrag = function () {
1557
		L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
1558
	};
1559
1560
	// @function preventOutline(el: HTMLElement)
1561
	// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
1562
	// of the element `el` invisible. Used internally by Leaflet to prevent
1563
	// focusable elements from displaying an outline when the user performs a
1564
	// drag interaction on them.
1565
	L.DomUtil.preventOutline = function (element) {
1566
		while (element.tabIndex === -1) {
1567
			element = element.parentNode;
1568
		}
1569
		if (!element || !element.style) { return; }
1570
		L.DomUtil.restoreOutline();
1571
		this._outlineElement = element;
1572
		this._outlineStyle = element.style.outline;
1573
		element.style.outline = 'none';
1574
		L.DomEvent.on(window, 'keydown', L.DomUtil.restoreOutline, this);
1575
	};
1576
1577
	// @function restoreOutline()
1578
	// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
1579
	L.DomUtil.restoreOutline = function () {
1580
		if (!this._outlineElement) { return; }
1581
		this._outlineElement.style.outline = this._outlineStyle;
1582
		delete this._outlineElement;
1583
		delete this._outlineStyle;
1584
		L.DomEvent.off(window, 'keydown', L.DomUtil.restoreOutline, this);
1585
	};
1586
})();
1587
1588
1589
1590
/* @class LatLng
1591
 * @aka L.LatLng
1592
 *
1593
 * Represents a geographical point with a certain latitude and longitude.
1594
 *
1595
 * @example
1596
 *
1597
 * ```
1598
 * var latlng = L.latLng(50.5, 30.5);
1599
 * ```
1600
 *
1601
 * 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:
1602
 *
1603
 * ```
1604
 * map.panTo([50, 30]);
1605
 * map.panTo({lon: 30, lat: 50});
1606
 * map.panTo({lat: 50, lng: 30});
1607
 * map.panTo(L.latLng(50, 30));
1608
 * ```
1609
 */
1610
1611
L.LatLng = function (lat, lng, alt) {
1612
	if (isNaN(lat) || isNaN(lng)) {
1613
		throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
1614
	}
1615
1616
	// @property lat: Number
1617
	// Latitude in degrees
1618
	this.lat = +lat;
1619
1620
	// @property lng: Number
1621
	// Longitude in degrees
1622
	this.lng = +lng;
1623
1624
	// @property alt: Number
1625
	// Altitude in meters (optional)
1626
	if (alt !== undefined) {
1627
		this.alt = +alt;
1628
	}
1629
};
1630
1631
L.LatLng.prototype = {
1632
	// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
1633
	// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overriden by setting `maxMargin` to a small number.
1634
	equals: function (obj, maxMargin) {
1635
		if (!obj) { return false; }
1636
1637
		obj = L.latLng(obj);
1638
1639
		var margin = Math.max(
1640
		        Math.abs(this.lat - obj.lat),
1641
		        Math.abs(this.lng - obj.lng));
1642
1643
		return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
1644
	},
1645
1646
	// @method toString(): String
1647
	// Returns a string representation of the point (for debugging purposes).
1648
	toString: function (precision) {
1649
		return 'LatLng(' +
1650
		        L.Util.formatNum(this.lat, precision) + ', ' +
1651
		        L.Util.formatNum(this.lng, precision) + ')';
1652
	},
1653
1654
	// @method distanceTo(otherLatLng: LatLng): Number
1655
	// Returns the distance (in meters) to the given `LatLng` calculated using the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula).
1656
	distanceTo: function (other) {
1657
		return L.CRS.Earth.distance(this, L.latLng(other));
1658
	},
1659
1660
	// @method wrap(): LatLng
1661
	// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
1662
	wrap: function () {
1663
		return L.CRS.Earth.wrapLatLng(this);
1664
	},
1665
1666
	// @method toBounds(sizeInMeters: Number): LatLngBounds
1667
	// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.
1668
	toBounds: function (sizeInMeters) {
1669
		var latAccuracy = 180 * sizeInMeters / 40075017,
1670
		    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
1671
1672
		return L.latLngBounds(
1673
		        [this.lat - latAccuracy, this.lng - lngAccuracy],
1674
		        [this.lat + latAccuracy, this.lng + lngAccuracy]);
1675
	},
1676
1677
	clone: function () {
1678
		return new L.LatLng(this.lat, this.lng, this.alt);
1679
	}
1680
};
1681
1682
1683
1684
// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
1685
// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
1686
1687
// @alternative
1688
// @factory L.latLng(coords: Array): LatLng
1689
// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
1690
1691
// @alternative
1692
// @factory L.latLng(coords: Object): LatLng
1693
// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
1694
1695
L.latLng = function (a, b, c) {
1696
	if (a instanceof L.LatLng) {
1697
		return a;
1698
	}
1699
	if (L.Util.isArray(a) && typeof a[0] !== 'object') {
1700
		if (a.length === 3) {
1701
			return new L.LatLng(a[0], a[1], a[2]);
1702
		}
1703
		if (a.length === 2) {
1704
			return new L.LatLng(a[0], a[1]);
1705
		}
1706
		return null;
1707
	}
1708
	if (a === undefined || a === null) {
1709
		return a;
1710
	}
1711
	if (typeof a === 'object' && 'lat' in a) {
1712
		return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
1713
	}
1714
	if (b === undefined) {
1715
		return null;
1716
	}
1717
	return new L.LatLng(a, b, c);
1718
};
1719
1720
1721
1722
/*
1723
 * @class LatLngBounds
1724
 * @aka L.LatLngBounds
1725
 *
1726
 * Represents a rectangular geographical area on a map.
1727
 *
1728
 * @example
1729
 *
1730
 * ```js
1731
 * var corner1 = L.latLng(40.712, -74.227),
1732
 * corner2 = L.latLng(40.774, -74.125),
1733
 * bounds = L.latLngBounds(corner1, corner2);
1734
 * ```
1735
 *
1736
 * 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:
1737
 *
1738
 * ```js
1739
 * map.fitBounds([
1740
 * 	[40.712, -74.227],
1741
 * 	[40.774, -74.125]
1742
 * ]);
1743
 * ```
1744
 *
1745
 * 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.
1746
 */
1747
1748
L.LatLngBounds = function (corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
1749
	if (!corner1) { return; }
1750
1751
	var latlngs = corner2 ? [corner1, corner2] : corner1;
1752
1753
	for (var i = 0, len = latlngs.length; i < len; i++) {
1754
		this.extend(latlngs[i]);
1755
	}
1756
};
1757
1758
L.LatLngBounds.prototype = {
1759
1760
	// @method extend(latlng: LatLng): this
1761
	// Extend the bounds to contain the given point
1762
1763
	// @alternative
1764
	// @method extend(otherBounds: LatLngBounds): this
1765
	// Extend the bounds to contain the given bounds
1766
	extend: function (obj) {
1767
		var sw = this._southWest,
1768
		    ne = this._northEast,
1769
		    sw2, ne2;
1770
1771
		if (obj instanceof L.LatLng) {
1772
			sw2 = obj;
1773
			ne2 = obj;
1774
1775
		} else if (obj instanceof L.LatLngBounds) {
1776
			sw2 = obj._southWest;
1777
			ne2 = obj._northEast;
1778
1779
			if (!sw2 || !ne2) { return this; }
1780
1781
		} else {
1782
			return obj ? this.extend(L.latLng(obj) || L.latLngBounds(obj)) : this;
1783
		}
1784
1785
		if (!sw && !ne) {
1786
			this._southWest = new L.LatLng(sw2.lat, sw2.lng);
1787
			this._northEast = new L.LatLng(ne2.lat, ne2.lng);
1788
		} else {
1789
			sw.lat = Math.min(sw2.lat, sw.lat);
1790
			sw.lng = Math.min(sw2.lng, sw.lng);
1791
			ne.lat = Math.max(ne2.lat, ne.lat);
1792
			ne.lng = Math.max(ne2.lng, ne.lng);
1793
		}
1794
1795
		return this;
1796
	},
1797
1798
	// @method pad(bufferRatio: Number): LatLngBounds
1799
	// Returns bigger bounds created by extending the current bounds by a given percentage in each direction.
1800
	pad: function (bufferRatio) {
1801
		var sw = this._southWest,
1802
		    ne = this._northEast,
1803
		    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
1804
		    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
1805
1806
		return new L.LatLngBounds(
1807
		        new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
1808
		        new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
1809
	},
1810
1811
	// @method getCenter(): LatLng
1812
	// Returns the center point of the bounds.
1813
	getCenter: function () {
1814
		return new L.LatLng(
1815
		        (this._southWest.lat + this._northEast.lat) / 2,
1816
		        (this._southWest.lng + this._northEast.lng) / 2);
1817
	},
1818
1819
	// @method getSouthWest(): LatLng
1820
	// Returns the south-west point of the bounds.
1821
	getSouthWest: function () {
1822
		return this._southWest;
1823
	},
1824
1825
	// @method getNorthEast(): LatLng
1826
	// Returns the north-east point of the bounds.
1827
	getNorthEast: function () {
1828
		return this._northEast;
1829
	},
1830
1831
	// @method getNorthWest(): LatLng
1832
	// Returns the north-west point of the bounds.
1833
	getNorthWest: function () {
1834
		return new L.LatLng(this.getNorth(), this.getWest());
1835
	},
1836
1837
	// @method getSouthEast(): LatLng
1838
	// Returns the south-east point of the bounds.
1839
	getSouthEast: function () {
1840
		return new L.LatLng(this.getSouth(), this.getEast());
1841
	},
1842
1843
	// @method getWest(): Number
1844
	// Returns the west longitude of the bounds
1845
	getWest: function () {
1846
		return this._southWest.lng;
1847
	},
1848
1849
	// @method getSouth(): Number
1850
	// Returns the south latitude of the bounds
1851
	getSouth: function () {
1852
		return this._southWest.lat;
1853
	},
1854
1855
	// @method getEast(): Number
1856
	// Returns the east longitude of the bounds
1857
	getEast: function () {
1858
		return this._northEast.lng;
1859
	},
1860
1861
	// @method getNorth(): Number
1862
	// Returns the north latitude of the bounds
1863
	getNorth: function () {
1864
		return this._northEast.lat;
1865
	},
1866
1867
	// @method contains(otherBounds: LatLngBounds): Boolean
1868
	// Returns `true` if the rectangle contains the given one.
1869
1870
	// @alternative
1871
	// @method contains (latlng: LatLng): Boolean
1872
	// Returns `true` if the rectangle contains the given point.
1873
	contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
1874
		if (typeof obj[0] === 'number' || obj instanceof L.LatLng || 'lat' in obj) {
1875
			obj = L.latLng(obj);
1876
		} else {
1877
			obj = L.latLngBounds(obj);
1878
		}
1879
1880
		var sw = this._southWest,
1881
		    ne = this._northEast,
1882
		    sw2, ne2;
1883
1884
		if (obj instanceof L.LatLngBounds) {
1885
			sw2 = obj.getSouthWest();
1886
			ne2 = obj.getNorthEast();
1887
		} else {
1888
			sw2 = ne2 = obj;
1889
		}
1890
1891
		return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
1892
		       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
1893
	},
1894
1895
	// @method intersects(otherBounds: LatLngBounds): Boolean
1896
	// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
1897
	intersects: function (bounds) {
1898
		bounds = L.latLngBounds(bounds);
1899
1900
		var sw = this._southWest,
1901
		    ne = this._northEast,
1902
		    sw2 = bounds.getSouthWest(),
1903
		    ne2 = bounds.getNorthEast(),
1904
1905
		    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
1906
		    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
1907
1908
		return latIntersects && lngIntersects;
1909
	},
1910
1911
	// @method overlaps(otherBounds: Bounds): Boolean
1912
	// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
1913
	overlaps: function (bounds) {
1914
		bounds = L.latLngBounds(bounds);
1915
1916
		var sw = this._southWest,
1917
		    ne = this._northEast,
1918
		    sw2 = bounds.getSouthWest(),
1919
		    ne2 = bounds.getNorthEast(),
1920
1921
		    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
1922
		    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
1923
1924
		return latOverlaps && lngOverlaps;
1925
	},
1926
1927
	// @method toBBoxString(): String
1928
	// 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.
1929
	toBBoxString: function () {
1930
		return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
1931
	},
1932
1933
	// @method equals(otherBounds: LatLngBounds): Boolean
1934
	// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds.
1935
	equals: function (bounds) {
1936
		if (!bounds) { return false; }
1937
1938
		bounds = L.latLngBounds(bounds);
1939
1940
		return this._southWest.equals(bounds.getSouthWest()) &&
1941
		       this._northEast.equals(bounds.getNorthEast());
1942
	},
1943
1944
	// @method isValid(): Boolean
1945
	// Returns `true` if the bounds are properly initialized.
1946
	isValid: function () {
1947
		return !!(this._southWest && this._northEast);
1948
	}
1949
};
1950
1951
// TODO International date line?
1952
1953
// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
1954
// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
1955
1956
// @alternative
1957
// @factory L.latLngBounds(latlngs: LatLng[])
1958
// 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).
1959
L.latLngBounds = function (a, b) {
1960
	if (a instanceof L.LatLngBounds) {
1961
		return a;
1962
	}
1963
	return new L.LatLngBounds(a, b);
1964
};
1965
1966
1967
1968
/*
1969
 * @namespace Projection
1970
 * @section
1971
 * Leaflet comes with a set of already defined Projections out of the box:
1972
 *
1973
 * @projection L.Projection.LonLat
1974
 *
1975
 * Equirectangular, or Plate Carree projection — the most simple projection,
1976
 * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
1977
 * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
1978
 * `EPSG:3395` and `Simple` CRS.
1979
 */
1980
1981
L.Projection = {};
1982
1983
L.Projection.LonLat = {
1984
	project: function (latlng) {
1985
		return new L.Point(latlng.lng, latlng.lat);
1986
	},
1987
1988
	unproject: function (point) {
1989
		return new L.LatLng(point.y, point.x);
1990
	},
1991
1992
	bounds: L.bounds([-180, -90], [180, 90])
1993
};
1994
1995
1996
1997
/*
1998
 * @namespace Projection
1999
 * @projection L.Projection.SphericalMercator
2000
 *
2001
 * Spherical Mercator projection — the most common projection for online maps,
2002
 * used by almost all free and commercial tile providers. Assumes that Earth is
2003
 * a sphere. Used by the `EPSG:3857` CRS.
2004
 */
2005
2006
L.Projection.SphericalMercator = {
2007
2008
	R: 6378137,
2009
	MAX_LATITUDE: 85.0511287798,
2010
2011
	project: function (latlng) {
2012
		var d = Math.PI / 180,
2013
		    max = this.MAX_LATITUDE,
2014
		    lat = Math.max(Math.min(max, latlng.lat), -max),
2015
		    sin = Math.sin(lat * d);
2016
2017
		return new L.Point(
2018
				this.R * latlng.lng * d,
2019
				this.R * Math.log((1 + sin) / (1 - sin)) / 2);
2020
	},
2021
2022
	unproject: function (point) {
2023
		var d = 180 / Math.PI;
2024
2025
		return new L.LatLng(
2026
			(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
2027
			point.x * d / this.R);
2028
	},
2029
2030
	bounds: (function () {
2031
		var d = 6378137 * Math.PI;
2032
		return L.bounds([-d, -d], [d, d]);
2033
	})()
2034
};
2035
2036
2037
2038
/*
2039
 * @class CRS
2040
 * @aka L.CRS
2041
 * Abstract class that defines coordinate reference systems for projecting
2042
 * geographical points into pixel (screen) coordinates and back (and to
2043
 * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
2044
 * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).
2045
 *
2046
 * Leaflet defines the most usual CRSs by default. If you want to use a
2047
 * CRS not defined by default, take a look at the
2048
 * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
2049
 */
2050
2051
L.CRS = {
2052
	// @method latLngToPoint(latlng: LatLng, zoom: Number): Point
2053
	// Projects geographical coordinates into pixel coordinates for a given zoom.
2054
	latLngToPoint: function (latlng, zoom) {
2055
		var projectedPoint = this.projection.project(latlng),
2056
		    scale = this.scale(zoom);
2057
2058
		return this.transformation._transform(projectedPoint, scale);
2059
	},
2060
2061
	// @method pointToLatLng(point: Point, zoom: Number): LatLng
2062
	// The inverse of `latLngToPoint`. Projects pixel coordinates on a given
2063
	// zoom into geographical coordinates.
2064
	pointToLatLng: function (point, zoom) {
2065
		var scale = this.scale(zoom),
2066
		    untransformedPoint = this.transformation.untransform(point, scale);
2067
2068
		return this.projection.unproject(untransformedPoint);
2069
	},
2070
2071
	// @method project(latlng: LatLng): Point
2072
	// Projects geographical coordinates into coordinates in units accepted for
2073
	// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
2074
	project: function (latlng) {
2075
		return this.projection.project(latlng);
2076
	},
2077
2078
	// @method unproject(point: Point): LatLng
2079
	// Given a projected coordinate returns the corresponding LatLng.
2080
	// The inverse of `project`.
2081
	unproject: function (point) {
2082
		return this.projection.unproject(point);
2083
	},
2084
2085
	// @method scale(zoom: Number): Number
2086
	// Returns the scale used when transforming projected coordinates into
2087
	// pixel coordinates for a particular zoom. For example, it returns
2088
	// `256 * 2^zoom` for Mercator-based CRS.
2089
	scale: function (zoom) {
2090
		return 256 * Math.pow(2, zoom);
2091
	},
2092
2093
	// @method zoom(scale: Number): Number
2094
	// Inverse of `scale()`, returns the zoom level corresponding to a scale
2095
	// factor of `scale`.
2096
	zoom: function (scale) {
2097
		return Math.log(scale / 256) / Math.LN2;
2098
	},
2099
2100
	// @method getProjectedBounds(zoom: Number): Bounds
2101
	// Returns the projection's bounds scaled and transformed for the provided `zoom`.
2102
	getProjectedBounds: function (zoom) {
2103
		if (this.infinite) { return null; }
2104
2105
		var b = this.projection.bounds,
2106
		    s = this.scale(zoom),
2107
		    min = this.transformation.transform(b.min, s),
2108
		    max = this.transformation.transform(b.max, s);
2109
2110
		return L.bounds(min, max);
2111
	},
2112
2113
	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
2114
	// Returns the distance between two geographical coordinates.
2115
2116
	// @property code: String
2117
	// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
2118
	//
2119
	// @property wrapLng: Number[]
2120
	// An array of two numbers defining whether the longitude (horizontal) coordinate
2121
	// axis wraps around a given range and how. Defaults to `[-180, 180]` in most
2122
	// geographical CRSs. If `undefined`, the longitude axis does not wrap around.
2123
	//
2124
	// @property wrapLat: Number[]
2125
	// Like `wrapLng`, but for the latitude (vertical) axis.
2126
2127
	// wrapLng: [min, max],
2128
	// wrapLat: [min, max],
2129
2130
	// @property infinite: Boolean
2131
	// If true, the coordinate space will be unbounded (infinite in both axes)
2132
	infinite: false,
2133
2134
	// @method wrapLatLng(latlng: LatLng): LatLng
2135
	// Returns a `LatLng` where lat and lng has been wrapped according to the
2136
	// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
2137
	// Only accepts actual `L.LatLng` instances, not arrays.
2138
	wrapLatLng: function (latlng) {
2139
		var lng = this.wrapLng ? L.Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
2140
		    lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
2141
		    alt = latlng.alt;
2142
2143
		return L.latLng(lat, lng, alt);
2144
	},
2145
2146
	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
2147
	// Returns a `LatLngBounds` with the same size as the given one, ensuring
2148
	// that its center is within the CRS's bounds.
2149
	// Only accepts actual `L.LatLngBounds` instances, not arrays.
2150
	wrapLatLngBounds: function (bounds) {
2151
		var center = bounds.getCenter(),
2152
		    newCenter = this.wrapLatLng(center),
2153
		    latShift = center.lat - newCenter.lat,
2154
		    lngShift = center.lng - newCenter.lng;
2155
2156
		if (latShift === 0 && lngShift === 0) {
2157
			return bounds;
2158
		}
2159
2160
		var sw = bounds.getSouthWest(),
2161
		    ne = bounds.getNorthEast(),
2162
		    newSw = L.latLng({lat: sw.lat - latShift, lng: sw.lng - lngShift}),
2163
		    newNe = L.latLng({lat: ne.lat - latShift, lng: ne.lng - lngShift});
2164
2165
		return new L.LatLngBounds(newSw, newNe);
2166
	}
2167
};
2168
2169
2170
2171
/*
2172
 * @namespace CRS
2173
 * @crs L.CRS.Simple
2174
 *
2175
 * A simple CRS that maps longitude and latitude into `x` and `y` directly.
2176
 * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
2177
 * axis should still be inverted (going from bottom to top). `distance()` returns
2178
 * simple euclidean distance.
2179
 */
2180
2181
L.CRS.Simple = L.extend({}, L.CRS, {
2182
	projection: L.Projection.LonLat,
2183
	transformation: new L.Transformation(1, 0, -1, 0),
2184
2185
	scale: function (zoom) {
2186
		return Math.pow(2, zoom);
2187
	},
2188
2189
	zoom: function (scale) {
2190
		return Math.log(scale) / Math.LN2;
2191
	},
2192
2193
	distance: function (latlng1, latlng2) {
2194
		var dx = latlng2.lng - latlng1.lng,
2195
		    dy = latlng2.lat - latlng1.lat;
2196
2197
		return Math.sqrt(dx * dx + dy * dy);
2198
	},
2199
2200
	infinite: true
2201
});
2202
2203
2204
2205
/*
2206
 * @namespace CRS
2207
 * @crs L.CRS.Earth
2208
 *
2209
 * Serves as the base for CRS that are global such that they cover the earth.
2210
 * Can only be used as the base for other CRS and cannot be used directly,
2211
 * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
2212
 * meters.
2213
 */
2214
2215
L.CRS.Earth = L.extend({}, L.CRS, {
2216
	wrapLng: [-180, 180],
2217
2218
	// Mean Earth Radius, as recommended for use by
2219
	// the International Union of Geodesy and Geophysics,
2220
	// see http://rosettacode.org/wiki/Haversine_formula
2221
	R: 6371000,
2222
2223
	// distance between two geographical points using spherical law of cosines approximation
2224
	distance: function (latlng1, latlng2) {
2225
		var rad = Math.PI / 180,
2226
		    lat1 = latlng1.lat * rad,
2227
		    lat2 = latlng2.lat * rad,
2228
		    a = Math.sin(lat1) * Math.sin(lat2) +
2229
		        Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);
2230
2231
		return this.R * Math.acos(Math.min(a, 1));
2232
	}
2233
});
2234
2235
2236
2237
/*
2238
 * @namespace CRS
2239
 * @crs L.CRS.EPSG3857
2240
 *
2241
 * The most common CRS for online maps, used by almost all free and commercial
2242
 * tile providers. Uses Spherical Mercator projection. Set in by default in
2243
 * Map's `crs` option.
2244
 */
2245
2246
L.CRS.EPSG3857 = L.extend({}, L.CRS.Earth, {
2247
	code: 'EPSG:3857',
2248
	projection: L.Projection.SphericalMercator,
2249
2250
	transformation: (function () {
2251
		var scale = 0.5 / (Math.PI * L.Projection.SphericalMercator.R);
2252
		return new L.Transformation(scale, 0.5, -scale, 0.5);
2253
	}())
2254
});
2255
2256
L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
2257
	code: 'EPSG:900913'
2258
});
2259
2260
2261
2262
/*
2263
 * @namespace CRS
2264
 * @crs L.CRS.EPSG4326
2265
 *
2266
 * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
2267
 *
2268
 * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
2269
 * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`
2270
 * with this CRS, ensure that there are two 256x256 pixel tiles covering the
2271
 * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
2272
 * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
2273
 */
2274
2275
L.CRS.EPSG4326 = L.extend({}, L.CRS.Earth, {
2276
	code: 'EPSG:4326',
2277
	projection: L.Projection.LonLat,
2278
	transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5)
2279
});
2280
2281
2282
2283
/*
2284
 * @class Map
2285
 * @aka L.Map
2286
 * @inherits Evented
2287
 *
2288
 * The central class of the API — it is used to create a map on a page and manipulate it.
2289
 *
2290
 * @example
2291
 *
2292
 * ```js
2293
 * // initialize the map on the "map" div with a given center and zoom
2294
 * var map = L.map('map', {
2295
 * 	center: [51.505, -0.09],
2296
 * 	zoom: 13
2297
 * });
2298
 * ```
2299
 *
2300
 */
2301
2302
L.Map = L.Evented.extend({
2303
2304
	options: {
2305
		// @section Map State Options
2306
		// @option crs: CRS = L.CRS.EPSG3857
2307
		// The [Coordinate Reference System](#crs) to use. Don't change this if you're not
2308
		// sure what it means.
2309
		crs: L.CRS.EPSG3857,
2310
2311
		// @option center: LatLng = undefined
2312
		// Initial geographic center of the map
2313
		center: undefined,
2314
2315
		// @option zoom: Number = undefined
2316
		// Initial map zoom level
2317
		zoom: undefined,
2318
2319
		// @option minZoom: Number = undefined
2320
		// Minimum zoom level of the map. Overrides any `minZoom` option set on map layers.
2321
		minZoom: undefined,
2322
2323
		// @option maxZoom: Number = undefined
2324
		// Maximum zoom level of the map. Overrides any `maxZoom` option set on map layers.
2325
		maxZoom: undefined,
2326
2327
		// @option layers: Layer[] = []
2328
		// Array of layers that will be added to the map initially
2329
		layers: [],
2330
2331
		// @option maxBounds: LatLngBounds = null
2332
		// When this option is set, the map restricts the view to the given
2333
		// geographical bounds, bouncing the user back if the user tries to pan
2334
		// outside the view. To set the restriction dynamically, use
2335
		// [`setMaxBounds`](#map-setmaxbounds) method.
2336
		maxBounds: undefined,
2337
2338
		// @option renderer: Renderer = *
2339
		// The default method for drawing vector layers on the map. `L.SVG`
2340
		// or `L.Canvas` by default depending on browser support.
2341
		renderer: undefined,
2342
2343
2344
		// @section Animation Options
2345
		// @option zoomAnimation: Boolean = true
2346
		// Whether the map zoom animation is enabled. By default it's enabled
2347
		// in all browsers that support CSS3 Transitions except Android.
2348
		zoomAnimation: true,
2349
2350
		// @option zoomAnimationThreshold: Number = 4
2351
		// Won't animate zoom if the zoom difference exceeds this value.
2352
		zoomAnimationThreshold: 4,
2353
2354
		// @option fadeAnimation: Boolean = true
2355
		// Whether the tile fade animation is enabled. By default it's enabled
2356
		// in all browsers that support CSS3 Transitions except Android.
2357
		fadeAnimation: true,
2358
2359
		// @option markerZoomAnimation: Boolean = true
2360
		// Whether markers animate their zoom with the zoom animation, if disabled
2361
		// they will disappear for the length of the animation. By default it's
2362
		// enabled in all browsers that support CSS3 Transitions except Android.
2363
		markerZoomAnimation: true,
2364
2365
		// @option transform3DLimit: Number = 2^23
2366
		// Defines the maximum size of a CSS translation transform. The default
2367
		// value should not be changed unless a web browser positions layers in
2368
		// the wrong place after doing a large `panBy`.
2369
		transform3DLimit: 8388608, // Precision limit of a 32-bit float
2370
2371
		// @section Interaction Options
2372
		// @option zoomSnap: Number = 1
2373
		// Forces the map's zoom level to always be a multiple of this, particularly
2374
		// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
2375
		// By default, the zoom level snaps to the nearest integer; lower values
2376
		// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
2377
		// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
2378
		zoomSnap: 1,
2379
2380
		// @option zoomDelta: Number = 1
2381
		// Controls how much the map's zoom level will change after a
2382
		// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
2383
		// or `-` on the keyboard, or using the [zoom controls](#control-zoom).
2384
		// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
2385
		zoomDelta: 1,
2386
2387
		// @option trackResize: Boolean = true
2388
		// Whether the map automatically handles browser window resize to update itself.
2389
		trackResize: true
2390
	},
2391
2392
	initialize: function (id, options) { // (HTMLElement or String, Object)
2393
		options = L.setOptions(this, options);
2394
2395
		this._initContainer(id);
2396
		this._initLayout();
2397
2398
		// hack for https://github.com/Leaflet/Leaflet/issues/1980
2399
		this._onResize = L.bind(this._onResize, this);
2400
2401
		this._initEvents();
2402
2403
		if (options.maxBounds) {
2404
			this.setMaxBounds(options.maxBounds);
2405
		}
2406
2407
		if (options.zoom !== undefined) {
2408
			this._zoom = this._limitZoom(options.zoom);
2409
		}
2410
2411
		if (options.center && options.zoom !== undefined) {
2412
			this.setView(L.latLng(options.center), options.zoom, {reset: true});
2413
		}
2414
2415
		this._handlers = [];
2416
		this._layers = {};
2417
		this._zoomBoundLayers = {};
2418
		this._sizeChanged = true;
2419
2420
		this.callInitHooks();
2421
2422
		// don't animate on browsers without hardware-accelerated transitions or old Android/Opera
2423
		this._zoomAnimated = L.DomUtil.TRANSITION && L.Browser.any3d && !L.Browser.mobileOpera &&
2424
				this.options.zoomAnimation;
2425
2426
		// zoom transitions run with the same duration for all layers, so if one of transitionend events
2427
		// happens after starting zoom animation (propagating to the map pane), we know that it ended globally
2428
		if (this._zoomAnimated) {
2429
			this._createAnimProxy();
2430
			L.DomEvent.on(this._proxy, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
2431
		}
2432
2433
		this._addLayers(this.options.layers);
2434
	},
2435
2436
2437
	// @section Methods for modifying map state
2438
2439
	// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
2440
	// Sets the view of the map (geographical center and zoom) with the given
2441
	// animation options.
2442
	setView: function (center, zoom, options) {
2443
2444
		zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
2445
		center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
2446
		options = options || {};
2447
2448
		this._stop();
2449
2450
		if (this._loaded && !options.reset && options !== true) {
2451
2452
			if (options.animate !== undefined) {
2453
				options.zoom = L.extend({animate: options.animate}, options.zoom);
2454
				options.pan = L.extend({animate: options.animate, duration: options.duration}, options.pan);
2455
			}
2456
2457
			// try animating pan or zoom
2458
			var moved = (this._zoom !== zoom) ?
2459
				this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
2460
				this._tryAnimatedPan(center, options.pan);
2461
2462
			if (moved) {
2463
				// prevent resize handler call, the view will refresh after animation anyway
2464
				clearTimeout(this._sizeTimer);
2465
				return this;
2466
			}
2467
		}
2468
2469
		// animation didn't start, just reset the map view
2470
		this._resetView(center, zoom);
2471
2472
		return this;
2473
	},
2474
2475
	// @method setZoom(zoom: Number, options: Zoom/pan options): this
2476
	// Sets the zoom of the map.
2477
	setZoom: function (zoom, options) {
2478
		if (!this._loaded) {
2479
			this._zoom = zoom;
2480
			return this;
2481
		}
2482
		return this.setView(this.getCenter(), zoom, {zoom: options});
2483
	},
2484
2485
	// @method zoomIn(delta?: Number, options?: Zoom options): this
2486
	// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
2487
	zoomIn: function (delta, options) {
2488
		delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
2489
		return this.setZoom(this._zoom + delta, options);
2490
	},
2491
2492
	// @method zoomOut(delta?: Number, options?: Zoom options): this
2493
	// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
2494
	zoomOut: function (delta, options) {
2495
		delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
2496
		return this.setZoom(this._zoom - delta, options);
2497
	},
2498
2499
	// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
2500
	// Zooms the map while keeping a specified geographical point on the map
2501
	// stationary (e.g. used internally for scroll zoom and double-click zoom).
2502
	// @alternative
2503
	// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
2504
	// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
2505
	setZoomAround: function (latlng, zoom, options) {
2506
		var scale = this.getZoomScale(zoom),
2507
		    viewHalf = this.getSize().divideBy(2),
2508
		    containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
2509
2510
		    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
2511
		    newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
2512
2513
		return this.setView(newCenter, zoom, {zoom: options});
2514
	},
2515
2516
	_getBoundsCenterZoom: function (bounds, options) {
2517
2518
		options = options || {};
2519
		bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
2520
2521
		var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
2522
		    paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
2523
2524
		    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
2525
2526
		zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
2527
2528
		var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
2529
2530
		    swPoint = this.project(bounds.getSouthWest(), zoom),
2531
		    nePoint = this.project(bounds.getNorthEast(), zoom),
2532
		    center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
2533
2534
		return {
2535
			center: center,
2536
			zoom: zoom
2537
		};
2538
	},
2539
2540
	// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this
2541
	// Sets a map view that contains the given geographical bounds with the
2542
	// maximum zoom level possible.
2543
	fitBounds: function (bounds, options) {
2544
2545
		bounds = L.latLngBounds(bounds);
2546
2547
		if (!bounds.isValid()) {
2548
			throw new Error('Bounds are not valid.');
2549
		}
2550
2551
		var target = this._getBoundsCenterZoom(bounds, options);
2552
		return this.setView(target.center, target.zoom, options);
2553
	},
2554
2555
	// @method fitWorld(options?: fitBounds options): this
2556
	// Sets a map view that mostly contains the whole world with the maximum
2557
	// zoom level possible.
2558
	fitWorld: function (options) {
2559
		return this.fitBounds([[-90, -180], [90, 180]], options);
2560
	},
2561
2562
	// @method panTo(latlng: LatLng, options?: Pan options): this
2563
	// Pans the map to a given center.
2564
	panTo: function (center, options) { // (LatLng)
2565
		return this.setView(center, this._zoom, {pan: options});
2566
	},
2567
2568
	// @method panBy(offset: Point): this
2569
	// Pans the map by a given number of pixels (animated).
2570
	panBy: function (offset, options) {
2571
		offset = L.point(offset).round();
2572
		options = options || {};
2573
2574
		if (!offset.x && !offset.y) {
2575
			return this.fire('moveend');
2576
		}
2577
		// If we pan too far, Chrome gets issues with tiles
2578
		// and makes them disappear or appear in the wrong place (slightly offset) #2602
2579
		if (options.animate !== true && !this.getSize().contains(offset)) {
2580
			this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
2581
			return this;
2582
		}
2583
2584
		if (!this._panAnim) {
2585
			this._panAnim = new L.PosAnimation();
2586
2587
			this._panAnim.on({
2588
				'step': this._onPanTransitionStep,
2589
				'end': this._onPanTransitionEnd
2590
			}, this);
2591
		}
2592
2593
		// don't fire movestart if animating inertia
2594
		if (!options.noMoveStart) {
2595
			this.fire('movestart');
2596
		}
2597
2598
		// animate pan unless animate: false specified
2599
		if (options.animate !== false) {
2600
			L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
2601
2602
			var newPos = this._getMapPanePos().subtract(offset).round();
2603
			this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
2604
		} else {
2605
			this._rawPanBy(offset);
2606
			this.fire('move').fire('moveend');
2607
		}
2608
2609
		return this;
2610
	},
2611
2612
	// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
2613
	// Sets the view of the map (geographical center and zoom) performing a smooth
2614
	// pan-zoom animation.
2615
	flyTo: function (targetCenter, targetZoom, options) {
2616
2617
		options = options || {};
2618
		if (options.animate === false || !L.Browser.any3d) {
2619
			return this.setView(targetCenter, targetZoom, options);
2620
		}
2621
2622
		this._stop();
2623
2624
		var from = this.project(this.getCenter()),
2625
		    to = this.project(targetCenter),
2626
		    size = this.getSize(),
2627
		    startZoom = this._zoom;
2628
2629
		targetCenter = L.latLng(targetCenter);
2630
		targetZoom = targetZoom === undefined ? startZoom : targetZoom;
2631
2632
		var w0 = Math.max(size.x, size.y),
2633
		    w1 = w0 * this.getZoomScale(startZoom, targetZoom),
2634
		    u1 = (to.distanceTo(from)) || 1,
2635
		    rho = 1.42,
2636
		    rho2 = rho * rho;
2637
2638
		function r(i) {
2639
			var s1 = i ? -1 : 1,
2640
			    s2 = i ? w1 : w0,
2641
			    t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
2642
			    b1 = 2 * s2 * rho2 * u1,
2643
			    b = t1 / b1,
2644
			    sq = Math.sqrt(b * b + 1) - b;
2645
2646
			    // workaround for floating point precision bug when sq = 0, log = -Infinite,
2647
			    // thus triggering an infinite loop in flyTo
2648
			    var log = sq < 0.000000001 ? -18 : Math.log(sq);
2649
2650
			return log;
2651
		}
2652
2653
		function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
2654
		function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
2655
		function tanh(n) { return sinh(n) / cosh(n); }
2656
2657
		var r0 = r(0);
2658
2659
		function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
2660
		function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
2661
2662
		function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
2663
2664
		var start = Date.now(),
2665
		    S = (r(1) - r0) / rho,
2666
		    duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
2667
2668
		function frame() {
2669
			var t = (Date.now() - start) / duration,
2670
			    s = easeOut(t) * S;
2671
2672
			if (t <= 1) {
2673
				this._flyToFrame = L.Util.requestAnimFrame(frame, this);
2674
2675
				this._move(
2676
					this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
2677
					this.getScaleZoom(w0 / w(s), startZoom),
2678
					{flyTo: true});
2679
2680
			} else {
2681
				this
2682
					._move(targetCenter, targetZoom)
2683
					._moveEnd(true);
2684
			}
2685
		}
2686
2687
		this._moveStart(true);
2688
2689
		frame.call(this);
2690
		return this;
2691
	},
2692
2693
	// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
2694
	// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
2695
	// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
2696
	flyToBounds: function (bounds, options) {
2697
		var target = this._getBoundsCenterZoom(bounds, options);
2698
		return this.flyTo(target.center, target.zoom, options);
2699
	},
2700
2701
	// @method setMaxBounds(bounds: Bounds): this
2702
	// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
2703
	setMaxBounds: function (bounds) {
2704
		bounds = L.latLngBounds(bounds);
2705
2706
		if (!bounds.isValid()) {
2707
			this.options.maxBounds = null;
2708
			return this.off('moveend', this._panInsideMaxBounds);
2709
		} else if (this.options.maxBounds) {
2710
			this.off('moveend', this._panInsideMaxBounds);
2711
		}
2712
2713
		this.options.maxBounds = bounds;
2714
2715
		if (this._loaded) {
2716
			this._panInsideMaxBounds();
2717
		}
2718
2719
		return this.on('moveend', this._panInsideMaxBounds);
2720
	},
2721
2722
	// @method setMinZoom(zoom: Number): this
2723
	// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
2724
	setMinZoom: function (zoom) {
2725
		this.options.minZoom = zoom;
2726
2727
		if (this._loaded && this.getZoom() < this.options.minZoom) {
2728
			return this.setZoom(zoom);
2729
		}
2730
2731
		return this;
2732
	},
2733
2734
	// @method setMaxZoom(zoom: Number): this
2735
	// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
2736
	setMaxZoom: function (zoom) {
2737
		this.options.maxZoom = zoom;
2738
2739
		if (this._loaded && (this.getZoom() > this.options.maxZoom)) {
2740
			return this.setZoom(zoom);
2741
		}
2742
2743
		return this;
2744
	},
2745
2746
	// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
2747
	// 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.
2748
	panInsideBounds: function (bounds, options) {
2749
		this._enforcingBounds = true;
2750
		var center = this.getCenter(),
2751
		    newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
2752
2753
		if (!center.equals(newCenter)) {
2754
			this.panTo(newCenter, options);
2755
		}
2756
2757
		this._enforcingBounds = false;
2758
		return this;
2759
	},
2760
2761
	// @method invalidateSize(options: Zoom/Pan options): this
2762
	// Checks if the map container size changed and updates the map if so —
2763
	// call it after you've changed the map size dynamically, also animating
2764
	// pan by default. If `options.pan` is `false`, panning will not occur.
2765
	// If `options.debounceMoveend` is `true`, it will delay `moveend` event so
2766
	// that it doesn't happen often even if the method is called many
2767
	// times in a row.
2768
2769
	// @alternative
2770
	// @method invalidateSize(animate: Boolean): this
2771
	// Checks if the map container size changed and updates the map if so —
2772
	// call it after you've changed the map size dynamically, also animating
2773
	// pan by default.
2774
	invalidateSize: function (options) {
2775
		if (!this._loaded) { return this; }
2776
2777
		options = L.extend({
2778
			animate: false,
2779
			pan: true
2780
		}, options === true ? {animate: true} : options);
2781
2782
		var oldSize = this.getSize();
2783
		this._sizeChanged = true;
2784
		this._lastCenter = null;
2785
2786
		var newSize = this.getSize(),
2787
		    oldCenter = oldSize.divideBy(2).round(),
2788
		    newCenter = newSize.divideBy(2).round(),
2789
		    offset = oldCenter.subtract(newCenter);
2790
2791
		if (!offset.x && !offset.y) { return this; }
2792
2793
		if (options.animate && options.pan) {
2794
			this.panBy(offset);
2795
2796
		} else {
2797
			if (options.pan) {
2798
				this._rawPanBy(offset);
2799
			}
2800
2801
			this.fire('move');
2802
2803
			if (options.debounceMoveend) {
2804
				clearTimeout(this._sizeTimer);
2805
				this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
2806
			} else {
2807
				this.fire('moveend');
2808
			}
2809
		}
2810
2811
		// @section Map state change events
2812
		// @event resize: ResizeEvent
2813
		// Fired when the map is resized.
2814
		return this.fire('resize', {
2815
			oldSize: oldSize,
2816
			newSize: newSize
2817
		});
2818
	},
2819
2820
	// @section Methods for modifying map state
2821
	// @method stop(): this
2822
	// Stops the currently running `panTo` or `flyTo` animation, if any.
2823
	stop: function () {
2824
		this.setZoom(this._limitZoom(this._zoom));
2825
		if (!this.options.zoomSnap) {
2826
			this.fire('viewreset');
2827
		}
2828
		return this._stop();
2829
	},
2830
2831
	// @section Geolocation methods
2832
	// @method locate(options?: Locate options): this
2833
	// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
2834
	// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
2835
	// and optionally sets the map view to the user's location with respect to
2836
	// detection accuracy (or to the world view if geolocation failed).
2837
	// Note that, if your page doesn't use HTTPS, this method will fail in
2838
	// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
2839
	// See `Locate options` for more details.
2840
	locate: function (options) {
2841
2842
		options = this._locateOptions = L.extend({
2843
			timeout: 10000,
2844
			watch: false
2845
			// setView: false
2846
			// maxZoom: <Number>
2847
			// maximumAge: 0
2848
			// enableHighAccuracy: false
2849
		}, options);
2850
2851
		if (!('geolocation' in navigator)) {
2852
			this._handleGeolocationError({
2853
				code: 0,
2854
				message: 'Geolocation not supported.'
2855
			});
2856
			return this;
2857
		}
2858
2859
		var onResponse = L.bind(this._handleGeolocationResponse, this),
2860
		    onError = L.bind(this._handleGeolocationError, this);
2861
2862
		if (options.watch) {
2863
			this._locationWatchId =
2864
			        navigator.geolocation.watchPosition(onResponse, onError, options);
2865
		} else {
2866
			navigator.geolocation.getCurrentPosition(onResponse, onError, options);
2867
		}
2868
		return this;
2869
	},
2870
2871
	// @method stopLocate(): this
2872
	// Stops watching location previously initiated by `map.locate({watch: true})`
2873
	// and aborts resetting the map view if map.locate was called with
2874
	// `{setView: true}`.
2875
	stopLocate: function () {
2876
		if (navigator.geolocation && navigator.geolocation.clearWatch) {
2877
			navigator.geolocation.clearWatch(this._locationWatchId);
2878
		}
2879
		if (this._locateOptions) {
2880
			this._locateOptions.setView = false;
2881
		}
2882
		return this;
2883
	},
2884
2885
	_handleGeolocationError: function (error) {
2886
		var c = error.code,
2887
		    message = error.message ||
2888
		            (c === 1 ? 'permission denied' :
2889
		            (c === 2 ? 'position unavailable' : 'timeout'));
2890
2891
		if (this._locateOptions.setView && !this._loaded) {
2892
			this.fitWorld();
2893
		}
2894
2895
		// @section Location events
2896
		// @event locationerror: ErrorEvent
2897
		// Fired when geolocation (using the [`locate`](#map-locate) method) failed.
2898
		this.fire('locationerror', {
2899
			code: c,
2900
			message: 'Geolocation error: ' + message + '.'
2901
		});
2902
	},
2903
2904
	_handleGeolocationResponse: function (pos) {
2905
		var lat = pos.coords.latitude,
2906
		    lng = pos.coords.longitude,
2907
		    latlng = new L.LatLng(lat, lng),
2908
		    bounds = latlng.toBounds(pos.coords.accuracy),
2909
		    options = this._locateOptions;
2910
2911
		if (options.setView) {
2912
			var zoom = this.getBoundsZoom(bounds);
2913
			this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
2914
		}
2915
2916
		var data = {
2917
			latlng: latlng,
2918
			bounds: bounds,
2919
			timestamp: pos.timestamp
2920
		};
2921
2922
		for (var i in pos.coords) {
2923
			if (typeof pos.coords[i] === 'number') {
2924
				data[i] = pos.coords[i];
2925
			}
2926
		}
2927
2928
		// @event locationfound: LocationEvent
2929
		// Fired when geolocation (using the [`locate`](#map-locate) method)
2930
		// went successfully.
2931
		this.fire('locationfound', data);
2932
	},
2933
2934
	// TODO handler.addTo
2935
	// TODO Appropiate docs section?
2936
	// @section Other Methods
2937
	// @method addHandler(name: String, HandlerClass: Function): this
2938
	// Adds a new `Handler` to the map, given its name and constructor function.
2939
	addHandler: function (name, HandlerClass) {
2940
		if (!HandlerClass) { return this; }
2941
2942
		var handler = this[name] = new HandlerClass(this);
2943
2944
		this._handlers.push(handler);
2945
2946
		if (this.options[name]) {
2947
			handler.enable();
2948
		}
2949
2950
		return this;
2951
	},
2952
2953
	// @method remove(): this
2954
	// Destroys the map and clears all related event listeners.
2955
	remove: function () {
2956
2957
		this._initEvents(true);
2958
2959
		if (this._containerId !== this._container._leaflet_id) {
2960
			throw new Error('Map container is being reused by another instance');
2961
		}
2962
2963
		try {
2964
			// throws error in IE6-8
2965
			delete this._container._leaflet_id;
2966
			delete this._containerId;
2967
		} catch (e) {
2968
			/*eslint-disable */
2969
			this._container._leaflet_id = undefined;
2970
			/*eslint-enable */
2971
			this._containerId = undefined;
2972
		}
2973
2974
		L.DomUtil.remove(this._mapPane);
2975
2976
		if (this._clearControlPos) {
2977
			this._clearControlPos();
2978
		}
2979
2980
		this._clearHandlers();
2981
2982
		if (this._loaded) {
2983
			// @section Map state change events
2984
			// @event unload: Event
2985
			// Fired when the map is destroyed with [remove](#map-remove) method.
2986
			this.fire('unload');
2987
		}
2988
2989
		for (var i in this._layers) {
2990
			this._layers[i].remove();
2991
		}
2992
2993
		return this;
2994
	},
2995
2996
	// @section Other Methods
2997
	// @method createPane(name: String, container?: HTMLElement): HTMLElement
2998
	// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
2999
	// then returns it. The pane is created as a children of `container`, or
3000
	// as a children of the main map pane if not set.
3001
	createPane: function (name, container) {
3002
		var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
3003
		    pane = L.DomUtil.create('div', className, container || this._mapPane);
3004
3005
		if (name) {
3006
			this._panes[name] = pane;
3007
		}
3008
		return pane;
3009
	},
3010
3011
	// @section Methods for Getting Map State
3012
3013
	// @method getCenter(): LatLng
3014
	// Returns the geographical center of the map view
3015
	getCenter: function () {
3016
		this._checkIfLoaded();
3017
3018
		if (this._lastCenter && !this._moved()) {
3019
			return this._lastCenter;
3020
		}
3021
		return this.layerPointToLatLng(this._getCenterLayerPoint());
3022
	},
3023
3024
	// @method getZoom(): Number
3025
	// Returns the current zoom level of the map view
3026
	getZoom: function () {
3027
		return this._zoom;
3028
	},
3029
3030
	// @method getBounds(): LatLngBounds
3031
	// Returns the geographical bounds visible in the current map view
3032
	getBounds: function () {
3033
		var bounds = this.getPixelBounds(),
3034
		    sw = this.unproject(bounds.getBottomLeft()),
3035
		    ne = this.unproject(bounds.getTopRight());
3036
3037
		return new L.LatLngBounds(sw, ne);
3038
	},
3039
3040
	// @method getMinZoom(): Number
3041
	// 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.
3042
	getMinZoom: function () {
3043
		return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
3044
	},
3045
3046
	// @method getMaxZoom(): Number
3047
	// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
3048
	getMaxZoom: function () {
3049
		return this.options.maxZoom === undefined ?
3050
			(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
3051
			this.options.maxZoom;
3052
	},
3053
3054
	// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean): Number
3055
	// Returns the maximum zoom level on which the given bounds fit to the map
3056
	// view in its entirety. If `inside` (optional) is set to `true`, the method
3057
	// instead returns the minimum zoom level on which the map view fits into
3058
	// the given bounds in its entirety.
3059
	getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
3060
		bounds = L.latLngBounds(bounds);
3061
		padding = L.point(padding || [0, 0]);
3062
3063
		var zoom = this.getZoom() || 0,
3064
		    min = this.getMinZoom(),
3065
		    max = this.getMaxZoom(),
3066
		    nw = bounds.getNorthWest(),
3067
		    se = bounds.getSouthEast(),
3068
		    size = this.getSize().subtract(padding),
3069
		    boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),
3070
		    snap = L.Browser.any3d ? this.options.zoomSnap : 1;
3071
3072
		var scale = Math.min(size.x / boundsSize.x, size.y / boundsSize.y);
3073
		zoom = this.getScaleZoom(scale, zoom);
3074
3075
		if (snap) {
3076
			zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
3077
			zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
3078
		}
3079
3080
		return Math.max(min, Math.min(max, zoom));
3081
	},
3082
3083
	// @method getSize(): Point
3084
	// Returns the current size of the map container (in pixels).
3085
	getSize: function () {
3086
		if (!this._size || this._sizeChanged) {
3087
			this._size = new L.Point(
3088
				this._container.clientWidth || 0,
3089
				this._container.clientHeight || 0);
3090
3091
			this._sizeChanged = false;
3092
		}
3093
		return this._size.clone();
3094
	},
3095
3096
	// @method getPixelBounds(): Bounds
3097
	// Returns the bounds of the current map view in projected pixel
3098
	// coordinates (sometimes useful in layer and overlay implementations).
3099
	getPixelBounds: function (center, zoom) {
3100
		var topLeftPoint = this._getTopLeftPoint(center, zoom);
3101
		return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
3102
	},
3103
3104
	// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
3105
	// the map pane? "left point of the map layer" can be confusing, specially
3106
	// since there can be negative offsets.
3107
	// @method getPixelOrigin(): Point
3108
	// Returns the projected pixel coordinates of the top left point of
3109
	// the map layer (useful in custom layer and overlay implementations).
3110
	getPixelOrigin: function () {
3111
		this._checkIfLoaded();
3112
		return this._pixelOrigin;
3113
	},
3114
3115
	// @method getPixelWorldBounds(zoom?: Number): Bounds
3116
	// Returns the world's bounds in pixel coordinates for zoom level `zoom`.
3117
	// If `zoom` is omitted, the map's current zoom level is used.
3118
	getPixelWorldBounds: function (zoom) {
3119
		return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
3120
	},
3121
3122
	// @section Other Methods
3123
3124
	// @method getPane(pane: String|HTMLElement): HTMLElement
3125
	// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
3126
	getPane: function (pane) {
3127
		return typeof pane === 'string' ? this._panes[pane] : pane;
3128
	},
3129
3130
	// @method getPanes(): Object
3131
	// Returns a plain object containing the names of all [panes](#map-pane) as keys and
3132
	// the panes as values.
3133
	getPanes: function () {
3134
		return this._panes;
3135
	},
3136
3137
	// @method getContainer: HTMLElement
3138
	// Returns the HTML element that contains the map.
3139
	getContainer: function () {
3140
		return this._container;
3141
	},
3142
3143
3144
	// @section Conversion Methods
3145
3146
	// @method getZoomScale(toZoom: Number, fromZoom: Number): Number
3147
	// Returns the scale factor to be applied to a map transition from zoom level
3148
	// `fromZoom` to `toZoom`. Used internally to help with zoom animations.
3149
	getZoomScale: function (toZoom, fromZoom) {
3150
		// TODO replace with universal implementation after refactoring projections
3151
		var crs = this.options.crs;
3152
		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3153
		return crs.scale(toZoom) / crs.scale(fromZoom);
3154
	},
3155
3156
	// @method getScaleZoom(scale: Number, fromZoom: Number): Number
3157
	// Returns the zoom level that the map would end up at, if it is at `fromZoom`
3158
	// level and everything is scaled by a factor of `scale`. Inverse of
3159
	// [`getZoomScale`](#map-getZoomScale).
3160
	getScaleZoom: function (scale, fromZoom) {
3161
		var crs = this.options.crs;
3162
		fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
3163
		var zoom = crs.zoom(scale * crs.scale(fromZoom));
3164
		return isNaN(zoom) ? Infinity : zoom;
3165
	},
3166
3167
	// @method project(latlng: LatLng, zoom: Number): Point
3168
	// Projects a geographical coordinate `LatLng` according to the projection
3169
	// of the map's CRS, then scales it according to `zoom` and the CRS's
3170
	// `Transformation`. The result is pixel coordinate relative to
3171
	// the CRS origin.
3172
	project: function (latlng, zoom) {
3173
		zoom = zoom === undefined ? this._zoom : zoom;
3174
		return this.options.crs.latLngToPoint(L.latLng(latlng), zoom);
3175
	},
3176
3177
	// @method unproject(point: Point, zoom: Number): LatLng
3178
	// Inverse of [`project`](#map-project).
3179
	unproject: function (point, zoom) {
3180
		zoom = zoom === undefined ? this._zoom : zoom;
3181
		return this.options.crs.pointToLatLng(L.point(point), zoom);
3182
	},
3183
3184
	// @method layerPointToLatLng(point: Point): LatLng
3185
	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
3186
	// returns the corresponding geographical coordinate (for the current zoom level).
3187
	layerPointToLatLng: function (point) {
3188
		var projectedPoint = L.point(point).add(this.getPixelOrigin());
3189
		return this.unproject(projectedPoint);
3190
	},
3191
3192
	// @method latLngToLayerPoint(latlng: LatLng): Point
3193
	// Given a geographical coordinate, returns the corresponding pixel coordinate
3194
	// relative to the [origin pixel](#map-getpixelorigin).
3195
	latLngToLayerPoint: function (latlng) {
3196
		var projectedPoint = this.project(L.latLng(latlng))._round();
3197
		return projectedPoint._subtract(this.getPixelOrigin());
3198
	},
3199
3200
	// @method wrapLatLng(latlng: LatLng): LatLng
3201
	// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
3202
	// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
3203
	// CRS's bounds.
3204
	// By default this means longitude is wrapped around the dateline so its
3205
	// value is between -180 and +180 degrees.
3206
	wrapLatLng: function (latlng) {
3207
		return this.options.crs.wrapLatLng(L.latLng(latlng));
3208
	},
3209
3210
	// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds
3211
	// Returns a `LatLngBounds` with the same size as the given one, ensuring that
3212
	// its center is within the CRS's bounds.
3213
	// By default this means the center longitude is wrapped around the dateline so its
3214
	// value is between -180 and +180 degrees, and the majority of the bounds
3215
	// overlaps the CRS's bounds.
3216
	wrapLatLngBounds: function (latlng) {
3217
		return this.options.crs.wrapLatLngBounds(L.latLngBounds(latlng));
3218
	},
3219
3220
	// @method distance(latlng1: LatLng, latlng2: LatLng): Number
3221
	// Returns the distance between two geographical coordinates according to
3222
	// the map's CRS. By default this measures distance in meters.
3223
	distance: function (latlng1, latlng2) {
3224
		return this.options.crs.distance(L.latLng(latlng1), L.latLng(latlng2));
3225
	},
3226
3227
	// @method containerPointToLayerPoint(point: Point): Point
3228
	// Given a pixel coordinate relative to the map container, returns the corresponding
3229
	// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
3230
	containerPointToLayerPoint: function (point) { // (Point)
3231
		return L.point(point).subtract(this._getMapPanePos());
3232
	},
3233
3234
	// @method layerPointToContainerPoint(point: Point): Point
3235
	// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
3236
	// returns the corresponding pixel coordinate relative to the map container.
3237
	layerPointToContainerPoint: function (point) { // (Point)
3238
		return L.point(point).add(this._getMapPanePos());
3239
	},
3240
3241
	// @method containerPointToLatLng(point: Point): LatLng
3242
	// Given a pixel coordinate relative to the map container, returns
3243
	// the corresponding geographical coordinate (for the current zoom level).
3244
	containerPointToLatLng: function (point) {
3245
		var layerPoint = this.containerPointToLayerPoint(L.point(point));
3246
		return this.layerPointToLatLng(layerPoint);
3247
	},
3248
3249
	// @method latLngToContainerPoint(latlng: LatLng): Point
3250
	// Given a geographical coordinate, returns the corresponding pixel coordinate
3251
	// relative to the map container.
3252
	latLngToContainerPoint: function (latlng) {
3253
		return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));
3254
	},
3255
3256
	// @method mouseEventToContainerPoint(ev: MouseEvent): Point
3257
	// Given a MouseEvent object, returns the pixel coordinate relative to the
3258
	// map container where the event took place.
3259
	mouseEventToContainerPoint: function (e) {
3260
		return L.DomEvent.getMousePosition(e, this._container);
3261
	},
3262
3263
	// @method mouseEventToLayerPoint(ev: MouseEvent): Point
3264
	// Given a MouseEvent object, returns the pixel coordinate relative to
3265
	// the [origin pixel](#map-getpixelorigin) where the event took place.
3266
	mouseEventToLayerPoint: function (e) {
3267
		return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
3268
	},
3269
3270
	// @method mouseEventToLatLng(ev: MouseEvent): LatLng
3271
	// Given a MouseEvent object, returns geographical coordinate where the
3272
	// event took place.
3273
	mouseEventToLatLng: function (e) { // (MouseEvent)
3274
		return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
3275
	},
3276
3277
3278
	// map initialization methods
3279
3280
	_initContainer: function (id) {
3281
		var container = this._container = L.DomUtil.get(id);
3282
3283
		if (!container) {
3284
			throw new Error('Map container not found.');
3285
		} else if (container._leaflet_id) {
3286
			throw new Error('Map container is already initialized.');
3287
		}
3288
3289
		L.DomEvent.addListener(container, 'scroll', this._onScroll, this);
3290
		this._containerId = L.Util.stamp(container);
3291
	},
3292
3293
	_initLayout: function () {
3294
		var container = this._container;
3295
3296
		this._fadeAnimated = this.options.fadeAnimation && L.Browser.any3d;
3297
3298
		L.DomUtil.addClass(container, 'leaflet-container' +
3299
			(L.Browser.touch ? ' leaflet-touch' : '') +
3300
			(L.Browser.retina ? ' leaflet-retina' : '') +
3301
			(L.Browser.ielt9 ? ' leaflet-oldie' : '') +
3302
			(L.Browser.safari ? ' leaflet-safari' : '') +
3303
			(this._fadeAnimated ? ' leaflet-fade-anim' : ''));
3304
3305
		var position = L.DomUtil.getStyle(container, 'position');
3306
3307
		if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
3308
			container.style.position = 'relative';
3309
		}
3310
3311
		this._initPanes();
3312
3313
		if (this._initControlPos) {
3314
			this._initControlPos();
3315
		}
3316
	},
3317
3318
	_initPanes: function () {
3319
		var panes = this._panes = {};
3320
		this._paneRenderers = {};
3321
3322
		// @section
3323
		//
3324
		// Panes are DOM elements used to control the ordering of layers on the map. You
3325
		// can access panes with [`map.getPane`](#map-getpane) or
3326
		// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
3327
		// [`map.createPane`](#map-createpane) method.
3328
		//
3329
		// Every map has the following default panes that differ only in zIndex.
3330
		//
3331
		// @pane mapPane: HTMLElement = 'auto'
3332
		// Pane that contains all other map panes
3333
3334
		this._mapPane = this.createPane('mapPane', this._container);
3335
		L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
3336
3337
		// @pane tilePane: HTMLElement = 200
3338
		// Pane for `GridLayer`s and `TileLayer`s
3339
		this.createPane('tilePane');
3340
		// @pane overlayPane: HTMLElement = 400
3341
		// Pane for vector overlays (`Path`s), like `Polyline`s and `Polygon`s
3342
		this.createPane('shadowPane');
3343
		// @pane shadowPane: HTMLElement = 500
3344
		// Pane for overlay shadows (e.g. `Marker` shadows)
3345
		this.createPane('overlayPane');
3346
		// @pane markerPane: HTMLElement = 600
3347
		// Pane for `Icon`s of `Marker`s
3348
		this.createPane('markerPane');
3349
		// @pane tooltipPane: HTMLElement = 650
3350
		// Pane for tooltip.
3351
		this.createPane('tooltipPane');
3352
		// @pane popupPane: HTMLElement = 700
3353
		// Pane for `Popup`s.
3354
		this.createPane('popupPane');
3355
3356
		if (!this.options.markerZoomAnimation) {
3357
			L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
3358
			L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
3359
		}
3360
	},
3361
3362
3363
	// private methods that modify map state
3364
3365
	// @section Map state change events
3366
	_resetView: function (center, zoom) {
3367
		L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
3368
3369
		var loading = !this._loaded;
3370
		this._loaded = true;
3371
		zoom = this._limitZoom(zoom);
3372
3373
		this.fire('viewprereset');
3374
3375
		var zoomChanged = this._zoom !== zoom;
3376
		this
3377
			._moveStart(zoomChanged)
3378
			._move(center, zoom)
3379
			._moveEnd(zoomChanged);
3380
3381
		// @event viewreset: Event
3382
		// Fired when the map needs to redraw its content (this usually happens
3383
		// on map zoom or load). Very useful for creating custom overlays.
3384
		this.fire('viewreset');
3385
3386
		// @event load: Event
3387
		// Fired when the map is initialized (when its center and zoom are set
3388
		// for the first time).
3389
		if (loading) {
3390
			this.fire('load');
3391
		}
3392
	},
3393
3394
	_moveStart: function (zoomChanged) {
3395
		// @event zoomstart: Event
3396
		// Fired when the map zoom is about to change (e.g. before zoom animation).
3397
		// @event movestart: Event
3398
		// Fired when the view of the map starts changing (e.g. user starts dragging the map).
3399
		if (zoomChanged) {
3400
			this.fire('zoomstart');
3401
		}
3402
		return this.fire('movestart');
3403
	},
3404
3405
	_move: function (center, zoom, data) {
3406
		if (zoom === undefined) {
3407
			zoom = this._zoom;
3408
		}
3409
		var zoomChanged = this._zoom !== zoom;
3410
3411
		this._zoom = zoom;
3412
		this._lastCenter = center;
3413
		this._pixelOrigin = this._getNewPixelOrigin(center);
3414
3415
		// @event zoom: Event
3416
		// Fired repeatedly during any change in zoom level, including zoom
3417
		// and fly animations.
3418
		if (zoomChanged || (data && data.pinch)) {	// Always fire 'zoom' if pinching because #3530
3419
			this.fire('zoom', data);
3420
		}
3421
3422
		// @event move: Event
3423
		// Fired repeatedly during any movement of the map, including pan and
3424
		// fly animations.
3425
		return this.fire('move', data);
3426
	},
3427
3428
	_moveEnd: function (zoomChanged) {
3429
		// @event zoomend: Event
3430
		// Fired when the map has changed, after any animations.
3431
		if (zoomChanged) {
3432
			this.fire('zoomend');
3433
		}
3434
3435
		// @event moveend: Event
3436
		// Fired when the center of the map stops changing (e.g. user stopped
3437
		// dragging the map).
3438
		return this.fire('moveend');
3439
	},
3440
3441
	_stop: function () {
3442
		L.Util.cancelAnimFrame(this._flyToFrame);
3443
		if (this._panAnim) {
3444
			this._panAnim.stop();
3445
		}
3446
		return this;
3447
	},
3448
3449
	_rawPanBy: function (offset) {
3450
		L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
3451
	},
3452
3453
	_getZoomSpan: function () {
3454
		return this.getMaxZoom() - this.getMinZoom();
3455
	},
3456
3457
	_panInsideMaxBounds: function () {
3458
		if (!this._enforcingBounds) {
3459
			this.panInsideBounds(this.options.maxBounds);
3460
		}
3461
	},
3462
3463
	_checkIfLoaded: function () {
3464
		if (!this._loaded) {
3465
			throw new Error('Set map center and zoom first.');
3466
		}
3467
	},
3468
3469
	// DOM event handling
3470
3471
	// @section Interaction events
3472
	_initEvents: function (remove) {
3473
		if (!L.DomEvent) { return; }
3474
3475
		this._targets = {};
3476
		this._targets[L.stamp(this._container)] = this;
3477
3478
		var onOff = remove ? 'off' : 'on';
3479
3480
		// @event click: MouseEvent
3481
		// Fired when the user clicks (or taps) the map.
3482
		// @event dblclick: MouseEvent
3483
		// Fired when the user double-clicks (or double-taps) the map.
3484
		// @event mousedown: MouseEvent
3485
		// Fired when the user pushes the mouse button on the map.
3486
		// @event mouseup: MouseEvent
3487
		// Fired when the user releases the mouse button on the map.
3488
		// @event mouseover: MouseEvent
3489
		// Fired when the mouse enters the map.
3490
		// @event mouseout: MouseEvent
3491
		// Fired when the mouse leaves the map.
3492
		// @event mousemove: MouseEvent
3493
		// Fired while the mouse moves over the map.
3494
		// @event contextmenu: MouseEvent
3495
		// Fired when the user pushes the right mouse button on the map, prevents
3496
		// default browser context menu from showing if there are listeners on
3497
		// this event. Also fired on mobile when the user holds a single touch
3498
		// for a second (also called long press).
3499
		// @event keypress: KeyboardEvent
3500
		// Fired when the user presses a key from the keyboard while the map is focused.
3501
		L.DomEvent[onOff](this._container, 'click dblclick mousedown mouseup ' +
3502
			'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this);
3503
3504
		if (this.options.trackResize) {
3505
			L.DomEvent[onOff](window, 'resize', this._onResize, this);
3506
		}
3507
3508
		if (L.Browser.any3d && this.options.transform3DLimit) {
3509
			this[onOff]('moveend', this._onMoveEnd);
3510
		}
3511
	},
3512
3513
	_onResize: function () {
3514
		L.Util.cancelAnimFrame(this._resizeRequest);
3515
		this._resizeRequest = L.Util.requestAnimFrame(
3516
		        function () { this.invalidateSize({debounceMoveend: true}); }, this);
3517
	},
3518
3519
	_onScroll: function () {
3520
		this._container.scrollTop  = 0;
3521
		this._container.scrollLeft = 0;
3522
	},
3523
3524
	_onMoveEnd: function () {
3525
		var pos = this._getMapPanePos();
3526
		if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
3527
			// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
3528
			// a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
3529
			this._resetView(this.getCenter(), this.getZoom());
3530
		}
3531
	},
3532
3533
	_findEventTargets: function (e, type) {
3534
		var targets = [],
3535
		    target,
3536
		    isHover = type === 'mouseout' || type === 'mouseover',
3537
		    src = e.target || e.srcElement,
3538
		    dragging = false;
3539
3540
		while (src) {
3541
			target = this._targets[L.stamp(src)];
3542
			if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
3543
				// Prevent firing click after you just dragged an object.
3544
				dragging = true;
3545
				break;
3546
			}
3547
			if (target && target.listens(type, true)) {
3548
				if (isHover && !L.DomEvent._isExternalTarget(src, e)) { break; }
3549
				targets.push(target);
3550
				if (isHover) { break; }
3551
			}
3552
			if (src === this._container) { break; }
3553
			src = src.parentNode;
3554
		}
3555
		if (!targets.length && !dragging && !isHover && L.DomEvent._isExternalTarget(src, e)) {
3556
			targets = [this];
3557
		}
3558
		return targets;
3559
	},
3560
3561
	_handleDOMEvent: function (e) {
3562
		if (!this._loaded || L.DomEvent._skipped(e)) { return; }
3563
3564
		var type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
3565
3566
		if (type === 'mousedown') {
3567
			// prevents outline when clicking on keyboard-focusable element
3568
			L.DomUtil.preventOutline(e.target || e.srcElement);
3569
		}
3570
3571
		this._fireDOMEvent(e, type);
3572
	},
3573
3574
	_fireDOMEvent: function (e, type, targets) {
3575
3576
		if (e.type === 'click') {
3577
			// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
3578
			// @event preclick: MouseEvent
3579
			// Fired before mouse click on the map (sometimes useful when you
3580
			// want something to happen on click before any existing click
3581
			// handlers start running).
3582
			var synth = L.Util.extend({}, e);
3583
			synth.type = 'preclick';
3584
			this._fireDOMEvent(synth, synth.type, targets);
3585
		}
3586
3587
		if (e._stopped) { return; }
3588
3589
		// Find the layer the event is propagating from and its parents.
3590
		targets = (targets || []).concat(this._findEventTargets(e, type));
3591
3592
		if (!targets.length) { return; }
3593
3594
		var target = targets[0];
3595
		if (type === 'contextmenu' && target.listens(type, true)) {
3596
			L.DomEvent.preventDefault(e);
3597
		}
3598
3599
		var data = {
3600
			originalEvent: e
3601
		};
3602
3603
		if (e.type !== 'keypress') {
3604
			var isMarker = target instanceof L.Marker;
3605
			data.containerPoint = isMarker ?
3606
					this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
3607
			data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
3608
			data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
3609
		}
3610
3611
		for (var i = 0; i < targets.length; i++) {
3612
			targets[i].fire(type, data, true);
3613
			if (data.originalEvent._stopped ||
3614
				(targets[i].options.nonBubblingEvents && L.Util.indexOf(targets[i].options.nonBubblingEvents, type) !== -1)) { return; }
3615
		}
3616
	},
3617
3618
	_draggableMoved: function (obj) {
3619
		obj = obj.dragging && obj.dragging.enabled() ? obj : this;
3620
		return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
3621
	},
3622
3623
	_clearHandlers: function () {
3624
		for (var i = 0, len = this._handlers.length; i < len; i++) {
3625
			this._handlers[i].disable();
3626
		}
3627
	},
3628
3629
	// @section Other Methods
3630
3631
	// @method whenReady(fn: Function, context?: Object): this
3632
	// Runs the given function `fn` when the map gets initialized with
3633
	// a view (center and zoom) and at least one layer, or immediately
3634
	// if it's already initialized, optionally passing a function context.
3635
	whenReady: function (callback, context) {
3636
		if (this._loaded) {
3637
			callback.call(context || this, {target: this});
3638
		} else {
3639
			this.on('load', callback, context);
3640
		}
3641
		return this;
3642
	},
3643
3644
3645
	// private methods for getting map state
3646
3647
	_getMapPanePos: function () {
3648
		return L.DomUtil.getPosition(this._mapPane) || new L.Point(0, 0);
3649
	},
3650
3651
	_moved: function () {
3652
		var pos = this._getMapPanePos();
3653
		return pos && !pos.equals([0, 0]);
3654
	},
3655
3656
	_getTopLeftPoint: function (center, zoom) {
3657
		var pixelOrigin = center && zoom !== undefined ?
3658
			this._getNewPixelOrigin(center, zoom) :
3659
			this.getPixelOrigin();
3660
		return pixelOrigin.subtract(this._getMapPanePos());
3661
	},
3662
3663
	_getNewPixelOrigin: function (center, zoom) {
3664
		var viewHalf = this.getSize()._divideBy(2);
3665
		return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
3666
	},
3667
3668
	_latLngToNewLayerPoint: function (latlng, zoom, center) {
3669
		var topLeft = this._getNewPixelOrigin(center, zoom);
3670
		return this.project(latlng, zoom)._subtract(topLeft);
3671
	},
3672
3673
	_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
3674
		var topLeft = this._getNewPixelOrigin(center, zoom);
3675
		return L.bounds([
3676
			this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
3677
			this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
3678
			this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
3679
			this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
3680
		]);
3681
	},
3682
3683
	// layer point of the current center
3684
	_getCenterLayerPoint: function () {
3685
		return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
3686
	},
3687
3688
	// offset of the specified place to the current center in pixels
3689
	_getCenterOffset: function (latlng) {
3690
		return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
3691
	},
3692
3693
	// adjust center for view to get inside bounds
3694
	_limitCenter: function (center, zoom, bounds) {
3695
3696
		if (!bounds) { return center; }
3697
3698
		var centerPoint = this.project(center, zoom),
3699
		    viewHalf = this.getSize().divideBy(2),
3700
		    viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
3701
		    offset = this._getBoundsOffset(viewBounds, bounds, zoom);
3702
3703
		// If offset is less than a pixel, ignore.
3704
		// This prevents unstable projections from getting into
3705
		// an infinite loop of tiny offsets.
3706
		if (offset.round().equals([0, 0])) {
3707
			return center;
3708
		}
3709
3710
		return this.unproject(centerPoint.add(offset), zoom);
3711
	},
3712
3713
	// adjust offset for view to get inside bounds
3714
	_limitOffset: function (offset, bounds) {
3715
		if (!bounds) { return offset; }
3716
3717
		var viewBounds = this.getPixelBounds(),
3718
		    newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
3719
3720
		return offset.add(this._getBoundsOffset(newBounds, bounds));
3721
	},
3722
3723
	// returns offset needed for pxBounds to get inside maxBounds at a specified zoom
3724
	_getBoundsOffset: function (pxBounds, maxBounds, zoom) {
3725
		var projectedMaxBounds = L.bounds(
3726
		        this.project(maxBounds.getNorthEast(), zoom),
3727
		        this.project(maxBounds.getSouthWest(), zoom)
3728
		    ),
3729
		    minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
3730
		    maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
3731
3732
		    dx = this._rebound(minOffset.x, -maxOffset.x),
3733
		    dy = this._rebound(minOffset.y, -maxOffset.y);
3734
3735
		return new L.Point(dx, dy);
3736
	},
3737
3738
	_rebound: function (left, right) {
3739
		return left + right > 0 ?
3740
			Math.round(left - right) / 2 :
3741
			Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
3742
	},
3743
3744
	_limitZoom: function (zoom) {
3745
		var min = this.getMinZoom(),
3746
		    max = this.getMaxZoom(),
3747
		    snap = L.Browser.any3d ? this.options.zoomSnap : 1;
3748
		if (snap) {
3749
			zoom = Math.round(zoom / snap) * snap;
3750
		}
3751
		return Math.max(min, Math.min(max, zoom));
3752
	},
3753
3754
	_onPanTransitionStep: function () {
3755
		this.fire('move');
3756
	},
3757
3758
	_onPanTransitionEnd: function () {
3759
		L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
3760
		this.fire('moveend');
3761
	},
3762
3763
	_tryAnimatedPan: function (center, options) {
3764
		// difference between the new and current centers in pixels
3765
		var offset = this._getCenterOffset(center)._floor();
3766
3767
		// don't animate too far unless animate: true specified in options
3768
		if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
3769
3770
		this.panBy(offset, options);
3771
3772
		return true;
3773
	},
3774
3775
	_createAnimProxy: function () {
3776
3777
		var proxy = this._proxy = L.DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');
3778
		this._panes.mapPane.appendChild(proxy);
3779
3780
		this.on('zoomanim', function (e) {
3781
			var prop = L.DomUtil.TRANSFORM,
3782
			    transform = proxy.style[prop];
3783
3784
			L.DomUtil.setTransform(proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
3785
3786
			// workaround for case when transform is the same and so transitionend event is not fired
3787
			if (transform === proxy.style[prop] && this._animatingZoom) {
3788
				this._onZoomTransitionEnd();
3789
			}
3790
		}, this);
3791
3792
		this.on('load moveend', function () {
3793
			var c = this.getCenter(),
3794
			    z = this.getZoom();
3795
			L.DomUtil.setTransform(proxy, this.project(c, z), this.getZoomScale(z, 1));
3796
		}, this);
3797
	},
3798
3799
	_catchTransitionEnd: function (e) {
3800
		if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
3801
			this._onZoomTransitionEnd();
3802
		}
3803
	},
3804
3805
	_nothingToAnimate: function () {
3806
		return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
3807
	},
3808
3809
	_tryAnimatedZoom: function (center, zoom, options) {
3810
3811
		if (this._animatingZoom) { return true; }
3812
3813
		options = options || {};
3814
3815
		// don't animate if disabled, not supported or zoom difference is too large
3816
		if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
3817
		        Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
3818
3819
		// offset is the pixel coords of the zoom origin relative to the current center
3820
		var scale = this.getZoomScale(zoom),
3821
		    offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
3822
3823
		// don't animate if the zoom origin isn't within one screen from the current center, unless forced
3824
		if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
3825
3826
		L.Util.requestAnimFrame(function () {
3827
			this
3828
			    ._moveStart(true)
3829
			    ._animateZoom(center, zoom, true);
3830
		}, this);
3831
3832
		return true;
3833
	},
3834
3835
	_animateZoom: function (center, zoom, startAnim, noUpdate) {
3836
		if (startAnim) {
3837
			this._animatingZoom = true;
3838
3839
			// remember what center/zoom to set after animation
3840
			this._animateToCenter = center;
3841
			this._animateToZoom = zoom;
3842
3843
			L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
3844
		}
3845
3846
		// @event zoomanim: ZoomAnimEvent
3847
		// Fired on every frame of a zoom animation
3848
		this.fire('zoomanim', {
3849
			center: center,
3850
			zoom: zoom,
3851
			noUpdate: noUpdate
3852
		});
3853
3854
		// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
3855
		setTimeout(L.bind(this._onZoomTransitionEnd, this), 250);
3856
	},
3857
3858
	_onZoomTransitionEnd: function () {
3859
		if (!this._animatingZoom) { return; }
3860
3861
		L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
3862
3863
		this._animatingZoom = false;
3864
3865
		this._move(this._animateToCenter, this._animateToZoom);
3866
3867
		// This anim frame should prevent an obscure iOS webkit tile loading race condition.
3868
		L.Util.requestAnimFrame(function () {
3869
			this._moveEnd(true);
3870
		}, this);
3871
	}
3872
});
3873
3874
// @section
3875
3876
// @factory L.map(id: String, options?: Map options)
3877
// Instantiates a map object given the DOM ID of a `<div>` element
3878
// and optionally an object literal with `Map options`.
3879
//
3880
// @alternative
3881
// @factory L.map(el: HTMLElement, options?: Map options)
3882
// Instantiates a map object given an instance of a `<div>` HTML element
3883
// and optionally an object literal with `Map options`.
3884
L.map = function (id, options) {
3885
	return new L.Map(id, options);
3886
};
3887
3888
3889
3890
3891
/*
3892
 * @class Layer
3893
 * @inherits Evented
3894
 * @aka L.Layer
3895
 * @aka ILayer
3896
 *
3897
 * A set of methods from the Layer base class that all Leaflet layers use.
3898
 * Inherits all methods, options and events from `L.Evented`.
3899
 *
3900
 * @example
3901
 *
3902
 * ```js
3903
 * var layer = L.Marker(latlng).addTo(map);
3904
 * layer.addTo(map);
3905
 * layer.remove();
3906
 * ```
3907
 *
3908
 * @event add: Event
3909
 * Fired after the layer is added to a map
3910
 *
3911
 * @event remove: Event
3912
 * Fired after the layer is removed from a map
3913
 */
3914
3915
3916
L.Layer = L.Evented.extend({
3917
3918
	// Classes extending `L.Layer` will inherit the following options:
3919
	options: {
3920
		// @option pane: String = 'overlayPane'
3921
		// 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.
3922
		pane: 'overlayPane',
3923
		nonBubblingEvents: [],  // Array of events that should not be bubbled to DOM parents (like the map),
3924
3925
		// @option attribution: String = null
3926
		// String to be shown in the attribution control, describes the layer data, e.g. "© Mapbox".
3927
		attribution: null
3928
	},
3929
3930
	/* @section
3931
	 * Classes extending `L.Layer` will inherit the following methods:
3932
	 *
3933
	 * @method addTo(map: Map): this
3934
	 * Adds the layer to the given map
3935
	 */
3936
	addTo: function (map) {
3937
		map.addLayer(this);
3938
		return this;
3939
	},
3940
3941
	// @method remove: this
3942
	// Removes the layer from the map it is currently active on.
3943
	remove: function () {
3944
		return this.removeFrom(this._map || this._mapToAdd);
3945
	},
3946
3947
	// @method removeFrom(map: Map): this
3948
	// Removes the layer from the given map
3949
	removeFrom: function (obj) {
3950
		if (obj) {
3951
			obj.removeLayer(this);
3952
		}
3953
		return this;
3954
	},
3955
3956
	// @method getPane(name? : String): HTMLElement
3957
	// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
3958
	getPane: function (name) {
3959
		return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
3960
	},
3961
3962
	addInteractiveTarget: function (targetEl) {
3963
		this._map._targets[L.stamp(targetEl)] = this;
3964
		return this;
3965
	},
3966
3967
	removeInteractiveTarget: function (targetEl) {
3968
		delete this._map._targets[L.stamp(targetEl)];
3969
		return this;
3970
	},
3971
3972
	// @method getAttribution: String
3973
	// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
3974
	getAttribution: function () {
3975
		return this.options.attribution;
3976
	},
3977
3978
	_layerAdd: function (e) {
3979
		var map = e.target;
3980
3981
		// check in case layer gets added and then removed before the map is ready
3982
		if (!map.hasLayer(this)) { return; }
3983
3984
		this._map = map;
3985
		this._zoomAnimated = map._zoomAnimated;
3986
3987
		if (this.getEvents) {
3988
			var events = this.getEvents();
3989
			map.on(events, this);
3990
			this.once('remove', function () {
3991
				map.off(events, this);
3992
			}, this);
3993
		}
3994
3995
		this.onAdd(map);
3996
3997
		if (this.getAttribution && map.attributionControl) {
3998
			map.attributionControl.addAttribution(this.getAttribution());
3999
		}
4000
4001
		this.fire('add');
4002
		map.fire('layeradd', {layer: this});
4003
	}
4004
});
4005
4006
/* @section Extension methods
4007
 * @uninheritable
4008
 *
4009
 * Every layer should extend from `L.Layer` and (re-)implement the following methods.
4010
 *
4011
 * @method onAdd(map: Map): this
4012
 * 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).
4013
 *
4014
 * @method onRemove(map: Map): this
4015
 * 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).
4016
 *
4017
 * @method getEvents(): Object
4018
 * 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.
4019
 *
4020
 * @method getAttribution(): String
4021
 * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
4022
 *
4023
 * @method beforeAdd(map: Map): this
4024
 * 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.
4025
 */
4026
4027
4028
/* @namespace Map
4029
 * @section Layer events
4030
 *
4031
 * @event layeradd: LayerEvent
4032
 * Fired when a new layer is added to the map.
4033
 *
4034
 * @event layerremove: LayerEvent
4035
 * Fired when some layer is removed from the map
4036
 *
4037
 * @section Methods for Layers and Controls
4038
 */
4039
L.Map.include({
4040
	// @method addLayer(layer: Layer): this
4041
	// Adds the given layer to the map
4042
	addLayer: function (layer) {
4043
		var id = L.stamp(layer);
4044
		if (this._layers[id]) { return this; }
4045
		this._layers[id] = layer;
4046
4047
		layer._mapToAdd = this;
4048
4049
		if (layer.beforeAdd) {
4050
			layer.beforeAdd(this);
4051
		}
4052
4053
		this.whenReady(layer._layerAdd, layer);
4054
4055
		return this;
4056
	},
4057
4058
	// @method removeLayer(layer: Layer): this
4059
	// Removes the given layer from the map.
4060
	removeLayer: function (layer) {
4061
		var id = L.stamp(layer);
4062
4063
		if (!this._layers[id]) { return this; }
4064
4065
		if (this._loaded) {
4066
			layer.onRemove(this);
4067
		}
4068
4069
		if (layer.getAttribution && this.attributionControl) {
4070
			this.attributionControl.removeAttribution(layer.getAttribution());
4071
		}
4072
4073
		delete this._layers[id];
4074
4075
		if (this._loaded) {
4076
			this.fire('layerremove', {layer: layer});
4077
			layer.fire('remove');
4078
		}
4079
4080
		layer._map = layer._mapToAdd = null;
4081
4082
		return this;
4083
	},
4084
4085
	// @method hasLayer(layer: Layer): Boolean
4086
	// Returns `true` if the given layer is currently added to the map
4087
	hasLayer: function (layer) {
4088
		return !!layer && (L.stamp(layer) in this._layers);
4089
	},
4090
4091
	/* @method eachLayer(fn: Function, context?: Object): this
4092
	 * Iterates over the layers of the map, optionally specifying context of the iterator function.
4093
	 * ```
4094
	 * map.eachLayer(function(layer){
4095
	 *     layer.bindPopup('Hello');
4096
	 * });
4097
	 * ```
4098
	 */
4099
	eachLayer: function (method, context) {
4100
		for (var i in this._layers) {
4101
			method.call(context, this._layers[i]);
4102
		}
4103
		return this;
4104
	},
4105
4106
	_addLayers: function (layers) {
4107
		layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];
4108
4109
		for (var i = 0, len = layers.length; i < len; i++) {
4110
			this.addLayer(layers[i]);
4111
		}
4112
	},
4113
4114
	_addZoomLimit: function (layer) {
4115
		if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
4116
			this._zoomBoundLayers[L.stamp(layer)] = layer;
4117
			this._updateZoomLevels();
4118
		}
4119
	},
4120
4121
	_removeZoomLimit: function (layer) {
4122
		var id = L.stamp(layer);
4123
4124
		if (this._zoomBoundLayers[id]) {
4125
			delete this._zoomBoundLayers[id];
4126
			this._updateZoomLevels();
4127
		}
4128
	},
4129
4130
	_updateZoomLevels: function () {
4131
		var minZoom = Infinity,
4132
		    maxZoom = -Infinity,
4133
		    oldZoomSpan = this._getZoomSpan();
4134
4135
		for (var i in this._zoomBoundLayers) {
4136
			var options = this._zoomBoundLayers[i].options;
4137
4138
			minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
4139
			maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
4140
		}
4141
4142
		this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
4143
		this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
4144
4145
		// @section Map state change events
4146
		// @event zoomlevelschange: Event
4147
		// Fired when the number of zoomlevels on the map is changed due
4148
		// to adding or removing a layer.
4149
		if (oldZoomSpan !== this._getZoomSpan()) {
4150
			this.fire('zoomlevelschange');
4151
		}
4152
4153
		if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
4154
			this.setZoom(this._layersMaxZoom);
4155
		}
4156
		if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
4157
			this.setZoom(this._layersMinZoom);
4158
		}
4159
	}
4160
});
4161
4162
4163
4164
/*
4165
 * @namespace DomEvent
4166
 * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
4167
 */
4168
4169
// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
4170
4171
4172
4173
var eventsKey = '_leaflet_events';
4174
4175
L.DomEvent = {
4176
4177
	// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
4178
	// Adds a listener function (`fn`) to a particular DOM event type of the
4179
	// element `el`. You can optionally specify the context of the listener
4180
	// (object the `this` keyword will point to). You can also pass several
4181
	// space-separated types (e.g. `'click dblclick'`).
4182
4183
	// @alternative
4184
	// @function on(el: HTMLElement, eventMap: Object, context?: Object): this
4185
	// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
4186
	on: function (obj, types, fn, context) {
4187
4188
		if (typeof types === 'object') {
4189
			for (var type in types) {
4190
				this._on(obj, type, types[type], fn);
4191
			}
4192
		} else {
4193
			types = L.Util.splitWords(types);
4194
4195
			for (var i = 0, len = types.length; i < len; i++) {
4196
				this._on(obj, types[i], fn, context);
4197
			}
4198
		}
4199
4200
		return this;
4201
	},
4202
4203
	// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
4204
	// Removes a previously added listener function. If no function is specified,
4205
	// it will remove all the listeners of that particular DOM event from the element.
4206
	// Note that if you passed a custom context to on, you must pass the same
4207
	// context to `off` in order to remove the listener.
4208
4209
	// @alternative
4210
	// @function off(el: HTMLElement, eventMap: Object, context?: Object): this
4211
	// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
4212
	off: function (obj, types, fn, context) {
4213
4214
		if (typeof types === 'object') {
4215
			for (var type in types) {
4216
				this._off(obj, type, types[type], fn);
4217
			}
4218
		} else {
4219
			types = L.Util.splitWords(types);
4220
4221
			for (var i = 0, len = types.length; i < len; i++) {
4222
				this._off(obj, types[i], fn, context);
4223
			}
4224
		}
4225
4226
		return this;
4227
	},
4228
4229
	_on: function (obj, type, fn, context) {
4230
		var id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : '');
4231
4232
		if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
4233
4234
		var handler = function (e) {
4235
			return fn.call(context || obj, e || window.event);
4236
		};
4237
4238
		var originalHandler = handler;
4239
4240
		if (L.Browser.pointer && type.indexOf('touch') === 0) {
4241
			this.addPointerListener(obj, type, handler, id);
4242
4243
		} else if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener &&
4244
		           !(L.Browser.pointer && L.Browser.chrome)) {
4245
			// Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener
4246
			// See #5180
4247
			this.addDoubleTapListener(obj, handler, id);
4248
4249
		} else if ('addEventListener' in obj) {
4250
4251
			if (type === 'mousewheel') {
4252
				obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
4253
4254
			} else if ((type === 'mouseenter') || (type === 'mouseleave')) {
4255
				handler = function (e) {
4256
					e = e || window.event;
4257
					if (L.DomEvent._isExternalTarget(obj, e)) {
4258
						originalHandler(e);
4259
					}
4260
				};
4261
				obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false);
4262
4263
			} else {
4264
				if (type === 'click' && L.Browser.android) {
4265
					handler = function (e) {
4266
						return L.DomEvent._filterClick(e, originalHandler);
4267
					};
4268
				}
4269
				obj.addEventListener(type, handler, false);
4270
			}
4271
4272
		} else if ('attachEvent' in obj) {
4273
			obj.attachEvent('on' + type, handler);
4274
		}
4275
4276
		obj[eventsKey] = obj[eventsKey] || {};
4277
		obj[eventsKey][id] = handler;
4278
4279
		return this;
4280
	},
4281
4282
	_off: function (obj, type, fn, context) {
4283
4284
		var id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : ''),
4285
		    handler = obj[eventsKey] && obj[eventsKey][id];
4286
4287
		if (!handler) { return this; }
4288
4289
		if (L.Browser.pointer && type.indexOf('touch') === 0) {
4290
			this.removePointerListener(obj, type, id);
4291
4292
		} else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
4293
			this.removeDoubleTapListener(obj, id);
4294
4295
		} else if ('removeEventListener' in obj) {
4296
4297
			if (type === 'mousewheel') {
4298
				obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
4299
4300
			} else {
4301
				obj.removeEventListener(
4302
					type === 'mouseenter' ? 'mouseover' :
4303
					type === 'mouseleave' ? 'mouseout' : type, handler, false);
4304
			}
4305
4306
		} else if ('detachEvent' in obj) {
4307
			obj.detachEvent('on' + type, handler);
4308
		}
4309
4310
		obj[eventsKey][id] = null;
4311
4312
		return this;
4313
	},
4314
4315
	// @function stopPropagation(ev: DOMEvent): this
4316
	// Stop the given event from propagation to parent elements. Used inside the listener functions:
4317
	// ```js
4318
	// L.DomEvent.on(div, 'click', function (ev) {
4319
	// 	L.DomEvent.stopPropagation(ev);
4320
	// });
4321
	// ```
4322
	stopPropagation: function (e) {
4323
4324
		if (e.stopPropagation) {
4325
			e.stopPropagation();
4326
		} else if (e.originalEvent) {  // In case of Leaflet event.
4327
			e.originalEvent._stopped = true;
4328
		} else {
4329
			e.cancelBubble = true;
4330
		}
4331
		L.DomEvent._skipped(e);
4332
4333
		return this;
4334
	},
4335
4336
	// @function disableScrollPropagation(el: HTMLElement): this
4337
	// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants).
4338
	disableScrollPropagation: function (el) {
4339
		return L.DomEvent.on(el, 'mousewheel', L.DomEvent.stopPropagation);
4340
	},
4341
4342
	// @function disableClickPropagation(el: HTMLElement): this
4343
	// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
4344
	// `'mousedown'` and `'touchstart'` events (plus browser variants).
4345
	disableClickPropagation: function (el) {
4346
		var stop = L.DomEvent.stopPropagation;
4347
4348
		L.DomEvent.on(el, L.Draggable.START.join(' '), stop);
4349
4350
		return L.DomEvent.on(el, {
4351
			click: L.DomEvent._fakeStop,
4352
			dblclick: stop
4353
		});
4354
	},
4355
4356
	// @function preventDefault(ev: DOMEvent): this
4357
	// Prevents the default action of the DOM Event `ev` from happening (such as
4358
	// following a link in the href of the a element, or doing a POST request
4359
	// with page reload when a `<form>` is submitted).
4360
	// Use it inside listener functions.
4361
	preventDefault: function (e) {
4362
4363
		if (e.preventDefault) {
4364
			e.preventDefault();
4365
		} else {
4366
			e.returnValue = false;
4367
		}
4368
		return this;
4369
	},
4370
4371
	// @function stop(ev): this
4372
	// Does `stopPropagation` and `preventDefault` at the same time.
4373
	stop: function (e) {
4374
		return L.DomEvent
4375
			.preventDefault(e)
4376
			.stopPropagation(e);
4377
	},
4378
4379
	// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
4380
	// Gets normalized mouse position from a DOM event relative to the
4381
	// `container` or to the whole page if not specified.
4382
	getMousePosition: function (e, container) {
4383
		if (!container) {
4384
			return new L.Point(e.clientX, e.clientY);
4385
		}
4386
4387
		var rect = container.getBoundingClientRect();
4388
4389
		return new L.Point(
4390
			e.clientX - rect.left - container.clientLeft,
4391
			e.clientY - rect.top - container.clientTop);
4392
	},
4393
4394
	// Chrome on Win scrolls double the pixels as in other platforms (see #4538),
4395
	// and Firefox scrolls device pixels, not CSS pixels
4396
	_wheelPxFactor: (L.Browser.win && L.Browser.chrome) ? 2 :
4397
	                L.Browser.gecko ? window.devicePixelRatio :
4398
	                1,
4399
4400
	// @function getWheelDelta(ev: DOMEvent): Number
4401
	// Gets normalized wheel delta from a mousewheel DOM event, in vertical
4402
	// pixels scrolled (negative if scrolling down).
4403
	// Events from pointing devices without precise scrolling are mapped to
4404
	// a best guess of 60 pixels.
4405
	getWheelDelta: function (e) {
4406
		return (L.Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
4407
		       (e.deltaY && e.deltaMode === 0) ? -e.deltaY / L.DomEvent._wheelPxFactor : // Pixels
4408
		       (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
4409
		       (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
4410
		       (e.deltaX || e.deltaZ) ? 0 :	// Skip horizontal/depth wheel events
4411
		       e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
4412
		       (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
4413
		       e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
4414
		       0;
4415
	},
4416
4417
	_skipEvents: {},
4418
4419
	_fakeStop: function (e) {
4420
		// fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
4421
		L.DomEvent._skipEvents[e.type] = true;
4422
	},
4423
4424
	_skipped: function (e) {
4425
		var skipped = this._skipEvents[e.type];
4426
		// reset when checking, as it's only used in map container and propagates outside of the map
4427
		this._skipEvents[e.type] = false;
4428
		return skipped;
4429
	},
4430
4431
	// check if element really left/entered the event target (for mouseenter/mouseleave)
4432
	_isExternalTarget: function (el, e) {
4433
4434
		var related = e.relatedTarget;
4435
4436
		if (!related) { return true; }
4437
4438
		try {
4439
			while (related && (related !== el)) {
4440
				related = related.parentNode;
4441
			}
4442
		} catch (err) {
4443
			return false;
4444
		}
4445
		return (related !== el);
4446
	},
4447
4448
	// this is a horrible workaround for a bug in Android where a single touch triggers two click events
4449
	_filterClick: function (e, handler) {
4450
		var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)),
4451
		    elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
4452
4453
		// are they closer together than 500ms yet more than 100ms?
4454
		// Android typically triggers them ~300ms apart while multiple listeners
4455
		// on the same event should be triggered far faster;
4456
		// or check if click is simulated on the element, and if it is, reject any non-simulated events
4457
4458
		if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
4459
			L.DomEvent.stop(e);
4460
			return;
4461
		}
4462
		L.DomEvent._lastClick = timeStamp;
4463
4464
		handler(e);
4465
	}
4466
};
4467
4468
// @function addListener(…): this
4469
// Alias to [`L.DomEvent.on`](#domevent-on)
4470
L.DomEvent.addListener = L.DomEvent.on;
4471
4472
// @function removeListener(…): this
4473
// Alias to [`L.DomEvent.off`](#domevent-off)
4474
L.DomEvent.removeListener = L.DomEvent.off;
4475
4476
4477
4478
/*
4479
 * @class PosAnimation
4480
 * @aka L.PosAnimation
4481
 * @inherits Evented
4482
 * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
4483
 *
4484
 * @example
4485
 * ```js
4486
 * var fx = new L.PosAnimation();
4487
 * fx.run(el, [300, 500], 0.5);
4488
 * ```
4489
 *
4490
 * @constructor L.PosAnimation()
4491
 * Creates a `PosAnimation` object.
4492
 *
4493
 */
4494
4495
L.PosAnimation = L.Evented.extend({
4496
4497
	// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
4498
	// Run an animation of a given element to a new position, optionally setting
4499
	// duration in seconds (`0.25` by default) and easing linearity factor (3rd
4500
	// argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
4501
	// `0.5` by default).
4502
	run: function (el, newPos, duration, easeLinearity) {
4503
		this.stop();
4504
4505
		this._el = el;
4506
		this._inProgress = true;
4507
		this._duration = duration || 0.25;
4508
		this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
4509
4510
		this._startPos = L.DomUtil.getPosition(el);
4511
		this._offset = newPos.subtract(this._startPos);
4512
		this._startTime = +new Date();
4513
4514
		// @event start: Event
4515
		// Fired when the animation starts
4516
		this.fire('start');
4517
4518
		this._animate();
4519
	},
4520
4521
	// @method stop()
4522
	// Stops the animation (if currently running).
4523
	stop: function () {
4524
		if (!this._inProgress) { return; }
4525
4526
		this._step(true);
4527
		this._complete();
4528
	},
4529
4530
	_animate: function () {
4531
		// animation loop
4532
		this._animId = L.Util.requestAnimFrame(this._animate, this);
4533
		this._step();
4534
	},
4535
4536
	_step: function (round) {
4537
		var elapsed = (+new Date()) - this._startTime,
4538
		    duration = this._duration * 1000;
4539
4540
		if (elapsed < duration) {
4541
			this._runFrame(this._easeOut(elapsed / duration), round);
4542
		} else {
4543
			this._runFrame(1);
4544
			this._complete();
4545
		}
4546
	},
4547
4548
	_runFrame: function (progress, round) {
4549
		var pos = this._startPos.add(this._offset.multiplyBy(progress));
4550
		if (round) {
4551
			pos._round();
4552
		}
4553
		L.DomUtil.setPosition(this._el, pos);
4554
4555
		// @event step: Event
4556
		// Fired continuously during the animation.
4557
		this.fire('step');
4558
	},
4559
4560
	_complete: function () {
4561
		L.Util.cancelAnimFrame(this._animId);
4562
4563
		this._inProgress = false;
4564
		// @event end: Event
4565
		// Fired when the animation ends.
4566
		this.fire('end');
4567
	},
4568
4569
	_easeOut: function (t) {
4570
		return 1 - Math.pow(1 - t, this._easeOutPower);
4571
	}
4572
});
4573
4574
4575
4576
/*
4577
 * @namespace Projection
4578
 * @projection L.Projection.Mercator
4579
 *
4580
 * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.
4581
 */
4582
4583
L.Projection.Mercator = {
4584
	R: 6378137,
4585
	R_MINOR: 6356752.314245179,
4586
4587
	bounds: L.bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
4588
4589
	project: function (latlng) {
4590
		var d = Math.PI / 180,
4591
		    r = this.R,
4592
		    y = latlng.lat * d,
4593
		    tmp = this.R_MINOR / r,
4594
		    e = Math.sqrt(1 - tmp * tmp),
4595
		    con = e * Math.sin(y);
4596
4597
		var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
4598
		y = -r * Math.log(Math.max(ts, 1E-10));
4599
4600
		return new L.Point(latlng.lng * d * r, y);
4601
	},
4602
4603
	unproject: function (point) {
4604
		var d = 180 / Math.PI,
4605
		    r = this.R,
4606
		    tmp = this.R_MINOR / r,
4607
		    e = Math.sqrt(1 - tmp * tmp),
4608
		    ts = Math.exp(-point.y / r),
4609
		    phi = Math.PI / 2 - 2 * Math.atan(ts);
4610
4611
		for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
4612
			con = e * Math.sin(phi);
4613
			con = Math.pow((1 - con) / (1 + con), e / 2);
4614
			dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
4615
			phi += dphi;
4616
		}
4617
4618
		return new L.LatLng(phi * d, point.x * d / r);
4619
	}
4620
};
4621
4622
4623
4624
/*
4625
 * @namespace CRS
4626
 * @crs L.CRS.EPSG3395
4627
 *
4628
 * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
4629
 */
4630
4631
L.CRS.EPSG3395 = L.extend({}, L.CRS.Earth, {
4632
	code: 'EPSG:3395',
4633
	projection: L.Projection.Mercator,
4634
4635
	transformation: (function () {
4636
		var scale = 0.5 / (Math.PI * L.Projection.Mercator.R);
4637
		return new L.Transformation(scale, 0.5, -scale, 0.5);
4638
	}())
4639
});
4640
4641
4642
4643
/*
4644
 * @class GridLayer
4645
 * @inherits Layer
4646
 * @aka L.GridLayer
4647
 *
4648
 * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
4649
 * 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.
4650
 *
4651
 *
4652
 * @section Synchronous usage
4653
 * @example
4654
 *
4655
 * 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.
4656
 *
4657
 * ```js
4658
 * var CanvasLayer = L.GridLayer.extend({
4659
 *     createTile: function(coords){
4660
 *         // create a <canvas> element for drawing
4661
 *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
4662
 *
4663
 *         // setup tile width and height according to the options
4664
 *         var size = this.getTileSize();
4665
 *         tile.width = size.x;
4666
 *         tile.height = size.y;
4667
 *
4668
 *         // get a canvas context and draw something on it using coords.x, coords.y and coords.z
4669
 *         var ctx = tile.getContext('2d');
4670
 *
4671
 *         // return the tile so it can be rendered on screen
4672
 *         return tile;
4673
 *     }
4674
 * });
4675
 * ```
4676
 *
4677
 * @section Asynchronous usage
4678
 * @example
4679
 *
4680
 * 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.
4681
 *
4682
 * ```js
4683
 * var CanvasLayer = L.GridLayer.extend({
4684
 *     createTile: function(coords, done){
4685
 *         var error;
4686
 *
4687
 *         // create a <canvas> element for drawing
4688
 *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');
4689
 *
4690
 *         // setup tile width and height according to the options
4691
 *         var size = this.getTileSize();
4692
 *         tile.width = size.x;
4693
 *         tile.height = size.y;
4694
 *
4695
 *         // draw something asynchronously and pass the tile to the done() callback
4696
 *         setTimeout(function() {
4697
 *             done(error, tile);
4698
 *         }, 1000);
4699
 *
4700
 *         return tile;
4701
 *     }
4702
 * });
4703
 * ```
4704
 *
4705
 * @section
4706
 */
4707
4708
4709
L.GridLayer = L.Layer.extend({
4710
4711
	// @section
4712
	// @aka GridLayer options
4713
	options: {
4714
		// @option tileSize: Number|Point = 256
4715
		// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
4716
		tileSize: 256,
4717
4718
		// @option opacity: Number = 1.0
4719
		// Opacity of the tiles. Can be used in the `createTile()` function.
4720
		opacity: 1,
4721
4722
		// @option updateWhenIdle: Boolean = depends
4723
		// If `false`, new tiles are loaded during panning, otherwise only after it (for better performance). `true` by default on mobile browsers, otherwise `false`.
4724
		updateWhenIdle: L.Browser.mobile,
4725
4726
		// @option updateWhenZooming: Boolean = true
4727
		// 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.
4728
		updateWhenZooming: true,
4729
4730
		// @option updateInterval: Number = 200
4731
		// Tiles will not update more than once every `updateInterval` milliseconds when panning.
4732
		updateInterval: 200,
4733
4734
		// @option zIndex: Number = 1
4735
		// The explicit zIndex of the tile layer.
4736
		zIndex: 1,
4737
4738
		// @option bounds: LatLngBounds = undefined
4739
		// If set, tiles will only be loaded inside the set `LatLngBounds`.
4740
		bounds: null,
4741
4742
		// @option minZoom: Number = 0
4743
		// The minimum zoom level that tiles will be loaded at. By default the entire map.
4744
		minZoom: 0,
4745
4746
		// @option maxZoom: Number = undefined
4747
		// The maximum zoom level that tiles will be loaded at.
4748
		maxZoom: undefined,
4749
4750
		// @option noWrap: Boolean = false
4751
		// Whether the layer is wrapped around the antimeridian. If `true`, the
4752
		// GridLayer will only be displayed once at low zoom levels. Has no
4753
		// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used
4754
		// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting
4755
		// tiles outside the CRS limits.
4756
		noWrap: false,
4757
4758
		// @option pane: String = 'tilePane'
4759
		// `Map pane` where the grid layer will be added.
4760
		pane: 'tilePane',
4761
4762
		// @option className: String = ''
4763
		// A custom class name to assign to the tile layer. Empty by default.
4764
		className: '',
4765
4766
		// @option keepBuffer: Number = 2
4767
		// When panning the map, keep this many rows and columns of tiles before unloading them.
4768
		keepBuffer: 2
4769
	},
4770
4771
	initialize: function (options) {
4772
		L.setOptions(this, options);
4773
	},
4774
4775
	onAdd: function () {
4776
		this._initContainer();
4777
4778
		this._levels = {};
4779
		this._tiles = {};
4780
4781
		this._resetView();
4782
		this._update();
4783
	},
4784
4785
	beforeAdd: function (map) {
4786
		map._addZoomLimit(this);
4787
	},
4788
4789
	onRemove: function (map) {
4790
		this._removeAllTiles();
4791
		L.DomUtil.remove(this._container);
4792
		map._removeZoomLimit(this);
4793
		this._container = null;
4794
		this._tileZoom = null;
4795
	},
4796
4797
	// @method bringToFront: this
4798
	// Brings the tile layer to the top of all tile layers.
4799
	bringToFront: function () {
4800
		if (this._map) {
4801
			L.DomUtil.toFront(this._container);
4802
			this._setAutoZIndex(Math.max);
4803
		}
4804
		return this;
4805
	},
4806
4807
	// @method bringToBack: this
4808
	// Brings the tile layer to the bottom of all tile layers.
4809
	bringToBack: function () {
4810
		if (this._map) {
4811
			L.DomUtil.toBack(this._container);
4812
			this._setAutoZIndex(Math.min);
4813
		}
4814
		return this;
4815
	},
4816
4817
	// @method getContainer: HTMLElement
4818
	// Returns the HTML element that contains the tiles for this layer.
4819
	getContainer: function () {
4820
		return this._container;
4821
	},
4822
4823
	// @method setOpacity(opacity: Number): this
4824
	// Changes the [opacity](#gridlayer-opacity) of the grid layer.
4825
	setOpacity: function (opacity) {
4826
		this.options.opacity = opacity;
4827
		this._updateOpacity();
4828
		return this;
4829
	},
4830
4831
	// @method setZIndex(zIndex: Number): this
4832
	// Changes the [zIndex](#gridlayer-zindex) of the grid layer.
4833
	setZIndex: function (zIndex) {
4834
		this.options.zIndex = zIndex;
4835
		this._updateZIndex();
4836
4837
		return this;
4838
	},
4839
4840
	// @method isLoading: Boolean
4841
	// Returns `true` if any tile in the grid layer has not finished loading.
4842
	isLoading: function () {
4843
		return this._loading;
4844
	},
4845
4846
	// @method redraw: this
4847
	// Causes the layer to clear all the tiles and request them again.
4848
	redraw: function () {
4849
		if (this._map) {
4850
			this._removeAllTiles();
4851
			this._update();
4852
		}
4853
		return this;
4854
	},
4855
4856
	getEvents: function () {
4857
		var events = {
4858
			viewprereset: this._invalidateAll,
4859
			viewreset: this._resetView,
4860
			zoom: this._resetView,
4861
			moveend: this._onMoveEnd
4862
		};
4863
4864
		if (!this.options.updateWhenIdle) {
4865
			// update tiles on move, but not more often than once per given interval
4866
			if (!this._onMove) {
4867
				this._onMove = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
4868
			}
4869
4870
			events.move = this._onMove;
4871
		}
4872
4873
		if (this._zoomAnimated) {
4874
			events.zoomanim = this._animateZoom;
4875
		}
4876
4877
		return events;
4878
	},
4879
4880
	// @section Extension methods
4881
	// Layers extending `GridLayer` shall reimplement the following method.
4882
	// @method createTile(coords: Object, done?: Function): HTMLElement
4883
	// Called only internally, must be overriden by classes extending `GridLayer`.
4884
	// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
4885
	// is specified, it must be called when the tile has finished loading and drawing.
4886
	createTile: function () {
4887
		return document.createElement('div');
4888
	},
4889
4890
	// @section
4891
	// @method getTileSize: Point
4892
	// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
4893
	getTileSize: function () {
4894
		var s = this.options.tileSize;
4895
		return s instanceof L.Point ? s : new L.Point(s, s);
4896
	},
4897
4898
	_updateZIndex: function () {
4899
		if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
4900
			this._container.style.zIndex = this.options.zIndex;
4901
		}
4902
	},
4903
4904
	_setAutoZIndex: function (compare) {
4905
		// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
4906
4907
		var layers = this.getPane().children,
4908
		    edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
4909
4910
		for (var i = 0, len = layers.length, zIndex; i < len; i++) {
4911
4912
			zIndex = layers[i].style.zIndex;
4913
4914
			if (layers[i] !== this._container && zIndex) {
4915
				edgeZIndex = compare(edgeZIndex, +zIndex);
4916
			}
4917
		}
4918
4919
		if (isFinite(edgeZIndex)) {
4920
			this.options.zIndex = edgeZIndex + compare(-1, 1);
4921
			this._updateZIndex();
4922
		}
4923
	},
4924
4925
	_updateOpacity: function () {
4926
		if (!this._map) { return; }
4927
4928
		// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
4929
		if (L.Browser.ielt9) { return; }
4930
4931
		L.DomUtil.setOpacity(this._container, this.options.opacity);
4932
4933
		var now = +new Date(),
4934
		    nextFrame = false,
4935
		    willPrune = false;
4936
4937
		for (var key in this._tiles) {
4938
			var tile = this._tiles[key];
4939
			if (!tile.current || !tile.loaded) { continue; }
4940
4941
			var fade = Math.min(1, (now - tile.loaded) / 200);
4942
4943
			L.DomUtil.setOpacity(tile.el, fade);
4944
			if (fade < 1) {
4945
				nextFrame = true;
4946
			} else {
4947
				if (tile.active) { willPrune = true; }
4948
				tile.active = true;
4949
			}
4950
		}
4951
4952
		if (willPrune && !this._noPrune) { this._pruneTiles(); }
4953
4954
		if (nextFrame) {
4955
			L.Util.cancelAnimFrame(this._fadeFrame);
4956
			this._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);
4957
		}
4958
	},
4959
4960
	_initContainer: function () {
4961
		if (this._container) { return; }
4962
4963
		this._container = L.DomUtil.create('div', 'leaflet-layer ' + (this.options.className || ''));
4964
		this._updateZIndex();
4965
4966
		if (this.options.opacity < 1) {
4967
			this._updateOpacity();
4968
		}
4969
4970
		this.getPane().appendChild(this._container);
4971
	},
4972
4973
	_updateLevels: function () {
4974
4975
		var zoom = this._tileZoom,
4976
		    maxZoom = this.options.maxZoom;
4977
4978
		if (zoom === undefined) { return undefined; }
4979
4980
		for (var z in this._levels) {
4981
			if (this._levels[z].el.children.length || z === zoom) {
4982
				this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
4983
			} else {
4984
				L.DomUtil.remove(this._levels[z].el);
4985
				this._removeTilesAtZoom(z);
4986
				delete this._levels[z];
4987
			}
4988
		}
4989
4990
		var level = this._levels[zoom],
4991
		    map = this._map;
4992
4993
		if (!level) {
4994
			level = this._levels[zoom] = {};
4995
4996
			level.el = L.DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
4997
			level.el.style.zIndex = maxZoom;
4998
4999
			level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
5000
			level.zoom = zoom;
5001
5002
			this._setZoomTransform(level, map.getCenter(), map.getZoom());
5003
5004
			// force the browser to consider the newly added element for transition
5005
			L.Util.falseFn(level.el.offsetWidth);
5006
		}
5007
5008
		this._level = level;
5009
5010
		return level;
5011
	},
5012
5013
	_pruneTiles: function () {
5014
		if (!this._map) {
5015
			return;
5016
		}
5017
5018
		var key, tile;
5019
5020
		var zoom = this._map.getZoom();
5021
		if (zoom > this.options.maxZoom ||
5022
			zoom < this.options.minZoom) {
5023
			this._removeAllTiles();
5024
			return;
5025
		}
5026
5027
		for (key in this._tiles) {
5028
			tile = this._tiles[key];
5029
			tile.retain = tile.current;
5030
		}
5031
5032
		for (key in this._tiles) {
5033
			tile = this._tiles[key];
5034
			if (tile.current && !tile.active) {
5035
				var coords = tile.coords;
5036
				if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
5037
					this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
5038
				}
5039
			}
5040
		}
5041
5042
		for (key in this._tiles) {
5043
			if (!this._tiles[key].retain) {
5044
				this._removeTile(key);
5045
			}
5046
		}
5047
	},
5048
5049
	_removeTilesAtZoom: function (zoom) {
5050
		for (var key in this._tiles) {
5051
			if (this._tiles[key].coords.z !== zoom) {
5052
				continue;
5053
			}
5054
			this._removeTile(key);
5055
		}
5056
	},
5057
5058
	_removeAllTiles: function () {
5059
		for (var key in this._tiles) {
5060
			this._removeTile(key);
5061
		}
5062
	},
5063
5064
	_invalidateAll: function () {
5065
		for (var z in this._levels) {
5066
			L.DomUtil.remove(this._levels[z].el);
5067
			delete this._levels[z];
5068
		}
5069
		this._removeAllTiles();
5070
5071
		this._tileZoom = null;
5072
	},
5073
5074
	_retainParent: function (x, y, z, minZoom) {
5075
		var x2 = Math.floor(x / 2),
5076
		    y2 = Math.floor(y / 2),
5077
		    z2 = z - 1,
5078
		    coords2 = new L.Point(+x2, +y2);
5079
		coords2.z = +z2;
5080
5081
		var key = this._tileCoordsToKey(coords2),
5082
		    tile = this._tiles[key];
5083
5084
		if (tile && tile.active) {
5085
			tile.retain = true;
5086
			return true;
5087
5088
		} else if (tile && tile.loaded) {
5089
			tile.retain = true;
5090
		}
5091
5092
		if (z2 > minZoom) {
5093
			return this._retainParent(x2, y2, z2, minZoom);
5094
		}
5095
5096
		return false;
5097
	},
5098
5099
	_retainChildren: function (x, y, z, maxZoom) {
5100
5101
		for (var i = 2 * x; i < 2 * x + 2; i++) {
5102
			for (var j = 2 * y; j < 2 * y + 2; j++) {
5103
5104
				var coords = new L.Point(i, j);
5105
				coords.z = z + 1;
5106
5107
				var key = this._tileCoordsToKey(coords),
5108
				    tile = this._tiles[key];
5109
5110
				if (tile && tile.active) {
5111
					tile.retain = true;
5112
					continue;
5113
5114
				} else if (tile && tile.loaded) {
5115
					tile.retain = true;
5116
				}
5117
5118
				if (z + 1 < maxZoom) {
5119
					this._retainChildren(i, j, z + 1, maxZoom);
5120
				}
5121
			}
5122
		}
5123
	},
5124
5125
	_resetView: function (e) {
5126
		var animating = e && (e.pinch || e.flyTo);
5127
		this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
5128
	},
5129
5130
	_animateZoom: function (e) {
5131
		this._setView(e.center, e.zoom, true, e.noUpdate);
5132
	},
5133
5134
	_setView: function (center, zoom, noPrune, noUpdate) {
5135
		var tileZoom = Math.round(zoom);
5136
		if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
5137
		    (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
5138
			tileZoom = undefined;
5139
		}
5140
5141
		var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
5142
5143
		if (!noUpdate || tileZoomChanged) {
5144
5145
			this._tileZoom = tileZoom;
5146
5147
			if (this._abortLoading) {
5148
				this._abortLoading();
5149
			}
5150
5151
			this._updateLevels();
5152
			this._resetGrid();
5153
5154
			if (tileZoom !== undefined) {
5155
				this._update(center);
5156
			}
5157
5158
			if (!noPrune) {
5159
				this._pruneTiles();
5160
			}
5161
5162
			// Flag to prevent _updateOpacity from pruning tiles during
5163
			// a zoom anim or a pinch gesture
5164
			this._noPrune = !!noPrune;
5165
		}
5166
5167
		this._setZoomTransforms(center, zoom);
5168
	},
5169
5170
	_setZoomTransforms: function (center, zoom) {
5171
		for (var i in this._levels) {
5172
			this._setZoomTransform(this._levels[i], center, zoom);
5173
		}
5174
	},
5175
5176
	_setZoomTransform: function (level, center, zoom) {
5177
		var scale = this._map.getZoomScale(zoom, level.zoom),
5178
		    translate = level.origin.multiplyBy(scale)
5179
		        .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
5180
5181
		if (L.Browser.any3d) {
5182
			L.DomUtil.setTransform(level.el, translate, scale);
5183
		} else {
5184
			L.DomUtil.setPosition(level.el, translate);
5185
		}
5186
	},
5187
5188
	_resetGrid: function () {
5189
		var map = this._map,
5190
		    crs = map.options.crs,
5191
		    tileSize = this._tileSize = this.getTileSize(),
5192
		    tileZoom = this._tileZoom;
5193
5194
		var bounds = this._map.getPixelWorldBounds(this._tileZoom);
5195
		if (bounds) {
5196
			this._globalTileRange = this._pxBoundsToTileRange(bounds);
5197
		}
5198
5199
		this._wrapX = crs.wrapLng && !this.options.noWrap && [
5200
			Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
5201
			Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
5202
		];
5203
		this._wrapY = crs.wrapLat && !this.options.noWrap && [
5204
			Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
5205
			Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
5206
		];
5207
	},
5208
5209
	_onMoveEnd: function () {
5210
		if (!this._map || this._map._animatingZoom) { return; }
5211
5212
		this._update();
5213
	},
5214
5215
	_getTiledPixelBounds: function (center) {
5216
		var map = this._map,
5217
		    mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
5218
		    scale = map.getZoomScale(mapZoom, this._tileZoom),
5219
		    pixelCenter = map.project(center, this._tileZoom).floor(),
5220
		    halfSize = map.getSize().divideBy(scale * 2);
5221
5222
		return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
5223
	},
5224
5225
	// Private method to load tiles in the grid's active zoom level according to map bounds
5226
	_update: function (center) {
5227
		var map = this._map;
5228
		if (!map) { return; }
5229
		var zoom = map.getZoom();
5230
5231
		if (center === undefined) { center = map.getCenter(); }
5232
		if (this._tileZoom === undefined) { return; }	// if out of minzoom/maxzoom
5233
5234
		var pixelBounds = this._getTiledPixelBounds(center),
5235
		    tileRange = this._pxBoundsToTileRange(pixelBounds),
5236
		    tileCenter = tileRange.getCenter(),
5237
		    queue = [],
5238
		    margin = this.options.keepBuffer,
5239
		    noPruneRange = new L.Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
5240
		                              tileRange.getTopRight().add([margin, -margin]));
5241
5242
		for (var key in this._tiles) {
5243
			var c = this._tiles[key].coords;
5244
			if (c.z !== this._tileZoom || !noPruneRange.contains(L.point(c.x, c.y))) {
5245
				this._tiles[key].current = false;
5246
			}
5247
		}
5248
5249
		// _update just loads more tiles. If the tile zoom level differs too much
5250
		// from the map's, let _setView reset levels and prune old tiles.
5251
		if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
5252
5253
		// create a queue of coordinates to load tiles from
5254
		for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
5255
			for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
5256
				var coords = new L.Point(i, j);
5257
				coords.z = this._tileZoom;
5258
5259
				if (!this._isValidTile(coords)) { continue; }
5260
5261
				var tile = this._tiles[this._tileCoordsToKey(coords)];
5262
				if (tile) {
5263
					tile.current = true;
5264
				} else {
5265
					queue.push(coords);
5266
				}
5267
			}
5268
		}
5269
5270
		// sort tile queue to load tiles in order of their distance to center
5271
		queue.sort(function (a, b) {
5272
			return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
5273
		});
5274
5275
		if (queue.length !== 0) {
5276
			// if it's the first batch of tiles to load
5277
			if (!this._loading) {
5278
				this._loading = true;
5279
				// @event loading: Event
5280
				// Fired when the grid layer starts loading tiles.
5281
				this.fire('loading');
5282
			}
5283
5284
			// create DOM fragment to append tiles in one batch
5285
			var fragment = document.createDocumentFragment();
5286
5287
			for (i = 0; i < queue.length; i++) {
5288
				this._addTile(queue[i], fragment);
5289
			}
5290
5291
			this._level.el.appendChild(fragment);
5292
		}
5293
	},
5294
5295
	_isValidTile: function (coords) {
5296
		var crs = this._map.options.crs;
5297
5298
		if (!crs.infinite) {
5299
			// don't load tile if it's out of bounds and not wrapped
5300
			var bounds = this._globalTileRange;
5301
			if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
5302
			    (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
5303
		}
5304
5305
		if (!this.options.bounds) { return true; }
5306
5307
		// don't load tile if it doesn't intersect the bounds in options
5308
		var tileBounds = this._tileCoordsToBounds(coords);
5309
		return L.latLngBounds(this.options.bounds).overlaps(tileBounds);
5310
	},
5311
5312
	_keyToBounds: function (key) {
5313
		return this._tileCoordsToBounds(this._keyToTileCoords(key));
5314
	},
5315
5316
	// converts tile coordinates to its geographical bounds
5317
	_tileCoordsToBounds: function (coords) {
5318
5319
		var map = this._map,
5320
		    tileSize = this.getTileSize(),
5321
5322
		    nwPoint = coords.scaleBy(tileSize),
5323
		    sePoint = nwPoint.add(tileSize),
5324
5325
		    nw = map.unproject(nwPoint, coords.z),
5326
		    se = map.unproject(sePoint, coords.z),
5327
		    bounds = new L.LatLngBounds(nw, se);
5328
5329
		if (!this.options.noWrap) {
5330
			map.wrapLatLngBounds(bounds);
5331
		}
5332
5333
		return bounds;
5334
	},
5335
5336
	// converts tile coordinates to key for the tile cache
5337
	_tileCoordsToKey: function (coords) {
5338
		return coords.x + ':' + coords.y + ':' + coords.z;
5339
	},
5340
5341
	// converts tile cache key to coordinates
5342
	_keyToTileCoords: function (key) {
5343
		var k = key.split(':'),
5344
		    coords = new L.Point(+k[0], +k[1]);
5345
		coords.z = +k[2];
5346
		return coords;
5347
	},
5348
5349
	_removeTile: function (key) {
5350
		var tile = this._tiles[key];
5351
		if (!tile) { return; }
5352
5353
		L.DomUtil.remove(tile.el);
5354
5355
		delete this._tiles[key];
5356
5357
		// @event tileunload: TileEvent
5358
		// Fired when a tile is removed (e.g. when a tile goes off the screen).
5359
		this.fire('tileunload', {
5360
			tile: tile.el,
5361
			coords: this._keyToTileCoords(key)
5362
		});
5363
	},
5364
5365
	_initTile: function (tile) {
5366
		L.DomUtil.addClass(tile, 'leaflet-tile');
5367
5368
		var tileSize = this.getTileSize();
5369
		tile.style.width = tileSize.x + 'px';
5370
		tile.style.height = tileSize.y + 'px';
5371
5372
		tile.onselectstart = L.Util.falseFn;
5373
		tile.onmousemove = L.Util.falseFn;
5374
5375
		// update opacity on tiles in IE7-8 because of filter inheritance problems
5376
		if (L.Browser.ielt9 && this.options.opacity < 1) {
5377
			L.DomUtil.setOpacity(tile, this.options.opacity);
5378
		}
5379
5380
		// without this hack, tiles disappear after zoom on Chrome for Android
5381
		// https://github.com/Leaflet/Leaflet/issues/2078
5382
		if (L.Browser.android && !L.Browser.android23) {
5383
			tile.style.WebkitBackfaceVisibility = 'hidden';
5384
		}
5385
	},
5386
5387
	_addTile: function (coords, container) {
5388
		var tilePos = this._getTilePos(coords),
5389
		    key = this._tileCoordsToKey(coords);
5390
5391
		var tile = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords));
5392
5393
		this._initTile(tile);
5394
5395
		// if createTile is defined with a second argument ("done" callback),
5396
		// we know that tile is async and will be ready later; otherwise
5397
		if (this.createTile.length < 2) {
5398
			// mark tile as ready, but delay one frame for opacity animation to happen
5399
			L.Util.requestAnimFrame(L.bind(this._tileReady, this, coords, null, tile));
5400
		}
5401
5402
		L.DomUtil.setPosition(tile, tilePos);
5403
5404
		// save tile in cache
5405
		this._tiles[key] = {
5406
			el: tile,
5407
			coords: coords,
5408
			current: true
5409
		};
5410
5411
		container.appendChild(tile);
5412
		// @event tileloadstart: TileEvent
5413
		// Fired when a tile is requested and starts loading.
5414
		this.fire('tileloadstart', {
5415
			tile: tile,
5416
			coords: coords
5417
		});
5418
	},
5419
5420
	_tileReady: function (coords, err, tile) {
5421
		if (!this._map) { return; }
5422
5423
		if (err) {
5424
			// @event tileerror: TileErrorEvent
5425
			// Fired when there is an error loading a tile.
5426
			this.fire('tileerror', {
5427
				error: err,
5428
				tile: tile,
5429
				coords: coords
5430
			});
5431
		}
5432
5433
		var key = this._tileCoordsToKey(coords);
5434
5435
		tile = this._tiles[key];
5436
		if (!tile) { return; }
5437
5438
		tile.loaded = +new Date();
5439
		if (this._map._fadeAnimated) {
5440
			L.DomUtil.setOpacity(tile.el, 0);
5441
			L.Util.cancelAnimFrame(this._fadeFrame);
5442
			this._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);
5443
		} else {
5444
			tile.active = true;
5445
			this._pruneTiles();
5446
		}
5447
5448
		if (!err) {
5449
			L.DomUtil.addClass(tile.el, 'leaflet-tile-loaded');
5450
5451
			// @event tileload: TileEvent
5452
			// Fired when a tile loads.
5453
			this.fire('tileload', {
5454
				tile: tile.el,
5455
				coords: coords
5456
			});
5457
		}
5458
5459
		if (this._noTilesToLoad()) {
5460
			this._loading = false;
5461
			// @event load: Event
5462
			// Fired when the grid layer loaded all visible tiles.
5463
			this.fire('load');
5464
5465
			if (L.Browser.ielt9 || !this._map._fadeAnimated) {
5466
				L.Util.requestAnimFrame(this._pruneTiles, this);
5467
			} else {
5468
				// Wait a bit more than 0.2 secs (the duration of the tile fade-in)
5469
				// to trigger a pruning.
5470
				setTimeout(L.bind(this._pruneTiles, this), 250);
5471
			}
5472
		}
5473
	},
5474
5475
	_getTilePos: function (coords) {
5476
		return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
5477
	},
5478
5479
	_wrapCoords: function (coords) {
5480
		var newCoords = new L.Point(
5481
			this._wrapX ? L.Util.wrapNum(coords.x, this._wrapX) : coords.x,
5482
			this._wrapY ? L.Util.wrapNum(coords.y, this._wrapY) : coords.y);
5483
		newCoords.z = coords.z;
5484
		return newCoords;
5485
	},
5486
5487
	_pxBoundsToTileRange: function (bounds) {
5488
		var tileSize = this.getTileSize();
5489
		return new L.Bounds(
5490
			bounds.min.unscaleBy(tileSize).floor(),
5491
			bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
5492
	},
5493
5494
	_noTilesToLoad: function () {
5495
		for (var key in this._tiles) {
5496
			if (!this._tiles[key].loaded) { return false; }
5497
		}
5498
		return true;
5499
	}
5500
});
5501
5502
// @factory L.gridLayer(options?: GridLayer options)
5503
// Creates a new instance of GridLayer with the supplied options.
5504
L.gridLayer = function (options) {
5505
	return new L.GridLayer(options);
5506
};
5507
5508
5509
5510
/*
5511
 * @class TileLayer
5512
 * @inherits GridLayer
5513
 * @aka L.TileLayer
5514
 * Used to load and display tile layers on the map. Extends `GridLayer`.
5515
 *
5516
 * @example
5517
 *
5518
 * ```js
5519
 * L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);
5520
 * ```
5521
 *
5522
 * @section URL template
5523
 * @example
5524
 *
5525
 * A string of the following form:
5526
 *
5527
 * ```
5528
 * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
5529
 * ```
5530
 *
5531
 * `{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 @2x to the URL to load retina tiles.
5532
 *
5533
 * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
5534
 *
5535
 * ```
5536
 * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
5537
 * ```
5538
 */
5539
5540
5541
L.TileLayer = L.GridLayer.extend({
5542
5543
	// @section
5544
	// @aka TileLayer options
5545
	options: {
5546
		// @option minZoom: Number = 0
5547
		// Minimum zoom number.
5548
		minZoom: 0,
5549
5550
		// @option maxZoom: Number = 18
5551
		// Maximum zoom number.
5552
		maxZoom: 18,
5553
5554
		// @option maxNativeZoom: Number = null
5555
		// Maximum zoom number the tile source has available. If it is specified,
5556
		// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
5557
		// from `maxNativeZoom` level and auto-scaled.
5558
		maxNativeZoom: null,
5559
5560
		// @option minNativeZoom: Number = null
5561
		// Minimum zoom number the tile source has available. If it is specified,
5562
		// the tiles on all zoom levels lower than `minNativeZoom` will be loaded
5563
		// from `minNativeZoom` level and auto-scaled.
5564
		minNativeZoom: null,
5565
5566
		// @option subdomains: String|String[] = 'abc'
5567
		// 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.
5568
		subdomains: 'abc',
5569
5570
		// @option errorTileUrl: String = ''
5571
		// URL to the tile image to show in place of the tile that failed to load.
5572
		errorTileUrl: '',
5573
5574
		// @option zoomOffset: Number = 0
5575
		// The zoom number used in tile URLs will be offset with this value.
5576
		zoomOffset: 0,
5577
5578
		// @option tms: Boolean = false
5579
		// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
5580
		tms: false,
5581
5582
		// @option zoomReverse: Boolean = false
5583
		// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
5584
		zoomReverse: false,
5585
5586
		// @option detectRetina: Boolean = false
5587
		// 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.
5588
		detectRetina: false,
5589
5590
		// @option crossOrigin: Boolean = false
5591
		// If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data.
5592
		crossOrigin: false
5593
	},
5594
5595
	initialize: function (url, options) {
5596
5597
		this._url = url;
5598
5599
		options = L.setOptions(this, options);
5600
5601
		// detecting retina displays, adjusting tileSize and zoom levels
5602
		if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
5603
5604
			options.tileSize = Math.floor(options.tileSize / 2);
5605
5606
			if (!options.zoomReverse) {
5607
				options.zoomOffset++;
5608
				options.maxZoom--;
5609
			} else {
5610
				options.zoomOffset--;
5611
				options.minZoom++;
5612
			}
5613
5614
			options.minZoom = Math.max(0, options.minZoom);
5615
		}
5616
5617
		if (typeof options.subdomains === 'string') {
5618
			options.subdomains = options.subdomains.split('');
5619
		}
5620
5621
		// for https://github.com/Leaflet/Leaflet/issues/137
5622
		if (!L.Browser.android) {
5623
			this.on('tileunload', this._onTileRemove);
5624
		}
5625
	},
5626
5627
	// @method setUrl(url: String, noRedraw?: Boolean): this
5628
	// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
5629
	setUrl: function (url, noRedraw) {
5630
		this._url = url;
5631
5632
		if (!noRedraw) {
5633
			this.redraw();
5634
		}
5635
		return this;
5636
	},
5637
5638
	// @method createTile(coords: Object, done?: Function): HTMLElement
5639
	// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
5640
	// to return an `<img>` HTML element with the appropiate image URL given `coords`. The `done`
5641
	// callback is called when the tile has been loaded.
5642
	createTile: function (coords, done) {
5643
		var tile = document.createElement('img');
5644
5645
		L.DomEvent.on(tile, 'load', L.bind(this._tileOnLoad, this, done, tile));
5646
		L.DomEvent.on(tile, 'error', L.bind(this._tileOnError, this, done, tile));
5647
5648
		if (this.options.crossOrigin) {
5649
			tile.crossOrigin = '';
5650
		}
5651
5652
		/*
5653
		 Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
5654
		 http://www.w3.org/TR/WCAG20-TECHS/H67
5655
		*/
5656
		tile.alt = '';
5657
5658
		/*
5659
		 Set role="presentation" to force screen readers to ignore this
5660
		 https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
5661
		*/
5662
		tile.setAttribute('role', 'presentation');
5663
5664
		tile.src = this.getTileUrl(coords);
5665
5666
		return tile;
5667
	},
5668
5669
	// @section Extension methods
5670
	// @uninheritable
5671
	// Layers extending `TileLayer` might reimplement the following method.
5672
	// @method getTileUrl(coords: Object): String
5673
	// Called only internally, returns the URL for a tile given its coordinates.
5674
	// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
5675
	getTileUrl: function (coords) {
5676
		var data = {
5677
			r: L.Browser.retina ? '@2x' : '',
5678
			s: this._getSubdomain(coords),
5679
			x: coords.x,
5680
			y: coords.y,
5681
			z: this._getZoomForUrl()
5682
		};
5683
		if (this._map && !this._map.options.crs.infinite) {
5684
			var invertedY = this._globalTileRange.max.y - coords.y;
5685
			if (this.options.tms) {
5686
				data['y'] = invertedY;
5687
			}
5688
			data['-y'] = invertedY;
5689
		}
5690
5691
		return L.Util.template(this._url, L.extend(data, this.options));
5692
	},
5693
5694
	_tileOnLoad: function (done, tile) {
5695
		// For https://github.com/Leaflet/Leaflet/issues/3332
5696
		if (L.Browser.ielt9) {
5697
			setTimeout(L.bind(done, this, null, tile), 0);
5698
		} else {
5699
			done(null, tile);
5700
		}
5701
	},
5702
5703
	_tileOnError: function (done, tile, e) {
5704
		var errorUrl = this.options.errorTileUrl;
5705
		if (errorUrl && tile.src !== errorUrl) {
5706
			tile.src = errorUrl;
5707
		}
5708
		done(e, tile);
5709
	},
5710
5711
	getTileSize: function () {
5712
		var map = this._map,
5713
		tileSize = L.GridLayer.prototype.getTileSize.call(this),
5714
		zoom = this._tileZoom + this.options.zoomOffset,
5715
		minNativeZoom = this.options.minNativeZoom,
5716
		maxNativeZoom = this.options.maxNativeZoom;
5717
5718
		// decrease tile size when scaling below minNativeZoom
5719
		if (minNativeZoom !== null && zoom < minNativeZoom) {
5720
			return tileSize.divideBy(map.getZoomScale(minNativeZoom, zoom)).round();
5721
		}
5722
5723
		// increase tile size when scaling above maxNativeZoom
5724
		if (maxNativeZoom !== null && zoom > maxNativeZoom) {
5725
			return tileSize.divideBy(map.getZoomScale(maxNativeZoom, zoom)).round();
5726
		}
5727
5728
		return tileSize;
5729
	},
5730
5731
	_onTileRemove: function (e) {
5732
		e.tile.onload = null;
5733
	},
5734
5735
	_getZoomForUrl: function () {
5736
		var zoom = this._tileZoom,
5737
		maxZoom = this.options.maxZoom,
5738
		zoomReverse = this.options.zoomReverse,
5739
		zoomOffset = this.options.zoomOffset,
5740
		minNativeZoom = this.options.minNativeZoom,
5741
		maxNativeZoom = this.options.maxNativeZoom;
5742
5743
		if (zoomReverse) {
5744
			zoom = maxZoom - zoom;
5745
		}
5746
5747
		zoom += zoomOffset;
5748
5749
		if (minNativeZoom !== null && zoom < minNativeZoom) {
5750
			return minNativeZoom;
5751
		}
5752
5753
		if (maxNativeZoom !== null && zoom > maxNativeZoom) {
5754
			return maxNativeZoom;
5755
		}
5756
5757
		return zoom;
5758
	},
5759
5760
	_getSubdomain: function (tilePoint) {
5761
		var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
5762
		return this.options.subdomains[index];
5763
	},
5764
5765
	// stops loading all tiles in the background layer
5766
	_abortLoading: function () {
5767
		var i, tile;
5768
		for (i in this._tiles) {
5769
			if (this._tiles[i].coords.z !== this._tileZoom) {
5770
				tile = this._tiles[i].el;
5771
5772
				tile.onload = L.Util.falseFn;
5773
				tile.onerror = L.Util.falseFn;
5774
5775
				if (!tile.complete) {
5776
					tile.src = L.Util.emptyImageUrl;
5777
					L.DomUtil.remove(tile);
5778
				}
5779
			}
5780
		}
5781
	}
5782
});
5783
5784
5785
// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
5786
// Instantiates a tile layer object given a `URL template` and optionally an options object.
5787
5788
L.tileLayer = function (url, options) {
5789
	return new L.TileLayer(url, options);
5790
};
5791
5792
5793
5794
/*
5795
 * @class TileLayer.WMS
5796
 * @inherits TileLayer
5797
 * @aka L.TileLayer.WMS
5798
 * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
5799
 *
5800
 * @example
5801
 *
5802
 * ```js
5803
 * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
5804
 * 	layers: 'nexrad-n0r-900913',
5805
 * 	format: 'image/png',
5806
 * 	transparent: true,
5807
 * 	attribution: "Weather data © 2012 IEM Nexrad"
5808
 * });
5809
 * ```
5810
 */
5811
5812
L.TileLayer.WMS = L.TileLayer.extend({
5813
5814
	// @section
5815
	// @aka TileLayer.WMS options
5816
	// If any custom options not documented here are used, they will be sent to the
5817
	// WMS server as extra parameters in each request URL. This can be useful for
5818
	// [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
5819
	defaultWmsParams: {
5820
		service: 'WMS',
5821
		request: 'GetMap',
5822
5823
		// @option layers: String = ''
5824
		// **(required)** Comma-separated list of WMS layers to show.
5825
		layers: '',
5826
5827
		// @option styles: String = ''
5828
		// Comma-separated list of WMS styles.
5829
		styles: '',
5830
5831
		// @option format: String = 'image/jpeg'
5832
		// WMS image format (use `'image/png'` for layers with transparency).
5833
		format: 'image/jpeg',
5834
5835
		// @option transparent: Boolean = false
5836
		// If `true`, the WMS service will return images with transparency.
5837
		transparent: false,
5838
5839
		// @option version: String = '1.1.1'
5840
		// Version of the WMS service to use
5841
		version: '1.1.1'
5842
	},
5843
5844
	options: {
5845
		// @option crs: CRS = null
5846
		// Coordinate Reference System to use for the WMS requests, defaults to
5847
		// map CRS. Don't change this if you're not sure what it means.
5848
		crs: null,
5849
5850
		// @option uppercase: Boolean = false
5851
		// If `true`, WMS request parameter keys will be uppercase.
5852
		uppercase: false
5853
	},
5854
5855
	initialize: function (url, options) {
5856
5857
		this._url = url;
5858
5859
		var wmsParams = L.extend({}, this.defaultWmsParams);
5860
5861
		// all keys that are not TileLayer options go to WMS params
5862
		for (var i in options) {
5863
			if (!(i in this.options)) {
5864
				wmsParams[i] = options[i];
5865
			}
5866
		}
5867
5868
		options = L.setOptions(this, options);
5869
5870
		wmsParams.width = wmsParams.height = options.tileSize * (options.detectRetina && L.Browser.retina ? 2 : 1);
5871
5872
		this.wmsParams = wmsParams;
5873
	},
5874
5875
	onAdd: function (map) {
5876
5877
		this._crs = this.options.crs || map.options.crs;
5878
		this._wmsVersion = parseFloat(this.wmsParams.version);
5879
5880
		var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
5881
		this.wmsParams[projectionKey] = this._crs.code;
5882
5883
		L.TileLayer.prototype.onAdd.call(this, map);
5884
	},
5885
5886
	getTileUrl: function (coords) {
5887
5888
		var tileBounds = this._tileCoordsToBounds(coords),
5889
		    nw = this._crs.project(tileBounds.getNorthWest()),
5890
		    se = this._crs.project(tileBounds.getSouthEast()),
5891
5892
		    bbox = (this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
5893
			    [se.y, nw.x, nw.y, se.x] :
5894
			    [nw.x, se.y, se.x, nw.y]).join(','),
5895
5896
		    url = L.TileLayer.prototype.getTileUrl.call(this, coords);
5897
5898
		return url +
5899
			L.Util.getParamString(this.wmsParams, url, this.options.uppercase) +
5900
			(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
5901
	},
5902
5903
	// @method setParams(params: Object, noRedraw?: Boolean): this
5904
	// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
5905
	setParams: function (params, noRedraw) {
5906
5907
		L.extend(this.wmsParams, params);
5908
5909
		if (!noRedraw) {
5910
			this.redraw();
5911
		}
5912
5913
		return this;
5914
	}
5915
});
5916
5917
5918
// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
5919
// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
5920
L.tileLayer.wms = function (url, options) {
5921
	return new L.TileLayer.WMS(url, options);
5922
};
5923
5924
5925
5926
/*
5927
 * @class ImageOverlay
5928
 * @aka L.ImageOverlay
5929
 * @inherits Interactive layer
5930
 *
5931
 * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
5932
 *
5933
 * @example
5934
 *
5935
 * ```js
5936
 * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
5937
 * 	imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
5938
 * L.imageOverlay(imageUrl, imageBounds).addTo(map);
5939
 * ```
5940
 */
5941
5942
L.ImageOverlay = L.Layer.extend({
5943
5944
	// @section
5945
	// @aka ImageOverlay options
5946
	options: {
5947
		// @option opacity: Number = 1.0
5948
		// The opacity of the image overlay.
5949
		opacity: 1,
5950
5951
		// @option alt: String = ''
5952
		// Text for the `alt` attribute of the image (useful for accessibility).
5953
		alt: '',
5954
5955
		// @option interactive: Boolean = false
5956
		// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
5957
		interactive: false,
5958
5959
		// @option crossOrigin: Boolean = false
5960
		// If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data.
5961
		crossOrigin: false
5962
	},
5963
5964
	initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
5965
		this._url = url;
5966
		this._bounds = L.latLngBounds(bounds);
5967
5968
		L.setOptions(this, options);
5969
	},
5970
5971
	onAdd: function () {
5972
		if (!this._image) {
5973
			this._initImage();
5974
5975
			if (this.options.opacity < 1) {
5976
				this._updateOpacity();
5977
			}
5978
		}
5979
5980
		if (this.options.interactive) {
5981
			L.DomUtil.addClass(this._image, 'leaflet-interactive');
5982
			this.addInteractiveTarget(this._image);
5983
		}
5984
5985
		this.getPane().appendChild(this._image);
5986
		this._reset();
5987
	},
5988
5989
	onRemove: function () {
5990
		L.DomUtil.remove(this._image);
5991
		if (this.options.interactive) {
5992
			this.removeInteractiveTarget(this._image);
5993
		}
5994
	},
5995
5996
	// @method setOpacity(opacity: Number): this
5997
	// Sets the opacity of the overlay.
5998
	setOpacity: function (opacity) {
5999
		this.options.opacity = opacity;
6000
6001
		if (this._image) {
6002
			this._updateOpacity();
6003
		}
6004
		return this;
6005
	},
6006
6007
	setStyle: function (styleOpts) {
6008
		if (styleOpts.opacity) {
6009
			this.setOpacity(styleOpts.opacity);
6010
		}
6011
		return this;
6012
	},
6013
6014
	// @method bringToFront(): this
6015
	// Brings the layer to the top of all overlays.
6016
	bringToFront: function () {
6017
		if (this._map) {
6018
			L.DomUtil.toFront(this._image);
6019
		}
6020
		return this;
6021
	},
6022
6023
	// @method bringToBack(): this
6024
	// Brings the layer to the bottom of all overlays.
6025
	bringToBack: function () {
6026
		if (this._map) {
6027
			L.DomUtil.toBack(this._image);
6028
		}
6029
		return this;
6030
	},
6031
6032
	// @method setUrl(url: String): this
6033
	// Changes the URL of the image.
6034
	setUrl: function (url) {
6035
		this._url = url;
6036
6037
		if (this._image) {
6038
			this._image.src = url;
6039
		}
6040
		return this;
6041
	},
6042
6043
	// @method setBounds(bounds: LatLngBounds): this
6044
	// Update the bounds that this ImageOverlay covers
6045
	setBounds: function (bounds) {
6046
		this._bounds = bounds;
6047
6048
		if (this._map) {
6049
			this._reset();
6050
		}
6051
		return this;
6052
	},
6053
6054
	getEvents: function () {
6055
		var events = {
6056
			zoom: this._reset,
6057
			viewreset: this._reset
6058
		};
6059
6060
		if (this._zoomAnimated) {
6061
			events.zoomanim = this._animateZoom;
6062
		}
6063
6064
		return events;
6065
	},
6066
6067
	// @method getBounds(): LatLngBounds
6068
	// Get the bounds that this ImageOverlay covers
6069
	getBounds: function () {
6070
		return this._bounds;
6071
	},
6072
6073
	// @method getElement(): HTMLElement
6074
	// Get the img element that represents the ImageOverlay on the map
6075
	getElement: function () {
6076
		return this._image;
6077
	},
6078
6079
	_initImage: function () {
6080
		var img = this._image = L.DomUtil.create('img',
6081
				'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : ''));
6082
6083
		img.onselectstart = L.Util.falseFn;
6084
		img.onmousemove = L.Util.falseFn;
6085
6086
		img.onload = L.bind(this.fire, this, 'load');
6087
6088
		if (this.options.crossOrigin) {
6089
			img.crossOrigin = '';
6090
		}
6091
6092
		img.src = this._url;
6093
		img.alt = this.options.alt;
6094
	},
6095
6096
	_animateZoom: function (e) {
6097
		var scale = this._map.getZoomScale(e.zoom),
6098
		    offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
6099
6100
		L.DomUtil.setTransform(this._image, offset, scale);
6101
	},
6102
6103
	_reset: function () {
6104
		var image = this._image,
6105
		    bounds = new L.Bounds(
6106
		        this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
6107
		        this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
6108
		    size = bounds.getSize();
6109
6110
		L.DomUtil.setPosition(image, bounds.min);
6111
6112
		image.style.width  = size.x + 'px';
6113
		image.style.height = size.y + 'px';
6114
	},
6115
6116
	_updateOpacity: function () {
6117
		L.DomUtil.setOpacity(this._image, this.options.opacity);
6118
	}
6119
});
6120
6121
// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
6122
// Instantiates an image overlay object given the URL of the image and the
6123
// geographical bounds it is tied to.
6124
L.imageOverlay = function (url, bounds, options) {
6125
	return new L.ImageOverlay(url, bounds, options);
6126
};
6127
6128
6129
6130
/*
6131
 * @class Icon
6132
 * @aka L.Icon
6133
 * @inherits Layer
6134
 *
6135
 * Represents an icon to provide when creating a marker.
6136
 *
6137
 * @example
6138
 *
6139
 * ```js
6140
 * var myIcon = L.icon({
6141
 *     iconUrl: 'my-icon.png',
6142
 *     iconRetinaUrl: 'my-icon@2x.png',
6143
 *     iconSize: [38, 95],
6144
 *     iconAnchor: [22, 94],
6145
 *     popupAnchor: [-3, -76],
6146
 *     shadowUrl: 'my-icon-shadow.png',
6147
 *     shadowRetinaUrl: 'my-icon-shadow@2x.png',
6148
 *     shadowSize: [68, 95],
6149
 *     shadowAnchor: [22, 94]
6150
 * });
6151
 *
6152
 * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
6153
 * ```
6154
 *
6155
 * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
6156
 *
6157
 */
6158
6159
L.Icon = L.Class.extend({
6160
6161
	/* @section
6162
	 * @aka Icon options
6163
	 *
6164
	 * @option iconUrl: String = null
6165
	 * **(required)** The URL to the icon image (absolute or relative to your script path).
6166
	 *
6167
	 * @option iconRetinaUrl: String = null
6168
	 * The URL to a retina sized version of the icon image (absolute or relative to your
6169
	 * script path). Used for Retina screen devices.
6170
	 *
6171
	 * @option iconSize: Point = null
6172
	 * Size of the icon image in pixels.
6173
	 *
6174
	 * @option iconAnchor: Point = null
6175
	 * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
6176
	 * will be aligned so that this point is at the marker's geographical location. Centered
6177
	 * by default if size is specified, also can be set in CSS with negative margins.
6178
	 *
6179
	 * @option popupAnchor: Point = null
6180
	 * The coordinates of the point from which popups will "open", relative to the icon anchor.
6181
	 *
6182
	 * @option shadowUrl: String = null
6183
	 * The URL to the icon shadow image. If not specified, no shadow image will be created.
6184
	 *
6185
	 * @option shadowRetinaUrl: String = null
6186
	 *
6187
	 * @option shadowSize: Point = null
6188
	 * Size of the shadow image in pixels.
6189
	 *
6190
	 * @option shadowAnchor: Point = null
6191
	 * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
6192
	 * as iconAnchor if not specified).
6193
	 *
6194
	 * @option className: String = ''
6195
	 * A custom class name to assign to both icon and shadow images. Empty by default.
6196
	 */
6197
6198
	initialize: function (options) {
6199
		L.setOptions(this, options);
6200
	},
6201
6202
	// @method createIcon(oldIcon?: HTMLElement): HTMLElement
6203
	// Called internally when the icon has to be shown, returns a `<img>` HTML element
6204
	// styled according to the options.
6205
	createIcon: function (oldIcon) {
6206
		return this._createIcon('icon', oldIcon);
6207
	},
6208
6209
	// @method createShadow(oldIcon?: HTMLElement): HTMLElement
6210
	// As `createIcon`, but for the shadow beneath it.
6211
	createShadow: function (oldIcon) {
6212
		return this._createIcon('shadow', oldIcon);
6213
	},
6214
6215
	_createIcon: function (name, oldIcon) {
6216
		var src = this._getIconUrl(name);
6217
6218
		if (!src) {
6219
			if (name === 'icon') {
6220
				throw new Error('iconUrl not set in Icon options (see the docs).');
6221
			}
6222
			return null;
6223
		}
6224
6225
		var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
6226
		this._setIconStyles(img, name);
6227
6228
		return img;
6229
	},
6230
6231
	_setIconStyles: function (img, name) {
6232
		var options = this.options;
6233
		var sizeOption = options[name + 'Size'];
6234
6235
		if (typeof sizeOption === 'number') {
6236
			sizeOption = [sizeOption, sizeOption];
6237
		}
6238
6239
		var size = L.point(sizeOption),
6240
		    anchor = L.point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
6241
		            size && size.divideBy(2, true));
6242
6243
		img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
6244
6245
		if (anchor) {
6246
			img.style.marginLeft = (-anchor.x) + 'px';
6247
			img.style.marginTop  = (-anchor.y) + 'px';
6248
		}
6249
6250
		if (size) {
6251
			img.style.width  = size.x + 'px';
6252
			img.style.height = size.y + 'px';
6253
		}
6254
	},
6255
6256
	_createImg: function (src, el) {
6257
		el = el || document.createElement('img');
6258
		el.src = src;
6259
		return el;
6260
	},
6261
6262
	_getIconUrl: function (name) {
6263
		return L.Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
6264
	}
6265
});
6266
6267
6268
// @factory L.icon(options: Icon options)
6269
// Creates an icon instance with the given options.
6270
L.icon = function (options) {
6271
	return new L.Icon(options);
6272
};
6273
6274
6275
6276
/*
6277
 * @miniclass Icon.Default (Icon)
6278
 * @aka L.Icon.Default
6279
 * @section
6280
 *
6281
 * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
6282
 * no icon is specified. Points to the blue marker image distributed with Leaflet
6283
 * releases.
6284
 *
6285
 * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
6286
 * (which is a set of `Icon options`).
6287
 *
6288
 * If you want to _completely_ replace the default icon, override the
6289
 * `L.Marker.prototype.options.icon` with your own icon instead.
6290
 */
6291
6292
L.Icon.Default = L.Icon.extend({
6293
6294
	options: {
6295
		iconUrl:       'marker-icon.png',
6296
		iconRetinaUrl: 'marker-icon-2x.png',
6297
		shadowUrl:     'marker-shadow.png',
6298
		iconSize:    [25, 41],
6299
		iconAnchor:  [12, 41],
6300
		popupAnchor: [1, -34],
6301
		tooltipAnchor: [16, -28],
6302
		shadowSize:  [41, 41]
6303
	},
6304
6305
	_getIconUrl: function (name) {
6306
		if (!L.Icon.Default.imagePath) {	// Deprecated, backwards-compatibility only
6307
			L.Icon.Default.imagePath = this._detectIconPath();
6308
		}
6309
6310
		// @option imagePath: String
6311
		// `L.Icon.Default` will try to auto-detect the absolute location of the
6312
		// blue icon images. If you are placing these images in a non-standard
6313
		// way, set this option to point to the right absolute path.
6314
		return (this.options.imagePath || L.Icon.Default.imagePath) + L.Icon.prototype._getIconUrl.call(this, name);
6315
	},
6316
6317
	_detectIconPath: function () {
6318
		var el = L.DomUtil.create('div',  'leaflet-default-icon-path', document.body);
6319
		var path = L.DomUtil.getStyle(el, 'background-image') ||
6320
		           L.DomUtil.getStyle(el, 'backgroundImage');	// IE8
6321
6322
		document.body.removeChild(el);
6323
6324
		return path.indexOf('url') === 0 ?
6325
			path.replace(/^url\([\"\']?/, '').replace(/marker-icon\.png[\"\']?\)$/, '') : '';
6326
	}
6327
});
6328
6329
6330
6331
/*
6332
 * @class Marker
6333
 * @inherits Interactive layer
6334
 * @aka L.Marker
6335
 * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
6336
 *
6337
 * @example
6338
 *
6339
 * ```js
6340
 * L.marker([50.5, 30.5]).addTo(map);
6341
 * ```
6342
 */
6343
6344
L.Marker = L.Layer.extend({
6345
6346
	// @section
6347
	// @aka Marker options
6348
	options: {
6349
		// @option icon: Icon = *
6350
		// Icon class to use for rendering the marker. See [Icon documentation](#L.Icon) for details on how to customize the marker icon. If not specified, a new `L.Icon.Default` is used.
6351
		icon: new L.Icon.Default(),
6352
6353
		// Option inherited from "Interactive layer" abstract class
6354
		interactive: true,
6355
6356
		// @option draggable: Boolean = false
6357
		// Whether the marker is draggable with mouse/touch or not.
6358
		draggable: false,
6359
6360
		// @option keyboard: Boolean = true
6361
		// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
6362
		keyboard: true,
6363
6364
		// @option title: String = ''
6365
		// Text for the browser tooltip that appear on marker hover (no tooltip by default).
6366
		title: '',
6367
6368
		// @option alt: String = ''
6369
		// Text for the `alt` attribute of the icon image (useful for accessibility).
6370
		alt: '',
6371
6372
		// @option zIndexOffset: Number = 0
6373
		// 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).
6374
		zIndexOffset: 0,
6375
6376
		// @option opacity: Number = 1.0
6377
		// The opacity of the marker.
6378
		opacity: 1,
6379
6380
		// @option riseOnHover: Boolean = false
6381
		// If `true`, the marker will get on top of others when you hover the mouse over it.
6382
		riseOnHover: false,
6383
6384
		// @option riseOffset: Number = 250
6385
		// The z-index offset used for the `riseOnHover` feature.
6386
		riseOffset: 250,
6387
6388
		// @option pane: String = 'markerPane'
6389
		// `Map pane` where the markers icon will be added.
6390
		pane: 'markerPane',
6391
6392
		// FIXME: shadowPane is no longer a valid option
6393
		nonBubblingEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu']
6394
	},
6395
6396
	/* @section
6397
	 *
6398
	 * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
6399
	 */
6400
6401
	initialize: function (latlng, options) {
6402
		L.setOptions(this, options);
6403
		this._latlng = L.latLng(latlng);
6404
	},
6405
6406
	onAdd: function (map) {
6407
		this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
6408
6409
		if (this._zoomAnimated) {
6410
			map.on('zoomanim', this._animateZoom, this);
6411
		}
6412
6413
		this._initIcon();
6414
		this.update();
6415
	},
6416
6417
	onRemove: function (map) {
6418
		if (this.dragging && this.dragging.enabled()) {
6419
			this.options.draggable = true;
6420
			this.dragging.removeHooks();
6421
		}
6422
6423
		if (this._zoomAnimated) {
6424
			map.off('zoomanim', this._animateZoom, this);
6425
		}
6426
6427
		this._removeIcon();
6428
		this._removeShadow();
6429
	},
6430
6431
	getEvents: function () {
6432
		return {
6433
			zoom: this.update,
6434
			viewreset: this.update
6435
		};
6436
	},
6437
6438
	// @method getLatLng: LatLng
6439
	// Returns the current geographical position of the marker.
6440
	getLatLng: function () {
6441
		return this._latlng;
6442
	},
6443
6444
	// @method setLatLng(latlng: LatLng): this
6445
	// Changes the marker position to the given point.
6446
	setLatLng: function (latlng) {
6447
		var oldLatLng = this._latlng;
6448
		this._latlng = L.latLng(latlng);
6449
		this.update();
6450
6451
		// @event move: Event
6452
		// 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`.
6453
		return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
6454
	},
6455
6456
	// @method setZIndexOffset(offset: Number): this
6457
	// Changes the [zIndex offset](#marker-zindexoffset) of the marker.
6458
	setZIndexOffset: function (offset) {
6459
		this.options.zIndexOffset = offset;
6460
		return this.update();
6461
	},
6462
6463
	// @method setIcon(icon: Icon): this
6464
	// Changes the marker icon.
6465
	setIcon: function (icon) {
6466
6467
		this.options.icon = icon;
6468
6469
		if (this._map) {
6470
			this._initIcon();
6471
			this.update();
6472
		}
6473
6474
		if (this._popup) {
6475
			this.bindPopup(this._popup, this._popup.options);
6476
		}
6477
6478
		return this;
6479
	},
6480
6481
	getElement: function () {
6482
		return this._icon;
6483
	},
6484
6485
	update: function () {
6486
6487
		if (this._icon) {
6488
			var pos = this._map.latLngToLayerPoint(this._latlng).round();
6489
			this._setPos(pos);
6490
		}
6491
6492
		return this;
6493
	},
6494
6495
	_initIcon: function () {
6496
		var options = this.options,
6497
		    classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
6498
6499
		var icon = options.icon.createIcon(this._icon),
6500
		    addIcon = false;
6501
6502
		// if we're not reusing the icon, remove the old one and init new one
6503
		if (icon !== this._icon) {
6504
			if (this._icon) {
6505
				this._removeIcon();
6506
			}
6507
			addIcon = true;
6508
6509
			if (options.title) {
6510
				icon.title = options.title;
6511
			}
6512
			if (options.alt) {
6513
				icon.alt = options.alt;
6514
			}
6515
		}
6516
6517
		L.DomUtil.addClass(icon, classToAdd);
6518
6519
		if (options.keyboard) {
6520
			icon.tabIndex = '0';
6521
		}
6522
6523
		this._icon = icon;
6524
6525
		if (options.riseOnHover) {
6526
			this.on({
6527
				mouseover: this._bringToFront,
6528
				mouseout: this._resetZIndex
6529
			});
6530
		}
6531
6532
		var newShadow = options.icon.createShadow(this._shadow),
6533
		    addShadow = false;
6534
6535
		if (newShadow !== this._shadow) {
6536
			this._removeShadow();
6537
			addShadow = true;
6538
		}
6539
6540
		if (newShadow) {
6541
			L.DomUtil.addClass(newShadow, classToAdd);
6542
			newShadow.alt = '';
6543
		}
6544
		this._shadow = newShadow;
6545
6546
6547
		if (options.opacity < 1) {
6548
			this._updateOpacity();
6549
		}
6550
6551
6552
		if (addIcon) {
6553
			this.getPane().appendChild(this._icon);
6554
		}
6555
		this._initInteraction();
6556
		if (newShadow && addShadow) {
6557
			this.getPane('shadowPane').appendChild(this._shadow);
6558
		}
6559
	},
6560
6561
	_removeIcon: function () {
6562
		if (this.options.riseOnHover) {
6563
			this.off({
6564
				mouseover: this._bringToFront,
6565
				mouseout: this._resetZIndex
6566
			});
6567
		}
6568
6569
		L.DomUtil.remove(this._icon);
6570
		this.removeInteractiveTarget(this._icon);
6571
6572
		this._icon = null;
6573
	},
6574
6575
	_removeShadow: function () {
6576
		if (this._shadow) {
6577
			L.DomUtil.remove(this._shadow);
6578
		}
6579
		this._shadow = null;
6580
	},
6581
6582
	_setPos: function (pos) {
6583
		L.DomUtil.setPosition(this._icon, pos);
6584
6585
		if (this._shadow) {
6586
			L.DomUtil.setPosition(this._shadow, pos);
6587
		}
6588
6589
		this._zIndex = pos.y + this.options.zIndexOffset;
6590
6591
		this._resetZIndex();
6592
	},
6593
6594
	_updateZIndex: function (offset) {
6595
		this._icon.style.zIndex = this._zIndex + offset;
6596
	},
6597
6598
	_animateZoom: function (opt) {
6599
		var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
6600
6601
		this._setPos(pos);
6602
	},
6603
6604
	_initInteraction: function () {
6605
6606
		if (!this.options.interactive) { return; }
6607
6608
		L.DomUtil.addClass(this._icon, 'leaflet-interactive');
6609
6610
		this.addInteractiveTarget(this._icon);
6611
6612
		if (L.Handler.MarkerDrag) {
6613
			var draggable = this.options.draggable;
6614
			if (this.dragging) {
6615
				draggable = this.dragging.enabled();
6616
				this.dragging.disable();
6617
			}
6618
6619
			this.dragging = new L.Handler.MarkerDrag(this);
6620
6621
			if (draggable) {
6622
				this.dragging.enable();
6623
			}
6624
		}
6625
	},
6626
6627
	// @method setOpacity(opacity: Number): this
6628
	// Changes the opacity of the marker.
6629
	setOpacity: function (opacity) {
6630
		this.options.opacity = opacity;
6631
		if (this._map) {
6632
			this._updateOpacity();
6633
		}
6634
6635
		return this;
6636
	},
6637
6638
	_updateOpacity: function () {
6639
		var opacity = this.options.opacity;
6640
6641
		L.DomUtil.setOpacity(this._icon, opacity);
6642
6643
		if (this._shadow) {
6644
			L.DomUtil.setOpacity(this._shadow, opacity);
6645
		}
6646
	},
6647
6648
	_bringToFront: function () {
6649
		this._updateZIndex(this.options.riseOffset);
6650
	},
6651
6652
	_resetZIndex: function () {
6653
		this._updateZIndex(0);
6654
	},
6655
6656
	_getPopupAnchor: function () {
6657
		return this.options.icon.options.popupAnchor || [0, 0];
6658
	},
6659
6660
	_getTooltipAnchor: function () {
6661
		return this.options.icon.options.tooltipAnchor || [0, 0];
6662
	}
6663
});
6664
6665
6666
// factory L.marker(latlng: LatLng, options? : Marker options)
6667
6668
// @factory L.marker(latlng: LatLng, options? : Marker options)
6669
// Instantiates a Marker object given a geographical point and optionally an options object.
6670
L.marker = function (latlng, options) {
6671
	return new L.Marker(latlng, options);
6672
};
6673
6674
6675
6676
/*
6677
 * @class DivIcon
6678
 * @aka L.DivIcon
6679
 * @inherits Icon
6680
 *
6681
 * Represents a lightweight icon for markers that uses a simple `<div>`
6682
 * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
6683
 *
6684
 * @example
6685
 * ```js
6686
 * var myIcon = L.divIcon({className: 'my-div-icon'});
6687
 * // you can set .my-div-icon styles in CSS
6688
 *
6689
 * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
6690
 * ```
6691
 *
6692
 * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
6693
 */
6694
6695
L.DivIcon = L.Icon.extend({
6696
	options: {
6697
		// @section
6698
		// @aka DivIcon options
6699
		iconSize: [12, 12], // also can be set through CSS
6700
6701
		// iconAnchor: (Point),
6702
		// popupAnchor: (Point),
6703
6704
		// @option html: String = ''
6705
		// Custom HTML code to put inside the div element, empty by default.
6706
		html: false,
6707
6708
		// @option bgPos: Point = [0, 0]
6709
		// Optional relative position of the background, in pixels
6710
		bgPos: null,
6711
6712
		className: 'leaflet-div-icon'
6713
	},
6714
6715
	createIcon: function (oldIcon) {
6716
		var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
6717
		    options = this.options;
6718
6719
		div.innerHTML = options.html !== false ? options.html : '';
6720
6721
		if (options.bgPos) {
6722
			var bgPos = L.point(options.bgPos);
6723
			div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
6724
		}
6725
		this._setIconStyles(div, 'icon');
6726
6727
		return div;
6728
	},
6729
6730
	createShadow: function () {
6731
		return null;
6732
	}
6733
});
6734
6735
// @factory L.divIcon(options: DivIcon options)
6736
// Creates a `DivIcon` instance with the given options.
6737
L.divIcon = function (options) {
6738
	return new L.DivIcon(options);
6739
};
6740
6741
6742
6743
/*
6744
 * @class DivOverlay
6745
 * @inherits Layer
6746
 * @aka L.DivOverlay
6747
 * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
6748
 */
6749
6750
// @namespace DivOverlay
6751
L.DivOverlay = L.Layer.extend({
6752
6753
	// @section
6754
	// @aka DivOverlay options
6755
	options: {
6756
		// @option offset: Point = Point(0, 7)
6757
		// The offset of the popup position. Useful to control the anchor
6758
		// of the popup when opening it on some overlays.
6759
		offset: [0, 7],
6760
6761
		// @option className: String = ''
6762
		// A custom CSS class name to assign to the popup.
6763
		className: '',
6764
6765
		// @option pane: String = 'popupPane'
6766
		// `Map pane` where the popup will be added.
6767
		pane: 'popupPane'
6768
	},
6769
6770
	initialize: function (options, source) {
6771
		L.setOptions(this, options);
6772
6773
		this._source = source;
6774
	},
6775
6776
	onAdd: function (map) {
6777
		this._zoomAnimated = map._zoomAnimated;
6778
6779
		if (!this._container) {
6780
			this._initLayout();
6781
		}
6782
6783
		if (map._fadeAnimated) {
6784
			L.DomUtil.setOpacity(this._container, 0);
6785
		}
6786
6787
		clearTimeout(this._removeTimeout);
6788
		this.getPane().appendChild(this._container);
6789
		this.update();
6790
6791
		if (map._fadeAnimated) {
6792
			L.DomUtil.setOpacity(this._container, 1);
6793
		}
6794
6795
		this.bringToFront();
6796
	},
6797
6798
	onRemove: function (map) {
6799
		if (map._fadeAnimated) {
6800
			L.DomUtil.setOpacity(this._container, 0);
6801
			this._removeTimeout = setTimeout(L.bind(L.DomUtil.remove, L.DomUtil, this._container), 200);
6802
		} else {
6803
			L.DomUtil.remove(this._container);
6804
		}
6805
	},
6806
6807
	// @namespace Popup
6808
	// @method getLatLng: LatLng
6809
	// Returns the geographical point of popup.
6810
	getLatLng: function () {
6811
		return this._latlng;
6812
	},
6813
6814
	// @method setLatLng(latlng: LatLng): this
6815
	// Sets the geographical point where the popup will open.
6816
	setLatLng: function (latlng) {
6817
		this._latlng = L.latLng(latlng);
6818
		if (this._map) {
6819
			this._updatePosition();
6820
			this._adjustPan();
6821
		}
6822
		return this;
6823
	},
6824
6825
	// @method getContent: String|HTMLElement
6826
	// Returns the content of the popup.
6827
	getContent: function () {
6828
		return this._content;
6829
	},
6830
6831
	// @method setContent(htmlContent: String|HTMLElement|Function): this
6832
	// Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
6833
	setContent: function (content) {
6834
		this._content = content;
6835
		this.update();
6836
		return this;
6837
	},
6838
6839
	// @method getElement: String|HTMLElement
6840
	// Alias for [getContent()](#popup-getcontent)
6841
	getElement: function () {
6842
		return this._container;
6843
	},
6844
6845
	// @method update: null
6846
	// Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
6847
	update: function () {
6848
		if (!this._map) { return; }
6849
6850
		this._container.style.visibility = 'hidden';
6851
6852
		this._updateContent();
6853
		this._updateLayout();
6854
		this._updatePosition();
6855
6856
		this._container.style.visibility = '';
6857
6858
		this._adjustPan();
6859
	},
6860
6861
	getEvents: function () {
6862
		var events = {
6863
			zoom: this._updatePosition,
6864
			viewreset: this._updatePosition
6865
		};
6866
6867
		if (this._zoomAnimated) {
6868
			events.zoomanim = this._animateZoom;
6869
		}
6870
		return events;
6871
	},
6872
6873
	// @method isOpen: Boolean
6874
	// Returns `true` when the popup is visible on the map.
6875
	isOpen: function () {
6876
		return !!this._map && this._map.hasLayer(this);
6877
	},
6878
6879
	// @method bringToFront: this
6880
	// Brings this popup in front of other popups (in the same map pane).
6881
	bringToFront: function () {
6882
		if (this._map) {
6883
			L.DomUtil.toFront(this._container);
6884
		}
6885
		return this;
6886
	},
6887
6888
	// @method bringToBack: this
6889
	// Brings this popup to the back of other popups (in the same map pane).
6890
	bringToBack: function () {
6891
		if (this._map) {
6892
			L.DomUtil.toBack(this._container);
6893
		}
6894
		return this;
6895
	},
6896
6897
	_updateContent: function () {
6898
		if (!this._content) { return; }
6899
6900
		var node = this._contentNode;
6901
		var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
6902
6903
		if (typeof content === 'string') {
6904
			node.innerHTML = content;
6905
		} else {
6906
			while (node.hasChildNodes()) {
6907
				node.removeChild(node.firstChild);
6908
			}
6909
			node.appendChild(content);
6910
		}
6911
		this.fire('contentupdate');
6912
	},
6913
6914
	_updatePosition: function () {
6915
		if (!this._map) { return; }
6916
6917
		var pos = this._map.latLngToLayerPoint(this._latlng),
6918
		    offset = L.point(this.options.offset),
6919
		    anchor = this._getAnchor();
6920
6921
		if (this._zoomAnimated) {
6922
			L.DomUtil.setPosition(this._container, pos.add(anchor));
6923
		} else {
6924
			offset = offset.add(pos).add(anchor);
6925
		}
6926
6927
		var bottom = this._containerBottom = -offset.y,
6928
		    left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
6929
6930
		// bottom position the popup in case the height of the popup changes (images loading etc)
6931
		this._container.style.bottom = bottom + 'px';
6932
		this._container.style.left = left + 'px';
6933
	},
6934
6935
	_getAnchor: function () {
6936
		return [0, 0];
6937
	}
6938
6939
});
6940
6941
6942
6943
/*
6944
 * @class Popup
6945
 * @inherits DivOverlay
6946
 * @aka L.Popup
6947
 * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
6948
 * open popups while making sure that only one popup is open at one time
6949
 * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
6950
 *
6951
 * @example
6952
 *
6953
 * If you want to just bind a popup to marker click and then open it, it's really easy:
6954
 *
6955
 * ```js
6956
 * marker.bindPopup(popupContent).openPopup();
6957
 * ```
6958
 * Path overlays like polylines also have a `bindPopup` method.
6959
 * Here's a more complicated way to open a popup on a map:
6960
 *
6961
 * ```js
6962
 * var popup = L.popup()
6963
 * 	.setLatLng(latlng)
6964
 * 	.setContent('<p>Hello world!<br />This is a nice popup.</p>')
6965
 * 	.openOn(map);
6966
 * ```
6967
 */
6968
6969
6970
// @namespace Popup
6971
L.Popup = L.DivOverlay.extend({
6972
6973
	// @section
6974
	// @aka Popup options
6975
	options: {
6976
		// @option maxWidth: Number = 300
6977
		// Max width of the popup, in pixels.
6978
		maxWidth: 300,
6979
6980
		// @option minWidth: Number = 50
6981
		// Min width of the popup, in pixels.
6982
		minWidth: 50,
6983
6984
		// @option maxHeight: Number = null
6985
		// If set, creates a scrollable container of the given height
6986
		// inside a popup if its content exceeds it.
6987
		maxHeight: null,
6988
6989
		// @option autoPan: Boolean = true
6990
		// Set it to `false` if you don't want the map to do panning animation
6991
		// to fit the opened popup.
6992
		autoPan: true,
6993
6994
		// @option autoPanPaddingTopLeft: Point = null
6995
		// The margin between the popup and the top left corner of the map
6996
		// view after autopanning was performed.
6997
		autoPanPaddingTopLeft: null,
6998
6999
		// @option autoPanPaddingBottomRight: Point = null
7000
		// The margin between the popup and the bottom right corner of the map
7001
		// view after autopanning was performed.
7002
		autoPanPaddingBottomRight: null,
7003
7004
		// @option autoPanPadding: Point = Point(5, 5)
7005
		// Equivalent of setting both top left and bottom right autopan padding to the same value.
7006
		autoPanPadding: [5, 5],
7007
7008
		// @option keepInView: Boolean = false
7009
		// Set it to `true` if you want to prevent users from panning the popup
7010
		// off of the screen while it is open.
7011
		keepInView: false,
7012
7013
		// @option closeButton: Boolean = true
7014
		// Controls the presence of a close button in the popup.
7015
		closeButton: true,
7016
7017
		// @option autoClose: Boolean = true
7018
		// Set it to `false` if you want to override the default behavior of
7019
		// the popup closing when user clicks the map (set globally by
7020
		// the Map's [closePopupOnClick](#map-closepopuponclick) option).
7021
		autoClose: true,
7022
7023
		// @option className: String = ''
7024
		// A custom CSS class name to assign to the popup.
7025
		className: ''
7026
	},
7027
7028
	// @namespace Popup
7029
	// @method openOn(map: Map): this
7030
	// Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
7031
	openOn: function (map) {
7032
		map.openPopup(this);
7033
		return this;
7034
	},
7035
7036
	onAdd: function (map) {
7037
		L.DivOverlay.prototype.onAdd.call(this, map);
7038
7039
		// @namespace Map
7040
		// @section Popup events
7041
		// @event popupopen: PopupEvent
7042
		// Fired when a popup is opened in the map
7043
		map.fire('popupopen', {popup: this});
7044
7045
		if (this._source) {
7046
			// @namespace Layer
7047
			// @section Popup events
7048
			// @event popupopen: PopupEvent
7049
			// Fired when a popup bound to this layer is opened
7050
			this._source.fire('popupopen', {popup: this}, true);
7051
			// For non-path layers, we toggle the popup when clicking
7052
			// again the layer, so prevent the map to reopen it.
7053
			if (!(this._source instanceof L.Path)) {
7054
				this._source.on('preclick', L.DomEvent.stopPropagation);
7055
			}
7056
		}
7057
	},
7058
7059
	onRemove: function (map) {
7060
		L.DivOverlay.prototype.onRemove.call(this, map);
7061
7062
		// @namespace Map
7063
		// @section Popup events
7064
		// @event popupclose: PopupEvent
7065
		// Fired when a popup in the map is closed
7066
		map.fire('popupclose', {popup: this});
7067
7068
		if (this._source) {
7069
			// @namespace Layer
7070
			// @section Popup events
7071
			// @event popupclose: PopupEvent
7072
			// Fired when a popup bound to this layer is closed
7073
			this._source.fire('popupclose', {popup: this}, true);
7074
			if (!(this._source instanceof L.Path)) {
7075
				this._source.off('preclick', L.DomEvent.stopPropagation);
7076
			}
7077
		}
7078
	},
7079
7080
	getEvents: function () {
7081
		var events = L.DivOverlay.prototype.getEvents.call(this);
7082
7083
		if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
7084
			events.preclick = this._close;
7085
		}
7086
7087
		if (this.options.keepInView) {
7088
			events.moveend = this._adjustPan;
7089
		}
7090
7091
		return events;
7092
	},
7093
7094
	_close: function () {
7095
		if (this._map) {
7096
			this._map.closePopup(this);
7097
		}
7098
	},
7099
7100
	_initLayout: function () {
7101
		var prefix = 'leaflet-popup',
7102
		    container = this._container = L.DomUtil.create('div',
7103
			prefix + ' ' + (this.options.className || '') +
7104
			' leaflet-zoom-animated');
7105
7106
		if (this.options.closeButton) {
7107
			var closeButton = this._closeButton = L.DomUtil.create('a', prefix + '-close-button', container);
7108
			closeButton.href = '#close';
7109
			closeButton.innerHTML = '&#215;';
7110
7111
			L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this);
7112
		}
7113
7114
		var wrapper = this._wrapper = L.DomUtil.create('div', prefix + '-content-wrapper', container);
7115
		this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
7116
7117
		L.DomEvent
7118
			.disableClickPropagation(wrapper)
7119
			.disableScrollPropagation(this._contentNode)
7120
			.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
7121
7122
		this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
7123
		this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
7124
	},
7125
7126
	_updateLayout: function () {
7127
		var container = this._contentNode,
7128
		    style = container.style;
7129
7130
		style.width = '';
7131
		style.whiteSpace = 'nowrap';
7132
7133
		var width = container.offsetWidth;
7134
		width = Math.min(width, this.options.maxWidth);
7135
		width = Math.max(width, this.options.minWidth);
7136
7137
		style.width = (width + 1) + 'px';
7138
		style.whiteSpace = '';
7139
7140
		style.height = '';
7141
7142
		var height = container.offsetHeight,
7143
		    maxHeight = this.options.maxHeight,
7144
		    scrolledClass = 'leaflet-popup-scrolled';
7145
7146
		if (maxHeight && height > maxHeight) {
7147
			style.height = maxHeight + 'px';
7148
			L.DomUtil.addClass(container, scrolledClass);
7149
		} else {
7150
			L.DomUtil.removeClass(container, scrolledClass);
7151
		}
7152
7153
		this._containerWidth = this._container.offsetWidth;
7154
	},
7155
7156
	_animateZoom: function (e) {
7157
		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
7158
		    anchor = this._getAnchor();
7159
		L.DomUtil.setPosition(this._container, pos.add(anchor));
7160
	},
7161
7162
	_adjustPan: function () {
7163
		if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
7164
7165
		var map = this._map,
7166
		    marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
7167
		    containerHeight = this._container.offsetHeight + marginBottom,
7168
		    containerWidth = this._containerWidth,
7169
		    layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
7170
7171
		layerPos._add(L.DomUtil.getPosition(this._container));
7172
7173
		var containerPos = map.layerPointToContainerPoint(layerPos),
7174
		    padding = L.point(this.options.autoPanPadding),
7175
		    paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
7176
		    paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
7177
		    size = map.getSize(),
7178
		    dx = 0,
7179
		    dy = 0;
7180
7181
		if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
7182
			dx = containerPos.x + containerWidth - size.x + paddingBR.x;
7183
		}
7184
		if (containerPos.x - dx - paddingTL.x < 0) { // left
7185
			dx = containerPos.x - paddingTL.x;
7186
		}
7187
		if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
7188
			dy = containerPos.y + containerHeight - size.y + paddingBR.y;
7189
		}
7190
		if (containerPos.y - dy - paddingTL.y < 0) { // top
7191
			dy = containerPos.y - paddingTL.y;
7192
		}
7193
7194
		// @namespace Map
7195
		// @section Popup events
7196
		// @event autopanstart: Event
7197
		// Fired when the map starts autopanning when opening a popup.
7198
		if (dx || dy) {
7199
			map
7200
			    .fire('autopanstart')
7201
			    .panBy([dx, dy]);
7202
		}
7203
	},
7204
7205
	_onCloseButtonClick: function (e) {
7206
		this._close();
7207
		L.DomEvent.stop(e);
7208
	},
7209
7210
	_getAnchor: function () {
7211
		// Where should we anchor the popup on the source layer?
7212
		return L.point(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
7213
	}
7214
7215
});
7216
7217
// @namespace Popup
7218
// @factory L.popup(options?: Popup options, source?: Layer)
7219
// 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.
7220
L.popup = function (options, source) {
7221
	return new L.Popup(options, source);
7222
};
7223
7224
7225
/* @namespace Map
7226
 * @section Interaction Options
7227
 * @option closePopupOnClick: Boolean = true
7228
 * Set it to `false` if you don't want popups to close when user clicks the map.
7229
 */
7230
L.Map.mergeOptions({
7231
	closePopupOnClick: true
7232
});
7233
7234
7235
// @namespace Map
7236
// @section Methods for Layers and Controls
7237
L.Map.include({
7238
	// @method openPopup(popup: Popup): this
7239
	// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
7240
	// @alternative
7241
	// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
7242
	// Creates a popup with the specified content and options and opens it in the given point on a map.
7243
	openPopup: function (popup, latlng, options) {
7244
		if (!(popup instanceof L.Popup)) {
7245
			popup = new L.Popup(options).setContent(popup);
7246
		}
7247
7248
		if (latlng) {
7249
			popup.setLatLng(latlng);
7250
		}
7251
7252
		if (this.hasLayer(popup)) {
7253
			return this;
7254
		}
7255
7256
		if (this._popup && this._popup.options.autoClose) {
7257
			this.closePopup();
7258
		}
7259
7260
		this._popup = popup;
7261
		return this.addLayer(popup);
7262
	},
7263
7264
	// @method closePopup(popup?: Popup): this
7265
	// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
7266
	closePopup: function (popup) {
7267
		if (!popup || popup === this._popup) {
7268
			popup = this._popup;
7269
			this._popup = null;
7270
		}
7271
		if (popup) {
7272
			this.removeLayer(popup);
7273
		}
7274
		return this;
7275
	}
7276
});
7277
7278
/*
7279
 * @namespace Layer
7280
 * @section Popup methods example
7281
 *
7282
 * All layers share a set of methods convenient for binding popups to it.
7283
 *
7284
 * ```js
7285
 * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
7286
 * layer.openPopup();
7287
 * layer.closePopup();
7288
 * ```
7289
 *
7290
 * 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.
7291
 */
7292
7293
// @section Popup methods
7294
L.Layer.include({
7295
7296
	// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
7297
	// Binds a popup to the layer with the passed `content` and sets up the
7298
	// neccessary event listeners. If a `Function` is passed it will receive
7299
	// the layer as the first argument and should return a `String` or `HTMLElement`.
7300
	bindPopup: function (content, options) {
7301
7302
		if (content instanceof L.Popup) {
7303
			L.setOptions(content, options);
7304
			this._popup = content;
7305
			content._source = this;
7306
		} else {
7307
			if (!this._popup || options) {
7308
				this._popup = new L.Popup(options, this);
7309
			}
7310
			this._popup.setContent(content);
7311
		}
7312
7313
		if (!this._popupHandlersAdded) {
7314
			this.on({
7315
				click: this._openPopup,
7316
				remove: this.closePopup,
7317
				move: this._movePopup
7318
			});
7319
			this._popupHandlersAdded = true;
7320
		}
7321
7322
		return this;
7323
	},
7324
7325
	// @method unbindPopup(): this
7326
	// Removes the popup previously bound with `bindPopup`.
7327
	unbindPopup: function () {
7328
		if (this._popup) {
7329
			this.off({
7330
				click: this._openPopup,
7331
				remove: this.closePopup,
7332
				move: this._movePopup
7333
			});
7334
			this._popupHandlersAdded = false;
7335
			this._popup = null;
7336
		}
7337
		return this;
7338
	},
7339
7340
	// @method openPopup(latlng?: LatLng): this
7341
	// Opens the bound popup at the specificed `latlng` or at the default popup anchor if no `latlng` is passed.
7342
	openPopup: function (layer, latlng) {
7343
		if (!(layer instanceof L.Layer)) {
7344
			latlng = layer;
7345
			layer = this;
7346
		}
7347
7348
		if (layer instanceof L.FeatureGroup) {
7349
			for (var id in this._layers) {
7350
				layer = this._layers[id];
7351
				break;
7352
			}
7353
		}
7354
7355
		if (!latlng) {
7356
			latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
7357
		}
7358
7359
		if (this._popup && this._map) {
7360
			// set popup source to this layer
7361
			this._popup._source = layer;
7362
7363
			// update the popup (content, layout, ect...)
7364
			this._popup.update();
7365
7366
			// open the popup on the map
7367
			this._map.openPopup(this._popup, latlng);
7368
		}
7369
7370
		return this;
7371
	},
7372
7373
	// @method closePopup(): this
7374
	// Closes the popup bound to this layer if it is open.
7375
	closePopup: function () {
7376
		if (this._popup) {
7377
			this._popup._close();
7378
		}
7379
		return this;
7380
	},
7381
7382
	// @method togglePopup(): this
7383
	// Opens or closes the popup bound to this layer depending on its current state.
7384
	togglePopup: function (target) {
7385
		if (this._popup) {
7386
			if (this._popup._map) {
7387
				this.closePopup();
7388
			} else {
7389
				this.openPopup(target);
7390
			}
7391
		}
7392
		return this;
7393
	},
7394
7395
	// @method isPopupOpen(): boolean
7396
	// Returns `true` if the popup bound to this layer is currently open.
7397
	isPopupOpen: function () {
7398
		return (this._popup ? this._popup.isOpen() : false);
7399
	},
7400
7401
	// @method setPopupContent(content: String|HTMLElement|Popup): this
7402
	// Sets the content of the popup bound to this layer.
7403
	setPopupContent: function (content) {
7404
		if (this._popup) {
7405
			this._popup.setContent(content);
7406
		}
7407
		return this;
7408
	},
7409
7410
	// @method getPopup(): Popup
7411
	// Returns the popup bound to this layer.
7412
	getPopup: function () {
7413
		return this._popup;
7414
	},
7415
7416
	_openPopup: function (e) {
7417
		var layer = e.layer || e.target;
7418
7419
		if (!this._popup) {
7420
			return;
7421
		}
7422
7423
		if (!this._map) {
7424
			return;
7425
		}
7426
7427
		// prevent map click
7428
		L.DomEvent.stop(e);
7429
7430
		// if this inherits from Path its a vector and we can just
7431
		// open the popup at the new location
7432
		if (layer instanceof L.Path) {
7433
			this.openPopup(e.layer || e.target, e.latlng);
7434
			return;
7435
		}
7436
7437
		// otherwise treat it like a marker and figure out
7438
		// if we should toggle it open/closed
7439
		if (this._map.hasLayer(this._popup) && this._popup._source === layer) {
7440
			this.closePopup();
7441
		} else {
7442
			this.openPopup(layer, e.latlng);
7443
		}
7444
	},
7445
7446
	_movePopup: function (e) {
7447
		this._popup.setLatLng(e.latlng);
7448
	}
7449
});
7450
7451
7452
7453
/*
7454
 * @class Tooltip
7455
 * @inherits DivOverlay
7456
 * @aka L.Tooltip
7457
 * Used to display small texts on top of map layers.
7458
 *
7459
 * @example
7460
 *
7461
 * ```js
7462
 * marker.bindTooltip("my tooltip text").openTooltip();
7463
 * ```
7464
 * Note about tooltip offset. Leaflet takes two options in consideration
7465
 * for computing tooltip offseting:
7466
 * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
7467
 *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
7468
 *   move it to the bottom. Negatives will move to the left and top.
7469
 * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
7470
 *   should adapt this value if you use a custom icon.
7471
 */
7472
7473
7474
// @namespace Tooltip
7475
L.Tooltip = L.DivOverlay.extend({
7476
7477
	// @section
7478
	// @aka Tooltip options
7479
	options: {
7480
		// @option pane: String = 'tooltipPane'
7481
		// `Map pane` where the tooltip will be added.
7482
		pane: 'tooltipPane',
7483
7484
		// @option offset: Point = Point(0, 0)
7485
		// Optional offset of the tooltip position.
7486
		offset: [0, 0],
7487
7488
		// @option direction: String = 'auto'
7489
		// Direction where to open the tooltip. Possible values are: `right`, `left`,
7490
		// `top`, `bottom`, `center`, `auto`.
7491
		// `auto` will dynamicaly switch between `right` and `left` according to the tooltip
7492
		// position on the map.
7493
		direction: 'auto',
7494
7495
		// @option permanent: Boolean = false
7496
		// Whether to open the tooltip permanently or only on mouseover.
7497
		permanent: false,
7498
7499
		// @option sticky: Boolean = false
7500
		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
7501
		sticky: false,
7502
7503
		// @option interactive: Boolean = false
7504
		// If true, the tooltip will listen to the feature events.
7505
		interactive: false,
7506
7507
		// @option opacity: Number = 0.9
7508
		// Tooltip container opacity.
7509
		opacity: 0.9
7510
	},
7511
7512
	onAdd: function (map) {
7513
		L.DivOverlay.prototype.onAdd.call(this, map);
7514
		this.setOpacity(this.options.opacity);
7515
7516
		// @namespace Map
7517
		// @section Tooltip events
7518
		// @event tooltipopen: TooltipEvent
7519
		// Fired when a tooltip is opened in the map.
7520
		map.fire('tooltipopen', {tooltip: this});
7521
7522
		if (this._source) {
7523
			// @namespace Layer
7524
			// @section Tooltip events
7525
			// @event tooltipopen: TooltipEvent
7526
			// Fired when a tooltip bound to this layer is opened.
7527
			this._source.fire('tooltipopen', {tooltip: this}, true);
7528
		}
7529
	},
7530
7531
	onRemove: function (map) {
7532
		L.DivOverlay.prototype.onRemove.call(this, map);
7533
7534
		// @namespace Map
7535
		// @section Tooltip events
7536
		// @event tooltipclose: TooltipEvent
7537
		// Fired when a tooltip in the map is closed.
7538
		map.fire('tooltipclose', {tooltip: this});
7539
7540
		if (this._source) {
7541
			// @namespace Layer
7542
			// @section Tooltip events
7543
			// @event tooltipclose: TooltipEvent
7544
			// Fired when a tooltip bound to this layer is closed.
7545
			this._source.fire('tooltipclose', {tooltip: this}, true);
7546
		}
7547
	},
7548
7549
	getEvents: function () {
7550
		var events = L.DivOverlay.prototype.getEvents.call(this);
7551
7552
		if (L.Browser.touch && !this.options.permanent) {
7553
			events.preclick = this._close;
7554
		}
7555
7556
		return events;
7557
	},
7558
7559
	_close: function () {
7560
		if (this._map) {
7561
			this._map.closeTooltip(this);
7562
		}
7563
	},
7564
7565
	_initLayout: function () {
7566
		var prefix = 'leaflet-tooltip',
7567
		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
7568
7569
		this._contentNode = this._container = L.DomUtil.create('div', className);
7570
	},
7571
7572
	_updateLayout: function () {},
7573
7574
	_adjustPan: function () {},
7575
7576
	_setPosition: function (pos) {
7577
		var map = this._map,
7578
		    container = this._container,
7579
		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
7580
		    tooltipPoint = map.layerPointToContainerPoint(pos),
7581
		    direction = this.options.direction,
7582
		    tooltipWidth = container.offsetWidth,
7583
		    tooltipHeight = container.offsetHeight,
7584
		    offset = L.point(this.options.offset),
7585
		    anchor = this._getAnchor();
7586
7587
		if (direction === 'top') {
7588
			pos = pos.add(L.point(-tooltipWidth / 2 + offset.x, -tooltipHeight + offset.y + anchor.y, true));
7589
		} else if (direction === 'bottom') {
7590
			pos = pos.subtract(L.point(tooltipWidth / 2 - offset.x, -offset.y, true));
7591
		} else if (direction === 'center') {
7592
			pos = pos.subtract(L.point(tooltipWidth / 2 + offset.x, tooltipHeight / 2 - anchor.y + offset.y, true));
7593
		} else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {
7594
			direction = 'right';
7595
			pos = pos.add(L.point(offset.x + anchor.x, anchor.y - tooltipHeight / 2 + offset.y, true));
7596
		} else {
7597
			direction = 'left';
7598
			pos = pos.subtract(L.point(tooltipWidth + anchor.x - offset.x, tooltipHeight / 2 - anchor.y - offset.y, true));
7599
		}
7600
7601
		L.DomUtil.removeClass(container, 'leaflet-tooltip-right');
7602
		L.DomUtil.removeClass(container, 'leaflet-tooltip-left');
7603
		L.DomUtil.removeClass(container, 'leaflet-tooltip-top');
7604
		L.DomUtil.removeClass(container, 'leaflet-tooltip-bottom');
7605
		L.DomUtil.addClass(container, 'leaflet-tooltip-' + direction);
7606
		L.DomUtil.setPosition(container, pos);
7607
	},
7608
7609
	_updatePosition: function () {
7610
		var pos = this._map.latLngToLayerPoint(this._latlng);
7611
		this._setPosition(pos);
7612
	},
7613
7614
	setOpacity: function (opacity) {
7615
		this.options.opacity = opacity;
7616
7617
		if (this._container) {
7618
			L.DomUtil.setOpacity(this._container, opacity);
7619
		}
7620
	},
7621
7622
	_animateZoom: function (e) {
7623
		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
7624
		this._setPosition(pos);
7625
	},
7626
7627
	_getAnchor: function () {
7628
		// Where should we anchor the tooltip on the source layer?
7629
		return L.point(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
7630
	}
7631
7632
});
7633
7634
// @namespace Tooltip
7635
// @factory L.tooltip(options?: Tooltip options, source?: Layer)
7636
// 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.
7637
L.tooltip = function (options, source) {
7638
	return new L.Tooltip(options, source);
7639
};
7640
7641
// @namespace Map
7642
// @section Methods for Layers and Controls
7643
L.Map.include({
7644
7645
	// @method openTooltip(tooltip: Tooltip): this
7646
	// Opens the specified tooltip.
7647
	// @alternative
7648
	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
7649
	// Creates a tooltip with the specified content and options and open it.
7650
	openTooltip: function (tooltip, latlng, options) {
7651
		if (!(tooltip instanceof L.Tooltip)) {
7652
			tooltip = new L.Tooltip(options).setContent(tooltip);
7653
		}
7654
7655
		if (latlng) {
7656
			tooltip.setLatLng(latlng);
7657
		}
7658
7659
		if (this.hasLayer(tooltip)) {
7660
			return this;
7661
		}
7662
7663
		return this.addLayer(tooltip);
7664
	},
7665
7666
	// @method closeTooltip(tooltip?: Tooltip): this
7667
	// Closes the tooltip given as parameter.
7668
	closeTooltip: function (tooltip) {
7669
		if (tooltip) {
7670
			this.removeLayer(tooltip);
7671
		}
7672
		return this;
7673
	}
7674
7675
});
7676
7677
/*
7678
 * @namespace Layer
7679
 * @section Tooltip methods example
7680
 *
7681
 * All layers share a set of methods convenient for binding tooltips to it.
7682
 *
7683
 * ```js
7684
 * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
7685
 * layer.openTooltip();
7686
 * layer.closeTooltip();
7687
 * ```
7688
 */
7689
7690
// @section Tooltip methods
7691
L.Layer.include({
7692
7693
	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
7694
	// Binds a tooltip to the layer with the passed `content` and sets up the
7695
	// neccessary event listeners. If a `Function` is passed it will receive
7696
	// the layer as the first argument and should return a `String` or `HTMLElement`.
7697
	bindTooltip: function (content, options) {
7698
7699
		if (content instanceof L.Tooltip) {
7700
			L.setOptions(content, options);
7701
			this._tooltip = content;
7702
			content._source = this;
7703
		} else {
7704
			if (!this._tooltip || options) {
7705
				this._tooltip = L.tooltip(options, this);
7706
			}
7707
			this._tooltip.setContent(content);
7708
7709
		}
7710
7711
		this._initTooltipInteractions();
7712
7713
		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
7714
			this.openTooltip();
7715
		}
7716
7717
		return this;
7718
	},
7719
7720
	// @method unbindTooltip(): this
7721
	// Removes the tooltip previously bound with `bindTooltip`.
7722
	unbindTooltip: function () {
7723
		if (this._tooltip) {
7724
			this._initTooltipInteractions(true);
7725
			this.closeTooltip();
7726
			this._tooltip = null;
7727
		}
7728
		return this;
7729
	},
7730
7731
	_initTooltipInteractions: function (remove) {
7732
		if (!remove && this._tooltipHandlersAdded) { return; }
7733
		var onOff = remove ? 'off' : 'on',
7734
		    events = {
7735
			remove: this.closeTooltip,
7736
			move: this._moveTooltip
7737
		    };
7738
		if (!this._tooltip.options.permanent) {
7739
			events.mouseover = this._openTooltip;
7740
			events.mouseout = this.closeTooltip;
7741
			if (this._tooltip.options.sticky) {
7742
				events.mousemove = this._moveTooltip;
7743
			}
7744
			if (L.Browser.touch) {
7745
				events.click = this._openTooltip;
7746
			}
7747
		} else {
7748
			events.add = this._openTooltip;
7749
		}
7750
		this[onOff](events);
7751
		this._tooltipHandlersAdded = !remove;
7752
	},
7753
7754
	// @method openTooltip(latlng?: LatLng): this
7755
	// Opens the bound tooltip at the specificed `latlng` or at the default tooltip anchor if no `latlng` is passed.
7756
	openTooltip: function (layer, latlng) {
7757
		if (!(layer instanceof L.Layer)) {
7758
			latlng = layer;
7759
			layer = this;
7760
		}
7761
7762
		if (layer instanceof L.FeatureGroup) {
7763
			for (var id in this._layers) {
7764
				layer = this._layers[id];
7765
				break;
7766
			}
7767
		}
7768
7769
		if (!latlng) {
7770
			latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
7771
		}
7772
7773
		if (this._tooltip && this._map) {
7774
7775
			// set tooltip source to this layer
7776
			this._tooltip._source = layer;
7777
7778
			// update the tooltip (content, layout, ect...)
7779
			this._tooltip.update();
7780
7781
			// open the tooltip on the map
7782
			this._map.openTooltip(this._tooltip, latlng);
7783
7784
			// Tooltip container may not be defined if not permanent and never
7785
			// opened.
7786
			if (this._tooltip.options.interactive && this._tooltip._container) {
7787
				L.DomUtil.addClass(this._tooltip._container, 'leaflet-clickable');
7788
				this.addInteractiveTarget(this._tooltip._container);
7789
			}
7790
		}
7791
7792
		return this;
7793
	},
7794
7795
	// @method closeTooltip(): this
7796
	// Closes the tooltip bound to this layer if it is open.
7797
	closeTooltip: function () {
7798
		if (this._tooltip) {
7799
			this._tooltip._close();
7800
			if (this._tooltip.options.interactive && this._tooltip._container) {
7801
				L.DomUtil.removeClass(this._tooltip._container, 'leaflet-clickable');
7802
				this.removeInteractiveTarget(this._tooltip._container);
7803
			}
7804
		}
7805
		return this;
7806
	},
7807
7808
	// @method toggleTooltip(): this
7809
	// Opens or closes the tooltip bound to this layer depending on its current state.
7810
	toggleTooltip: function (target) {
7811
		if (this._tooltip) {
7812
			if (this._tooltip._map) {
7813
				this.closeTooltip();
7814
			} else {
7815
				this.openTooltip(target);
7816
			}
7817
		}
7818
		return this;
7819
	},
7820
7821
	// @method isTooltipOpen(): boolean
7822
	// Returns `true` if the tooltip bound to this layer is currently open.
7823
	isTooltipOpen: function () {
7824
		return this._tooltip.isOpen();
7825
	},
7826
7827
	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
7828
	// Sets the content of the tooltip bound to this layer.
7829
	setTooltipContent: function (content) {
7830
		if (this._tooltip) {
7831
			this._tooltip.setContent(content);
7832
		}
7833
		return this;
7834
	},
7835
7836
	// @method getTooltip(): Tooltip
7837
	// Returns the tooltip bound to this layer.
7838
	getTooltip: function () {
7839
		return this._tooltip;
7840
	},
7841
7842
	_openTooltip: function (e) {
7843
		var layer = e.layer || e.target;
7844
7845
		if (!this._tooltip || !this._map) {
7846
			return;
7847
		}
7848
		this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
7849
	},
7850
7851
	_moveTooltip: function (e) {
7852
		var latlng = e.latlng, containerPoint, layerPoint;
7853
		if (this._tooltip.options.sticky && e.originalEvent) {
7854
			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
7855
			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
7856
			latlng = this._map.layerPointToLatLng(layerPoint);
7857
		}
7858
		this._tooltip.setLatLng(latlng);
7859
	}
7860
});
7861
7862
7863
7864
/*
7865
 * @class LayerGroup
7866
 * @aka L.LayerGroup
7867
 * @inherits Layer
7868
 *
7869
 * Used to group several layers and handle them as one. If you add it to the map,
7870
 * any layers added or removed from the group will be added/removed on the map as
7871
 * well. Extends `Layer`.
7872
 *
7873
 * @example
7874
 *
7875
 * ```js
7876
 * L.layerGroup([marker1, marker2])
7877
 * 	.addLayer(polyline)
7878
 * 	.addTo(map);
7879
 * ```
7880
 */
7881
7882
L.LayerGroup = L.Layer.extend({
7883
7884
	initialize: function (layers) {
7885
		this._layers = {};
7886
7887
		var i, len;
7888
7889
		if (layers) {
7890
			for (i = 0, len = layers.length; i < len; i++) {
7891
				this.addLayer(layers[i]);
7892
			}
7893
		}
7894
	},
7895
7896
	// @method addLayer(layer: Layer): this
7897
	// Adds the given layer to the group.
7898
	addLayer: function (layer) {
7899
		var id = this.getLayerId(layer);
7900
7901
		this._layers[id] = layer;
7902
7903
		if (this._map) {
7904
			this._map.addLayer(layer);
7905
		}
7906
7907
		return this;
7908
	},
7909
7910
	// @method removeLayer(layer: Layer): this
7911
	// Removes the given layer from the group.
7912
	// @alternative
7913
	// @method removeLayer(id: Number): this
7914
	// Removes the layer with the given internal ID from the group.
7915
	removeLayer: function (layer) {
7916
		var id = layer in this._layers ? layer : this.getLayerId(layer);
7917
7918
		if (this._map && this._layers[id]) {
7919
			this._map.removeLayer(this._layers[id]);
7920
		}
7921
7922
		delete this._layers[id];
7923
7924
		return this;
7925
	},
7926
7927
	// @method hasLayer(layer: Layer): Boolean
7928
	// Returns `true` if the given layer is currently added to the group.
7929
	hasLayer: function (layer) {
7930
		return !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers);
7931
	},
7932
7933
	// @method clearLayers(): this
7934
	// Removes all the layers from the group.
7935
	clearLayers: function () {
7936
		for (var i in this._layers) {
7937
			this.removeLayer(this._layers[i]);
7938
		}
7939
		return this;
7940
	},
7941
7942
	// @method invoke(methodName: String, …): this
7943
	// Calls `methodName` on every layer contained in this group, passing any
7944
	// additional parameters. Has no effect if the layers contained do not
7945
	// implement `methodName`.
7946
	invoke: function (methodName) {
7947
		var args = Array.prototype.slice.call(arguments, 1),
7948
		    i, layer;
7949
7950
		for (i in this._layers) {
7951
			layer = this._layers[i];
7952
7953
			if (layer[methodName]) {
7954
				layer[methodName].apply(layer, args);
7955
			}
7956
		}
7957
7958
		return this;
7959
	},
7960
7961
	onAdd: function (map) {
7962
		for (var i in this._layers) {
7963
			map.addLayer(this._layers[i]);
7964
		}
7965
	},
7966
7967
	onRemove: function (map) {
7968
		for (var i in this._layers) {
7969
			map.removeLayer(this._layers[i]);
7970
		}
7971
	},
7972
7973
	// @method eachLayer(fn: Function, context?: Object): this
7974
	// Iterates over the layers of the group, optionally specifying context of the iterator function.
7975
	// ```js
7976
	// group.eachLayer(function (layer) {
7977
	// 	layer.bindPopup('Hello');
7978
	// });
7979
	// ```
7980
	eachLayer: function (method, context) {
7981
		for (var i in this._layers) {
7982
			method.call(context, this._layers[i]);
7983
		}
7984
		return this;
7985
	},
7986
7987
	// @method getLayer(id: Number): Layer
7988
	// Returns the layer with the given internal ID.
7989
	getLayer: function (id) {
7990
		return this._layers[id];
7991
	},
7992
7993
	// @method getLayers(): Layer[]
7994
	// Returns an array of all the layers added to the group.
7995
	getLayers: function () {
7996
		var layers = [];
7997
7998
		for (var i in this._layers) {
7999
			layers.push(this._layers[i]);
8000
		}
8001
		return layers;
8002
	},
8003
8004
	// @method setZIndex(zIndex: Number): this
8005
	// Calls `setZIndex` on every layer contained in this group, passing the z-index.
8006
	setZIndex: function (zIndex) {
8007
		return this.invoke('setZIndex', zIndex);
8008
	},
8009
8010
	// @method getLayerId(layer: Layer): Number
8011
	// Returns the internal ID for a layer
8012
	getLayerId: function (layer) {
8013
		return L.stamp(layer);
8014
	}
8015
});
8016
8017
8018
// @factory L.layerGroup(layers: Layer[])
8019
// Create a layer group, optionally given an initial set of layers.
8020
L.layerGroup = function (layers) {
8021
	return new L.LayerGroup(layers);
8022
};
8023
8024
8025
8026
/*
8027
 * @class FeatureGroup
8028
 * @aka L.FeatureGroup
8029
 * @inherits LayerGroup
8030
 *
8031
 * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
8032
 *  * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
8033
 *  * Events are propagated to the `FeatureGroup`, so if the group has an event
8034
 * handler, it will handle events from any of the layers. This includes mouse events
8035
 * and custom events.
8036
 *  * Has `layeradd` and `layerremove` events
8037
 *
8038
 * @example
8039
 *
8040
 * ```js
8041
 * L.featureGroup([marker1, marker2, polyline])
8042
 * 	.bindPopup('Hello world!')
8043
 * 	.on('click', function() { alert('Clicked on a member of the group!'); })
8044
 * 	.addTo(map);
8045
 * ```
8046
 */
8047
8048
L.FeatureGroup = L.LayerGroup.extend({
8049
8050
	addLayer: function (layer) {
8051
		if (this.hasLayer(layer)) {
8052
			return this;
8053
		}
8054
8055
		layer.addEventParent(this);
8056
8057
		L.LayerGroup.prototype.addLayer.call(this, layer);
8058
8059
		// @event layeradd: LayerEvent
8060
		// Fired when a layer is added to this `FeatureGroup`
8061
		return this.fire('layeradd', {layer: layer});
8062
	},
8063
8064
	removeLayer: function (layer) {
8065
		if (!this.hasLayer(layer)) {
8066
			return this;
8067
		}
8068
		if (layer in this._layers) {
8069
			layer = this._layers[layer];
8070
		}
8071
8072
		layer.removeEventParent(this);
8073
8074
		L.LayerGroup.prototype.removeLayer.call(this, layer);
8075
8076
		// @event layerremove: LayerEvent
8077
		// Fired when a layer is removed from this `FeatureGroup`
8078
		return this.fire('layerremove', {layer: layer});
8079
	},
8080
8081
	// @method setStyle(style: Path options): this
8082
	// Sets the given path options to each layer of the group that has a `setStyle` method.
8083
	setStyle: function (style) {
8084
		return this.invoke('setStyle', style);
8085
	},
8086
8087
	// @method bringToFront(): this
8088
	// Brings the layer group to the top of all other layers
8089
	bringToFront: function () {
8090
		return this.invoke('bringToFront');
8091
	},
8092
8093
	// @method bringToBack(): this
8094
	// Brings the layer group to the top of all other layers
8095
	bringToBack: function () {
8096
		return this.invoke('bringToBack');
8097
	},
8098
8099
	// @method getBounds(): LatLngBounds
8100
	// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
8101
	getBounds: function () {
8102
		var bounds = new L.LatLngBounds();
8103
8104
		for (var id in this._layers) {
8105
			var layer = this._layers[id];
8106
			bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
8107
		}
8108
		return bounds;
8109
	}
8110
});
8111
8112
// @factory L.featureGroup(layers: Layer[])
8113
// Create a feature group, optionally given an initial set of layers.
8114
L.featureGroup = function (layers) {
8115
	return new L.FeatureGroup(layers);
8116
};
8117
8118
8119
8120
/*
8121
 * @class Renderer
8122
 * @inherits Layer
8123
 * @aka L.Renderer
8124
 *
8125
 * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
8126
 * DOM container of the renderer, its bounds, and its zoom animation.
8127
 *
8128
 * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
8129
 * itself can be added or removed to the map. All paths use a renderer, which can
8130
 * be implicit (the map will decide the type of renderer and use it automatically)
8131
 * or explicit (using the [`renderer`](#path-renderer) option of the path).
8132
 *
8133
 * Do not use this class directly, use `SVG` and `Canvas` instead.
8134
 *
8135
 * @event update: Event
8136
 * Fired when the renderer updates its bounds, center and zoom, for example when
8137
 * its map has moved
8138
 */
8139
8140
L.Renderer = L.Layer.extend({
8141
8142
	// @section
8143
	// @aka Renderer options
8144
	options: {
8145
		// @option padding: Number = 0.1
8146
		// How much to extend the clip area around the map view (relative to its size)
8147
		// e.g. 0.1 would be 10% of map view in each direction
8148
		padding: 0.1
8149
	},
8150
8151
	initialize: function (options) {
8152
		L.setOptions(this, options);
8153
		L.stamp(this);
8154
		this._layers = this._layers || {};
8155
	},
8156
8157
	onAdd: function () {
8158
		if (!this._container) {
8159
			this._initContainer(); // defined by renderer implementations
8160
8161
			if (this._zoomAnimated) {
8162
				L.DomUtil.addClass(this._container, 'leaflet-zoom-animated');
8163
			}
8164
		}
8165
8166
		this.getPane().appendChild(this._container);
8167
		this._update();
8168
		this.on('update', this._updatePaths, this);
8169
	},
8170
8171
	onRemove: function () {
8172
		L.DomUtil.remove(this._container);
8173
		this.off('update', this._updatePaths, this);
8174
	},
8175
8176
	getEvents: function () {
8177
		var events = {
8178
			viewreset: this._reset,
8179
			zoom: this._onZoom,
8180
			moveend: this._update,
8181
			zoomend: this._onZoomEnd
8182
		};
8183
		if (this._zoomAnimated) {
8184
			events.zoomanim = this._onAnimZoom;
8185
		}
8186
		return events;
8187
	},
8188
8189
	_onAnimZoom: function (ev) {
8190
		this._updateTransform(ev.center, ev.zoom);
8191
	},
8192
8193
	_onZoom: function () {
8194
		this._updateTransform(this._map.getCenter(), this._map.getZoom());
8195
	},
8196
8197
	_updateTransform: function (center, zoom) {
8198
		var scale = this._map.getZoomScale(zoom, this._zoom),
8199
		    position = L.DomUtil.getPosition(this._container),
8200
		    viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
8201
		    currentCenterPoint = this._map.project(this._center, zoom),
8202
		    destCenterPoint = this._map.project(center, zoom),
8203
		    centerOffset = destCenterPoint.subtract(currentCenterPoint),
8204
8205
		    topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
8206
8207
		if (L.Browser.any3d) {
8208
			L.DomUtil.setTransform(this._container, topLeftOffset, scale);
8209
		} else {
8210
			L.DomUtil.setPosition(this._container, topLeftOffset);
8211
		}
8212
	},
8213
8214
	_reset: function () {
8215
		this._update();
8216
		this._updateTransform(this._center, this._zoom);
8217
8218
		for (var id in this._layers) {
8219
			this._layers[id]._reset();
8220
		}
8221
	},
8222
8223
	_onZoomEnd: function () {
8224
		for (var id in this._layers) {
8225
			this._layers[id]._project();
8226
		}
8227
	},
8228
8229
	_updatePaths: function () {
8230
		for (var id in this._layers) {
8231
			this._layers[id]._update();
8232
		}
8233
	},
8234
8235
	_update: function () {
8236
		// Update pixel bounds of renderer container (for positioning/sizing/clipping later)
8237
		// Subclasses are responsible of firing the 'update' event.
8238
		var p = this.options.padding,
8239
		    size = this._map.getSize(),
8240
		    min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
8241
8242
		this._bounds = new L.Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
8243
8244
		this._center = this._map.getCenter();
8245
		this._zoom = this._map.getZoom();
8246
	}
8247
});
8248
8249
8250
L.Map.include({
8251
	// @namespace Map; @method getRenderer(layer: Path): Renderer
8252
	// Returns the instance of `Renderer` that should be used to render the given
8253
	// `Path`. It will ensure that the `renderer` options of the map and paths
8254
	// are respected, and that the renderers do exist on the map.
8255
	getRenderer: function (layer) {
8256
		// @namespace Path; @option renderer: Renderer
8257
		// Use this specific instance of `Renderer` for this path. Takes
8258
		// precedence over the map's [default renderer](#map-renderer).
8259
		var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
8260
8261
		if (!renderer) {
8262
			// @namespace Map; @option preferCanvas: Boolean = false
8263
			// Whether `Path`s should be rendered on a `Canvas` renderer.
8264
			// By default, all `Path`s are rendered in a `SVG` renderer.
8265
			renderer = this._renderer = (this.options.preferCanvas && L.canvas()) || L.svg();
8266
		}
8267
8268
		if (!this.hasLayer(renderer)) {
8269
			this.addLayer(renderer);
8270
		}
8271
		return renderer;
8272
	},
8273
8274
	_getPaneRenderer: function (name) {
8275
		if (name === 'overlayPane' || name === undefined) {
8276
			return false;
8277
		}
8278
8279
		var renderer = this._paneRenderers[name];
8280
		if (renderer === undefined) {
8281
			renderer = (L.SVG && L.svg({pane: name})) || (L.Canvas && L.canvas({pane: name}));
8282
			this._paneRenderers[name] = renderer;
8283
		}
8284
		return renderer;
8285
	}
8286
});
8287
8288
8289
8290
/*
8291
 * @class Path
8292
 * @aka L.Path
8293
 * @inherits Interactive layer
8294
 *
8295
 * An abstract class that contains options and constants shared between vector
8296
 * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
8297
 */
8298
8299
L.Path = L.Layer.extend({
8300
8301
	// @section
8302
	// @aka Path options
8303
	options: {
8304
		// @option stroke: Boolean = true
8305
		// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
8306
		stroke: true,
8307
8308
		// @option color: String = '#3388ff'
8309
		// Stroke color
8310
		color: '#3388ff',
8311
8312
		// @option weight: Number = 3
8313
		// Stroke width in pixels
8314
		weight: 3,
8315
8316
		// @option opacity: Number = 1.0
8317
		// Stroke opacity
8318
		opacity: 1,
8319
8320
		// @option lineCap: String= 'round'
8321
		// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
8322
		lineCap: 'round',
8323
8324
		// @option lineJoin: String = 'round'
8325
		// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
8326
		lineJoin: 'round',
8327
8328
		// @option dashArray: String = null
8329
		// 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).
8330
		dashArray: null,
8331
8332
		// @option dashOffset: String = null
8333
		// 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).
8334
		dashOffset: null,
8335
8336
		// @option fill: Boolean = depends
8337
		// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
8338
		fill: false,
8339
8340
		// @option fillColor: String = *
8341
		// Fill color. Defaults to the value of the [`color`](#path-color) option
8342
		fillColor: null,
8343
8344
		// @option fillOpacity: Number = 0.2
8345
		// Fill opacity.
8346
		fillOpacity: 0.2,
8347
8348
		// @option fillRule: String = 'evenodd'
8349
		// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
8350
		fillRule: 'evenodd',
8351
8352
		// className: '',
8353
8354
		// Option inherited from "Interactive layer" abstract class
8355
		interactive: true
8356
	},
8357
8358
	beforeAdd: function (map) {
8359
		// Renderer is set here because we need to call renderer.getEvents
8360
		// before this.getEvents.
8361
		this._renderer = map.getRenderer(this);
8362
	},
8363
8364
	onAdd: function () {
8365
		this._renderer._initPath(this);
8366
		this._reset();
8367
		this._renderer._addPath(this);
8368
	},
8369
8370
	onRemove: function () {
8371
		this._renderer._removePath(this);
8372
	},
8373
8374
	// @method redraw(): this
8375
	// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
8376
	redraw: function () {
8377
		if (this._map) {
8378
			this._renderer._updatePath(this);
8379
		}
8380
		return this;
8381
	},
8382
8383
	// @method setStyle(style: Path options): this
8384
	// Changes the appearance of a Path based on the options in the `Path options` object.
8385
	setStyle: function (style) {
8386
		L.setOptions(this, style);
8387
		if (this._renderer) {
8388
			this._renderer._updateStyle(this);
8389
		}
8390
		return this;
8391
	},
8392
8393
	// @method bringToFront(): this
8394
	// Brings the layer to the top of all path layers.
8395
	bringToFront: function () {
8396
		if (this._renderer) {
8397
			this._renderer._bringToFront(this);
8398
		}
8399
		return this;
8400
	},
8401
8402
	// @method bringToBack(): this
8403
	// Brings the layer to the bottom of all path layers.
8404
	bringToBack: function () {
8405
		if (this._renderer) {
8406
			this._renderer._bringToBack(this);
8407
		}
8408
		return this;
8409
	},
8410
8411
	getElement: function () {
8412
		return this._path;
8413
	},
8414
8415
	_reset: function () {
8416
		// defined in children classes
8417
		this._project();
8418
		this._update();
8419
	},
8420
8421
	_clickTolerance: function () {
8422
		// used when doing hit detection for Canvas layers
8423
		return (this.options.stroke ? this.options.weight / 2 : 0) + (L.Browser.touch ? 10 : 0);
8424
	}
8425
});
8426
8427
8428
8429
/*
8430
 * @namespace LineUtil
8431
 *
8432
 * Various utility functions for polyine points processing, used by Leaflet internally to make polylines lightning-fast.
8433
 */
8434
8435
L.LineUtil = {
8436
8437
	// Simplify polyline with vertex reduction and Douglas-Peucker simplification.
8438
	// Improves rendering performance dramatically by lessening the number of points to draw.
8439
8440
	// @function simplify(points: Point[], tolerance: Number): Point[]
8441
	// Dramatically reduces the number of points in a polyline while retaining
8442
	// its shape and returns a new array of simplified points, using the
8443
	// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
8444
	// Used for a huge performance boost when processing/displaying Leaflet polylines for
8445
	// each zoom level and also reducing visual noise. tolerance affects the amount of
8446
	// simplification (lesser value means higher quality but slower and with more points).
8447
	// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
8448
	simplify: function (points, tolerance) {
8449
		if (!tolerance || !points.length) {
8450
			return points.slice();
8451
		}
8452
8453
		var sqTolerance = tolerance * tolerance;
8454
8455
		// stage 1: vertex reduction
8456
		points = this._reducePoints(points, sqTolerance);
8457
8458
		// stage 2: Douglas-Peucker simplification
8459
		points = this._simplifyDP(points, sqTolerance);
8460
8461
		return points;
8462
	},
8463
8464
	// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
8465
	// Returns the distance between point `p` and segment `p1` to `p2`.
8466
	pointToSegmentDistance:  function (p, p1, p2) {
8467
		return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true));
8468
	},
8469
8470
	// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
8471
	// Returns the closest point from a point `p` on a segment `p1` to `p2`.
8472
	closestPointOnSegment: function (p, p1, p2) {
8473
		return this._sqClosestPointOnSegment(p, p1, p2);
8474
	},
8475
8476
	// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
8477
	_simplifyDP: function (points, sqTolerance) {
8478
8479
		var len = points.length,
8480
		    ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
8481
		    markers = new ArrayConstructor(len);
8482
8483
		markers[0] = markers[len - 1] = 1;
8484
8485
		this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
8486
8487
		var i,
8488
		    newPoints = [];
8489
8490
		for (i = 0; i < len; i++) {
8491
			if (markers[i]) {
8492
				newPoints.push(points[i]);
8493
			}
8494
		}
8495
8496
		return newPoints;
8497
	},
8498
8499
	_simplifyDPStep: function (points, markers, sqTolerance, first, last) {
8500
8501
		var maxSqDist = 0,
8502
		    index, i, sqDist;
8503
8504
		for (i = first + 1; i <= last - 1; i++) {
8505
			sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true);
8506
8507
			if (sqDist > maxSqDist) {
8508
				index = i;
8509
				maxSqDist = sqDist;
8510
			}
8511
		}
8512
8513
		if (maxSqDist > sqTolerance) {
8514
			markers[index] = 1;
8515
8516
			this._simplifyDPStep(points, markers, sqTolerance, first, index);
8517
			this._simplifyDPStep(points, markers, sqTolerance, index, last);
8518
		}
8519
	},
8520
8521
	// reduce points that are too close to each other to a single point
8522
	_reducePoints: function (points, sqTolerance) {
8523
		var reducedPoints = [points[0]];
8524
8525
		for (var i = 1, prev = 0, len = points.length; i < len; i++) {
8526
			if (this._sqDist(points[i], points[prev]) > sqTolerance) {
8527
				reducedPoints.push(points[i]);
8528
				prev = i;
8529
			}
8530
		}
8531
		if (prev < len - 1) {
8532
			reducedPoints.push(points[len - 1]);
8533
		}
8534
		return reducedPoints;
8535
	},
8536
8537
8538
	// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
8539
	// Clips the segment a to b by rectangular bounds with the
8540
	// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
8541
	// (modifying the segment points directly!). Used by Leaflet to only show polyline
8542
	// points that are on the screen or near, increasing performance.
8543
	clipSegment: function (a, b, bounds, useLastCode, round) {
8544
		var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds),
8545
		    codeB = this._getBitCode(b, bounds),
8546
8547
		    codeOut, p, newCode;
8548
8549
		// save 2nd code to avoid calculating it on the next segment
8550
		this._lastCode = codeB;
8551
8552
		while (true) {
8553
			// if a,b is inside the clip window (trivial accept)
8554
			if (!(codeA | codeB)) {
8555
				return [a, b];
8556
			}
8557
8558
			// if a,b is outside the clip window (trivial reject)
8559
			if (codeA & codeB) {
8560
				return false;
8561
			}
8562
8563
			// other cases
8564
			codeOut = codeA || codeB;
8565
			p = this._getEdgeIntersection(a, b, codeOut, bounds, round);
8566
			newCode = this._getBitCode(p, bounds);
8567
8568
			if (codeOut === codeA) {
8569
				a = p;
8570
				codeA = newCode;
8571
			} else {
8572
				b = p;
8573
				codeB = newCode;
8574
			}
8575
		}
8576
	},
8577
8578
	_getEdgeIntersection: function (a, b, code, bounds, round) {
8579
		var dx = b.x - a.x,
8580
		    dy = b.y - a.y,
8581
		    min = bounds.min,
8582
		    max = bounds.max,
8583
		    x, y;
8584
8585
		if (code & 8) { // top
8586
			x = a.x + dx * (max.y - a.y) / dy;
8587
			y = max.y;
8588
8589
		} else if (code & 4) { // bottom
8590
			x = a.x + dx * (min.y - a.y) / dy;
8591
			y = min.y;
8592
8593
		} else if (code & 2) { // right
8594
			x = max.x;
8595
			y = a.y + dy * (max.x - a.x) / dx;
8596
8597
		} else if (code & 1) { // left
8598
			x = min.x;
8599
			y = a.y + dy * (min.x - a.x) / dx;
8600
		}
8601
8602
		return new L.Point(x, y, round);
8603
	},
8604
8605
	_getBitCode: function (p, bounds) {
8606
		var code = 0;
8607
8608
		if (p.x < bounds.min.x) { // left
8609
			code |= 1;
8610
		} else if (p.x > bounds.max.x) { // right
8611
			code |= 2;
8612
		}
8613
8614
		if (p.y < bounds.min.y) { // bottom
8615
			code |= 4;
8616
		} else if (p.y > bounds.max.y) { // top
8617
			code |= 8;
8618
		}
8619
8620
		return code;
8621
	},
8622
8623
	// square distance (to avoid unnecessary Math.sqrt calls)
8624
	_sqDist: function (p1, p2) {
8625
		var dx = p2.x - p1.x,
8626
		    dy = p2.y - p1.y;
8627
		return dx * dx + dy * dy;
8628
	},
8629
8630
	// return closest point on segment or distance to that point
8631
	_sqClosestPointOnSegment: function (p, p1, p2, sqDist) {
8632
		var x = p1.x,
8633
		    y = p1.y,
8634
		    dx = p2.x - x,
8635
		    dy = p2.y - y,
8636
		    dot = dx * dx + dy * dy,
8637
		    t;
8638
8639
		if (dot > 0) {
8640
			t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
8641
8642
			if (t > 1) {
8643
				x = p2.x;
8644
				y = p2.y;
8645
			} else if (t > 0) {
8646
				x += dx * t;
8647
				y += dy * t;
8648
			}
8649
		}
8650
8651
		dx = p.x - x;
8652
		dy = p.y - y;
8653
8654
		return sqDist ? dx * dx + dy * dy : new L.Point(x, y);
8655
	}
8656
};
8657
8658
8659
8660
/*
8661
 * @class Polyline
8662
 * @aka L.Polyline
8663
 * @inherits Path
8664
 *
8665
 * A class for drawing polyline overlays on a map. Extends `Path`.
8666
 *
8667
 * @example
8668
 *
8669
 * ```js
8670
 * // create a red polyline from an array of LatLng points
8671
 * var latlngs = [
8672
 * 	[45.51, -122.68],
8673
 * 	[37.77, -122.43],
8674
 * 	[34.04, -118.2]
8675
 * ];
8676
 *
8677
 * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
8678
 *
8679
 * // zoom the map to the polyline
8680
 * map.fitBounds(polyline.getBounds());
8681
 * ```
8682
 *
8683
 * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
8684
 *
8685
 * ```js
8686
 * // create a red polyline from an array of arrays of LatLng points
8687
 * var latlngs = [
8688
 * 	[[45.51, -122.68],
8689
 * 	 [37.77, -122.43],
8690
 * 	 [34.04, -118.2]],
8691
 * 	[[40.78, -73.91],
8692
 * 	 [41.83, -87.62],
8693
 * 	 [32.76, -96.72]]
8694
 * ];
8695
 * ```
8696
 */
8697
8698
L.Polyline = L.Path.extend({
8699
8700
	// @section
8701
	// @aka Polyline options
8702
	options: {
8703
		// @option smoothFactor: Number = 1.0
8704
		// How much to simplify the polyline on each zoom level. More means
8705
		// better performance and smoother look, and less means more accurate representation.
8706
		smoothFactor: 1.0,
8707
8708
		// @option noClip: Boolean = false
8709
		// Disable polyline clipping.
8710
		noClip: false
8711
	},
8712
8713
	initialize: function (latlngs, options) {
8714
		L.setOptions(this, options);
8715
		this._setLatLngs(latlngs);
8716
	},
8717
8718
	// @method getLatLngs(): LatLng[]
8719
	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
8720
	getLatLngs: function () {
8721
		return this._latlngs;
8722
	},
8723
8724
	// @method setLatLngs(latlngs: LatLng[]): this
8725
	// Replaces all the points in the polyline with the given array of geographical points.
8726
	setLatLngs: function (latlngs) {
8727
		this._setLatLngs(latlngs);
8728
		return this.redraw();
8729
	},
8730
8731
	// @method isEmpty(): Boolean
8732
	// Returns `true` if the Polyline has no LatLngs.
8733
	isEmpty: function () {
8734
		return !this._latlngs.length;
8735
	},
8736
8737
	closestLayerPoint: function (p) {
8738
		var minDistance = Infinity,
8739
		    minPoint = null,
8740
		    closest = L.LineUtil._sqClosestPointOnSegment,
8741
		    p1, p2;
8742
8743
		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
8744
			var points = this._parts[j];
8745
8746
			for (var i = 1, len = points.length; i < len; i++) {
8747
				p1 = points[i - 1];
8748
				p2 = points[i];
8749
8750
				var sqDist = closest(p, p1, p2, true);
8751
8752
				if (sqDist < minDistance) {
8753
					minDistance = sqDist;
8754
					minPoint = closest(p, p1, p2);
8755
				}
8756
			}
8757
		}
8758
		if (minPoint) {
8759
			minPoint.distance = Math.sqrt(minDistance);
8760
		}
8761
		return minPoint;
8762
	},
8763
8764
	// @method getCenter(): LatLng
8765
	// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
8766
	getCenter: function () {
8767
		// throws error when not yet added to map as this center calculation requires projected coordinates
8768
		if (!this._map) {
8769
			throw new Error('Must add layer to map before using getCenter()');
8770
		}
8771
8772
		var i, halfDist, segDist, dist, p1, p2, ratio,
8773
		    points = this._rings[0],
8774
		    len = points.length;
8775
8776
		if (!len) { return null; }
8777
8778
		// polyline centroid algorithm; only uses the first ring if there are multiple
8779
8780
		for (i = 0, halfDist = 0; i < len - 1; i++) {
8781
			halfDist += points[i].distanceTo(points[i + 1]) / 2;
8782
		}
8783
8784
		// The line is so small in the current view that all points are on the same pixel.
8785
		if (halfDist === 0) {
8786
			return this._map.layerPointToLatLng(points[0]);
8787
		}
8788
8789
		for (i = 0, dist = 0; i < len - 1; i++) {
8790
			p1 = points[i];
8791
			p2 = points[i + 1];
8792
			segDist = p1.distanceTo(p2);
8793
			dist += segDist;
8794
8795
			if (dist > halfDist) {
8796
				ratio = (dist - halfDist) / segDist;
8797
				return this._map.layerPointToLatLng([
8798
					p2.x - ratio * (p2.x - p1.x),
8799
					p2.y - ratio * (p2.y - p1.y)
8800
				]);
8801
			}
8802
		}
8803
	},
8804
8805
	// @method getBounds(): LatLngBounds
8806
	// Returns the `LatLngBounds` of the path.
8807
	getBounds: function () {
8808
		return this._bounds;
8809
	},
8810
8811
	// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
8812
	// Adds a given point to the polyline. By default, adds to the first ring of
8813
	// the polyline in case of a multi-polyline, but can be overridden by passing
8814
	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
8815
	addLatLng: function (latlng, latlngs) {
8816
		latlngs = latlngs || this._defaultShape();
8817
		latlng = L.latLng(latlng);
8818
		latlngs.push(latlng);
8819
		this._bounds.extend(latlng);
8820
		return this.redraw();
8821
	},
8822
8823
	_setLatLngs: function (latlngs) {
8824
		this._bounds = new L.LatLngBounds();
8825
		this._latlngs = this._convertLatLngs(latlngs);
8826
	},
8827
8828
	_defaultShape: function () {
8829
		return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
8830
	},
8831
8832
	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
8833
	_convertLatLngs: function (latlngs) {
8834
		var result = [],
8835
		    flat = L.Polyline._flat(latlngs);
8836
8837
		for (var i = 0, len = latlngs.length; i < len; i++) {
8838
			if (flat) {
8839
				result[i] = L.latLng(latlngs[i]);
8840
				this._bounds.extend(result[i]);
8841
			} else {
8842
				result[i] = this._convertLatLngs(latlngs[i]);
8843
			}
8844
		}
8845
8846
		return result;
8847
	},
8848
8849
	_project: function () {
8850
		var pxBounds = new L.Bounds();
8851
		this._rings = [];
8852
		this._projectLatlngs(this._latlngs, this._rings, pxBounds);
8853
8854
		var w = this._clickTolerance(),
8855
		    p = new L.Point(w, w);
8856
8857
		if (this._bounds.isValid() && pxBounds.isValid()) {
8858
			pxBounds.min._subtract(p);
8859
			pxBounds.max._add(p);
8860
			this._pxBounds = pxBounds;
8861
		}
8862
	},
8863
8864
	// recursively turns latlngs into a set of rings with projected coordinates
8865
	_projectLatlngs: function (latlngs, result, projectedBounds) {
8866
		var flat = latlngs[0] instanceof L.LatLng,
8867
		    len = latlngs.length,
8868
		    i, ring;
8869
8870
		if (flat) {
8871
			ring = [];
8872
			for (i = 0; i < len; i++) {
8873
				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
8874
				projectedBounds.extend(ring[i]);
8875
			}
8876
			result.push(ring);
8877
		} else {
8878
			for (i = 0; i < len; i++) {
8879
				this._projectLatlngs(latlngs[i], result, projectedBounds);
8880
			}
8881
		}
8882
	},
8883
8884
	// clip polyline by renderer bounds so that we have less to render for performance
8885
	_clipPoints: function () {
8886
		var bounds = this._renderer._bounds;
8887
8888
		this._parts = [];
8889
		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
8890
			return;
8891
		}
8892
8893
		if (this.options.noClip) {
8894
			this._parts = this._rings;
8895
			return;
8896
		}
8897
8898
		var parts = this._parts,
8899
		    i, j, k, len, len2, segment, points;
8900
8901
		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
8902
			points = this._rings[i];
8903
8904
			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
8905
				segment = L.LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);
8906
8907
				if (!segment) { continue; }
8908
8909
				parts[k] = parts[k] || [];
8910
				parts[k].push(segment[0]);
8911
8912
				// if segment goes out of screen, or it's the last one, it's the end of the line part
8913
				if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
8914
					parts[k].push(segment[1]);
8915
					k++;
8916
				}
8917
			}
8918
		}
8919
	},
8920
8921
	// simplify each clipped part of the polyline for performance
8922
	_simplifyPoints: function () {
8923
		var parts = this._parts,
8924
		    tolerance = this.options.smoothFactor;
8925
8926
		for (var i = 0, len = parts.length; i < len; i++) {
8927
			parts[i] = L.LineUtil.simplify(parts[i], tolerance);
8928
		}
8929
	},
8930
8931
	_update: function () {
8932
		if (!this._map) { return; }
8933
8934
		this._clipPoints();
8935
		this._simplifyPoints();
8936
		this._updatePath();
8937
	},
8938
8939
	_updatePath: function () {
8940
		this._renderer._updatePoly(this);
8941
	}
8942
});
8943
8944
// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
8945
// Instantiates a polyline object given an array of geographical points and
8946
// optionally an options object. You can create a `Polyline` object with
8947
// multiple separate lines (`MultiPolyline`) by passing an array of arrays
8948
// of geographic points.
8949
L.polyline = function (latlngs, options) {
8950
	return new L.Polyline(latlngs, options);
8951
};
8952
8953
L.Polyline._flat = function (latlngs) {
8954
	// true if it's a flat array of latlngs; false if nested
8955
	return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
8956
};
8957
8958
8959
8960
/*
8961
 * @namespace PolyUtil
8962
 * Various utility functions for polygon geometries.
8963
 */
8964
8965
L.PolyUtil = {};
8966
8967
/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
8968
 * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgeman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
8969
 * Used by Leaflet to only show polygon points that are on the screen or near, increasing
8970
 * performance. Note that polygon points needs different algorithm for clipping
8971
 * than polyline, so there's a seperate method for it.
8972
 */
8973
L.PolyUtil.clipPolygon = function (points, bounds, round) {
8974
	var clippedPoints,
8975
	    edges = [1, 4, 2, 8],
8976
	    i, j, k,
8977
	    a, b,
8978
	    len, edge, p,
8979
	    lu = L.LineUtil;
8980
8981
	for (i = 0, len = points.length; i < len; i++) {
8982
		points[i]._code = lu._getBitCode(points[i], bounds);
8983
	}
8984
8985
	// for each edge (left, bottom, right, top)
8986
	for (k = 0; k < 4; k++) {
8987
		edge = edges[k];
8988
		clippedPoints = [];
8989
8990
		for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
8991
			a = points[i];
8992
			b = points[j];
8993
8994
			// if a is inside the clip window
8995
			if (!(a._code & edge)) {
8996
				// if b is outside the clip window (a->b goes out of screen)
8997
				if (b._code & edge) {
8998
					p = lu._getEdgeIntersection(b, a, edge, bounds, round);
8999
					p._code = lu._getBitCode(p, bounds);
9000
					clippedPoints.push(p);
9001
				}
9002
				clippedPoints.push(a);
9003
9004
			// else if b is inside the clip window (a->b enters the screen)
9005
			} else if (!(b._code & edge)) {
9006
				p = lu._getEdgeIntersection(b, a, edge, bounds, round);
9007
				p._code = lu._getBitCode(p, bounds);
9008
				clippedPoints.push(p);
9009
			}
9010
		}
9011
		points = clippedPoints;
9012
	}
9013
9014
	return points;
9015
};
9016
9017
9018
9019
/*
9020
 * @class Polygon
9021
 * @aka L.Polygon
9022
 * @inherits Polyline
9023
 *
9024
 * A class for drawing polygon overlays on a map. Extends `Polyline`.
9025
 *
9026
 * 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.
9027
 *
9028
 *
9029
 * @example
9030
 *
9031
 * ```js
9032
 * // create a red polygon from an array of LatLng points
9033
 * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];
9034
 *
9035
 * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
9036
 *
9037
 * // zoom the map to the polygon
9038
 * map.fitBounds(polygon.getBounds());
9039
 * ```
9040
 *
9041
 * 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:
9042
 *
9043
 * ```js
9044
 * var latlngs = [
9045
 *   [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
9046
 *   [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
9047
 * ];
9048
 * ```
9049
 *
9050
 * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
9051
 *
9052
 * ```js
9053
 * var latlngs = [
9054
 *   [ // first polygon
9055
 *     [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring
9056
 *     [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole
9057
 *   ],
9058
 *   [ // second polygon
9059
 *     [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]
9060
 *   ]
9061
 * ];
9062
 * ```
9063
 */
9064
9065
L.Polygon = L.Polyline.extend({
9066
9067
	options: {
9068
		fill: true
9069
	},
9070
9071
	isEmpty: function () {
9072
		return !this._latlngs.length || !this._latlngs[0].length;
9073
	},
9074
9075
	getCenter: function () {
9076
		// throws error when not yet added to map as this center calculation requires projected coordinates
9077
		if (!this._map) {
9078
			throw new Error('Must add layer to map before using getCenter()');
9079
		}
9080
9081
		var i, j, p1, p2, f, area, x, y, center,
9082
		    points = this._rings[0],
9083
		    len = points.length;
9084
9085
		if (!len) { return null; }
9086
9087
		// polygon centroid algorithm; only uses the first ring if there are multiple
9088
9089
		area = x = y = 0;
9090
9091
		for (i = 0, j = len - 1; i < len; j = i++) {
9092
			p1 = points[i];
9093
			p2 = points[j];
9094
9095
			f = p1.y * p2.x - p2.y * p1.x;
9096
			x += (p1.x + p2.x) * f;
9097
			y += (p1.y + p2.y) * f;
9098
			area += f * 3;
9099
		}
9100
9101
		if (area === 0) {
9102
			// Polygon is so small that all points are on same pixel.
9103
			center = points[0];
9104
		} else {
9105
			center = [x / area, y / area];
9106
		}
9107
		return this._map.layerPointToLatLng(center);
9108
	},
9109
9110
	_convertLatLngs: function (latlngs) {
9111
		var result = L.Polyline.prototype._convertLatLngs.call(this, latlngs),
9112
		    len = result.length;
9113
9114
		// remove last point if it equals first one
9115
		if (len >= 2 && result[0] instanceof L.LatLng && result[0].equals(result[len - 1])) {
9116
			result.pop();
9117
		}
9118
		return result;
9119
	},
9120
9121
	_setLatLngs: function (latlngs) {
9122
		L.Polyline.prototype._setLatLngs.call(this, latlngs);
9123
		if (L.Polyline._flat(this._latlngs)) {
9124
			this._latlngs = [this._latlngs];
9125
		}
9126
	},
9127
9128
	_defaultShape: function () {
9129
		return L.Polyline._flat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
9130
	},
9131
9132
	_clipPoints: function () {
9133
		// polygons need a different clipping algorithm so we redefine that
9134
9135
		var bounds = this._renderer._bounds,
9136
		    w = this.options.weight,
9137
		    p = new L.Point(w, w);
9138
9139
		// increase clip padding by stroke width to avoid stroke on clip edges
9140
		bounds = new L.Bounds(bounds.min.subtract(p), bounds.max.add(p));
9141
9142
		this._parts = [];
9143
		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
9144
			return;
9145
		}
9146
9147
		if (this.options.noClip) {
9148
			this._parts = this._rings;
9149
			return;
9150
		}
9151
9152
		for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
9153
			clipped = L.PolyUtil.clipPolygon(this._rings[i], bounds, true);
9154
			if (clipped.length) {
9155
				this._parts.push(clipped);
9156
			}
9157
		}
9158
	},
9159
9160
	_updatePath: function () {
9161
		this._renderer._updatePoly(this, true);
9162
	}
9163
});
9164
9165
9166
// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
9167
L.polygon = function (latlngs, options) {
9168
	return new L.Polygon(latlngs, options);
9169
};
9170
9171
9172
9173
/*
9174
 * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
9175
 */
9176
9177
/*
9178
 * @class Rectangle
9179
 * @aka L.Retangle
9180
 * @inherits Polygon
9181
 *
9182
 * A class for drawing rectangle overlays on a map. Extends `Polygon`.
9183
 *
9184
 * @example
9185
 *
9186
 * ```js
9187
 * // define rectangle geographical bounds
9188
 * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
9189
 *
9190
 * // create an orange rectangle
9191
 * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
9192
 *
9193
 * // zoom the map to the rectangle bounds
9194
 * map.fitBounds(bounds);
9195
 * ```
9196
 *
9197
 */
9198
9199
9200
L.Rectangle = L.Polygon.extend({
9201
	initialize: function (latLngBounds, options) {
9202
		L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
9203
	},
9204
9205
	// @method setBounds(latLngBounds: LatLngBounds): this
9206
	// Redraws the rectangle with the passed bounds.
9207
	setBounds: function (latLngBounds) {
9208
		return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
9209
	},
9210
9211
	_boundsToLatLngs: function (latLngBounds) {
9212
		latLngBounds = L.latLngBounds(latLngBounds);
9213
		return [
9214
			latLngBounds.getSouthWest(),
9215
			latLngBounds.getNorthWest(),
9216
			latLngBounds.getNorthEast(),
9217
			latLngBounds.getSouthEast()
9218
		];
9219
	}
9220
});
9221
9222
9223
// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
9224
L.rectangle = function (latLngBounds, options) {
9225
	return new L.Rectangle(latLngBounds, options);
9226
};
9227
9228
9229
9230
/*
9231
 * @class CircleMarker
9232
 * @aka L.CircleMarker
9233
 * @inherits Path
9234
 *
9235
 * A circle of a fixed size with radius specified in pixels. Extends `Path`.
9236
 */
9237
9238
L.CircleMarker = L.Path.extend({
9239
9240
	// @section
9241
	// @aka CircleMarker options
9242
	options: {
9243
		fill: true,
9244
9245
		// @option radius: Number = 10
9246
		// Radius of the circle marker, in pixels
9247
		radius: 10
9248
	},
9249
9250
	initialize: function (latlng, options) {
9251
		L.setOptions(this, options);
9252
		this._latlng = L.latLng(latlng);
9253
		this._radius = this.options.radius;
9254
	},
9255
9256
	// @method setLatLng(latLng: LatLng): this
9257
	// Sets the position of a circle marker to a new location.
9258
	setLatLng: function (latlng) {
9259
		this._latlng = L.latLng(latlng);
9260
		this.redraw();
9261
		return this.fire('move', {latlng: this._latlng});
9262
	},
9263
9264
	// @method getLatLng(): LatLng
9265
	// Returns the current geographical position of the circle marker
9266
	getLatLng: function () {
9267
		return this._latlng;
9268
	},
9269
9270
	// @method setRadius(radius: Number): this
9271
	// Sets the radius of a circle marker. Units are in pixels.
9272
	setRadius: function (radius) {
9273
		this.options.radius = this._radius = radius;
9274
		return this.redraw();
9275
	},
9276
9277
	// @method getRadius(): Number
9278
	// Returns the current radius of the circle
9279
	getRadius: function () {
9280
		return this._radius;
9281
	},
9282
9283
	setStyle : function (options) {
9284
		var radius = options && options.radius || this._radius;
9285
		L.Path.prototype.setStyle.call(this, options);
9286
		this.setRadius(radius);
9287
		return this;
9288
	},
9289
9290
	_project: function () {
9291
		this._point = this._map.latLngToLayerPoint(this._latlng);
9292
		this._updateBounds();
9293
	},
9294
9295
	_updateBounds: function () {
9296
		var r = this._radius,
9297
		    r2 = this._radiusY || r,
9298
		    w = this._clickTolerance(),
9299
		    p = [r + w, r2 + w];
9300
		this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));
9301
	},
9302
9303
	_update: function () {
9304
		if (this._map) {
9305
			this._updatePath();
9306
		}
9307
	},
9308
9309
	_updatePath: function () {
9310
		this._renderer._updateCircle(this);
9311
	},
9312
9313
	_empty: function () {
9314
		return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
9315
	}
9316
});
9317
9318
9319
// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
9320
// Instantiates a circle marker object given a geographical point, and an optional options object.
9321
L.circleMarker = function (latlng, options) {
9322
	return new L.CircleMarker(latlng, options);
9323
};
9324
9325
9326
9327
/*
9328
 * @class Circle
9329
 * @aka L.Circle
9330
 * @inherits CircleMarker
9331
 *
9332
 * A class for drawing circle overlays on a map. Extends `CircleMarker`.
9333
 *
9334
 * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
9335
 *
9336
 * @example
9337
 *
9338
 * ```js
9339
 * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
9340
 * ```
9341
 */
9342
9343
L.Circle = L.CircleMarker.extend({
9344
9345
	initialize: function (latlng, options, legacyOptions) {
9346
		if (typeof options === 'number') {
9347
			// Backwards compatibility with 0.7.x factory (latlng, radius, options?)
9348
			options = L.extend({}, legacyOptions, {radius: options});
9349
		}
9350
		L.setOptions(this, options);
9351
		this._latlng = L.latLng(latlng);
9352
9353
		if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
9354
9355
		// @section
9356
		// @aka Circle options
9357
		// @option radius: Number; Radius of the circle, in meters.
9358
		this._mRadius = this.options.radius;
9359
	},
9360
9361
	// @method setRadius(radius: Number): this
9362
	// Sets the radius of a circle. Units are in meters.
9363
	setRadius: function (radius) {
9364
		this._mRadius = radius;
9365
		return this.redraw();
9366
	},
9367
9368
	// @method getRadius(): Number
9369
	// Returns the current radius of a circle. Units are in meters.
9370
	getRadius: function () {
9371
		return this._mRadius;
9372
	},
9373
9374
	// @method getBounds(): LatLngBounds
9375
	// Returns the `LatLngBounds` of the path.
9376
	getBounds: function () {
9377
		var half = [this._radius, this._radiusY || this._radius];
9378
9379
		return new L.LatLngBounds(
9380
			this._map.layerPointToLatLng(this._point.subtract(half)),
9381
			this._map.layerPointToLatLng(this._point.add(half)));
9382
	},
9383
9384
	setStyle: L.Path.prototype.setStyle,
9385
9386
	_project: function () {
9387
9388
		var lng = this._latlng.lng,
9389
		    lat = this._latlng.lat,
9390
		    map = this._map,
9391
		    crs = map.options.crs;
9392
9393
		if (crs.distance === L.CRS.Earth.distance) {
9394
			var d = Math.PI / 180,
9395
			    latR = (this._mRadius / L.CRS.Earth.R) / d,
9396
			    top = map.project([lat + latR, lng]),
9397
			    bottom = map.project([lat - latR, lng]),
9398
			    p = top.add(bottom).divideBy(2),
9399
			    lat2 = map.unproject(p).lat,
9400
			    lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
9401
			            (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
9402
9403
			if (isNaN(lngR) || lngR === 0) {
9404
				lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
9405
			}
9406
9407
			this._point = p.subtract(map.getPixelOrigin());
9408
			this._radius = isNaN(lngR) ? 0 : Math.max(Math.round(p.x - map.project([lat2, lng - lngR]).x), 1);
9409
			this._radiusY = Math.max(Math.round(p.y - top.y), 1);
9410
9411
		} else {
9412
			var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
9413
9414
			this._point = map.latLngToLayerPoint(this._latlng);
9415
			this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
9416
		}
9417
9418
		this._updateBounds();
9419
	}
9420
});
9421
9422
// @factory L.circle(latlng: LatLng, options?: Circle options)
9423
// Instantiates a circle object given a geographical point, and an options object
9424
// which contains the circle radius.
9425
// @alternative
9426
// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
9427
// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
9428
// Do not use in new applications or plugins.
9429
L.circle = function (latlng, options, legacyOptions) {
9430
	return new L.Circle(latlng, options, legacyOptions);
9431
};
9432
9433
9434
9435
/*
9436
 * @class SVG
9437
 * @inherits Renderer
9438
 * @aka L.SVG
9439
 *
9440
 * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
9441
 * Inherits `Renderer`.
9442
 *
9443
 * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
9444
 * available in all web browsers, notably Android 2.x and 3.x.
9445
 *
9446
 * Although SVG is not available on IE7 and IE8, these browsers support
9447
 * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
9448
 * (a now deprecated technology), and the SVG renderer will fall back to VML in
9449
 * this case.
9450
 *
9451
 * @example
9452
 *
9453
 * Use SVG by default for all paths in the map:
9454
 *
9455
 * ```js
9456
 * var map = L.map('map', {
9457
 * 	renderer: L.svg()
9458
 * });
9459
 * ```
9460
 *
9461
 * Use a SVG renderer with extra padding for specific vector geometries:
9462
 *
9463
 * ```js
9464
 * var map = L.map('map');
9465
 * var myRenderer = L.svg({ padding: 0.5 });
9466
 * var line = L.polyline( coordinates, { renderer: myRenderer } );
9467
 * var circle = L.circle( center, { renderer: myRenderer } );
9468
 * ```
9469
 */
9470
9471
L.SVG = L.Renderer.extend({
9472
9473
	getEvents: function () {
9474
		var events = L.Renderer.prototype.getEvents.call(this);
9475
		events.zoomstart = this._onZoomStart;
9476
		return events;
9477
	},
9478
9479
	_initContainer: function () {
9480
		this._container = L.SVG.create('svg');
9481
9482
		// makes it possible to click through svg root; we'll reset it back in individual paths
9483
		this._container.setAttribute('pointer-events', 'none');
9484
9485
		this._rootGroup = L.SVG.create('g');
9486
		this._container.appendChild(this._rootGroup);
9487
	},
9488
9489
	_onZoomStart: function () {
9490
		// Drag-then-pinch interactions might mess up the center and zoom.
9491
		// In this case, the easiest way to prevent this is re-do the renderer
9492
		//   bounds and padding when the zooming starts.
9493
		this._update();
9494
	},
9495
9496
	_update: function () {
9497
		if (this._map._animatingZoom && this._bounds) { return; }
9498
9499
		L.Renderer.prototype._update.call(this);
9500
9501
		var b = this._bounds,
9502
		    size = b.getSize(),
9503
		    container = this._container;
9504
9505
		// set size of svg-container if changed
9506
		if (!this._svgSize || !this._svgSize.equals(size)) {
9507
			this._svgSize = size;
9508
			container.setAttribute('width', size.x);
9509
			container.setAttribute('height', size.y);
9510
		}
9511
9512
		// movement: update container viewBox so that we don't have to change coordinates of individual layers
9513
		L.DomUtil.setPosition(container, b.min);
9514
		container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
9515
9516
		this.fire('update');
9517
	},
9518
9519
	// methods below are called by vector layers implementations
9520
9521
	_initPath: function (layer) {
9522
		var path = layer._path = L.SVG.create('path');
9523
9524
		// @namespace Path
9525
		// @option className: String = null
9526
		// Custom class name set on an element. Only for SVG renderer.
9527
		if (layer.options.className) {
9528
			L.DomUtil.addClass(path, layer.options.className);
9529
		}
9530
9531
		if (layer.options.interactive) {
9532
			L.DomUtil.addClass(path, 'leaflet-interactive');
9533
		}
9534
9535
		this._updateStyle(layer);
9536
		this._layers[L.stamp(layer)] = layer;
9537
	},
9538
9539
	_addPath: function (layer) {
9540
		this._rootGroup.appendChild(layer._path);
9541
		layer.addInteractiveTarget(layer._path);
9542
	},
9543
9544
	_removePath: function (layer) {
9545
		L.DomUtil.remove(layer._path);
9546
		layer.removeInteractiveTarget(layer._path);
9547
		delete this._layers[L.stamp(layer)];
9548
	},
9549
9550
	_updatePath: function (layer) {
9551
		layer._project();
9552
		layer._update();
9553
	},
9554
9555
	_updateStyle: function (layer) {
9556
		var path = layer._path,
9557
		    options = layer.options;
9558
9559
		if (!path) { return; }
9560
9561
		if (options.stroke) {
9562
			path.setAttribute('stroke', options.color);
9563
			path.setAttribute('stroke-opacity', options.opacity);
9564
			path.setAttribute('stroke-width', options.weight);
9565
			path.setAttribute('stroke-linecap', options.lineCap);
9566
			path.setAttribute('stroke-linejoin', options.lineJoin);
9567
9568
			if (options.dashArray) {
9569
				path.setAttribute('stroke-dasharray', options.dashArray);
9570
			} else {
9571
				path.removeAttribute('stroke-dasharray');
9572
			}
9573
9574
			if (options.dashOffset) {
9575
				path.setAttribute('stroke-dashoffset', options.dashOffset);
9576
			} else {
9577
				path.removeAttribute('stroke-dashoffset');
9578
			}
9579
		} else {
9580
			path.setAttribute('stroke', 'none');
9581
		}
9582
9583
		if (options.fill) {
9584
			path.setAttribute('fill', options.fillColor || options.color);
9585
			path.setAttribute('fill-opacity', options.fillOpacity);
9586
			path.setAttribute('fill-rule', options.fillRule || 'evenodd');
9587
		} else {
9588
			path.setAttribute('fill', 'none');
9589
		}
9590
	},
9591
9592
	_updatePoly: function (layer, closed) {
9593
		this._setPath(layer, L.SVG.pointsToPath(layer._parts, closed));
9594
	},
9595
9596
	_updateCircle: function (layer) {
9597
		var p = layer._point,
9598
		    r = layer._radius,
9599
		    r2 = layer._radiusY || r,
9600
		    arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
9601
9602
		// drawing a circle with two half-arcs
9603
		var d = layer._empty() ? 'M0 0' :
9604
				'M' + (p.x - r) + ',' + p.y +
9605
				arc + (r * 2) + ',0 ' +
9606
				arc + (-r * 2) + ',0 ';
9607
9608
		this._setPath(layer, d);
9609
	},
9610
9611
	_setPath: function (layer, path) {
9612
		layer._path.setAttribute('d', path);
9613
	},
9614
9615
	// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
9616
	_bringToFront: function (layer) {
9617
		L.DomUtil.toFront(layer._path);
9618
	},
9619
9620
	_bringToBack: function (layer) {
9621
		L.DomUtil.toBack(layer._path);
9622
	}
9623
});
9624
9625
9626
// @namespace SVG; @section
9627
// There are several static functions which can be called without instantiating L.SVG:
9628
L.extend(L.SVG, {
9629
	// @function create(name: String): SVGElement
9630
	// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
9631
	// corresponding to the class name passed. For example, using 'line' will return
9632
	// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
9633
	create: function (name) {
9634
		return document.createElementNS('http://www.w3.org/2000/svg', name);
9635
	},
9636
9637
	// @function pointsToPath(rings: Point[], closed: Boolean): String
9638
	// Generates a SVG path string for multiple rings, with each ring turning
9639
	// into "M..L..L.." instructions
9640
	pointsToPath: function (rings, closed) {
9641
		var str = '',
9642
		    i, j, len, len2, points, p;
9643
9644
		for (i = 0, len = rings.length; i < len; i++) {
9645
			points = rings[i];
9646
9647
			for (j = 0, len2 = points.length; j < len2; j++) {
9648
				p = points[j];
9649
				str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
9650
			}
9651
9652
			// closes the ring for polygons; "x" is VML syntax
9653
			str += closed ? (L.Browser.svg ? 'z' : 'x') : '';
9654
		}
9655
9656
		// SVG complains about empty path strings
9657
		return str || 'M0 0';
9658
	}
9659
});
9660
9661
// @namespace Browser; @property svg: Boolean
9662
// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
9663
L.Browser.svg = !!(document.createElementNS && L.SVG.create('svg').createSVGRect);
9664
9665
9666
// @namespace SVG
9667
// @factory L.svg(options?: Renderer options)
9668
// Creates a SVG renderer with the given options.
9669
L.svg = function (options) {
9670
	return L.Browser.svg || L.Browser.vml ? new L.SVG(options) : null;
9671
};
9672
9673
9674
9675
/*
9676
 * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
9677
 */
9678
9679
/*
9680
 * @class SVG
9681
 *
9682
 * Although SVG is not available on IE7 and IE8, these browsers support [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language), and the SVG renderer will fall back to VML in this case.
9683
 *
9684
 * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
9685
 * with old versions of Internet Explorer.
9686
 */
9687
9688
// @namespace Browser; @property vml: Boolean
9689
// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
9690
L.Browser.vml = !L.Browser.svg && (function () {
9691
	try {
9692
		var div = document.createElement('div');
9693
		div.innerHTML = '<v:shape adj="1"/>';
9694
9695
		var shape = div.firstChild;
9696
		shape.style.behavior = 'url(#default#VML)';
9697
9698
		return shape && (typeof shape.adj === 'object');
9699
9700
	} catch (e) {
9701
		return false;
9702
	}
9703
}());
9704
9705
// redefine some SVG methods to handle VML syntax which is similar but with some differences
9706
L.SVG.include(!L.Browser.vml ? {} : {
9707
9708
	_initContainer: function () {
9709
		this._container = L.DomUtil.create('div', 'leaflet-vml-container');
9710
	},
9711
9712
	_update: function () {
9713
		if (this._map._animatingZoom) { return; }
9714
		L.Renderer.prototype._update.call(this);
9715
		this.fire('update');
9716
	},
9717
9718
	_initPath: function (layer) {
9719
		var container = layer._container = L.SVG.create('shape');
9720
9721
		L.DomUtil.addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
9722
9723
		container.coordsize = '1 1';
9724
9725
		layer._path = L.SVG.create('path');
9726
		container.appendChild(layer._path);
9727
9728
		this._updateStyle(layer);
9729
		this._layers[L.stamp(layer)] = layer;
9730
	},
9731
9732
	_addPath: function (layer) {
9733
		var container = layer._container;
9734
		this._container.appendChild(container);
9735
9736
		if (layer.options.interactive) {
9737
			layer.addInteractiveTarget(container);
9738
		}
9739
	},
9740
9741
	_removePath: function (layer) {
9742
		var container = layer._container;
9743
		L.DomUtil.remove(container);
9744
		layer.removeInteractiveTarget(container);
9745
		delete this._layers[L.stamp(layer)];
9746
	},
9747
9748
	_updateStyle: function (layer) {
9749
		var stroke = layer._stroke,
9750
		    fill = layer._fill,
9751
		    options = layer.options,
9752
		    container = layer._container;
9753
9754
		container.stroked = !!options.stroke;
9755
		container.filled = !!options.fill;
9756
9757
		if (options.stroke) {
9758
			if (!stroke) {
9759
				stroke = layer._stroke = L.SVG.create('stroke');
9760
			}
9761
			container.appendChild(stroke);
9762
			stroke.weight = options.weight + 'px';
9763
			stroke.color = options.color;
9764
			stroke.opacity = options.opacity;
9765
9766
			if (options.dashArray) {
9767
				stroke.dashStyle = L.Util.isArray(options.dashArray) ?
9768
				    options.dashArray.join(' ') :
9769
				    options.dashArray.replace(/( *, *)/g, ' ');
9770
			} else {
9771
				stroke.dashStyle = '';
9772
			}
9773
			stroke.endcap = options.lineCap.replace('butt', 'flat');
9774
			stroke.joinstyle = options.lineJoin;
9775
9776
		} else if (stroke) {
9777
			container.removeChild(stroke);
9778
			layer._stroke = null;
9779
		}
9780
9781
		if (options.fill) {
9782
			if (!fill) {
9783
				fill = layer._fill = L.SVG.create('fill');
9784
			}
9785
			container.appendChild(fill);
9786
			fill.color = options.fillColor || options.color;
9787
			fill.opacity = options.fillOpacity;
9788
9789
		} else if (fill) {
9790
			container.removeChild(fill);
9791
			layer._fill = null;
9792
		}
9793
	},
9794
9795
	_updateCircle: function (layer) {
9796
		var p = layer._point.round(),
9797
		    r = Math.round(layer._radius),
9798
		    r2 = Math.round(layer._radiusY || r);
9799
9800
		this._setPath(layer, layer._empty() ? 'M0 0' :
9801
				'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
9802
	},
9803
9804
	_setPath: function (layer, path) {
9805
		layer._path.v = path;
9806
	},
9807
9808
	_bringToFront: function (layer) {
9809
		L.DomUtil.toFront(layer._container);
9810
	},
9811
9812
	_bringToBack: function (layer) {
9813
		L.DomUtil.toBack(layer._container);
9814
	}
9815
});
9816
9817
if (L.Browser.vml) {
9818
	L.SVG.create = (function () {
9819
		try {
9820
			document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
9821
			return function (name) {
9822
				return document.createElement('<lvml:' + name + ' class="lvml">');
9823
			};
9824
		} catch (e) {
9825
			return function (name) {
9826
				return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
9827
			};
9828
		}
9829
	})();
9830
}
9831
9832
9833
9834
/*
9835
 * @class Canvas
9836
 * @inherits Renderer
9837
 * @aka L.Canvas
9838
 *
9839
 * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
9840
 * Inherits `Renderer`.
9841
 *
9842
 * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
9843
 * available in all web browsers, notably IE8, and overlapping geometries might
9844
 * not display properly in some edge cases.
9845
 *
9846
 * @example
9847
 *
9848
 * Use Canvas by default for all paths in the map:
9849
 *
9850
 * ```js
9851
 * var map = L.map('map', {
9852
 * 	renderer: L.canvas()
9853
 * });
9854
 * ```
9855
 *
9856
 * Use a Canvas renderer with extra padding for specific vector geometries:
9857
 *
9858
 * ```js
9859
 * var map = L.map('map');
9860
 * var myRenderer = L.canvas({ padding: 0.5 });
9861
 * var line = L.polyline( coordinates, { renderer: myRenderer } );
9862
 * var circle = L.circle( center, { renderer: myRenderer } );
9863
 * ```
9864
 */
9865
9866
L.Canvas = L.Renderer.extend({
9867
	getEvents: function () {
9868
		var events = L.Renderer.prototype.getEvents.call(this);
9869
		events.viewprereset = this._onViewPreReset;
9870
		return events;
9871
	},
9872
9873
	_onViewPreReset: function () {
9874
		// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once
9875
		this._postponeUpdatePaths = true;
9876
	},
9877
9878
	onAdd: function () {
9879
		L.Renderer.prototype.onAdd.call(this);
9880
9881
		// Redraw vectors since canvas is cleared upon removal,
9882
		// in case of removing the renderer itself from the map.
9883
		this._draw();
9884
	},
9885
9886
	_initContainer: function () {
9887
		var container = this._container = document.createElement('canvas');
9888
9889
		L.DomEvent
9890
			.on(container, 'mousemove', L.Util.throttle(this._onMouseMove, 32, this), this)
9891
			.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)
9892
			.on(container, 'mouseout', this._handleMouseOut, this);
9893
9894
		this._ctx = container.getContext('2d');
9895
	},
9896
9897
	_updatePaths: function () {
9898
		if (this._postponeUpdatePaths) { return; }
9899
9900
		var layer;
9901
		this._redrawBounds = null;
9902
		for (var id in this._layers) {
9903
			layer = this._layers[id];
9904
			layer._update();
9905
		}
9906
		this._redraw();
9907
	},
9908
9909
	_update: function () {
9910
		if (this._map._animatingZoom && this._bounds) { return; }
9911
9912
		this._drawnLayers = {};
9913
9914
		L.Renderer.prototype._update.call(this);
9915
9916
		var b = this._bounds,
9917
		    container = this._container,
9918
		    size = b.getSize(),
9919
		    m = L.Browser.retina ? 2 : 1;
9920
9921
		L.DomUtil.setPosition(container, b.min);
9922
9923
		// set canvas size (also clearing it); use double size on retina
9924
		container.width = m * size.x;
9925
		container.height = m * size.y;
9926
		container.style.width = size.x + 'px';
9927
		container.style.height = size.y + 'px';
9928
9929
		if (L.Browser.retina) {
9930
			this._ctx.scale(2, 2);
9931
		}
9932
9933
		// translate so we use the same path coordinates after canvas element moves
9934
		this._ctx.translate(-b.min.x, -b.min.y);
9935
9936
		// Tell paths to redraw themselves
9937
		this.fire('update');
9938
	},
9939
9940
	_reset: function () {
9941
		L.Renderer.prototype._reset.call(this);
9942
9943
		if (this._postponeUpdatePaths) {
9944
			this._postponeUpdatePaths = false;
9945
			this._updatePaths();
9946
		}
9947
	},
9948
9949
	_initPath: function (layer) {
9950
		this._updateDashArray(layer);
9951
		this._layers[L.stamp(layer)] = layer;
9952
9953
		var order = layer._order = {
9954
			layer: layer,
9955
			prev: this._drawLast,
9956
			next: null
9957
		};
9958
		if (this._drawLast) { this._drawLast.next = order; }
9959
		this._drawLast = order;
9960
		this._drawFirst = this._drawFirst || this._drawLast;
9961
	},
9962
9963
	_addPath: function (layer) {
9964
		this._requestRedraw(layer);
9965
	},
9966
9967
	_removePath: function (layer) {
9968
		var order = layer._order;
9969
		var next = order.next;
9970
		var prev = order.prev;
9971
9972
		if (next) {
9973
			next.prev = prev;
9974
		} else {
9975
			this._drawLast = prev;
9976
		}
9977
		if (prev) {
9978
			prev.next = next;
9979
		} else {
9980
			this._drawFirst = next;
9981
		}
9982
9983
		delete layer._order;
9984
9985
		delete this._layers[L.stamp(layer)];
9986
9987
		this._requestRedraw(layer);
9988
	},
9989
9990
	_updatePath: function (layer) {
9991
		// Redraw the union of the layer's old pixel
9992
		// bounds and the new pixel bounds.
9993
		this._extendRedrawBounds(layer);
9994
		layer._project();
9995
		layer._update();
9996
		// The redraw will extend the redraw bounds
9997
		// with the new pixel bounds.
9998
		this._requestRedraw(layer);
9999
	},
10000
10001
	_updateStyle: function (layer) {
10002
		this._updateDashArray(layer);
10003
		this._requestRedraw(layer);
10004
	},
10005
10006
	_updateDashArray: function (layer) {
10007
		if (layer.options.dashArray) {
10008
			var parts = layer.options.dashArray.split(','),
10009
			    dashArray = [],
10010
			    i;
10011
			for (i = 0; i < parts.length; i++) {
10012
				dashArray.push(Number(parts[i]));
10013
			}
10014
			layer.options._dashArray = dashArray;
10015
		}
10016
	},
10017
10018
	_requestRedraw: function (layer) {
10019
		if (!this._map) { return; }
10020
10021
		this._extendRedrawBounds(layer);
10022
		this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._redraw, this);
10023
	},
10024
10025
	_extendRedrawBounds: function (layer) {
10026
		var padding = (layer.options.weight || 0) + 1;
10027
		this._redrawBounds = this._redrawBounds || new L.Bounds();
10028
		this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
10029
		this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
10030
	},
10031
10032
	_redraw: function () {
10033
		this._redrawRequest = null;
10034
10035
		if (this._redrawBounds) {
10036
			this._redrawBounds.min._floor();
10037
			this._redrawBounds.max._ceil();
10038
		}
10039
10040
		this._clear(); // clear layers in redraw bounds
10041
		this._draw(); // draw layers
10042
10043
		this._redrawBounds = null;
10044
	},
10045
10046
	_clear: function () {
10047
		var bounds = this._redrawBounds;
10048
		if (bounds) {
10049
			var size = bounds.getSize();
10050
			this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
10051
		} else {
10052
			this._ctx.clearRect(0, 0, this._container.width, this._container.height);
10053
		}
10054
	},
10055
10056
	_draw: function () {
10057
		var layer, bounds = this._redrawBounds;
10058
		this._ctx.save();
10059
		if (bounds) {
10060
			var size = bounds.getSize();
10061
			this._ctx.beginPath();
10062
			this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
10063
			this._ctx.clip();
10064
		}
10065
10066
		this._drawing = true;
10067
10068
		for (var order = this._drawFirst; order; order = order.next) {
10069
			layer = order.layer;
10070
			if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
10071
				layer._updatePath();
10072
			}
10073
		}
10074
10075
		this._drawing = false;
10076
10077
		this._ctx.restore();  // Restore state before clipping.
10078
	},
10079
10080
	_updatePoly: function (layer, closed) {
10081
		if (!this._drawing) { return; }
10082
10083
		var i, j, len2, p,
10084
		    parts = layer._parts,
10085
		    len = parts.length,
10086
		    ctx = this._ctx;
10087
10088
		if (!len) { return; }
10089
10090
		this._drawnLayers[layer._leaflet_id] = layer;
10091
10092
		ctx.beginPath();
10093
10094
		if (ctx.setLineDash) {
10095
			ctx.setLineDash(layer.options && layer.options._dashArray || []);
10096
		}
10097
10098
		for (i = 0; i < len; i++) {
10099
			for (j = 0, len2 = parts[i].length; j < len2; j++) {
10100
				p = parts[i][j];
10101
				ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
10102
			}
10103
			if (closed) {
10104
				ctx.closePath();
10105
			}
10106
		}
10107
10108
		this._fillStroke(ctx, layer);
10109
10110
		// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
10111
	},
10112
10113
	_updateCircle: function (layer) {
10114
10115
		if (!this._drawing || layer._empty()) { return; }
10116
10117
		var p = layer._point,
10118
		    ctx = this._ctx,
10119
		    r = layer._radius,
10120
		    s = (layer._radiusY || r) / r;
10121
10122
		this._drawnLayers[layer._leaflet_id] = layer;
10123
10124
		if (s !== 1) {
10125
			ctx.save();
10126
			ctx.scale(1, s);
10127
		}
10128
10129
		ctx.beginPath();
10130
		ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
10131
10132
		if (s !== 1) {
10133
			ctx.restore();
10134
		}
10135
10136
		this._fillStroke(ctx, layer);
10137
	},
10138
10139
	_fillStroke: function (ctx, layer) {
10140
		var options = layer.options;
10141
10142
		if (options.fill) {
10143
			ctx.globalAlpha = options.fillOpacity;
10144
			ctx.fillStyle = options.fillColor || options.color;
10145
			ctx.fill(options.fillRule || 'evenodd');
10146
		}
10147
10148
		if (options.stroke && options.weight !== 0) {
10149
			ctx.globalAlpha = options.opacity;
10150
			ctx.lineWidth = options.weight;
10151
			ctx.strokeStyle = options.color;
10152
			ctx.lineCap = options.lineCap;
10153
			ctx.lineJoin = options.lineJoin;
10154
			ctx.stroke();
10155
		}
10156
	},
10157
10158
	// Canvas obviously doesn't have mouse events for individual drawn objects,
10159
	// so we emulate that by calculating what's under the mouse on mousemove/click manually
10160
10161
	_onClick: function (e) {
10162
		var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
10163
10164
		for (var order = this._drawFirst; order; order = order.next) {
10165
			layer = order.layer;
10166
			if (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {
10167
				clickedLayer = layer;
10168
			}
10169
		}
10170
		if (clickedLayer)  {
10171
			L.DomEvent._fakeStop(e);
10172
			this._fireEvent([clickedLayer], e);
10173
		}
10174
	},
10175
10176
	_onMouseMove: function (e) {
10177
		if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
10178
10179
		var point = this._map.mouseEventToLayerPoint(e);
10180
		this._handleMouseHover(e, point);
10181
	},
10182
10183
10184
	_handleMouseOut: function (e) {
10185
		var layer = this._hoveredLayer;
10186
		if (layer) {
10187
			// if we're leaving the layer, fire mouseout
10188
			L.DomUtil.removeClass(this._container, 'leaflet-interactive');
10189
			this._fireEvent([layer], e, 'mouseout');
10190
			this._hoveredLayer = null;
10191
		}
10192
	},
10193
10194
	_handleMouseHover: function (e, point) {
10195
		var layer, candidateHoveredLayer;
10196
10197
		for (var order = this._drawFirst; order; order = order.next) {
10198
			layer = order.layer;
10199
			if (layer.options.interactive && layer._containsPoint(point)) {
10200
				candidateHoveredLayer = layer;
10201
			}
10202
		}
10203
10204
		if (candidateHoveredLayer !== this._hoveredLayer) {
10205
			this._handleMouseOut(e);
10206
10207
			if (candidateHoveredLayer) {
10208
				L.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
10209
				this._fireEvent([candidateHoveredLayer], e, 'mouseover');
10210
				this._hoveredLayer = candidateHoveredLayer;
10211
			}
10212
		}
10213
10214
		if (this._hoveredLayer) {
10215
			this._fireEvent([this._hoveredLayer], e);
10216
		}
10217
	},
10218
10219
	_fireEvent: function (layers, e, type) {
10220
		this._map._fireDOMEvent(e, type || e.type, layers);
10221
	},
10222
10223
	_bringToFront: function (layer) {
10224
		var order = layer._order;
10225
		var next = order.next;
10226
		var prev = order.prev;
10227
10228
		if (next) {
10229
			next.prev = prev;
10230
		} else {
10231
			// Already last
10232
			return;
10233
		}
10234
		if (prev) {
10235
			prev.next = next;
10236
		} else if (next) {
10237
			// Update first entry unless this is the
10238
			// signle entry
10239
			this._drawFirst = next;
10240
		}
10241
10242
		order.prev = this._drawLast;
10243
		this._drawLast.next = order;
10244
10245
		order.next = null;
10246
		this._drawLast = order;
10247
10248
		this._requestRedraw(layer);
10249
	},
10250
10251
	_bringToBack: function (layer) {
10252
		var order = layer._order;
10253
		var next = order.next;
10254
		var prev = order.prev;
10255
10256
		if (prev) {
10257
			prev.next = next;
10258
		} else {
10259
			// Already first
10260
			return;
10261
		}
10262
		if (next) {
10263
			next.prev = prev;
10264
		} else if (prev) {
10265
			// Update last entry unless this is the
10266
			// signle entry
10267
			this._drawLast = prev;
10268
		}
10269
10270
		order.prev = null;
10271
10272
		order.next = this._drawFirst;
10273
		this._drawFirst.prev = order;
10274
		this._drawFirst = order;
10275
10276
		this._requestRedraw(layer);
10277
	}
10278
});
10279
10280
// @namespace Browser; @property canvas: Boolean
10281
// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
10282
L.Browser.canvas = (function () {
10283
	return !!document.createElement('canvas').getContext;
10284
}());
10285
10286
// @namespace Canvas
10287
// @factory L.canvas(options?: Renderer options)
10288
// Creates a Canvas renderer with the given options.
10289
L.canvas = function (options) {
10290
	return L.Browser.canvas ? new L.Canvas(options) : null;
10291
};
10292
10293
L.Polyline.prototype._containsPoint = function (p, closed) {
10294
	var i, j, k, len, len2, part,
10295
	    w = this._clickTolerance();
10296
10297
	if (!this._pxBounds.contains(p)) { return false; }
10298
10299
	// hit detection for polylines
10300
	for (i = 0, len = this._parts.length; i < len; i++) {
10301
		part = this._parts[i];
10302
10303
		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
10304
			if (!closed && (j === 0)) { continue; }
10305
10306
			if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
10307
				return true;
10308
			}
10309
		}
10310
	}
10311
	return false;
10312
};
10313
10314
L.Polygon.prototype._containsPoint = function (p) {
10315
	var inside = false,
10316
	    part, p1, p2, i, j, k, len, len2;
10317
10318
	if (!this._pxBounds.contains(p)) { return false; }
10319
10320
	// ray casting algorithm for detecting if point is in polygon
10321
	for (i = 0, len = this._parts.length; i < len; i++) {
10322
		part = this._parts[i];
10323
10324
		for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
10325
			p1 = part[j];
10326
			p2 = part[k];
10327
10328
			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)) {
10329
				inside = !inside;
10330
			}
10331
		}
10332
	}
10333
10334
	// also check if it's on polygon stroke
10335
	return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
10336
};
10337
10338
L.CircleMarker.prototype._containsPoint = function (p) {
10339
	return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
10340
};
10341
10342
10343
10344
/*
10345
 * @class GeoJSON
10346
 * @aka L.GeoJSON
10347
 * @inherits FeatureGroup
10348
 *
10349
 * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
10350
 * GeoJSON data and display it on the map. Extends `FeatureGroup`.
10351
 *
10352
 * @example
10353
 *
10354
 * ```js
10355
 * L.geoJSON(data, {
10356
 * 	style: function (feature) {
10357
 * 		return {color: feature.properties.color};
10358
 * 	}
10359
 * }).bindPopup(function (layer) {
10360
 * 	return layer.feature.properties.description;
10361
 * }).addTo(map);
10362
 * ```
10363
 */
10364
10365
L.GeoJSON = L.FeatureGroup.extend({
10366
10367
	/* @section
10368
	 * @aka GeoJSON options
10369
	 *
10370
	 * @option pointToLayer: Function = *
10371
	 * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
10372
	 * called when data is added, passing the GeoJSON point feature and its `LatLng`.
10373
	 * The default is to spawn a default `Marker`:
10374
	 * ```js
10375
	 * function(geoJsonPoint, latlng) {
10376
	 * 	return L.marker(latlng);
10377
	 * }
10378
	 * ```
10379
	 *
10380
	 * @option style: Function = *
10381
	 * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
10382
	 * called internally when data is added.
10383
	 * The default value is to not override any defaults:
10384
	 * ```js
10385
	 * function (geoJsonFeature) {
10386
	 * 	return {}
10387
	 * }
10388
	 * ```
10389
	 *
10390
	 * @option onEachFeature: Function = *
10391
	 * A `Function` that will be called once for each created `Feature`, after it has
10392
	 * been created and styled. Useful for attaching events and popups to features.
10393
	 * The default is to do nothing with the newly created layers:
10394
	 * ```js
10395
	 * function (feature, layer) {}
10396
	 * ```
10397
	 *
10398
	 * @option filter: Function = *
10399
	 * A `Function` that will be used to decide whether to include a feature or not.
10400
	 * The default is to include all features:
10401
	 * ```js
10402
	 * function (geoJsonFeature) {
10403
	 * 	return true;
10404
	 * }
10405
	 * ```
10406
	 * Note: dynamically changing the `filter` option will have effect only on newly
10407
	 * added data. It will _not_ re-evaluate already included features.
10408
	 *
10409
	 * @option coordsToLatLng: Function = *
10410
	 * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
10411
	 * The default is the `coordsToLatLng` static method.
10412
	 */
10413
10414
	initialize: function (geojson, options) {
10415
		L.setOptions(this, options);
10416
10417
		this._layers = {};
10418
10419
		if (geojson) {
10420
			this.addData(geojson);
10421
		}
10422
	},
10423
10424
	// @method addData( <GeoJSON> data ): this
10425
	// Adds a GeoJSON object to the layer.
10426
	addData: function (geojson) {
10427
		var features = L.Util.isArray(geojson) ? geojson : geojson.features,
10428
		    i, len, feature;
10429
10430
		if (features) {
10431
			for (i = 0, len = features.length; i < len; i++) {
10432
				// only add this if geometry or geometries are set and not null
10433
				feature = features[i];
10434
				if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
10435
					this.addData(feature);
10436
				}
10437
			}
10438
			return this;
10439
		}
10440
10441
		var options = this.options;
10442
10443
		if (options.filter && !options.filter(geojson)) { return this; }
10444
10445
		var layer = L.GeoJSON.geometryToLayer(geojson, options);
10446
		if (!layer) {
10447
			return this;
10448
		}
10449
		layer.feature = L.GeoJSON.asFeature(geojson);
10450
10451
		layer.defaultOptions = layer.options;
10452
		this.resetStyle(layer);
10453
10454
		if (options.onEachFeature) {
10455
			options.onEachFeature(geojson, layer);
10456
		}
10457
10458
		return this.addLayer(layer);
10459
	},
10460
10461
	// @method resetStyle( <Path> layer ): this
10462
	// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
10463
	resetStyle: function (layer) {
10464
		// reset any custom styles
10465
		layer.options = L.Util.extend({}, layer.defaultOptions);
10466
		this._setLayerStyle(layer, this.options.style);
10467
		return this;
10468
	},
10469
10470
	// @method setStyle( <Function> style ): this
10471
	// Changes styles of GeoJSON vector layers with the given style function.
10472
	setStyle: function (style) {
10473
		return this.eachLayer(function (layer) {
10474
			this._setLayerStyle(layer, style);
10475
		}, this);
10476
	},
10477
10478
	_setLayerStyle: function (layer, style) {
10479
		if (typeof style === 'function') {
10480
			style = style(layer.feature);
10481
		}
10482
		if (layer.setStyle) {
10483
			layer.setStyle(style);
10484
		}
10485
	}
10486
});
10487
10488
// @section
10489
// There are several static functions which can be called without instantiating L.GeoJSON:
10490
L.extend(L.GeoJSON, {
10491
	// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
10492
	// Creates a `Layer` from a given GeoJSON feature. Can use a custom
10493
	// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
10494
	// functions if provided as options.
10495
	geometryToLayer: function (geojson, options) {
10496
10497
		var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
10498
		    coords = geometry ? geometry.coordinates : null,
10499
		    layers = [],
10500
		    pointToLayer = options && options.pointToLayer,
10501
		    coordsToLatLng = options && options.coordsToLatLng || this.coordsToLatLng,
10502
		    latlng, latlngs, i, len;
10503
10504
		if (!coords && !geometry) {
10505
			return null;
10506
		}
10507
10508
		switch (geometry.type) {
10509
		case 'Point':
10510
			latlng = coordsToLatLng(coords);
10511
			return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);
10512
10513
		case 'MultiPoint':
10514
			for (i = 0, len = coords.length; i < len; i++) {
10515
				latlng = coordsToLatLng(coords[i]);
10516
				layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));
10517
			}
10518
			return new L.FeatureGroup(layers);
10519
10520
		case 'LineString':
10521
		case 'MultiLineString':
10522
			latlngs = this.coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, coordsToLatLng);
10523
			return new L.Polyline(latlngs, options);
10524
10525
		case 'Polygon':
10526
		case 'MultiPolygon':
10527
			latlngs = this.coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, coordsToLatLng);
10528
			return new L.Polygon(latlngs, options);
10529
10530
		case 'GeometryCollection':
10531
			for (i = 0, len = geometry.geometries.length; i < len; i++) {
10532
				var layer = this.geometryToLayer({
10533
					geometry: geometry.geometries[i],
10534
					type: 'Feature',
10535
					properties: geojson.properties
10536
				}, options);
10537
10538
				if (layer) {
10539
					layers.push(layer);
10540
				}
10541
			}
10542
			return new L.FeatureGroup(layers);
10543
10544
		default:
10545
			throw new Error('Invalid GeoJSON object.');
10546
		}
10547
	},
10548
10549
	// @function coordsToLatLng(coords: Array): LatLng
10550
	// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
10551
	// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
10552
	coordsToLatLng: function (coords) {
10553
		return new L.LatLng(coords[1], coords[0], coords[2]);
10554
	},
10555
10556
	// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
10557
	// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
10558
	// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
10559
	// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
10560
	coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) {
10561
		var latlngs = [];
10562
10563
		for (var i = 0, len = coords.length, latlng; i < len; i++) {
10564
			latlng = levelsDeep ?
10565
			        this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) :
10566
			        (coordsToLatLng || this.coordsToLatLng)(coords[i]);
10567
10568
			latlngs.push(latlng);
10569
		}
10570
10571
		return latlngs;
10572
	},
10573
10574
	// @function latLngToCoords(latlng: LatLng): Array
10575
	// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
10576
	latLngToCoords: function (latlng) {
10577
		return latlng.alt !== undefined ?
10578
				[latlng.lng, latlng.lat, latlng.alt] :
10579
				[latlng.lng, latlng.lat];
10580
	},
10581
10582
	// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
10583
	// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
10584
	// `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.
10585
	latLngsToCoords: function (latlngs, levelsDeep, closed) {
10586
		var coords = [];
10587
10588
		for (var i = 0, len = latlngs.length; i < len; i++) {
10589
			coords.push(levelsDeep ?
10590
				L.GeoJSON.latLngsToCoords(latlngs[i], levelsDeep - 1, closed) :
10591
				L.GeoJSON.latLngToCoords(latlngs[i]));
10592
		}
10593
10594
		if (!levelsDeep && closed) {
10595
			coords.push(coords[0]);
10596
		}
10597
10598
		return coords;
10599
	},
10600
10601
	getFeature: function (layer, newGeometry) {
10602
		return layer.feature ?
10603
				L.extend({}, layer.feature, {geometry: newGeometry}) :
10604
				L.GeoJSON.asFeature(newGeometry);
10605
	},
10606
10607
	// @function asFeature(geojson: Object): Object
10608
	// Normalize GeoJSON geometries/features into GeoJSON features.
10609
	asFeature: function (geojson) {
10610
		if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
10611
			return geojson;
10612
		}
10613
10614
		return {
10615
			type: 'Feature',
10616
			properties: {},
10617
			geometry: geojson
10618
		};
10619
	}
10620
});
10621
10622
var PointToGeoJSON = {
10623
	toGeoJSON: function () {
10624
		return L.GeoJSON.getFeature(this, {
10625
			type: 'Point',
10626
			coordinates: L.GeoJSON.latLngToCoords(this.getLatLng())
10627
		});
10628
	}
10629
};
10630
10631
// @namespace Marker
10632
// @method toGeoJSON(): Object
10633
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
10634
L.Marker.include(PointToGeoJSON);
10635
10636
// @namespace CircleMarker
10637
// @method toGeoJSON(): Object
10638
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
10639
L.Circle.include(PointToGeoJSON);
10640
L.CircleMarker.include(PointToGeoJSON);
10641
10642
10643
// @namespace Polyline
10644
// @method toGeoJSON(): Object
10645
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
10646
L.Polyline.prototype.toGeoJSON = function () {
10647
	var multi = !L.Polyline._flat(this._latlngs);
10648
10649
	var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);
10650
10651
	return L.GeoJSON.getFeature(this, {
10652
		type: (multi ? 'Multi' : '') + 'LineString',
10653
		coordinates: coords
10654
	});
10655
};
10656
10657
// @namespace Polygon
10658
// @method toGeoJSON(): Object
10659
// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
10660
L.Polygon.prototype.toGeoJSON = function () {
10661
	var holes = !L.Polyline._flat(this._latlngs),
10662
	    multi = holes && !L.Polyline._flat(this._latlngs[0]);
10663
10664
	var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true);
10665
10666
	if (!holes) {
10667
		coords = [coords];
10668
	}
10669
10670
	return L.GeoJSON.getFeature(this, {
10671
		type: (multi ? 'Multi' : '') + 'Polygon',
10672
		coordinates: coords
10673
	});
10674
};
10675
10676
10677
// @namespace LayerGroup
10678
L.LayerGroup.include({
10679
	toMultiPoint: function () {
10680
		var coords = [];
10681
10682
		this.eachLayer(function (layer) {
10683
			coords.push(layer.toGeoJSON().geometry.coordinates);
10684
		});
10685
10686
		return L.GeoJSON.getFeature(this, {
10687
			type: 'MultiPoint',
10688
			coordinates: coords
10689
		});
10690
	},
10691
10692
	// @method toGeoJSON(): Object
10693
	// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `GeometryCollection`).
10694
	toGeoJSON: function () {
10695
10696
		var type = this.feature && this.feature.geometry && this.feature.geometry.type;
10697
10698
		if (type === 'MultiPoint') {
10699
			return this.toMultiPoint();
10700
		}
10701
10702
		var isGeometryCollection = type === 'GeometryCollection',
10703
		    jsons = [];
10704
10705
		this.eachLayer(function (layer) {
10706
			if (layer.toGeoJSON) {
10707
				var json = layer.toGeoJSON();
10708
				jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
10709
			}
10710
		});
10711
10712
		if (isGeometryCollection) {
10713
			return L.GeoJSON.getFeature(this, {
10714
				geometries: jsons,
10715
				type: 'GeometryCollection'
10716
			});
10717
		}
10718
10719
		return {
10720
			type: 'FeatureCollection',
10721
			features: jsons
10722
		};
10723
	}
10724
});
10725
10726
// @namespace GeoJSON
10727
// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
10728
// Creates a GeoJSON layer. Optionally accepts an object in
10729
// [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map
10730
// (you can alternatively add it later with `addData` method) and an `options` object.
10731
L.geoJSON = function (geojson, options) {
10732
	return new L.GeoJSON(geojson, options);
10733
};
10734
// Backward compatibility.
10735
L.geoJson = L.geoJSON;
10736
10737
10738
10739
/*
10740
 * @class Draggable
10741
 * @aka L.Draggable
10742
 * @inherits Evented
10743
 *
10744
 * A class for making DOM elements draggable (including touch support).
10745
 * Used internally for map and marker dragging. Only works for elements
10746
 * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
10747
 *
10748
 * @example
10749
 * ```js
10750
 * var draggable = new L.Draggable(elementToDrag);
10751
 * draggable.enable();
10752
 * ```
10753
 */
10754
10755
L.Draggable = L.Evented.extend({
10756
10757
	options: {
10758
		// @option clickTolerance: Number = 3
10759
		// The max number of pixels a user can shift the mouse pointer during a click
10760
		// for it to be considered a valid click (as opposed to a mouse drag).
10761
		clickTolerance: 3
10762
	},
10763
10764
	statics: {
10765
		START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
10766
		END: {
10767
			mousedown: 'mouseup',
10768
			touchstart: 'touchend',
10769
			pointerdown: 'touchend',
10770
			MSPointerDown: 'touchend'
10771
		},
10772
		MOVE: {
10773
			mousedown: 'mousemove',
10774
			touchstart: 'touchmove',
10775
			pointerdown: 'touchmove',
10776
			MSPointerDown: 'touchmove'
10777
		}
10778
	},
10779
10780
	// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline: Boolean)
10781
	// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
10782
	initialize: function (element, dragStartTarget, preventOutline) {
10783
		this._element = element;
10784
		this._dragStartTarget = dragStartTarget || element;
10785
		this._preventOutline = preventOutline;
10786
	},
10787
10788
	// @method enable()
10789
	// Enables the dragging ability
10790
	enable: function () {
10791
		if (this._enabled) { return; }
10792
10793
		L.DomEvent.on(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);
10794
10795
		this._enabled = true;
10796
	},
10797
10798
	// @method disable()
10799
	// Disables the dragging ability
10800
	disable: function () {
10801
		if (!this._enabled) { return; }
10802
10803
		// If we're currently dragging this draggable,
10804
		// disabling it counts as first ending the drag.
10805
		if (L.Draggable._dragging === this) {
10806
			this.finishDrag();
10807
		}
10808
10809
		L.DomEvent.off(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);
10810
10811
		this._enabled = false;
10812
		this._moved = false;
10813
	},
10814
10815
	_onDown: function (e) {
10816
		// Ignore simulated events, since we handle both touch and
10817
		// mouse explicitly; otherwise we risk getting duplicates of
10818
		// touch events, see #4315.
10819
		// Also ignore the event if disabled; this happens in IE11
10820
		// under some circumstances, see #3666.
10821
		if (e._simulated || !this._enabled) { return; }
10822
10823
		this._moved = false;
10824
10825
		if (L.DomUtil.hasClass(this._element, 'leaflet-zoom-anim')) { return; }
10826
10827
		if (L.Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
10828
		L.Draggable._dragging = this;  // Prevent dragging multiple objects at once.
10829
10830
		if (this._preventOutline) {
10831
			L.DomUtil.preventOutline(this._element);
10832
		}
10833
10834
		L.DomUtil.disableImageDrag();
10835
		L.DomUtil.disableTextSelection();
10836
10837
		if (this._moving) { return; }
10838
10839
		// @event down: Event
10840
		// Fired when a drag is about to start.
10841
		this.fire('down');
10842
10843
		var first = e.touches ? e.touches[0] : e;
10844
10845
		this._startPoint = new L.Point(first.clientX, first.clientY);
10846
10847
		L.DomEvent
10848
			.on(document, L.Draggable.MOVE[e.type], this._onMove, this)
10849
			.on(document, L.Draggable.END[e.type], this._onUp, this);
10850
	},
10851
10852
	_onMove: function (e) {
10853
		// Ignore simulated events, since we handle both touch and
10854
		// mouse explicitly; otherwise we risk getting duplicates of
10855
		// touch events, see #4315.
10856
		// Also ignore the event if disabled; this happens in IE11
10857
		// under some circumstances, see #3666.
10858
		if (e._simulated || !this._enabled) { return; }
10859
10860
		if (e.touches && e.touches.length > 1) {
10861
			this._moved = true;
10862
			return;
10863
		}
10864
10865
		var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
10866
		    newPoint = new L.Point(first.clientX, first.clientY),
10867
		    offset = newPoint.subtract(this._startPoint);
10868
10869
		if (!offset.x && !offset.y) { return; }
10870
		if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
10871
10872
		L.DomEvent.preventDefault(e);
10873
10874
		if (!this._moved) {
10875
			// @event dragstart: Event
10876
			// Fired when a drag starts
10877
			this.fire('dragstart');
10878
10879
			this._moved = true;
10880
			this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
10881
10882
			L.DomUtil.addClass(document.body, 'leaflet-dragging');
10883
10884
			this._lastTarget = e.target || e.srcElement;
10885
			// IE and Edge do not give the <use> element, so fetch it
10886
			// if necessary
10887
			if ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) {
10888
				this._lastTarget = this._lastTarget.correspondingUseElement;
10889
			}
10890
			L.DomUtil.addClass(this._lastTarget, 'leaflet-drag-target');
10891
		}
10892
10893
		this._newPos = this._startPos.add(offset);
10894
		this._moving = true;
10895
10896
		L.Util.cancelAnimFrame(this._animRequest);
10897
		this._lastEvent = e;
10898
		this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true);
10899
	},
10900
10901
	_updatePosition: function () {
10902
		var e = {originalEvent: this._lastEvent};
10903
10904
		// @event predrag: Event
10905
		// Fired continuously during dragging *before* each corresponding
10906
		// update of the element's position.
10907
		this.fire('predrag', e);
10908
		L.DomUtil.setPosition(this._element, this._newPos);
10909
10910
		// @event drag: Event
10911
		// Fired continuously during dragging.
10912
		this.fire('drag', e);
10913
	},
10914
10915
	_onUp: function (e) {
10916
		// Ignore simulated events, since we handle both touch and
10917
		// mouse explicitly; otherwise we risk getting duplicates of
10918
		// touch events, see #4315.
10919
		// Also ignore the event if disabled; this happens in IE11
10920
		// under some circumstances, see #3666.
10921
		if (e._simulated || !this._enabled) { return; }
10922
		this.finishDrag();
10923
	},
10924
10925
	finishDrag: function () {
10926
		L.DomUtil.removeClass(document.body, 'leaflet-dragging');
10927
10928
		if (this._lastTarget) {
10929
			L.DomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');
10930
			this._lastTarget = null;
10931
		}
10932
10933
		for (var i in L.Draggable.MOVE) {
10934
			L.DomEvent
10935
				.off(document, L.Draggable.MOVE[i], this._onMove, this)
10936
				.off(document, L.Draggable.END[i], this._onUp, this);
10937
		}
10938
10939
		L.DomUtil.enableImageDrag();
10940
		L.DomUtil.enableTextSelection();
10941
10942
		if (this._moved && this._moving) {
10943
			// ensure drag is not fired after dragend
10944
			L.Util.cancelAnimFrame(this._animRequest);
10945
10946
			// @event dragend: DragEndEvent
10947
			// Fired when the drag ends.
10948
			this.fire('dragend', {
10949
				distance: this._newPos.distanceTo(this._startPos)
10950
			});
10951
		}
10952
10953
		this._moving = false;
10954
		L.Draggable._dragging = false;
10955
	}
10956
10957
});
10958
10959
10960
10961
/*
10962
	L.Handler is a base class for handler classes that are used internally to inject
10963
	interaction features like dragging to classes like Map and Marker.
10964
*/
10965
10966
// @class Handler
10967
// @aka L.Handler
10968
// Abstract class for map interaction handlers
10969
10970
L.Handler = L.Class.extend({
10971
	initialize: function (map) {
10972
		this._map = map;
10973
	},
10974
10975
	// @method enable(): this
10976
	// Enables the handler
10977
	enable: function () {
10978
		if (this._enabled) { return this; }
10979
10980
		this._enabled = true;
10981
		this.addHooks();
10982
		return this;
10983
	},
10984
10985
	// @method disable(): this
10986
	// Disables the handler
10987
	disable: function () {
10988
		if (!this._enabled) { return this; }
10989
10990
		this._enabled = false;
10991
		this.removeHooks();
10992
		return this;
10993
	},
10994
10995
	// @method enabled(): Boolean
10996
	// Returns `true` if the handler is enabled
10997
	enabled: function () {
10998
		return !!this._enabled;
10999
	}
11000
11001
	// @section Extension methods
11002
	// Classes inheriting from `Handler` must implement the two following methods:
11003
	// @method addHooks()
11004
	// Called when the handler is enabled, should add event hooks.
11005
	// @method removeHooks()
11006
	// Called when the handler is disabled, should remove the event hooks added previously.
11007
});
11008
11009
11010
11011
/*
11012
 * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
11013
 */
11014
11015
// @namespace Map
11016
// @section Interaction Options
11017
L.Map.mergeOptions({
11018
	// @option dragging: Boolean = true
11019
	// Whether the map be draggable with mouse/touch or not.
11020
	dragging: true,
11021
11022
	// @section Panning Inertia Options
11023
	// @option inertia: Boolean = *
11024
	// If enabled, panning of the map will have an inertia effect where
11025
	// the map builds momentum while dragging and continues moving in
11026
	// the same direction for some time. Feels especially nice on touch
11027
	// devices. Enabled by default unless running on old Android devices.
11028
	inertia: !L.Browser.android23,
11029
11030
	// @option inertiaDeceleration: Number = 3000
11031
	// The rate with which the inertial movement slows down, in pixels/second².
11032
	inertiaDeceleration: 3400, // px/s^2
11033
11034
	// @option inertiaMaxSpeed: Number = Infinity
11035
	// Max speed of the inertial movement, in pixels/second.
11036
	inertiaMaxSpeed: Infinity, // px/s
11037
11038
	// @option easeLinearity: Number = 0.2
11039
	easeLinearity: 0.2,
11040
11041
	// TODO refactor, move to CRS
11042
	// @option worldCopyJump: Boolean = false
11043
	// With this option enabled, the map tracks when you pan to another "copy"
11044
	// of the world and seamlessly jumps to the original one so that all overlays
11045
	// like markers and vector layers are still visible.
11046
	worldCopyJump: false,
11047
11048
	// @option maxBoundsViscosity: Number = 0.0
11049
	// If `maxBounds` is set, this option will control how solid the bounds
11050
	// are when dragging the map around. The default value of `0.0` allows the
11051
	// user to drag outside the bounds at normal speed, higher values will
11052
	// slow down map dragging outside bounds, and `1.0` makes the bounds fully
11053
	// solid, preventing the user from dragging outside the bounds.
11054
	maxBoundsViscosity: 0.0
11055
});
11056
11057
L.Map.Drag = L.Handler.extend({
11058
	addHooks: function () {
11059
		if (!this._draggable) {
11060
			var map = this._map;
11061
11062
			this._draggable = new L.Draggable(map._mapPane, map._container);
11063
11064
			this._draggable.on({
11065
				down: this._onDown,
11066
				dragstart: this._onDragStart,
11067
				drag: this._onDrag,
11068
				dragend: this._onDragEnd
11069
			}, this);
11070
11071
			this._draggable.on('predrag', this._onPreDragLimit, this);
11072
			if (map.options.worldCopyJump) {
11073
				this._draggable.on('predrag', this._onPreDragWrap, this);
11074
				map.on('zoomend', this._onZoomEnd, this);
11075
11076
				map.whenReady(this._onZoomEnd, this);
11077
			}
11078
		}
11079
		L.DomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
11080
		this._draggable.enable();
11081
		this._positions = [];
11082
		this._times = [];
11083
	},
11084
11085
	removeHooks: function () {
11086
		L.DomUtil.removeClass(this._map._container, 'leaflet-grab');
11087
		L.DomUtil.removeClass(this._map._container, 'leaflet-touch-drag');
11088
		this._draggable.disable();
11089
	},
11090
11091
	moved: function () {
11092
		return this._draggable && this._draggable._moved;
11093
	},
11094
11095
	moving: function () {
11096
		return this._draggable && this._draggable._moving;
11097
	},
11098
11099
	_onDown: function () {
11100
		this._map._stop();
11101
	},
11102
11103
	_onDragStart: function () {
11104
		var map = this._map;
11105
11106
		if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
11107
			var bounds = L.latLngBounds(this._map.options.maxBounds);
11108
11109
			this._offsetLimit = L.bounds(
11110
				this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
11111
				this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
11112
					.add(this._map.getSize()));
11113
11114
			this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
11115
		} else {
11116
			this._offsetLimit = null;
11117
		}
11118
11119
		map
11120
		    .fire('movestart')
11121
		    .fire('dragstart');
11122
11123
		if (map.options.inertia) {
11124
			this._positions = [];
11125
			this._times = [];
11126
		}
11127
	},
11128
11129
	_onDrag: function (e) {
11130
		if (this._map.options.inertia) {
11131
			var time = this._lastTime = +new Date(),
11132
			    pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
11133
11134
			this._positions.push(pos);
11135
			this._times.push(time);
11136
11137
			if (time - this._times[0] > 50) {
11138
				this._positions.shift();
11139
				this._times.shift();
11140
			}
11141
		}
11142
11143
		this._map
11144
		    .fire('move', e)
11145
		    .fire('drag', e);
11146
	},
11147
11148
	_onZoomEnd: function () {
11149
		var pxCenter = this._map.getSize().divideBy(2),
11150
		    pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
11151
11152
		this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
11153
		this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
11154
	},
11155
11156
	_viscousLimit: function (value, threshold) {
11157
		return value - (value - threshold) * this._viscosity;
11158
	},
11159
11160
	_onPreDragLimit: function () {
11161
		if (!this._viscosity || !this._offsetLimit) { return; }
11162
11163
		var offset = this._draggable._newPos.subtract(this._draggable._startPos);
11164
11165
		var limit = this._offsetLimit;
11166
		if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
11167
		if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
11168
		if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
11169
		if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
11170
11171
		this._draggable._newPos = this._draggable._startPos.add(offset);
11172
	},
11173
11174
	_onPreDragWrap: function () {
11175
		// TODO refactor to be able to adjust map pane position after zoom
11176
		var worldWidth = this._worldWidth,
11177
		    halfWidth = Math.round(worldWidth / 2),
11178
		    dx = this._initialWorldOffset,
11179
		    x = this._draggable._newPos.x,
11180
		    newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
11181
		    newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
11182
		    newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
11183
11184
		this._draggable._absPos = this._draggable._newPos.clone();
11185
		this._draggable._newPos.x = newX;
11186
	},
11187
11188
	_onDragEnd: function (e) {
11189
		var map = this._map,
11190
		    options = map.options,
11191
11192
		    noInertia = !options.inertia || this._times.length < 2;
11193
11194
		map.fire('dragend', e);
11195
11196
		if (noInertia) {
11197
			map.fire('moveend');
11198
11199
		} else {
11200
11201
			var direction = this._lastPos.subtract(this._positions[0]),
11202
			    duration = (this._lastTime - this._times[0]) / 1000,
11203
			    ease = options.easeLinearity,
11204
11205
			    speedVector = direction.multiplyBy(ease / duration),
11206
			    speed = speedVector.distanceTo([0, 0]),
11207
11208
			    limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
11209
			    limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
11210
11211
			    decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
11212
			    offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
11213
11214
			if (!offset.x && !offset.y) {
11215
				map.fire('moveend');
11216
11217
			} else {
11218
				offset = map._limitOffset(offset, map.options.maxBounds);
11219
11220
				L.Util.requestAnimFrame(function () {
11221
					map.panBy(offset, {
11222
						duration: decelerationDuration,
11223
						easeLinearity: ease,
11224
						noMoveStart: true,
11225
						animate: true
11226
					});
11227
				});
11228
			}
11229
		}
11230
	}
11231
});
11232
11233
// @section Handlers
11234
// @property dragging: Handler
11235
// Map dragging handler (by both mouse and touch).
11236
L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);
11237
11238
11239
11240
/*
11241
 * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
11242
 */
11243
11244
// @namespace Map
11245
// @section Interaction Options
11246
11247
L.Map.mergeOptions({
11248
	// @option doubleClickZoom: Boolean|String = true
11249
	// Whether the map can be zoomed in by double clicking on it and
11250
	// zoomed out by double clicking while holding shift. If passed
11251
	// `'center'`, double-click zoom will zoom to the center of the
11252
	//  view regardless of where the mouse was.
11253
	doubleClickZoom: true
11254
});
11255
11256
L.Map.DoubleClickZoom = L.Handler.extend({
11257
	addHooks: function () {
11258
		this._map.on('dblclick', this._onDoubleClick, this);
11259
	},
11260
11261
	removeHooks: function () {
11262
		this._map.off('dblclick', this._onDoubleClick, this);
11263
	},
11264
11265
	_onDoubleClick: function (e) {
11266
		var map = this._map,
11267
		    oldZoom = map.getZoom(),
11268
		    delta = map.options.zoomDelta,
11269
		    zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
11270
11271
		if (map.options.doubleClickZoom === 'center') {
11272
			map.setZoom(zoom);
11273
		} else {
11274
			map.setZoomAround(e.containerPoint, zoom);
11275
		}
11276
	}
11277
});
11278
11279
// @section Handlers
11280
//
11281
// Map properties include interaction handlers that allow you to control
11282
// interaction behavior in runtime, enabling or disabling certain features such
11283
// as dragging or touch zoom (see `Handler` methods). For example:
11284
//
11285
// ```js
11286
// map.doubleClickZoom.disable();
11287
// ```
11288
//
11289
// @property doubleClickZoom: Handler
11290
// Double click zoom handler.
11291
L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
11292
11293
11294
11295
/*
11296
 * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
11297
 */
11298
11299
// @namespace Map
11300
// @section Interaction Options
11301
L.Map.mergeOptions({
11302
	// @section Mousewheel options
11303
	// @option scrollWheelZoom: Boolean|String = true
11304
	// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
11305
	// it will zoom to the center of the view regardless of where the mouse was.
11306
	scrollWheelZoom: true,
11307
11308
	// @option wheelDebounceTime: Number = 40
11309
	// Limits the rate at which a wheel can fire (in milliseconds). By default
11310
	// user can't zoom via wheel more often than once per 40 ms.
11311
	wheelDebounceTime: 40,
11312
11313
	// @option wheelPxPerZoomLevel: Number = 60
11314
	// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
11315
	// mean a change of one full zoom level. Smaller values will make wheel-zooming
11316
	// faster (and vice versa).
11317
	wheelPxPerZoomLevel: 60
11318
});
11319
11320
L.Map.ScrollWheelZoom = L.Handler.extend({
11321
	addHooks: function () {
11322
		L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
11323
11324
		this._delta = 0;
11325
	},
11326
11327
	removeHooks: function () {
11328
		L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll, this);
11329
	},
11330
11331
	_onWheelScroll: function (e) {
11332
		var delta = L.DomEvent.getWheelDelta(e);
11333
11334
		var debounce = this._map.options.wheelDebounceTime;
11335
11336
		this._delta += delta;
11337
		this._lastMousePos = this._map.mouseEventToContainerPoint(e);
11338
11339
		if (!this._startTime) {
11340
			this._startTime = +new Date();
11341
		}
11342
11343
		var left = Math.max(debounce - (+new Date() - this._startTime), 0);
11344
11345
		clearTimeout(this._timer);
11346
		this._timer = setTimeout(L.bind(this._performZoom, this), left);
11347
11348
		L.DomEvent.stop(e);
11349
	},
11350
11351
	_performZoom: function () {
11352
		var map = this._map,
11353
		    zoom = map.getZoom(),
11354
		    snap = this._map.options.zoomSnap || 0;
11355
11356
		map._stop(); // stop panning and fly animations if any
11357
11358
		// map the delta with a sigmoid function to -4..4 range leaning on -1..1
11359
		var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
11360
		    d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
11361
		    d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
11362
		    delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
11363
11364
		this._delta = 0;
11365
		this._startTime = null;
11366
11367
		if (!delta) { return; }
11368
11369
		if (map.options.scrollWheelZoom === 'center') {
11370
			map.setZoom(zoom + delta);
11371
		} else {
11372
			map.setZoomAround(this._lastMousePos, zoom + delta);
11373
		}
11374
	}
11375
});
11376
11377
// @section Handlers
11378
// @property scrollWheelZoom: Handler
11379
// Scroll wheel zoom handler.
11380
L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
11381
11382
11383
11384
/*
11385
 * Extends the event handling code with double tap support for mobile browsers.
11386
 */
11387
11388
L.extend(L.DomEvent, {
11389
11390
	_touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
11391
	_touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
11392
11393
	// inspired by Zepto touch code by Thomas Fuchs
11394
	addDoubleTapListener: function (obj, handler, id) {
11395
		var last, touch,
11396
		    doubleTap = false,
11397
		    delay = 250;
11398
11399
		function onTouchStart(e) {
11400
			var count;
11401
11402
			if (L.Browser.pointer) {
11403
				if ((!L.Browser.edge) || e.pointerType === 'mouse') { return; }
11404
				count = L.DomEvent._pointersCount;
11405
			} else {
11406
				count = e.touches.length;
11407
			}
11408
11409
			if (count > 1) { return; }
11410
11411
			var now = Date.now(),
11412
			    delta = now - (last || now);
11413
11414
			touch = e.touches ? e.touches[0] : e;
11415
			doubleTap = (delta > 0 && delta <= delay);
11416
			last = now;
11417
		}
11418
11419
		function onTouchEnd(e) {
11420
			if (doubleTap && !touch.cancelBubble) {
11421
				if (L.Browser.pointer) {
11422
					if ((!L.Browser.edge) || e.pointerType === 'mouse') { return; }
11423
11424
					// work around .type being readonly with MSPointer* events
11425
					var newTouch = {},
11426
					    prop, i;
11427
11428
					for (i in touch) {
11429
						prop = touch[i];
11430
						newTouch[i] = prop && prop.bind ? prop.bind(touch) : prop;
11431
					}
11432
					touch = newTouch;
11433
				}
11434
				touch.type = 'dblclick';
11435
				handler(touch);
11436
				last = null;
11437
			}
11438
		}
11439
11440
		var pre = '_leaflet_',
11441
		    touchstart = this._touchstart,
11442
		    touchend = this._touchend;
11443
11444
		obj[pre + touchstart + id] = onTouchStart;
11445
		obj[pre + touchend + id] = onTouchEnd;
11446
		obj[pre + 'dblclick' + id] = handler;
11447
11448
		obj.addEventListener(touchstart, onTouchStart, false);
11449
		obj.addEventListener(touchend, onTouchEnd, false);
11450
11451
		// On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),
11452
		// the browser doesn't fire touchend/pointerup events but does fire
11453
		// native dblclicks. See #4127.
11454
		// Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.
11455
		obj.addEventListener('dblclick', handler, false);
11456
11457
		return this;
11458
	},
11459
11460
	removeDoubleTapListener: function (obj, id) {
11461
		var pre = '_leaflet_',
11462
		    touchstart = obj[pre + this._touchstart + id],
11463
		    touchend = obj[pre + this._touchend + id],
11464
		    dblclick = obj[pre + 'dblclick' + id];
11465
11466
		obj.removeEventListener(this._touchstart, touchstart, false);
11467
		obj.removeEventListener(this._touchend, touchend, false);
11468
		if (!L.Browser.edge) {
11469
			obj.removeEventListener('dblclick', dblclick, false);
11470
		}
11471
11472
		return this;
11473
	}
11474
});
11475
11476
11477
11478
/*
11479
 * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
11480
 */
11481
11482
L.extend(L.DomEvent, {
11483
11484
	POINTER_DOWN:   L.Browser.msPointer ? 'MSPointerDown'   : 'pointerdown',
11485
	POINTER_MOVE:   L.Browser.msPointer ? 'MSPointerMove'   : 'pointermove',
11486
	POINTER_UP:     L.Browser.msPointer ? 'MSPointerUp'     : 'pointerup',
11487
	POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
11488
	TAG_WHITE_LIST: ['INPUT', 'SELECT', 'OPTION'],
11489
11490
	_pointers: {},
11491
	_pointersCount: 0,
11492
11493
	// Provides a touch events wrapper for (ms)pointer events.
11494
	// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
11495
11496
	addPointerListener: function (obj, type, handler, id) {
11497
11498
		if (type === 'touchstart') {
11499
			this._addPointerStart(obj, handler, id);
11500
11501
		} else if (type === 'touchmove') {
11502
			this._addPointerMove(obj, handler, id);
11503
11504
		} else if (type === 'touchend') {
11505
			this._addPointerEnd(obj, handler, id);
11506
		}
11507
11508
		return this;
11509
	},
11510
11511
	removePointerListener: function (obj, type, id) {
11512
		var handler = obj['_leaflet_' + type + id];
11513
11514
		if (type === 'touchstart') {
11515
			obj.removeEventListener(this.POINTER_DOWN, handler, false);
11516
11517
		} else if (type === 'touchmove') {
11518
			obj.removeEventListener(this.POINTER_MOVE, handler, false);
11519
11520
		} else if (type === 'touchend') {
11521
			obj.removeEventListener(this.POINTER_UP, handler, false);
11522
			obj.removeEventListener(this.POINTER_CANCEL, handler, false);
11523
		}
11524
11525
		return this;
11526
	},
11527
11528
	_addPointerStart: function (obj, handler, id) {
11529
		var onDown = L.bind(function (e) {
11530
			if (e.pointerType !== 'mouse' && e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
11531
				// In IE11, some touch events needs to fire for form controls, or
11532
				// the controls will stop working. We keep a whitelist of tag names that
11533
				// need these events. For other target tags, we prevent default on the event.
11534
				if (this.TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) {
11535
					L.DomEvent.preventDefault(e);
11536
				} else {
11537
					return;
11538
				}
11539
			}
11540
11541
			this._handlePointer(e, handler);
11542
		}, this);
11543
11544
		obj['_leaflet_touchstart' + id] = onDown;
11545
		obj.addEventListener(this.POINTER_DOWN, onDown, false);
11546
11547
		// need to keep track of what pointers and how many are active to provide e.touches emulation
11548
		if (!this._pointerDocListener) {
11549
			var pointerUp = L.bind(this._globalPointerUp, this);
11550
11551
			// we listen documentElement as any drags that end by moving the touch off the screen get fired there
11552
			document.documentElement.addEventListener(this.POINTER_DOWN, L.bind(this._globalPointerDown, this), true);
11553
			document.documentElement.addEventListener(this.POINTER_MOVE, L.bind(this._globalPointerMove, this), true);
11554
			document.documentElement.addEventListener(this.POINTER_UP, pointerUp, true);
11555
			document.documentElement.addEventListener(this.POINTER_CANCEL, pointerUp, true);
11556
11557
			this._pointerDocListener = true;
11558
		}
11559
	},
11560
11561
	_globalPointerDown: function (e) {
11562
		this._pointers[e.pointerId] = e;
11563
		this._pointersCount++;
11564
	},
11565
11566
	_globalPointerMove: function (e) {
11567
		if (this._pointers[e.pointerId]) {
11568
			this._pointers[e.pointerId] = e;
11569
		}
11570
	},
11571
11572
	_globalPointerUp: function (e) {
11573
		delete this._pointers[e.pointerId];
11574
		this._pointersCount--;
11575
	},
11576
11577
	_handlePointer: function (e, handler) {
11578
		e.touches = [];
11579
		for (var i in this._pointers) {
11580
			e.touches.push(this._pointers[i]);
11581
		}
11582
		e.changedTouches = [e];
11583
11584
		handler(e);
11585
	},
11586
11587
	_addPointerMove: function (obj, handler, id) {
11588
		var onMove = L.bind(function (e) {
11589
			// don't fire touch moves when mouse isn't down
11590
			if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
11591
11592
			this._handlePointer(e, handler);
11593
		}, this);
11594
11595
		obj['_leaflet_touchmove' + id] = onMove;
11596
		obj.addEventListener(this.POINTER_MOVE, onMove, false);
11597
	},
11598
11599
	_addPointerEnd: function (obj, handler, id) {
11600
		var onUp = L.bind(function (e) {
11601
			this._handlePointer(e, handler);
11602
		}, this);
11603
11604
		obj['_leaflet_touchend' + id] = onUp;
11605
		obj.addEventListener(this.POINTER_UP, onUp, false);
11606
		obj.addEventListener(this.POINTER_CANCEL, onUp, false);
11607
	}
11608
});
11609
11610
11611
11612
/*
11613
 * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
11614
 */
11615
11616
// @namespace Map
11617
// @section Interaction Options
11618
L.Map.mergeOptions({
11619
	// @section Touch interaction options
11620
	// @option touchZoom: Boolean|String = *
11621
	// Whether the map can be zoomed by touch-dragging with two fingers. If
11622
	// passed `'center'`, it will zoom to the center of the view regardless of
11623
	// where the touch events (fingers) were. Enabled for touch-capable web
11624
	// browsers except for old Androids.
11625
	touchZoom: L.Browser.touch && !L.Browser.android23,
11626
11627
	// @option bounceAtZoomLimits: Boolean = true
11628
	// Set it to false if you don't want the map to zoom beyond min/max zoom
11629
	// and then bounce back when pinch-zooming.
11630
	bounceAtZoomLimits: true
11631
});
11632
11633
L.Map.TouchZoom = L.Handler.extend({
11634
	addHooks: function () {
11635
		L.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');
11636
		L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
11637
	},
11638
11639
	removeHooks: function () {
11640
		L.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');
11641
		L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
11642
	},
11643
11644
	_onTouchStart: function (e) {
11645
		var map = this._map;
11646
		if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
11647
11648
		var p1 = map.mouseEventToContainerPoint(e.touches[0]),
11649
		    p2 = map.mouseEventToContainerPoint(e.touches[1]);
11650
11651
		this._centerPoint = map.getSize()._divideBy(2);
11652
		this._startLatLng = map.containerPointToLatLng(this._centerPoint);
11653
		if (map.options.touchZoom !== 'center') {
11654
			this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
11655
		}
11656
11657
		this._startDist = p1.distanceTo(p2);
11658
		this._startZoom = map.getZoom();
11659
11660
		this._moved = false;
11661
		this._zooming = true;
11662
11663
		map._stop();
11664
11665
		L.DomEvent
11666
		    .on(document, 'touchmove', this._onTouchMove, this)
11667
		    .on(document, 'touchend', this._onTouchEnd, this);
11668
11669
		L.DomEvent.preventDefault(e);
11670
	},
11671
11672
	_onTouchMove: function (e) {
11673
		if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
11674
11675
		var map = this._map,
11676
		    p1 = map.mouseEventToContainerPoint(e.touches[0]),
11677
		    p2 = map.mouseEventToContainerPoint(e.touches[1]),
11678
		    scale = p1.distanceTo(p2) / this._startDist;
11679
11680
11681
		this._zoom = map.getScaleZoom(scale, this._startZoom);
11682
11683
		if (!map.options.bounceAtZoomLimits && (
11684
			(this._zoom < map.getMinZoom() && scale < 1) ||
11685
			(this._zoom > map.getMaxZoom() && scale > 1))) {
11686
			this._zoom = map._limitZoom(this._zoom);
11687
		}
11688
11689
		if (map.options.touchZoom === 'center') {
11690
			this._center = this._startLatLng;
11691
			if (scale === 1) { return; }
11692
		} else {
11693
			// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
11694
			var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
11695
			if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
11696
			this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
11697
		}
11698
11699
		if (!this._moved) {
11700
			map._moveStart(true);
11701
			this._moved = true;
11702
		}
11703
11704
		L.Util.cancelAnimFrame(this._animRequest);
11705
11706
		var moveFn = L.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
11707
		this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
11708
11709
		L.DomEvent.preventDefault(e);
11710
	},
11711
11712
	_onTouchEnd: function () {
11713
		if (!this._moved || !this._zooming) {
11714
			this._zooming = false;
11715
			return;
11716
		}
11717
11718
		this._zooming = false;
11719
		L.Util.cancelAnimFrame(this._animRequest);
11720
11721
		L.DomEvent
11722
		    .off(document, 'touchmove', this._onTouchMove)
11723
		    .off(document, 'touchend', this._onTouchEnd);
11724
11725
		// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
11726
		if (this._map.options.zoomAnimation) {
11727
			this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
11728
		} else {
11729
			this._map._resetView(this._center, this._map._limitZoom(this._zoom));
11730
		}
11731
	}
11732
});
11733
11734
// @section Handlers
11735
// @property touchZoom: Handler
11736
// Touch zoom handler.
11737
L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
11738
11739
11740
11741
/*
11742
 * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
11743
 */
11744
11745
// @namespace Map
11746
// @section Interaction Options
11747
L.Map.mergeOptions({
11748
	// @section Touch interaction options
11749
	// @option tap: Boolean = true
11750
	// Enables mobile hacks for supporting instant taps (fixing 200ms click
11751
	// delay on iOS/Android) and touch holds (fired as `contextmenu` events).
11752
	tap: true,
11753
11754
	// @option tapTolerance: Number = 15
11755
	// The max number of pixels a user can shift his finger during touch
11756
	// for it to be considered a valid tap.
11757
	tapTolerance: 15
11758
});
11759
11760
L.Map.Tap = L.Handler.extend({
11761
	addHooks: function () {
11762
		L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);
11763
	},
11764
11765
	removeHooks: function () {
11766
		L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);
11767
	},
11768
11769
	_onDown: function (e) {
11770
		if (!e.touches) { return; }
11771
11772
		L.DomEvent.preventDefault(e);
11773
11774
		this._fireClick = true;
11775
11776
		// don't simulate click or track longpress if more than 1 touch
11777
		if (e.touches.length > 1) {
11778
			this._fireClick = false;
11779
			clearTimeout(this._holdTimeout);
11780
			return;
11781
		}
11782
11783
		var first = e.touches[0],
11784
		    el = first.target;
11785
11786
		this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
11787
11788
		// if touching a link, highlight it
11789
		if (el.tagName && el.tagName.toLowerCase() === 'a') {
11790
			L.DomUtil.addClass(el, 'leaflet-active');
11791
		}
11792
11793
		// simulate long hold but setting a timeout
11794
		this._holdTimeout = setTimeout(L.bind(function () {
11795
			if (this._isTapValid()) {
11796
				this._fireClick = false;
11797
				this._onUp();
11798
				this._simulateEvent('contextmenu', first);
11799
			}
11800
		}, this), 1000);
11801
11802
		this._simulateEvent('mousedown', first);
11803
11804
		L.DomEvent.on(document, {
11805
			touchmove: this._onMove,
11806
			touchend: this._onUp
11807
		}, this);
11808
	},
11809
11810
	_onUp: function (e) {
11811
		clearTimeout(this._holdTimeout);
11812
11813
		L.DomEvent.off(document, {
11814
			touchmove: this._onMove,
11815
			touchend: this._onUp
11816
		}, this);
11817
11818
		if (this._fireClick && e && e.changedTouches) {
11819
11820
			var first = e.changedTouches[0],
11821
			    el = first.target;
11822
11823
			if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
11824
				L.DomUtil.removeClass(el, 'leaflet-active');
11825
			}
11826
11827
			this._simulateEvent('mouseup', first);
11828
11829
			// simulate click if the touch didn't move too much
11830
			if (this._isTapValid()) {
11831
				this._simulateEvent('click', first);
11832
			}
11833
		}
11834
	},
11835
11836
	_isTapValid: function () {
11837
		return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
11838
	},
11839
11840
	_onMove: function (e) {
11841
		var first = e.touches[0];
11842
		this._newPos = new L.Point(first.clientX, first.clientY);
11843
		this._simulateEvent('mousemove', first);
11844
	},
11845
11846
	_simulateEvent: function (type, e) {
11847
		var simulatedEvent = document.createEvent('MouseEvents');
11848
11849
		simulatedEvent._simulated = true;
11850
		e.target._simulatedClick = true;
11851
11852
		simulatedEvent.initMouseEvent(
11853
		        type, true, true, window, 1,
11854
		        e.screenX, e.screenY,
11855
		        e.clientX, e.clientY,
11856
		        false, false, false, false, 0, null);
11857
11858
		e.target.dispatchEvent(simulatedEvent);
11859
	}
11860
});
11861
11862
// @section Handlers
11863
// @property tap: Handler
11864
// Mobile touch hacks (quick tap and touch hold) handler.
11865
if (L.Browser.touch && !L.Browser.pointer) {
11866
	L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);
11867
}
11868
11869
11870
11871
/*
11872
 * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
11873
 * (zoom to a selected bounding box), enabled by default.
11874
 */
11875
11876
// @namespace Map
11877
// @section Interaction Options
11878
L.Map.mergeOptions({
11879
	// @option boxZoom: Boolean = true
11880
	// Whether the map can be zoomed to a rectangular area specified by
11881
	// dragging the mouse while pressing the shift key.
11882
	boxZoom: true
11883
});
11884
11885
L.Map.BoxZoom = L.Handler.extend({
11886
	initialize: function (map) {
11887
		this._map = map;
11888
		this._container = map._container;
11889
		this._pane = map._panes.overlayPane;
11890
	},
11891
11892
	addHooks: function () {
11893
		L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
11894
	},
11895
11896
	removeHooks: function () {
11897
		L.DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);
11898
	},
11899
11900
	moved: function () {
11901
		return this._moved;
11902
	},
11903
11904
	_resetState: function () {
11905
		this._moved = false;
11906
	},
11907
11908
	_onMouseDown: function (e) {
11909
		if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
11910
11911
		this._resetState();
11912
11913
		L.DomUtil.disableTextSelection();
11914
		L.DomUtil.disableImageDrag();
11915
11916
		this._startPoint = this._map.mouseEventToContainerPoint(e);
11917
11918
		L.DomEvent.on(document, {
11919
			contextmenu: L.DomEvent.stop,
11920
			mousemove: this._onMouseMove,
11921
			mouseup: this._onMouseUp,
11922
			keydown: this._onKeyDown
11923
		}, this);
11924
	},
11925
11926
	_onMouseMove: function (e) {
11927
		if (!this._moved) {
11928
			this._moved = true;
11929
11930
			this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._container);
11931
			L.DomUtil.addClass(this._container, 'leaflet-crosshair');
11932
11933
			this._map.fire('boxzoomstart');
11934
		}
11935
11936
		this._point = this._map.mouseEventToContainerPoint(e);
11937
11938
		var bounds = new L.Bounds(this._point, this._startPoint),
11939
		    size = bounds.getSize();
11940
11941
		L.DomUtil.setPosition(this._box, bounds.min);
11942
11943
		this._box.style.width  = size.x + 'px';
11944
		this._box.style.height = size.y + 'px';
11945
	},
11946
11947
	_finish: function () {
11948
		if (this._moved) {
11949
			L.DomUtil.remove(this._box);
11950
			L.DomUtil.removeClass(this._container, 'leaflet-crosshair');
11951
		}
11952
11953
		L.DomUtil.enableTextSelection();
11954
		L.DomUtil.enableImageDrag();
11955
11956
		L.DomEvent.off(document, {
11957
			contextmenu: L.DomEvent.stop,
11958
			mousemove: this._onMouseMove,
11959
			mouseup: this._onMouseUp,
11960
			keydown: this._onKeyDown
11961
		}, this);
11962
	},
11963
11964
	_onMouseUp: function (e) {
11965
		if ((e.which !== 1) && (e.button !== 1)) { return; }
11966
11967
		this._finish();
11968
11969
		if (!this._moved) { return; }
11970
		// Postpone to next JS tick so internal click event handling
11971
		// still see it as "moved".
11972
		setTimeout(L.bind(this._resetState, this), 0);
11973
11974
		var bounds = new L.LatLngBounds(
11975
		        this._map.containerPointToLatLng(this._startPoint),
11976
		        this._map.containerPointToLatLng(this._point));
11977
11978
		this._map
11979
			.fitBounds(bounds)
11980
			.fire('boxzoomend', {boxZoomBounds: bounds});
11981
	},
11982
11983
	_onKeyDown: function (e) {
11984
		if (e.keyCode === 27) {
11985
			this._finish();
11986
		}
11987
	}
11988
});
11989
11990
// @section Handlers
11991
// @property boxZoom: Handler
11992
// Box (shift-drag with mouse) zoom handler.
11993
L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
11994
11995
11996
11997
/*
11998
 * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
11999
 */
12000
12001
// @namespace Map
12002
// @section Keyboard Navigation Options
12003
L.Map.mergeOptions({
12004
	// @option keyboard: Boolean = true
12005
	// Makes the map focusable and allows users to navigate the map with keyboard
12006
	// arrows and `+`/`-` keys.
12007
	keyboard: true,
12008
12009
	// @option keyboardPanDelta: Number = 80
12010
	// Amount of pixels to pan when pressing an arrow key.
12011
	keyboardPanDelta: 80
12012
});
12013
12014
L.Map.Keyboard = L.Handler.extend({
12015
12016
	keyCodes: {
12017
		left:    [37],
12018
		right:   [39],
12019
		down:    [40],
12020
		up:      [38],
12021
		zoomIn:  [187, 107, 61, 171],
12022
		zoomOut: [189, 109, 54, 173]
12023
	},
12024
12025
	initialize: function (map) {
12026
		this._map = map;
12027
12028
		this._setPanDelta(map.options.keyboardPanDelta);
12029
		this._setZoomDelta(map.options.zoomDelta);
12030
	},
12031
12032
	addHooks: function () {
12033
		var container = this._map._container;
12034
12035
		// make the container focusable by tabbing
12036
		if (container.tabIndex <= 0) {
12037
			container.tabIndex = '0';
12038
		}
12039
12040
		L.DomEvent.on(container, {
12041
			focus: this._onFocus,
12042
			blur: this._onBlur,
12043
			mousedown: this._onMouseDown
12044
		}, this);
12045
12046
		this._map.on({
12047
			focus: this._addHooks,
12048
			blur: this._removeHooks
12049
		}, this);
12050
	},
12051
12052
	removeHooks: function () {
12053
		this._removeHooks();
12054
12055
		L.DomEvent.off(this._map._container, {
12056
			focus: this._onFocus,
12057
			blur: this._onBlur,
12058
			mousedown: this._onMouseDown
12059
		}, this);
12060
12061
		this._map.off({
12062
			focus: this._addHooks,
12063
			blur: this._removeHooks
12064
		}, this);
12065
	},
12066
12067
	_onMouseDown: function () {
12068
		if (this._focused) { return; }
12069
12070
		var body = document.body,
12071
		    docEl = document.documentElement,
12072
		    top = body.scrollTop || docEl.scrollTop,
12073
		    left = body.scrollLeft || docEl.scrollLeft;
12074
12075
		this._map._container.focus();
12076
12077
		window.scrollTo(left, top);
12078
	},
12079
12080
	_onFocus: function () {
12081
		this._focused = true;
12082
		this._map.fire('focus');
12083
	},
12084
12085
	_onBlur: function () {
12086
		this._focused = false;
12087
		this._map.fire('blur');
12088
	},
12089
12090
	_setPanDelta: function (panDelta) {
12091
		var keys = this._panKeys = {},
12092
		    codes = this.keyCodes,
12093
		    i, len;
12094
12095
		for (i = 0, len = codes.left.length; i < len; i++) {
12096
			keys[codes.left[i]] = [-1 * panDelta, 0];
12097
		}
12098
		for (i = 0, len = codes.right.length; i < len; i++) {
12099
			keys[codes.right[i]] = [panDelta, 0];
12100
		}
12101
		for (i = 0, len = codes.down.length; i < len; i++) {
12102
			keys[codes.down[i]] = [0, panDelta];
12103
		}
12104
		for (i = 0, len = codes.up.length; i < len; i++) {
12105
			keys[codes.up[i]] = [0, -1 * panDelta];
12106
		}
12107
	},
12108
12109
	_setZoomDelta: function (zoomDelta) {
12110
		var keys = this._zoomKeys = {},
12111
		    codes = this.keyCodes,
12112
		    i, len;
12113
12114
		for (i = 0, len = codes.zoomIn.length; i < len; i++) {
12115
			keys[codes.zoomIn[i]] = zoomDelta;
12116
		}
12117
		for (i = 0, len = codes.zoomOut.length; i < len; i++) {
12118
			keys[codes.zoomOut[i]] = -zoomDelta;
12119
		}
12120
	},
12121
12122
	_addHooks: function () {
12123
		L.DomEvent.on(document, 'keydown', this._onKeyDown, this);
12124
	},
12125
12126
	_removeHooks: function () {
12127
		L.DomEvent.off(document, 'keydown', this._onKeyDown, this);
12128
	},
12129
12130
	_onKeyDown: function (e) {
12131
		if (e.altKey || e.ctrlKey || e.metaKey) { return; }
12132
12133
		var key = e.keyCode,
12134
		    map = this._map,
12135
		    offset;
12136
12137
		if (key in this._panKeys) {
12138
12139
			if (map._panAnim && map._panAnim._inProgress) { return; }
12140
12141
			offset = this._panKeys[key];
12142
			if (e.shiftKey) {
12143
				offset = L.point(offset).multiplyBy(3);
12144
			}
12145
12146
			map.panBy(offset);
12147
12148
			if (map.options.maxBounds) {
12149
				map.panInsideBounds(map.options.maxBounds);
12150
			}
12151
12152
		} else if (key in this._zoomKeys) {
12153
			map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
12154
12155
		} else if (key === 27) {
12156
			map.closePopup();
12157
12158
		} else {
12159
			return;
12160
		}
12161
12162
		L.DomEvent.stop(e);
12163
	}
12164
});
12165
12166
// @section Handlers
12167
// @section Handlers
12168
// @property keyboard: Handler
12169
// Keyboard navigation handler.
12170
L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard);
12171
12172
12173
12174
/*
12175
 * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
12176
 */
12177
12178
12179
/* @namespace Marker
12180
 * @section Interaction handlers
12181
 *
12182
 * 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:
12183
 *
12184
 * ```js
12185
 * marker.dragging.disable();
12186
 * ```
12187
 *
12188
 * @property dragging: Handler
12189
 * Marker dragging handler (by both mouse and touch).
12190
 */
12191
12192
L.Handler.MarkerDrag = L.Handler.extend({
12193
	initialize: function (marker) {
12194
		this._marker = marker;
12195
	},
12196
12197
	addHooks: function () {
12198
		var icon = this._marker._icon;
12199
12200
		if (!this._draggable) {
12201
			this._draggable = new L.Draggable(icon, icon, true);
12202
		}
12203
12204
		this._draggable.on({
12205
			dragstart: this._onDragStart,
12206
			drag: this._onDrag,
12207
			dragend: this._onDragEnd
12208
		}, this).enable();
12209
12210
		L.DomUtil.addClass(icon, 'leaflet-marker-draggable');
12211
	},
12212
12213
	removeHooks: function () {
12214
		this._draggable.off({
12215
			dragstart: this._onDragStart,
12216
			drag: this._onDrag,
12217
			dragend: this._onDragEnd
12218
		}, this).disable();
12219
12220
		if (this._marker._icon) {
12221
			L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
12222
		}
12223
	},
12224
12225
	moved: function () {
12226
		return this._draggable && this._draggable._moved;
12227
	},
12228
12229
	_onDragStart: function () {
12230
		// @section Dragging events
12231
		// @event dragstart: Event
12232
		// Fired when the user starts dragging the marker.
12233
12234
		// @event movestart: Event
12235
		// Fired when the marker starts moving (because of dragging).
12236
12237
		this._oldLatLng = this._marker.getLatLng();
12238
		this._marker
12239
		    .closePopup()
12240
		    .fire('movestart')
12241
		    .fire('dragstart');
12242
	},
12243
12244
	_onDrag: function (e) {
12245
		var marker = this._marker,
12246
		    shadow = marker._shadow,
12247
		    iconPos = L.DomUtil.getPosition(marker._icon),
12248
		    latlng = marker._map.layerPointToLatLng(iconPos);
12249
12250
		// update shadow position
12251
		if (shadow) {
12252
			L.DomUtil.setPosition(shadow, iconPos);
12253
		}
12254
12255
		marker._latlng = latlng;
12256
		e.latlng = latlng;
12257
		e.oldLatLng = this._oldLatLng;
12258
12259
		// @event drag: Event
12260
		// Fired repeatedly while the user drags the marker.
12261
		marker
12262
		    .fire('move', e)
12263
		    .fire('drag', e);
12264
	},
12265
12266
	_onDragEnd: function (e) {
12267
		// @event dragend: DragEndEvent
12268
		// Fired when the user stops dragging the marker.
12269
12270
		// @event moveend: Event
12271
		// Fired when the marker stops moving (because of dragging).
12272
		delete this._oldLatLng;
12273
		this._marker
12274
		    .fire('moveend')
12275
		    .fire('dragend', e);
12276
	}
12277
});
12278
12279
12280
12281
/*
12282
 * @class Control
12283
 * @aka L.Control
12284
 * @inherits Class
12285
 *
12286
 * L.Control is a base class for implementing map controls. Handles positioning.
12287
 * All other controls extend from this class.
12288
 */
12289
12290
L.Control = L.Class.extend({
12291
	// @section
12292
	// @aka Control options
12293
	options: {
12294
		// @option position: String = 'topright'
12295
		// The position of the control (one of the map corners). Possible values are `'topleft'`,
12296
		// `'topright'`, `'bottomleft'` or `'bottomright'`
12297
		position: 'topright'
12298
	},
12299
12300
	initialize: function (options) {
12301
		L.setOptions(this, options);
12302
	},
12303
12304
	/* @section
12305
	 * Classes extending L.Control will inherit the following methods:
12306
	 *
12307
	 * @method getPosition: string
12308
	 * Returns the position of the control.
12309
	 */
12310
	getPosition: function () {
12311
		return this.options.position;
12312
	},
12313
12314
	// @method setPosition(position: string): this
12315
	// Sets the position of the control.
12316
	setPosition: function (position) {
12317
		var map = this._map;
12318
12319
		if (map) {
12320
			map.removeControl(this);
12321
		}
12322
12323
		this.options.position = position;
12324
12325
		if (map) {
12326
			map.addControl(this);
12327
		}
12328
12329
		return this;
12330
	},
12331
12332
	// @method getContainer: HTMLElement
12333
	// Returns the HTMLElement that contains the control.
12334
	getContainer: function () {
12335
		return this._container;
12336
	},
12337
12338
	// @method addTo(map: Map): this
12339
	// Adds the control to the given map.
12340
	addTo: function (map) {
12341
		this.remove();
12342
		this._map = map;
12343
12344
		var container = this._container = this.onAdd(map),
12345
		    pos = this.getPosition(),
12346
		    corner = map._controlCorners[pos];
12347
12348
		L.DomUtil.addClass(container, 'leaflet-control');
12349
12350
		if (pos.indexOf('bottom') !== -1) {
12351
			corner.insertBefore(container, corner.firstChild);
12352
		} else {
12353
			corner.appendChild(container);
12354
		}
12355
12356
		return this;
12357
	},
12358
12359
	// @method remove: this
12360
	// Removes the control from the map it is currently active on.
12361
	remove: function () {
12362
		if (!this._map) {
12363
			return this;
12364
		}
12365
12366
		L.DomUtil.remove(this._container);
12367
12368
		if (this.onRemove) {
12369
			this.onRemove(this._map);
12370
		}
12371
12372
		this._map = null;
12373
12374
		return this;
12375
	},
12376
12377
	_refocusOnMap: function (e) {
12378
		// if map exists and event is not a keyboard event
12379
		if (this._map && e && e.screenX > 0 && e.screenY > 0) {
12380
			this._map.getContainer().focus();
12381
		}
12382
	}
12383
});
12384
12385
L.control = function (options) {
12386
	return new L.Control(options);
12387
};
12388
12389
/* @section Extension methods
12390
 * @uninheritable
12391
 *
12392
 * Every control should extend from `L.Control` and (re-)implement the following methods.
12393
 *
12394
 * @method onAdd(map: Map): HTMLElement
12395
 * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
12396
 *
12397
 * @method onRemove(map: Map)
12398
 * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
12399
 */
12400
12401
/* @namespace Map
12402
 * @section Methods for Layers and Controls
12403
 */
12404
L.Map.include({
12405
	// @method addControl(control: Control): this
12406
	// Adds the given control to the map
12407
	addControl: function (control) {
12408
		control.addTo(this);
12409
		return this;
12410
	},
12411
12412
	// @method removeControl(control: Control): this
12413
	// Removes the given control from the map
12414
	removeControl: function (control) {
12415
		control.remove();
12416
		return this;
12417
	},
12418
12419
	_initControlPos: function () {
12420
		var corners = this._controlCorners = {},
12421
		    l = 'leaflet-',
12422
		    container = this._controlContainer =
12423
		            L.DomUtil.create('div', l + 'control-container', this._container);
12424
12425
		function createCorner(vSide, hSide) {
12426
			var className = l + vSide + ' ' + l + hSide;
12427
12428
			corners[vSide + hSide] = L.DomUtil.create('div', className, container);
12429
		}
12430
12431
		createCorner('top', 'left');
12432
		createCorner('top', 'right');
12433
		createCorner('bottom', 'left');
12434
		createCorner('bottom', 'right');
12435
	},
12436
12437
	_clearControlPos: function () {
12438
		L.DomUtil.remove(this._controlContainer);
12439
	}
12440
});
12441
12442
12443
12444
/*
12445
 * @class Control.Zoom
12446
 * @aka L.Control.Zoom
12447
 * @inherits Control
12448
 *
12449
 * 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`.
12450
 */
12451
12452
L.Control.Zoom = L.Control.extend({
12453
	// @section
12454
	// @aka Control.Zoom options
12455
	options: {
12456
		position: 'topleft',
12457
12458
		// @option zoomInText: String = '+'
12459
		// The text set on the 'zoom in' button.
12460
		zoomInText: '+',
12461
12462
		// @option zoomInTitle: String = 'Zoom in'
12463
		// The title set on the 'zoom in' button.
12464
		zoomInTitle: 'Zoom in',
12465
12466
		// @option zoomOutText: String = '-'
12467
		// The text set on the 'zoom out' button.
12468
		zoomOutText: '-',
12469
12470
		// @option zoomOutTitle: String = 'Zoom out'
12471
		// The title set on the 'zoom out' button.
12472
		zoomOutTitle: 'Zoom out'
12473
	},
12474
12475
	onAdd: function (map) {
12476
		var zoomName = 'leaflet-control-zoom',
12477
		    container = L.DomUtil.create('div', zoomName + ' leaflet-bar'),
12478
		    options = this.options;
12479
12480
		this._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,
12481
		        zoomName + '-in',  container, this._zoomIn);
12482
		this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
12483
		        zoomName + '-out', container, this._zoomOut);
12484
12485
		this._updateDisabled();
12486
		map.on('zoomend zoomlevelschange', this._updateDisabled, this);
12487
12488
		return container;
12489
	},
12490
12491
	onRemove: function (map) {
12492
		map.off('zoomend zoomlevelschange', this._updateDisabled, this);
12493
	},
12494
12495
	disable: function () {
12496
		this._disabled = true;
12497
		this._updateDisabled();
12498
		return this;
12499
	},
12500
12501
	enable: function () {
12502
		this._disabled = false;
12503
		this._updateDisabled();
12504
		return this;
12505
	},
12506
12507
	_zoomIn: function (e) {
12508
		if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
12509
			this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
12510
		}
12511
	},
12512
12513
	_zoomOut: function (e) {
12514
		if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
12515
			this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
12516
		}
12517
	},
12518
12519
	_createButton: function (html, title, className, container, fn) {
12520
		var link = L.DomUtil.create('a', className, container);
12521
		link.innerHTML = html;
12522
		link.href = '#';
12523
		link.title = title;
12524
12525
		/*
12526
		 * Will force screen readers like VoiceOver to read this as "Zoom in - button"
12527
		 */
12528
		link.setAttribute('role', 'button');
12529
		link.setAttribute('aria-label', title);
12530
12531
		L.DomEvent
12532
		    .on(link, 'mousedown dblclick', L.DomEvent.stopPropagation)
12533
		    .on(link, 'click', L.DomEvent.stop)
12534
		    .on(link, 'click', fn, this)
12535
		    .on(link, 'click', this._refocusOnMap, this);
12536
12537
		return link;
12538
	},
12539
12540
	_updateDisabled: function () {
12541
		var map = this._map,
12542
		    className = 'leaflet-disabled';
12543
12544
		L.DomUtil.removeClass(this._zoomInButton, className);
12545
		L.DomUtil.removeClass(this._zoomOutButton, className);
12546
12547
		if (this._disabled || map._zoom === map.getMinZoom()) {
12548
			L.DomUtil.addClass(this._zoomOutButton, className);
12549
		}
12550
		if (this._disabled || map._zoom === map.getMaxZoom()) {
12551
			L.DomUtil.addClass(this._zoomInButton, className);
12552
		}
12553
	}
12554
});
12555
12556
// @namespace Map
12557
// @section Control options
12558
// @option zoomControl: Boolean = true
12559
// Whether a [zoom control](#control-zoom) is added to the map by default.
12560
L.Map.mergeOptions({
12561
	zoomControl: true
12562
});
12563
12564
L.Map.addInitHook(function () {
12565
	if (this.options.zoomControl) {
12566
		this.zoomControl = new L.Control.Zoom();
12567
		this.addControl(this.zoomControl);
12568
	}
12569
});
12570
12571
// @namespace Control.Zoom
12572
// @factory L.control.zoom(options: Control.Zoom options)
12573
// Creates a zoom control
12574
L.control.zoom = function (options) {
12575
	return new L.Control.Zoom(options);
12576
};
12577
12578
12579
12580
/*
12581
 * @class Control.Attribution
12582
 * @aka L.Control.Attribution
12583
 * @inherits Control
12584
 *
12585
 * 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.
12586
 */
12587
12588
L.Control.Attribution = L.Control.extend({
12589
	// @section
12590
	// @aka Control.Attribution options
12591
	options: {
12592
		position: 'bottomright',
12593
12594
		// @option prefix: String = 'Leaflet'
12595
		// The HTML text shown before the attributions. Pass `false` to disable.
12596
		prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
12597
	},
12598
12599
	initialize: function (options) {
12600
		L.setOptions(this, options);
12601
12602
		this._attributions = {};
12603
	},
12604
12605
	onAdd: function (map) {
12606
		map.attributionControl = this;
12607
		this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
12608
		if (L.DomEvent) {
12609
			L.DomEvent.disableClickPropagation(this._container);
12610
		}
12611
12612
		// TODO ugly, refactor
12613
		for (var i in map._layers) {
12614
			if (map._layers[i].getAttribution) {
12615
				this.addAttribution(map._layers[i].getAttribution());
12616
			}
12617
		}
12618
12619
		this._update();
12620
12621
		return this._container;
12622
	},
12623
12624
	// @method setPrefix(prefix: String): this
12625
	// Sets the text before the attributions.
12626
	setPrefix: function (prefix) {
12627
		this.options.prefix = prefix;
12628
		this._update();
12629
		return this;
12630
	},
12631
12632
	// @method addAttribution(text: String): this
12633
	// Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
12634
	addAttribution: function (text) {
12635
		if (!text) { return this; }
12636
12637
		if (!this._attributions[text]) {
12638
			this._attributions[text] = 0;
12639
		}
12640
		this._attributions[text]++;
12641
12642
		this._update();
12643
12644
		return this;
12645
	},
12646
12647
	// @method removeAttribution(text: String): this
12648
	// Removes an attribution text.
12649
	removeAttribution: function (text) {
12650
		if (!text) { return this; }
12651
12652
		if (this._attributions[text]) {
12653
			this._attributions[text]--;
12654
			this._update();
12655
		}
12656
12657
		return this;
12658
	},
12659
12660
	_update: function () {
12661
		if (!this._map) { return; }
12662
12663
		var attribs = [];
12664
12665
		for (var i in this._attributions) {
12666
			if (this._attributions[i]) {
12667
				attribs.push(i);
12668
			}
12669
		}
12670
12671
		var prefixAndAttribs = [];
12672
12673
		if (this.options.prefix) {
12674
			prefixAndAttribs.push(this.options.prefix);
12675
		}
12676
		if (attribs.length) {
12677
			prefixAndAttribs.push(attribs.join(', '));
12678
		}
12679
12680
		this._container.innerHTML = prefixAndAttribs.join(' | ');
12681
	}
12682
});
12683
12684
// @namespace Map
12685
// @section Control options
12686
// @option attributionControl: Boolean = true
12687
// Whether a [attribution control](#control-attribution) is added to the map by default.
12688
L.Map.mergeOptions({
12689
	attributionControl: true
12690
});
12691
12692
L.Map.addInitHook(function () {
12693
	if (this.options.attributionControl) {
12694
		new L.Control.Attribution().addTo(this);
12695
	}
12696
});
12697
12698
// @namespace Control.Attribution
12699
// @factory L.control.attribution(options: Control.Attribution options)
12700
// Creates an attribution control.
12701
L.control.attribution = function (options) {
12702
	return new L.Control.Attribution(options);
12703
};
12704
12705
12706
12707
/*
12708
 * @class Control.Scale
12709
 * @aka L.Control.Scale
12710
 * @inherits Control
12711
 *
12712
 * 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`.
12713
 *
12714
 * @example
12715
 *
12716
 * ```js
12717
 * L.control.scale().addTo(map);
12718
 * ```
12719
 */
12720
12721
L.Control.Scale = L.Control.extend({
12722
	// @section
12723
	// @aka Control.Scale options
12724
	options: {
12725
		position: 'bottomleft',
12726
12727
		// @option maxWidth: Number = 100
12728
		// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
12729
		maxWidth: 100,
12730
12731
		// @option metric: Boolean = True
12732
		// Whether to show the metric scale line (m/km).
12733
		metric: true,
12734
12735
		// @option imperial: Boolean = True
12736
		// Whether to show the imperial scale line (mi/ft).
12737
		imperial: true
12738
12739
		// @option updateWhenIdle: Boolean = false
12740
		// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
12741
	},
12742
12743
	onAdd: function (map) {
12744
		var className = 'leaflet-control-scale',
12745
		    container = L.DomUtil.create('div', className),
12746
		    options = this.options;
12747
12748
		this._addScales(options, className + '-line', container);
12749
12750
		map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
12751
		map.whenReady(this._update, this);
12752
12753
		return container;
12754
	},
12755
12756
	onRemove: function (map) {
12757
		map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
12758
	},
12759
12760
	_addScales: function (options, className, container) {
12761
		if (options.metric) {
12762
			this._mScale = L.DomUtil.create('div', className, container);
12763
		}
12764
		if (options.imperial) {
12765
			this._iScale = L.DomUtil.create('div', className, container);
12766
		}
12767
	},
12768
12769
	_update: function () {
12770
		var map = this._map,
12771
		    y = map.getSize().y / 2;
12772
12773
		var maxMeters = map.distance(
12774
				map.containerPointToLatLng([0, y]),
12775
				map.containerPointToLatLng([this.options.maxWidth, y]));
12776
12777
		this._updateScales(maxMeters);
12778
	},
12779
12780
	_updateScales: function (maxMeters) {
12781
		if (this.options.metric && maxMeters) {
12782
			this._updateMetric(maxMeters);
12783
		}
12784
		if (this.options.imperial && maxMeters) {
12785
			this._updateImperial(maxMeters);
12786
		}
12787
	},
12788
12789
	_updateMetric: function (maxMeters) {
12790
		var meters = this._getRoundNum(maxMeters),
12791
		    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
12792
12793
		this._updateScale(this._mScale, label, meters / maxMeters);
12794
	},
12795
12796
	_updateImperial: function (maxMeters) {
12797
		var maxFeet = maxMeters * 3.2808399,
12798
		    maxMiles, miles, feet;
12799
12800
		if (maxFeet > 5280) {
12801
			maxMiles = maxFeet / 5280;
12802
			miles = this._getRoundNum(maxMiles);
12803
			this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
12804
12805
		} else {
12806
			feet = this._getRoundNum(maxFeet);
12807
			this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
12808
		}
12809
	},
12810
12811
	_updateScale: function (scale, text, ratio) {
12812
		scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
12813
		scale.innerHTML = text;
12814
	},
12815
12816
	_getRoundNum: function (num) {
12817
		var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
12818
		    d = num / pow10;
12819
12820
		d = d >= 10 ? 10 :
12821
		    d >= 5 ? 5 :
12822
		    d >= 3 ? 3 :
12823
		    d >= 2 ? 2 : 1;
12824
12825
		return pow10 * d;
12826
	}
12827
});
12828
12829
12830
// @factory L.control.scale(options?: Control.Scale options)
12831
// Creates an scale control with the given options.
12832
L.control.scale = function (options) {
12833
	return new L.Control.Scale(options);
12834
};
12835
12836
12837
12838
/*
12839
 * @class Control.Layers
12840
 * @aka L.Control.Layers
12841
 * @inherits Control
12842
 *
12843
 * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control.html)). Extends `Control`.
12844
 *
12845
 * @example
12846
 *
12847
 * ```js
12848
 * var baseLayers = {
12849
 * 	"Mapbox": mapbox,
12850
 * 	"OpenStreetMap": osm
12851
 * };
12852
 *
12853
 * var overlays = {
12854
 * 	"Marker": marker,
12855
 * 	"Roads": roadsLayer
12856
 * };
12857
 *
12858
 * L.control.layers(baseLayers, overlays).addTo(map);
12859
 * ```
12860
 *
12861
 * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
12862
 *
12863
 * ```js
12864
 * {
12865
 *     "<someName1>": layer1,
12866
 *     "<someName2>": layer2
12867
 * }
12868
 * ```
12869
 *
12870
 * The layer names can contain HTML, which allows you to add additional styling to the items:
12871
 *
12872
 * ```js
12873
 * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
12874
 * ```
12875
 */
12876
12877
12878
L.Control.Layers = L.Control.extend({
12879
	// @section
12880
	// @aka Control.Layers options
12881
	options: {
12882
		// @option collapsed: Boolean = true
12883
		// If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
12884
		collapsed: true,
12885
		position: 'topright',
12886
12887
		// @option autoZIndex: Boolean = true
12888
		// 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.
12889
		autoZIndex: true,
12890
12891
		// @option hideSingleBase: Boolean = false
12892
		// If `true`, the base layers in the control will be hidden when there is only one.
12893
		hideSingleBase: false,
12894
12895
		// @option sortLayers: Boolean = false
12896
		// Whether to sort the layers. When `false`, layers will keep the order
12897
		// in which they were added to the control.
12898
		sortLayers: false,
12899
12900
		// @option sortFunction: Function = *
12901
		// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
12902
		// that will be used for sorting the layers, when `sortLayers` is `true`.
12903
		// The function receives both the `L.Layer` instances and their names, as in
12904
		// `sortFunction(layerA, layerB, nameA, nameB)`.
12905
		// By default, it sorts layers alphabetically by their name.
12906
		sortFunction: function (layerA, layerB, nameA, nameB) {
12907
			return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
12908
		}
12909
	},
12910
12911
	initialize: function (baseLayers, overlays, options) {
12912
		L.setOptions(this, options);
12913
12914
		this._layers = [];
12915
		this._lastZIndex = 0;
12916
		this._handlingClick = false;
12917
12918
		for (var i in baseLayers) {
12919
			this._addLayer(baseLayers[i], i);
12920
		}
12921
12922
		for (i in overlays) {
12923
			this._addLayer(overlays[i], i, true);
12924
		}
12925
	},
12926
12927
	onAdd: function (map) {
12928
		this._initLayout();
12929
		this._update();
12930
12931
		this._map = map;
12932
		map.on('zoomend', this._checkDisabledLayers, this);
12933
12934
		return this._container;
12935
	},
12936
12937
	onRemove: function () {
12938
		this._map.off('zoomend', this._checkDisabledLayers, this);
12939
12940
		for (var i = 0; i < this._layers.length; i++) {
12941
			this._layers[i].layer.off('add remove', this._onLayerChange, this);
12942
		}
12943
	},
12944
12945
	// @method addBaseLayer(layer: Layer, name: String): this
12946
	// Adds a base layer (radio button entry) with the given name to the control.
12947
	addBaseLayer: function (layer, name) {
12948
		this._addLayer(layer, name);
12949
		return (this._map) ? this._update() : this;
12950
	},
12951
12952
	// @method addOverlay(layer: Layer, name: String): this
12953
	// Adds an overlay (checkbox entry) with the given name to the control.
12954
	addOverlay: function (layer, name) {
12955
		this._addLayer(layer, name, true);
12956
		return (this._map) ? this._update() : this;
12957
	},
12958
12959
	// @method removeLayer(layer: Layer): this
12960
	// Remove the given layer from the control.
12961
	removeLayer: function (layer) {
12962
		layer.off('add remove', this._onLayerChange, this);
12963
12964
		var obj = this._getLayer(L.stamp(layer));
12965
		if (obj) {
12966
			this._layers.splice(this._layers.indexOf(obj), 1);
12967
		}
12968
		return (this._map) ? this._update() : this;
12969
	},
12970
12971
	// @method expand(): this
12972
	// Expand the control container if collapsed.
12973
	expand: function () {
12974
		L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
12975
		this._form.style.height = null;
12976
		var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
12977
		if (acceptableHeight < this._form.clientHeight) {
12978
			L.DomUtil.addClass(this._form, 'leaflet-control-layers-scrollbar');
12979
			this._form.style.height = acceptableHeight + 'px';
12980
		} else {
12981
			L.DomUtil.removeClass(this._form, 'leaflet-control-layers-scrollbar');
12982
		}
12983
		this._checkDisabledLayers();
12984
		return this;
12985
	},
12986
12987
	// @method collapse(): this
12988
	// Collapse the control container if expanded.
12989
	collapse: function () {
12990
		L.DomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');
12991
		return this;
12992
	},
12993
12994
	_initLayout: function () {
12995
		var className = 'leaflet-control-layers',
12996
		    container = this._container = L.DomUtil.create('div', className),
12997
		    collapsed = this.options.collapsed;
12998
12999
		// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
13000
		container.setAttribute('aria-haspopup', true);
13001
13002
		L.DomEvent.disableClickPropagation(container);
13003
		if (!L.Browser.touch) {
13004
			L.DomEvent.disableScrollPropagation(container);
13005
		}
13006
13007
		var form = this._form = L.DomUtil.create('form', className + '-list');
13008
13009
		if (collapsed) {
13010
			this._map.on('click', this.collapse, this);
13011
13012
			if (!L.Browser.android) {
13013
				L.DomEvent.on(container, {
13014
					mouseenter: this.expand,
13015
					mouseleave: this.collapse
13016
				}, this);
13017
			}
13018
		}
13019
13020
		var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
13021
		link.href = '#';
13022
		link.title = 'Layers';
13023
13024
		if (L.Browser.touch) {
13025
			L.DomEvent
13026
			    .on(link, 'click', L.DomEvent.stop)
13027
			    .on(link, 'click', this.expand, this);
13028
		} else {
13029
			L.DomEvent.on(link, 'focus', this.expand, this);
13030
		}
13031
13032
		// work around for Firefox Android issue https://github.com/Leaflet/Leaflet/issues/2033
13033
		L.DomEvent.on(form, 'click', function () {
13034
			setTimeout(L.bind(this._onInputClick, this), 0);
13035
		}, this);
13036
13037
		// TODO keyboard accessibility
13038
13039
		if (!collapsed) {
13040
			this.expand();
13041
		}
13042
13043
		this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
13044
		this._separator = L.DomUtil.create('div', className + '-separator', form);
13045
		this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
13046
13047
		container.appendChild(form);
13048
	},
13049
13050
	_getLayer: function (id) {
13051
		for (var i = 0; i < this._layers.length; i++) {
13052
13053
			if (this._layers[i] && L.stamp(this._layers[i].layer) === id) {
13054
				return this._layers[i];
13055
			}
13056
		}
13057
	},
13058
13059
	_addLayer: function (layer, name, overlay) {
13060
		layer.on('add remove', this._onLayerChange, this);
13061
13062
		this._layers.push({
13063
			layer: layer,
13064
			name: name,
13065
			overlay: overlay
13066
		});
13067
13068
		if (this.options.sortLayers) {
13069
			this._layers.sort(L.bind(function (a, b) {
13070
				return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
13071
			}, this));
13072
		}
13073
13074
		if (this.options.autoZIndex && layer.setZIndex) {
13075
			this._lastZIndex++;
13076
			layer.setZIndex(this._lastZIndex);
13077
		}
13078
	},
13079
13080
	_update: function () {
13081
		if (!this._container) { return this; }
13082
13083
		L.DomUtil.empty(this._baseLayersList);
13084
		L.DomUtil.empty(this._overlaysList);
13085
13086
		var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
13087
13088
		for (i = 0; i < this._layers.length; i++) {
13089
			obj = this._layers[i];
13090
			this._addItem(obj);
13091
			overlaysPresent = overlaysPresent || obj.overlay;
13092
			baseLayersPresent = baseLayersPresent || !obj.overlay;
13093
			baseLayersCount += !obj.overlay ? 1 : 0;
13094
		}
13095
13096
		// Hide base layers section if there's only one layer.
13097
		if (this.options.hideSingleBase) {
13098
			baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
13099
			this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
13100
		}
13101
13102
		this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
13103
13104
		return this;
13105
	},
13106
13107
	_onLayerChange: function (e) {
13108
		if (!this._handlingClick) {
13109
			this._update();
13110
		}
13111
13112
		var obj = this._getLayer(L.stamp(e.target));
13113
13114
		// @namespace Map
13115
		// @section Layer events
13116
		// @event baselayerchange: LayersControlEvent
13117
		// Fired when the base layer is changed through the [layer control](#control-layers).
13118
		// @event overlayadd: LayersControlEvent
13119
		// Fired when an overlay is selected through the [layer control](#control-layers).
13120
		// @event overlayremove: LayersControlEvent
13121
		// Fired when an overlay is deselected through the [layer control](#control-layers).
13122
		// @namespace Control.Layers
13123
		var type = obj.overlay ?
13124
			(e.type === 'add' ? 'overlayadd' : 'overlayremove') :
13125
			(e.type === 'add' ? 'baselayerchange' : null);
13126
13127
		if (type) {
13128
			this._map.fire(type, obj);
13129
		}
13130
	},
13131
13132
	// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
13133
	_createRadioElement: function (name, checked) {
13134
13135
		var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
13136
				name + '"' + (checked ? ' checked="checked"' : '') + '/>';
13137
13138
		var radioFragment = document.createElement('div');
13139
		radioFragment.innerHTML = radioHtml;
13140
13141
		return radioFragment.firstChild;
13142
	},
13143
13144
	_addItem: function (obj) {
13145
		var label = document.createElement('label'),
13146
		    checked = this._map.hasLayer(obj.layer),
13147
		    input;
13148
13149
		if (obj.overlay) {
13150
			input = document.createElement('input');
13151
			input.type = 'checkbox';
13152
			input.className = 'leaflet-control-layers-selector';
13153
			input.defaultChecked = checked;
13154
		} else {
13155
			input = this._createRadioElement('leaflet-base-layers', checked);
13156
		}
13157
13158
		input.layerId = L.stamp(obj.layer);
13159
13160
		L.DomEvent.on(input, 'click', this._onInputClick, this);
13161
13162
		var name = document.createElement('span');
13163
		name.innerHTML = ' ' + obj.name;
13164
13165
		// Helps from preventing layer control flicker when checkboxes are disabled
13166
		// https://github.com/Leaflet/Leaflet/issues/2771
13167
		var holder = document.createElement('div');
13168
13169
		label.appendChild(holder);
13170
		holder.appendChild(input);
13171
		holder.appendChild(name);
13172
13173
		var container = obj.overlay ? this._overlaysList : this._baseLayersList;
13174
		container.appendChild(label);
13175
13176
		this._checkDisabledLayers();
13177
		return label;
13178
	},
13179
13180
	_onInputClick: function () {
13181
		var inputs = this._form.getElementsByTagName('input'),
13182
		    input, layer, hasLayer;
13183
		var addedLayers = [],
13184
		    removedLayers = [];
13185
13186
		this._handlingClick = true;
13187
13188
		for (var i = inputs.length - 1; i >= 0; i--) {
13189
			input = inputs[i];
13190
			layer = this._getLayer(input.layerId).layer;
13191
			hasLayer = this._map.hasLayer(layer);
13192
13193
			if (input.checked && !hasLayer) {
13194
				addedLayers.push(layer);
13195
13196
			} else if (!input.checked && hasLayer) {
13197
				removedLayers.push(layer);
13198
			}
13199
		}
13200
13201
		// Bugfix issue 2318: Should remove all old layers before readding new ones
13202
		for (i = 0; i < removedLayers.length; i++) {
13203
			this._map.removeLayer(removedLayers[i]);
13204
		}
13205
		for (i = 0; i < addedLayers.length; i++) {
13206
			this._map.addLayer(addedLayers[i]);
13207
		}
13208
13209
		this._handlingClick = false;
13210
13211
		this._refocusOnMap();
13212
	},
13213
13214
	_checkDisabledLayers: function () {
13215
		var inputs = this._form.getElementsByTagName('input'),
13216
		    input,
13217
		    layer,
13218
		    zoom = this._map.getZoom();
13219
13220
		for (var i = inputs.length - 1; i >= 0; i--) {
13221
			input = inputs[i];
13222
			layer = this._getLayer(input.layerId).layer;
13223
			input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
13224
			                 (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
13225
13226
		}
13227
	},
13228
13229
	_expand: function () {
13230
		// Backward compatibility, remove me in 1.1.
13231
		return this.expand();
13232
	},
13233
13234
	_collapse: function () {
13235
		// Backward compatibility, remove me in 1.1.
13236
		return this.collapse();
13237
	}
13238
13239
});
13240
13241
13242
// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
13243
// Creates an attribution 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.
13244
L.control.layers = function (baseLayers, overlays, options) {
13245
	return new L.Control.Layers(baseLayers, overlays, options);
13246
};
13247
13248
13249
13250
}(window, document));
13251
//# sourceMappingURL=leaflet-src.map
(-)a/koha-tmpl/intranet-tmpl/lib/leaflet/leaflet-src.map (+1 lines)
Line 0 Link Here
1
{"version":3,"sources":["src/Leaflet.js","src/core/Util.js","src/core/Class.js","src/core/Events.js","src/core/Browser.js","src/geometry/Point.js","src/geometry/Bounds.js","src/geometry/Transformation.js","src/dom/DomUtil.js","src/geo/LatLng.js","src/geo/LatLngBounds.js","src/geo/projection/Projection.LonLat.js","src/geo/projection/Projection.SphericalMercator.js","src/geo/crs/CRS.js","src/geo/crs/CRS.Simple.js","src/geo/crs/CRS.Earth.js","src/geo/crs/CRS.EPSG3857.js","src/geo/crs/CRS.EPSG4326.js","src/map/Map.js","src/layer/Layer.js","src/dom/DomEvent.js","src/dom/PosAnimation.js","src/geo/projection/Projection.Mercator.js","src/geo/crs/CRS.EPSG3395.js","src/layer/tile/GridLayer.js","src/layer/tile/TileLayer.js","src/layer/tile/TileLayer.WMS.js","src/layer/ImageOverlay.js","src/layer/marker/Icon.js","src/layer/marker/Icon.Default.js","src/layer/marker/Marker.js","src/layer/marker/DivIcon.js","src/layer/DivOverlay.js","src/layer/Popup.js","src/layer/Tooltip.js","src/layer/LayerGroup.js","src/layer/FeatureGroup.js","src/layer/vector/Renderer.js","src/layer/vector/Path.js","src/geometry/LineUtil.js","src/layer/vector/Polyline.js","src/geometry/PolyUtil.js","src/layer/vector/Polygon.js","src/layer/vector/Rectangle.js","src/layer/vector/CircleMarker.js","src/layer/vector/Circle.js","src/layer/vector/SVG.js","src/layer/vector/SVG.VML.js","src/layer/vector/Canvas.js","src/layer/GeoJSON.js","src/dom/Draggable.js","src/core/Handler.js","src/map/handler/Map.Drag.js","src/map/handler/Map.DoubleClickZoom.js","src/map/handler/Map.ScrollWheelZoom.js","src/dom/DomEvent.DoubleTap.js","src/dom/DomEvent.Pointer.js","src/map/handler/Map.TouchZoom.js","src/map/handler/Map.Tap.js","src/map/handler/Map.BoxZoom.js","src/map/handler/Map.Keyboard.js","src/layer/marker/Marker.Drag.js","src/control/Control.js","src/control/Control.Zoom.js","src/control/Control.Attribution.js","src/control/Control.Scale.js","src/control/Control.Layers.js"],"names":[],"mappings":";;;;yCAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1PA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9GA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACjSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACvJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AChUA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnPA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC1BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpkDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/QA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACvTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AChBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACh2BA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzRA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACjIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/IA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtVA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AChEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACrMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACvKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzSA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACvJA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACzGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC7OA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3fA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxYA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3NA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/CA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AClOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACpDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACtFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3FA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACnIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC/HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC3HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC9KA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACxGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AChKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;ACrIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AC5HA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AChIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","sourcesContent":["\r\nvar L = {\r\n\tversion: \"1.0.3+ed36a04\"\r\n};\r\n\r\nfunction expose() {\r\n\tvar oldL = window.L;\r\n\r\n\tL.noConflict = function () {\r\n\t\twindow.L = oldL;\r\n\t\treturn this;\r\n\t};\r\n\r\n\twindow.L = L;\r\n}\r\n\r\n// define Leaflet for Node module pattern loaders, including Browserify\r\nif (typeof module === 'object' && typeof module.exports === 'object') {\r\n\tmodule.exports = L;\r\n\r\n// define Leaflet as an AMD module\r\n} else if (typeof define === 'function' && define.amd) {\r\n\tdefine(L);\r\n}\r\n\r\n// define Leaflet as a global L variable, saving the original L to restore later if needed\r\nif (typeof window !== 'undefined') {\r\n\texpose();\r\n}\r\n","/*\r\n * @namespace Util\r\n *\r\n * Various utility functions, used by Leaflet internally.\r\n */\r\n\r\nL.Util = {\r\n\r\n\t// @function extend(dest: Object, src?: Object): Object\r\n\t// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.\r\n\textend: function (dest) {\r\n\t\tvar i, j, len, src;\r\n\r\n\t\tfor (j = 1, len = arguments.length; j < len; j++) {\r\n\t\t\tsrc = arguments[j];\r\n\t\t\tfor (i in src) {\r\n\t\t\t\tdest[i] = src[i];\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn dest;\r\n\t},\r\n\r\n\t// @function create(proto: Object, properties?: Object): Object\r\n\t// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)\r\n\tcreate: Object.create || (function () {\r\n\t\tfunction F() {}\r\n\t\treturn function (proto) {\r\n\t\t\tF.prototype = proto;\r\n\t\t\treturn new F();\r\n\t\t};\r\n\t})(),\r\n\r\n\t// @function bind(fn: Function, …): Function\r\n\t// 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).\r\n\t// Has a `L.bind()` shortcut.\r\n\tbind: function (fn, obj) {\r\n\t\tvar slice = Array.prototype.slice;\r\n\r\n\t\tif (fn.bind) {\r\n\t\t\treturn fn.bind.apply(fn, slice.call(arguments, 1));\r\n\t\t}\r\n\r\n\t\tvar args = slice.call(arguments, 2);\r\n\r\n\t\treturn function () {\r\n\t\t\treturn fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);\r\n\t\t};\r\n\t},\r\n\r\n\t// @function stamp(obj: Object): Number\r\n\t// Returns the unique ID of an object, assiging it one if it doesn't have it.\r\n\tstamp: function (obj) {\r\n\t\t/*eslint-disable */\r\n\t\tobj._leaflet_id = obj._leaflet_id || ++L.Util.lastId;\r\n\t\treturn obj._leaflet_id;\r\n\t\t/*eslint-enable */\r\n\t},\r\n\r\n\t// @property lastId: Number\r\n\t// Last unique ID used by [`stamp()`](#util-stamp)\r\n\tlastId: 0,\r\n\r\n\t// @function throttle(fn: Function, time: Number, context: Object): Function\r\n\t// Returns a function which executes function `fn` with the given scope `context`\r\n\t// (so that the `this` keyword refers to `context` inside `fn`'s code). The function\r\n\t// `fn` will be called no more than one time per given amount of `time`. The arguments\r\n\t// received by the bound function will be any arguments passed when binding the\r\n\t// function, followed by any arguments passed when invoking the bound function.\r\n\t// Has an `L.bind` shortcut.\r\n\tthrottle: function (fn, time, context) {\r\n\t\tvar lock, args, wrapperFn, later;\r\n\r\n\t\tlater = function () {\r\n\t\t\t// reset lock and call if queued\r\n\t\t\tlock = false;\r\n\t\t\tif (args) {\r\n\t\t\t\twrapperFn.apply(context, args);\r\n\t\t\t\targs = false;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\twrapperFn = function () {\r\n\t\t\tif (lock) {\r\n\t\t\t\t// called too soon, queue to call later\r\n\t\t\t\targs = arguments;\r\n\r\n\t\t\t} else {\r\n\t\t\t\t// call and lock until later\r\n\t\t\t\tfn.apply(context, arguments);\r\n\t\t\t\tsetTimeout(later, time);\r\n\t\t\t\tlock = true;\r\n\t\t\t}\r\n\t\t};\r\n\r\n\t\treturn wrapperFn;\r\n\t},\r\n\r\n\t// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number\r\n\t// Returns the number `num` modulo `range` in such a way so it lies within\r\n\t// `range[0]` and `range[1]`. The returned value will be always smaller than\r\n\t// `range[1]` unless `includeMax` is set to `true`.\r\n\twrapNum: function (x, range, includeMax) {\r\n\t\tvar max = range[1],\r\n\t\t    min = range[0],\r\n\t\t    d = max - min;\r\n\t\treturn x === max && includeMax ? x : ((x - min) % d + d) % d + min;\r\n\t},\r\n\r\n\t// @function falseFn(): Function\r\n\t// Returns a function which always returns `false`.\r\n\tfalseFn: function () { return false; },\r\n\r\n\t// @function formatNum(num: Number, digits?: Number): Number\r\n\t// Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.\r\n\tformatNum: function (num, digits) {\r\n\t\tvar pow = Math.pow(10, digits || 5);\r\n\t\treturn Math.round(num * pow) / pow;\r\n\t},\r\n\r\n\t// @function trim(str: String): String\r\n\t// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)\r\n\ttrim: function (str) {\r\n\t\treturn str.trim ? str.trim() : str.replace(/^\\s+|\\s+$/g, '');\r\n\t},\r\n\r\n\t// @function splitWords(str: String): String[]\r\n\t// Trims and splits the string on whitespace and returns the array of parts.\r\n\tsplitWords: function (str) {\r\n\t\treturn L.Util.trim(str).split(/\\s+/);\r\n\t},\r\n\r\n\t// @function setOptions(obj: Object, options: Object): Object\r\n\t// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.\r\n\tsetOptions: function (obj, options) {\r\n\t\tif (!obj.hasOwnProperty('options')) {\r\n\t\t\tobj.options = obj.options ? L.Util.create(obj.options) : {};\r\n\t\t}\r\n\t\tfor (var i in options) {\r\n\t\t\tobj.options[i] = options[i];\r\n\t\t}\r\n\t\treturn obj.options;\r\n\t},\r\n\r\n\t// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String\r\n\t// Converts an object into a parameter URL string, e.g. `{a: \"foo\", b: \"bar\"}`\r\n\t// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will\r\n\t// be appended at the end. If `uppercase` is `true`, the parameter names will\r\n\t// be uppercased (e.g. `'?A=foo&B=bar'`)\r\n\tgetParamString: function (obj, existingUrl, uppercase) {\r\n\t\tvar params = [];\r\n\t\tfor (var i in obj) {\r\n\t\t\tparams.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));\r\n\t\t}\r\n\t\treturn ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');\r\n\t},\r\n\r\n\t// @function template(str: String, data: Object): String\r\n\t// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`\r\n\t// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string\r\n\t// `('Hello foo, bar')`. You can also specify functions instead of strings for\r\n\t// data values — they will be evaluated passing `data` as an argument.\r\n\ttemplate: function (str, data) {\r\n\t\treturn str.replace(L.Util.templateRe, function (str, key) {\r\n\t\t\tvar value = data[key];\r\n\r\n\t\t\tif (value === undefined) {\r\n\t\t\t\tthrow new Error('No value provided for variable ' + str);\r\n\r\n\t\t\t} else if (typeof value === 'function') {\r\n\t\t\t\tvalue = value(data);\r\n\t\t\t}\r\n\t\t\treturn value;\r\n\t\t});\r\n\t},\r\n\r\n\ttemplateRe: /\\{ *([\\w_\\-]+) *\\}/g,\r\n\r\n\t// @function isArray(obj): Boolean\r\n\t// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)\r\n\tisArray: Array.isArray || function (obj) {\r\n\t\treturn (Object.prototype.toString.call(obj) === '[object Array]');\r\n\t},\r\n\r\n\t// @function indexOf(array: Array, el: Object): Number\r\n\t// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)\r\n\tindexOf: function (array, el) {\r\n\t\tfor (var i = 0; i < array.length; i++) {\r\n\t\t\tif (array[i] === el) { return i; }\r\n\t\t}\r\n\t\treturn -1;\r\n\t},\r\n\r\n\t// @property emptyImageUrl: String\r\n\t// Data URI string containing a base64-encoded empty GIF image.\r\n\t// Used as a hack to free memory from unused images on WebKit-powered\r\n\t// mobile devices (by setting image `src` to this string).\r\n\temptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='\r\n};\r\n\r\n(function () {\r\n\t// inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/\r\n\r\n\tfunction getPrefixed(name) {\r\n\t\treturn window['webkit' + name] || window['moz' + name] || window['ms' + name];\r\n\t}\r\n\r\n\tvar lastTime = 0;\r\n\r\n\t// fallback for IE 7-8\r\n\tfunction timeoutDefer(fn) {\r\n\t\tvar time = +new Date(),\r\n\t\t    timeToCall = Math.max(0, 16 - (time - lastTime));\r\n\r\n\t\tlastTime = time + timeToCall;\r\n\t\treturn window.setTimeout(fn, timeToCall);\r\n\t}\r\n\r\n\tvar requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer,\r\n\t    cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||\r\n\t               getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };\r\n\r\n\r\n\t// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number\r\n\t// Schedules `fn` to be executed when the browser repaints. `fn` is bound to\r\n\t// `context` if given. When `immediate` is set, `fn` is called immediately if\r\n\t// the browser doesn't have native support for\r\n\t// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),\r\n\t// otherwise it's delayed. Returns a request ID that can be used to cancel the request.\r\n\tL.Util.requestAnimFrame = function (fn, context, immediate) {\r\n\t\tif (immediate && requestFn === timeoutDefer) {\r\n\t\t\tfn.call(context);\r\n\t\t} else {\r\n\t\t\treturn requestFn.call(window, L.bind(fn, context));\r\n\t\t}\r\n\t};\r\n\r\n\t// @function cancelAnimFrame(id: Number): undefined\r\n\t// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).\r\n\tL.Util.cancelAnimFrame = function (id) {\r\n\t\tif (id) {\r\n\t\t\tcancelFn.call(window, id);\r\n\t\t}\r\n\t};\r\n})();\r\n\r\n// shortcuts for most used utility functions\r\nL.extend = L.Util.extend;\r\nL.bind = L.Util.bind;\r\nL.stamp = L.Util.stamp;\r\nL.setOptions = L.Util.setOptions;\r\n","\r\n// @class Class\r\n// @aka L.Class\r\n\r\n// @section\r\n// @uninheritable\r\n\r\n// Thanks to John Resig and Dean Edwards for inspiration!\r\n\r\nL.Class = function () {};\r\n\r\nL.Class.extend = function (props) {\r\n\r\n\t// @function extend(props: Object): Function\r\n\t// [Extends the current class](#class-inheritance) given the properties to be included.\r\n\t// Returns a Javascript function that is a class constructor (to be called with `new`).\r\n\tvar NewClass = function () {\r\n\r\n\t\t// call the constructor\r\n\t\tif (this.initialize) {\r\n\t\t\tthis.initialize.apply(this, arguments);\r\n\t\t}\r\n\r\n\t\t// call all constructor hooks\r\n\t\tthis.callInitHooks();\r\n\t};\r\n\r\n\tvar parentProto = NewClass.__super__ = this.prototype;\r\n\r\n\tvar proto = L.Util.create(parentProto);\r\n\tproto.constructor = NewClass;\r\n\r\n\tNewClass.prototype = proto;\r\n\r\n\t// inherit parent's statics\r\n\tfor (var i in this) {\r\n\t\tif (this.hasOwnProperty(i) && i !== 'prototype') {\r\n\t\t\tNewClass[i] = this[i];\r\n\t\t}\r\n\t}\r\n\r\n\t// mix static properties into the class\r\n\tif (props.statics) {\r\n\t\tL.extend(NewClass, props.statics);\r\n\t\tdelete props.statics;\r\n\t}\r\n\r\n\t// mix includes into the prototype\r\n\tif (props.includes) {\r\n\t\tL.Util.extend.apply(null, [proto].concat(props.includes));\r\n\t\tdelete props.includes;\r\n\t}\r\n\r\n\t// merge options\r\n\tif (proto.options) {\r\n\t\tprops.options = L.Util.extend(L.Util.create(proto.options), props.options);\r\n\t}\r\n\r\n\t// mix given properties into the prototype\r\n\tL.extend(proto, props);\r\n\r\n\tproto._initHooks = [];\r\n\r\n\t// add method for calling all hooks\r\n\tproto.callInitHooks = function () {\r\n\r\n\t\tif (this._initHooksCalled) { return; }\r\n\r\n\t\tif (parentProto.callInitHooks) {\r\n\t\t\tparentProto.callInitHooks.call(this);\r\n\t\t}\r\n\r\n\t\tthis._initHooksCalled = true;\r\n\r\n\t\tfor (var i = 0, len = proto._initHooks.length; i < len; i++) {\r\n\t\t\tproto._initHooks[i].call(this);\r\n\t\t}\r\n\t};\r\n\r\n\treturn NewClass;\r\n};\r\n\r\n\r\n// @function include(properties: Object): this\r\n// [Includes a mixin](#class-includes) into the current class.\r\nL.Class.include = function (props) {\r\n\tL.extend(this.prototype, props);\r\n\treturn this;\r\n};\r\n\r\n// @function mergeOptions(options: Object): this\r\n// [Merges `options`](#class-options) into the defaults of the class.\r\nL.Class.mergeOptions = function (options) {\r\n\tL.extend(this.prototype.options, options);\r\n\treturn this;\r\n};\r\n\r\n// @function addInitHook(fn: Function): this\r\n// Adds a [constructor hook](#class-constructor-hooks) to the class.\r\nL.Class.addInitHook = function (fn) { // (Function) || (String, args...)\r\n\tvar args = Array.prototype.slice.call(arguments, 1);\r\n\r\n\tvar init = typeof fn === 'function' ? fn : function () {\r\n\t\tthis[fn].apply(this, args);\r\n\t};\r\n\r\n\tthis.prototype._initHooks = this.prototype._initHooks || [];\r\n\tthis.prototype._initHooks.push(init);\r\n\treturn this;\r\n};\r\n","/*\r\n * @class Evented\r\n * @aka L.Evented\r\n * @inherits Class\r\n *\r\n * 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).\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * map.on('click', function(e) {\r\n * \talert(e.latlng);\r\n * } );\r\n * ```\r\n *\r\n * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:\r\n *\r\n * ```js\r\n * function onClick(e) { ... }\r\n *\r\n * map.on('click', onClick);\r\n * map.off('click', onClick);\r\n * ```\r\n */\r\n\r\n\r\nL.Evented = L.Class.extend({\r\n\r\n\t/* @method on(type: String, fn: Function, context?: Object): this\r\n\t * 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'`).\r\n\t *\r\n\t * @alternative\r\n\t * @method on(eventMap: Object): this\r\n\t * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\t */\r\n\ton: function (types, fn, context) {\r\n\r\n\t\t// types can be a map of types/handlers\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\t// we don't process space-separated events here for performance;\r\n\t\t\t\t// it's a hot path since Layer uses the on(obj) syntax\r\n\t\t\t\tthis._on(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\t// types can be a string of space-separated words\r\n\t\t\ttypes = L.Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t/* @method off(type: String, fn?: Function, context?: Object): this\r\n\t * 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.\r\n\t *\r\n\t * @alternative\r\n\t * @method off(eventMap: Object): this\r\n\t * Removes a set of type/listener pairs.\r\n\t *\r\n\t * @alternative\r\n\t * @method off: this\r\n\t * Removes all listeners to all events on the object.\r\n\t */\r\n\toff: function (types, fn, context) {\r\n\r\n\t\tif (!types) {\r\n\t\t\t// clear all listeners if called without arguments\r\n\t\t\tdelete this._events;\r\n\r\n\t\t} else if (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis._off(type, types[type], fn);\r\n\t\t\t}\r\n\r\n\t\t} else {\r\n\t\t\ttypes = L.Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._off(types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// attach listener (without syntactic sugar now)\r\n\t_on: function (type, fn, context) {\r\n\t\tthis._events = this._events || {};\r\n\r\n\t\t/* get/init listeners for type */\r\n\t\tvar typeListeners = this._events[type];\r\n\t\tif (!typeListeners) {\r\n\t\t\ttypeListeners = [];\r\n\t\t\tthis._events[type] = typeListeners;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\t// Less memory footprint.\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\t\tvar newListener = {fn: fn, ctx: context},\r\n\t\t    listeners = typeListeners;\r\n\r\n\t\t// check if fn already there\r\n\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\tif (listeners[i].fn === fn && listeners[i].ctx === context) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tlisteners.push(newListener);\r\n\t},\r\n\r\n\t_off: function (type, fn, context) {\r\n\t\tvar listeners,\r\n\t\t    i,\r\n\t\t    len;\r\n\r\n\t\tif (!this._events) { return; }\r\n\r\n\t\tlisteners = this._events[type];\r\n\r\n\t\tif (!listeners) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!fn) {\r\n\t\t\t// Set all removed listeners to noop so they are not called if remove happens in fire\r\n\t\t\tfor (i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\tlisteners[i].fn = L.Util.falseFn;\r\n\t\t\t}\r\n\t\t\t// clear all listeners for a type if function isn't specified\r\n\t\t\tdelete this._events[type];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (context === this) {\r\n\t\t\tcontext = undefined;\r\n\t\t}\r\n\r\n\t\tif (listeners) {\r\n\r\n\t\t\t// find fn and remove it\r\n\t\t\tfor (i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\tvar l = listeners[i];\r\n\t\t\t\tif (l.ctx !== context) { continue; }\r\n\t\t\t\tif (l.fn === fn) {\r\n\r\n\t\t\t\t\t// set the removed listener to noop so that's not called if remove happens in fire\r\n\t\t\t\t\tl.fn = L.Util.falseFn;\r\n\r\n\t\t\t\t\tif (this._firingCount) {\r\n\t\t\t\t\t\t/* copy array in case events are being fired */\r\n\t\t\t\t\t\tthis._events[type] = listeners = listeners.slice();\r\n\t\t\t\t\t}\r\n\t\t\t\t\tlisteners.splice(i, 1);\r\n\r\n\t\t\t\t\treturn;\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method fire(type: String, data?: Object, propagate?: Boolean): this\r\n\t// Fires an event of the specified type. You can optionally provide an data\r\n\t// object — the first argument of the listener function will contain its\r\n\t// properties. The event can optionally be propagated to event parents.\r\n\tfire: function (type, data, propagate) {\r\n\t\tif (!this.listens(type, propagate)) { return this; }\r\n\r\n\t\tvar event = L.Util.extend({}, data, {type: type, target: this});\r\n\r\n\t\tif (this._events) {\r\n\t\t\tvar listeners = this._events[type];\r\n\r\n\t\t\tif (listeners) {\r\n\t\t\t\tthis._firingCount = (this._firingCount + 1) || 1;\r\n\t\t\t\tfor (var i = 0, len = listeners.length; i < len; i++) {\r\n\t\t\t\t\tvar l = listeners[i];\r\n\t\t\t\t\tl.fn.call(l.ctx || this, event);\r\n\t\t\t\t}\r\n\r\n\t\t\t\tthis._firingCount--;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// propagate the event to parents (set with addEventParent)\r\n\t\t\tthis._propagateEvent(event);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method listens(type: String): Boolean\r\n\t// Returns `true` if a particular event type has any listeners attached to it.\r\n\tlistens: function (type, propagate) {\r\n\t\tvar listeners = this._events && this._events[type];\r\n\t\tif (listeners && listeners.length) { return true; }\r\n\r\n\t\tif (propagate) {\r\n\t\t\t// also check parents for listeners if event propagates\r\n\t\t\tfor (var id in this._eventParents) {\r\n\t\t\t\tif (this._eventParents[id].listens(type, propagate)) { return true; }\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t},\r\n\r\n\t// @method once(…): this\r\n\t// Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.\r\n\tonce: function (types, fn, context) {\r\n\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis.once(type, types[type], fn);\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar handler = L.bind(function () {\r\n\t\t\tthis\r\n\t\t\t    .off(types, fn, context)\r\n\t\t\t    .off(types, handler, context);\r\n\t\t}, this);\r\n\r\n\t\t// add a listener that's executed once and removed after that\r\n\t\treturn this\r\n\t\t    .on(types, fn, context)\r\n\t\t    .on(types, handler, context);\r\n\t},\r\n\r\n\t// @method addEventParent(obj: Evented): this\r\n\t// Adds an event parent - an `Evented` that will receive propagated events\r\n\taddEventParent: function (obj) {\r\n\t\tthis._eventParents = this._eventParents || {};\r\n\t\tthis._eventParents[L.stamp(obj)] = obj;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeEventParent(obj: Evented): this\r\n\t// Removes an event parent, so it will stop receiving propagated events\r\n\tremoveEventParent: function (obj) {\r\n\t\tif (this._eventParents) {\r\n\t\t\tdelete this._eventParents[L.stamp(obj)];\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_propagateEvent: function (e) {\r\n\t\tfor (var id in this._eventParents) {\r\n\t\t\tthis._eventParents[id].fire(e.type, L.extend({layer: e.target}, e), true);\r\n\t\t}\r\n\t}\r\n});\r\n\r\nvar proto = L.Evented.prototype;\r\n\r\n// aliases; we should ditch those eventually\r\n\r\n// @method addEventListener(…): this\r\n// Alias to [`on(…)`](#evented-on)\r\nproto.addEventListener = proto.on;\r\n\r\n// @method removeEventListener(…): this\r\n// Alias to [`off(…)`](#evented-off)\r\n\r\n// @method clearAllEventListeners(…): this\r\n// Alias to [`off()`](#evented-off)\r\nproto.removeEventListener = proto.clearAllEventListeners = proto.off;\r\n\r\n// @method addOneTimeEventListener(…): this\r\n// Alias to [`once(…)`](#evented-once)\r\nproto.addOneTimeEventListener = proto.once;\r\n\r\n// @method fireEvent(…): this\r\n// Alias to [`fire(…)`](#evented-fire)\r\nproto.fireEvent = proto.fire;\r\n\r\n// @method hasEventListeners(…): Boolean\r\n// Alias to [`listens(…)`](#evented-listens)\r\nproto.hasEventListeners = proto.listens;\r\n\r\nL.Mixin = {Events: proto};\r\n","/*\r\n * @namespace Browser\r\n * @aka L.Browser\r\n *\r\n * A namespace with static properties for browser/feature detection used by Leaflet internally.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * if (L.Browser.ielt9) {\r\n *   alert('Upgrade your browser, dude!');\r\n * }\r\n * ```\r\n */\r\n\r\n(function () {\r\n\r\n\tvar ua = navigator.userAgent.toLowerCase(),\r\n\t    doc = document.documentElement,\r\n\r\n\t    ie = 'ActiveXObject' in window,\r\n\r\n\t    webkit    = ua.indexOf('webkit') !== -1,\r\n\t    phantomjs = ua.indexOf('phantom') !== -1,\r\n\t    android23 = ua.search('android [23]') !== -1,\r\n\t    chrome    = ua.indexOf('chrome') !== -1,\r\n\t    gecko     = ua.indexOf('gecko') !== -1  && !webkit && !window.opera && !ie,\r\n\r\n\t    win = navigator.platform.indexOf('Win') === 0,\r\n\r\n\t    mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1,\r\n\t    msPointer = !window.PointerEvent && window.MSPointerEvent,\r\n\t    pointer = window.PointerEvent || msPointer,\r\n\r\n\t    ie3d = ie && ('transition' in doc.style),\r\n\t    webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,\r\n\t    gecko3d = 'MozPerspective' in doc.style,\r\n\t    opera12 = 'OTransition' in doc.style;\r\n\r\n\r\n\tvar touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||\r\n\t\t\t(window.DocumentTouch && document instanceof window.DocumentTouch));\r\n\r\n\tL.Browser = {\r\n\r\n\t\t// @property ie: Boolean\r\n\t\t// `true` for all Internet Explorer versions (not Edge).\r\n\t\tie: ie,\r\n\r\n\t\t// @property ielt9: Boolean\r\n\t\t// `true` for Internet Explorer versions less than 9.\r\n\t\tielt9: ie && !document.addEventListener,\r\n\r\n\t\t// @property edge: Boolean\r\n\t\t// `true` for the Edge web browser.\r\n\t\tedge: 'msLaunchUri' in navigator && !('documentMode' in document),\r\n\r\n\t\t// @property webkit: Boolean\r\n\t\t// `true` for webkit-based browsers like Chrome and Safari (including mobile versions).\r\n\t\twebkit: webkit,\r\n\r\n\t\t// @property gecko: Boolean\r\n\t\t// `true` for gecko-based browsers like Firefox.\r\n\t\tgecko: gecko,\r\n\r\n\t\t// @property android: Boolean\r\n\t\t// `true` for any browser running on an Android platform.\r\n\t\tandroid: ua.indexOf('android') !== -1,\r\n\r\n\t\t// @property android23: Boolean\r\n\t\t// `true` for browsers running on Android 2 or Android 3.\r\n\t\tandroid23: android23,\r\n\r\n\t\t// @property chrome: Boolean\r\n\t\t// `true` for the Chrome browser.\r\n\t\tchrome: chrome,\r\n\r\n\t\t// @property safari: Boolean\r\n\t\t// `true` for the Safari browser.\r\n\t\tsafari: !chrome && ua.indexOf('safari') !== -1,\r\n\r\n\r\n\t\t// @property win: Boolean\r\n\t\t// `true` when the browser is running in a Windows platform\r\n\t\twin: win,\r\n\r\n\r\n\t\t// @property ie3d: Boolean\r\n\t\t// `true` for all Internet Explorer versions supporting CSS transforms.\r\n\t\tie3d: ie3d,\r\n\r\n\t\t// @property webkit3d: Boolean\r\n\t\t// `true` for webkit-based browsers supporting CSS transforms.\r\n\t\twebkit3d: webkit3d,\r\n\r\n\t\t// @property gecko3d: Boolean\r\n\t\t// `true` for gecko-based browsers supporting CSS transforms.\r\n\t\tgecko3d: gecko3d,\r\n\r\n\t\t// @property opera12: Boolean\r\n\t\t// `true` for the Opera browser supporting CSS transforms (version 12 or later).\r\n\t\topera12: opera12,\r\n\r\n\t\t// @property any3d: Boolean\r\n\t\t// `true` for all browsers supporting CSS transforms.\r\n\t\tany3d: !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantomjs,\r\n\r\n\r\n\t\t// @property mobile: Boolean\r\n\t\t// `true` for all browsers running in a mobile device.\r\n\t\tmobile: mobile,\r\n\r\n\t\t// @property mobileWebkit: Boolean\r\n\t\t// `true` for all webkit-based browsers in a mobile device.\r\n\t\tmobileWebkit: mobile && webkit,\r\n\r\n\t\t// @property mobileWebkit3d: Boolean\r\n\t\t// `true` for all webkit-based browsers in a mobile device supporting CSS transforms.\r\n\t\tmobileWebkit3d: mobile && webkit3d,\r\n\r\n\t\t// @property mobileOpera: Boolean\r\n\t\t// `true` for the Opera browser in a mobile device.\r\n\t\tmobileOpera: mobile && window.opera,\r\n\r\n\t\t// @property mobileGecko: Boolean\r\n\t\t// `true` for gecko-based browsers running in a mobile device.\r\n\t\tmobileGecko: mobile && gecko,\r\n\r\n\r\n\t\t// @property touch: Boolean\r\n\t\t// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).\r\n\t\t// This does not necessarily mean that the browser is running in a computer with\r\n\t\t// a touchscreen, it only means that the browser is capable of understanding\r\n\t\t// touch events.\r\n\t\ttouch: !!touch,\r\n\r\n\t\t// @property msPointer: Boolean\r\n\t\t// `true` for browsers implementing the Microsoft touch events model (notably IE10).\r\n\t\tmsPointer: !!msPointer,\r\n\r\n\t\t// @property pointer: Boolean\r\n\t\t// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).\r\n\t\tpointer: !!pointer,\r\n\r\n\r\n\t\t// @property retina: Boolean\r\n\t\t// `true` for browsers on a high-resolution \"retina\" screen.\r\n\t\tretina: (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1\r\n\t};\r\n\r\n}());\r\n","/*\r\n * @class Point\r\n * @aka L.Point\r\n *\r\n * Represents a point with `x` and `y` coordinates in pixels.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var point = L.point(200, 300);\r\n * ```\r\n *\r\n * 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:\r\n *\r\n * ```js\r\n * map.panBy([200, 300]);\r\n * map.panBy(L.point(200, 300));\r\n * ```\r\n */\r\n\r\nL.Point = function (x, y, round) {\r\n\t// @property x: Number; The `x` coordinate of the point\r\n\tthis.x = (round ? Math.round(x) : x);\r\n\t// @property y: Number; The `y` coordinate of the point\r\n\tthis.y = (round ? Math.round(y) : y);\r\n};\r\n\r\nL.Point.prototype = {\r\n\r\n\t// @method clone(): Point\r\n\t// Returns a copy of the current point.\r\n\tclone: function () {\r\n\t\treturn new L.Point(this.x, this.y);\r\n\t},\r\n\r\n\t// @method add(otherPoint: Point): Point\r\n\t// Returns the result of addition of the current and the given points.\r\n\tadd: function (point) {\r\n\t\t// non-destructive, returns a new point\r\n\t\treturn this.clone()._add(L.point(point));\r\n\t},\r\n\r\n\t_add: function (point) {\r\n\t\t// destructive, used directly for performance in situations where it's safe to modify existing point\r\n\t\tthis.x += point.x;\r\n\t\tthis.y += point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method subtract(otherPoint: Point): Point\r\n\t// Returns the result of subtraction of the given point from the current.\r\n\tsubtract: function (point) {\r\n\t\treturn this.clone()._subtract(L.point(point));\r\n\t},\r\n\r\n\t_subtract: function (point) {\r\n\t\tthis.x -= point.x;\r\n\t\tthis.y -= point.y;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method divideBy(num: Number): Point\r\n\t// Returns the result of division of the current point by the given number.\r\n\tdivideBy: function (num) {\r\n\t\treturn this.clone()._divideBy(num);\r\n\t},\r\n\r\n\t_divideBy: function (num) {\r\n\t\tthis.x /= num;\r\n\t\tthis.y /= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method multiplyBy(num: Number): Point\r\n\t// Returns the result of multiplication of the current point by the given number.\r\n\tmultiplyBy: function (num) {\r\n\t\treturn this.clone()._multiplyBy(num);\r\n\t},\r\n\r\n\t_multiplyBy: function (num) {\r\n\t\tthis.x *= num;\r\n\t\tthis.y *= num;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method scaleBy(scale: Point): Point\r\n\t// Multiply each coordinate of the current point by each coordinate of\r\n\t// `scale`. In linear algebra terms, multiply the point by the\r\n\t// [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)\r\n\t// defined by `scale`.\r\n\tscaleBy: function (point) {\r\n\t\treturn new L.Point(this.x * point.x, this.y * point.y);\r\n\t},\r\n\r\n\t// @method unscaleBy(scale: Point): Point\r\n\t// Inverse of `scaleBy`. Divide each coordinate of the current point by\r\n\t// each coordinate of `scale`.\r\n\tunscaleBy: function (point) {\r\n\t\treturn new L.Point(this.x / point.x, this.y / point.y);\r\n\t},\r\n\r\n\t// @method round(): Point\r\n\t// Returns a copy of the current point with rounded coordinates.\r\n\tround: function () {\r\n\t\treturn this.clone()._round();\r\n\t},\r\n\r\n\t_round: function () {\r\n\t\tthis.x = Math.round(this.x);\r\n\t\tthis.y = Math.round(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method floor(): Point\r\n\t// Returns a copy of the current point with floored coordinates (rounded down).\r\n\tfloor: function () {\r\n\t\treturn this.clone()._floor();\r\n\t},\r\n\r\n\t_floor: function () {\r\n\t\tthis.x = Math.floor(this.x);\r\n\t\tthis.y = Math.floor(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method ceil(): Point\r\n\t// Returns a copy of the current point with ceiled coordinates (rounded up).\r\n\tceil: function () {\r\n\t\treturn this.clone()._ceil();\r\n\t},\r\n\r\n\t_ceil: function () {\r\n\t\tthis.x = Math.ceil(this.x);\r\n\t\tthis.y = Math.ceil(this.y);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method distanceTo(otherPoint: Point): Number\r\n\t// Returns the cartesian distance between the current and the given points.\r\n\tdistanceTo: function (point) {\r\n\t\tpoint = L.point(point);\r\n\r\n\t\tvar x = point.x - this.x,\r\n\t\t    y = point.y - this.y;\r\n\r\n\t\treturn Math.sqrt(x * x + y * y);\r\n\t},\r\n\r\n\t// @method equals(otherPoint: Point): Boolean\r\n\t// Returns `true` if the given point has the same coordinates.\r\n\tequals: function (point) {\r\n\t\tpoint = L.point(point);\r\n\r\n\t\treturn point.x === this.x &&\r\n\t\t       point.y === this.y;\r\n\t},\r\n\r\n\t// @method contains(otherPoint: Point): Boolean\r\n\t// Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).\r\n\tcontains: function (point) {\r\n\t\tpoint = L.point(point);\r\n\r\n\t\treturn Math.abs(point.x) <= Math.abs(this.x) &&\r\n\t\t       Math.abs(point.y) <= Math.abs(this.y);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point for debugging purposes.\r\n\ttoString: function () {\r\n\t\treturn 'Point(' +\r\n\t\t        L.Util.formatNum(this.x) + ', ' +\r\n\t\t        L.Util.formatNum(this.y) + ')';\r\n\t}\r\n};\r\n\r\n// @factory L.point(x: Number, y: Number, round?: Boolean)\r\n// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Number[])\r\n// Expects an array of the form `[x, y]` instead.\r\n\r\n// @alternative\r\n// @factory L.point(coords: Object)\r\n// Expects a plain object of the form `{x: Number, y: Number}` instead.\r\nL.point = function (x, y, round) {\r\n\tif (x instanceof L.Point) {\r\n\t\treturn x;\r\n\t}\r\n\tif (L.Util.isArray(x)) {\r\n\t\treturn new L.Point(x[0], x[1]);\r\n\t}\r\n\tif (x === undefined || x === null) {\r\n\t\treturn x;\r\n\t}\r\n\tif (typeof x === 'object' && 'x' in x && 'y' in x) {\r\n\t\treturn new L.Point(x.x, x.y);\r\n\t}\r\n\treturn new L.Point(x, y, round);\r\n};\r\n","/*\r\n * @class Bounds\r\n * @aka L.Bounds\r\n *\r\n * Represents a rectangular area in pixel coordinates.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var p1 = L.point(10, 10),\r\n * p2 = L.point(40, 60),\r\n * bounds = L.bounds(p1, p2);\r\n * ```\r\n *\r\n * 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:\r\n *\r\n * ```js\r\n * otherBounds.intersects([[10, 10], [40, 60]]);\r\n * ```\r\n */\r\n\r\nL.Bounds = function (a, b) {\r\n\tif (!a) { return; }\r\n\r\n\tvar points = b ? [a, b] : a;\r\n\r\n\tfor (var i = 0, len = points.length; i < len; i++) {\r\n\t\tthis.extend(points[i]);\r\n\t}\r\n};\r\n\r\nL.Bounds.prototype = {\r\n\t// @method extend(point: Point): this\r\n\t// Extends the bounds to contain the given point.\r\n\textend: function (point) { // (Point)\r\n\t\tpoint = L.point(point);\r\n\r\n\t\t// @property min: Point\r\n\t\t// The top left corner of the rectangle.\r\n\t\t// @property max: Point\r\n\t\t// The bottom right corner of the rectangle.\r\n\t\tif (!this.min && !this.max) {\r\n\t\t\tthis.min = point.clone();\r\n\t\t\tthis.max = point.clone();\r\n\t\t} else {\r\n\t\t\tthis.min.x = Math.min(point.x, this.min.x);\r\n\t\t\tthis.max.x = Math.max(point.x, this.max.x);\r\n\t\t\tthis.min.y = Math.min(point.y, this.min.y);\r\n\t\t\tthis.max.y = Math.max(point.y, this.max.y);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getCenter(round?: Boolean): Point\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function (round) {\r\n\t\treturn new L.Point(\r\n\t\t        (this.min.x + this.max.x) / 2,\r\n\t\t        (this.min.y + this.max.y) / 2, round);\r\n\t},\r\n\r\n\t// @method getBottomLeft(): Point\r\n\t// Returns the bottom-left point of the bounds.\r\n\tgetBottomLeft: function () {\r\n\t\treturn new L.Point(this.min.x, this.max.y);\r\n\t},\r\n\r\n\t// @method getTopRight(): Point\r\n\t// Returns the top-right point of the bounds.\r\n\tgetTopRight: function () { // -> Point\r\n\t\treturn new L.Point(this.max.x, this.min.y);\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the size of the given bounds\r\n\tgetSize: function () {\r\n\t\treturn this.max.subtract(this.min);\r\n\t},\r\n\r\n\t// @method contains(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\t// @alternative\r\n\t// @method contains(point: Point): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) {\r\n\t\tvar min, max;\r\n\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof L.Point) {\r\n\t\t\tobj = L.point(obj);\r\n\t\t} else {\r\n\t\t\tobj = L.bounds(obj);\r\n\t\t}\r\n\r\n\t\tif (obj instanceof L.Bounds) {\r\n\t\t\tmin = obj.min;\r\n\t\t\tmax = obj.max;\r\n\t\t} else {\r\n\t\t\tmin = max = obj;\r\n\t\t}\r\n\r\n\t\treturn (min.x >= this.min.x) &&\r\n\t\t       (max.x <= this.max.x) &&\r\n\t\t       (min.y >= this.min.y) &&\r\n\t\t       (max.y <= this.max.y);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds\r\n\t// intersect if they have at least one point in common.\r\n\tintersects: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = L.bounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t    max = this.max,\r\n\t\t    min2 = bounds.min,\r\n\t\t    max2 = bounds.max,\r\n\t\t    xIntersects = (max2.x >= min.x) && (min2.x <= max.x),\r\n\t\t    yIntersects = (max2.y >= min.y) && (min2.y <= max.y);\r\n\r\n\t\treturn xIntersects && yIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds\r\n\t// overlap if their intersection is an area.\r\n\toverlaps: function (bounds) { // (Bounds) -> Boolean\r\n\t\tbounds = L.bounds(bounds);\r\n\r\n\t\tvar min = this.min,\r\n\t\t    max = this.max,\r\n\t\t    min2 = bounds.min,\r\n\t\t    max2 = bounds.max,\r\n\t\t    xOverlaps = (max2.x > min.x) && (min2.x < max.x),\r\n\t\t    yOverlaps = (max2.y > min.y) && (min2.y < max.y);\r\n\r\n\t\treturn xOverlaps && yOverlaps;\r\n\t},\r\n\r\n\tisValid: function () {\r\n\t\treturn !!(this.min && this.max);\r\n\t}\r\n};\r\n\r\n\r\n// @factory L.bounds(topLeft: Point, bottomRight: Point)\r\n// Creates a Bounds object from two coordinates (usually top-left and bottom-right corners).\r\n// @alternative\r\n// @factory L.bounds(points: Point[])\r\n// Creates a Bounds object from the points it contains\r\nL.bounds = function (a, b) {\r\n\tif (!a || a instanceof L.Bounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new L.Bounds(a, b);\r\n};\r\n","/*\r\n * @class Transformation\r\n * @aka L.Transformation\r\n *\r\n * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`\r\n * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing\r\n * the reverse. Used by Leaflet in its projections code.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var transformation = new L.Transformation(2, 5, -1, 10),\r\n * \tp = L.point(1, 2),\r\n * \tp2 = transformation.transform(p), //  L.point(7, 8)\r\n * \tp3 = transformation.untransform(p2); //  L.point(1, 2)\r\n * ```\r\n */\r\n\r\n\r\n// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)\r\n// Creates a `Transformation` object with the given coefficients.\r\nL.Transformation = function (a, b, c, d) {\r\n\tthis._a = a;\r\n\tthis._b = b;\r\n\tthis._c = c;\r\n\tthis._d = d;\r\n};\r\n\r\nL.Transformation.prototype = {\r\n\t// @method transform(point: Point, scale?: Number): Point\r\n\t// Returns a transformed point, optionally multiplied by the given scale.\r\n\t// Only accepts actual `L.Point` instances, not arrays.\r\n\ttransform: function (point, scale) { // (Point, Number) -> Point\r\n\t\treturn this._transform(point.clone(), scale);\r\n\t},\r\n\r\n\t// destructive transform (faster)\r\n\t_transform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\tpoint.x = scale * (this._a * point.x + this._b);\r\n\t\tpoint.y = scale * (this._c * point.y + this._d);\r\n\t\treturn point;\r\n\t},\r\n\r\n\t// @method untransform(point: Point, scale?: Number): Point\r\n\t// Returns the reverse transformation of the given point, optionally divided\r\n\t// by the given scale. Only accepts actual `L.Point` instances, not arrays.\r\n\tuntransform: function (point, scale) {\r\n\t\tscale = scale || 1;\r\n\t\treturn new L.Point(\r\n\t\t        (point.x / scale - this._b) / this._a,\r\n\t\t        (point.y / scale - this._d) / this._c);\r\n\t}\r\n};\r\n","/*\r\n * @namespace DomUtil\r\n *\r\n * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)\r\n * tree, used by Leaflet internally.\r\n *\r\n * Most functions expecting or returning a `HTMLElement` also work for\r\n * SVG elements. The only difference is that classes refer to CSS classes\r\n * in HTML and SVG classes in SVG.\r\n */\r\n\r\nL.DomUtil = {\r\n\r\n\t// @function get(id: String|HTMLElement): HTMLElement\r\n\t// Returns an element given its DOM id, or returns the element itself\r\n\t// if it was passed directly.\r\n\tget: function (id) {\r\n\t\treturn typeof id === 'string' ? document.getElementById(id) : id;\r\n\t},\r\n\r\n\t// @function getStyle(el: HTMLElement, styleAttrib: String): String\r\n\t// Returns the value for a certain style attribute on an element,\r\n\t// including computed values or values set through CSS.\r\n\tgetStyle: function (el, style) {\r\n\r\n\t\tvar value = el.style[style] || (el.currentStyle && el.currentStyle[style]);\r\n\r\n\t\tif ((!value || value === 'auto') && document.defaultView) {\r\n\t\t\tvar css = document.defaultView.getComputedStyle(el, null);\r\n\t\t\tvalue = css ? css[style] : null;\r\n\t\t}\r\n\r\n\t\treturn value === 'auto' ? null : value;\r\n\t},\r\n\r\n\t// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement\r\n\t// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.\r\n\tcreate: function (tagName, className, container) {\r\n\r\n\t\tvar el = document.createElement(tagName);\r\n\t\tel.className = className || '';\r\n\r\n\t\tif (container) {\r\n\t\t\tcontainer.appendChild(el);\r\n\t\t}\r\n\r\n\t\treturn el;\r\n\t},\r\n\r\n\t// @function remove(el: HTMLElement)\r\n\t// Removes `el` from its parent element\r\n\tremove: function (el) {\r\n\t\tvar parent = el.parentNode;\r\n\t\tif (parent) {\r\n\t\t\tparent.removeChild(el);\r\n\t\t}\r\n\t},\r\n\r\n\t// @function empty(el: HTMLElement)\r\n\t// Removes all of `el`'s children elements from `el`\r\n\tempty: function (el) {\r\n\t\twhile (el.firstChild) {\r\n\t\t\tel.removeChild(el.firstChild);\r\n\t\t}\r\n\t},\r\n\r\n\t// @function toFront(el: HTMLElement)\r\n\t// Makes `el` the last children of its parent, so it renders in front of the other children.\r\n\ttoFront: function (el) {\r\n\t\tel.parentNode.appendChild(el);\r\n\t},\r\n\r\n\t// @function toBack(el: HTMLElement)\r\n\t// Makes `el` the first children of its parent, so it renders back from the other children.\r\n\ttoBack: function (el) {\r\n\t\tvar parent = el.parentNode;\r\n\t\tparent.insertBefore(el, parent.firstChild);\r\n\t},\r\n\r\n\t// @function hasClass(el: HTMLElement, name: String): Boolean\r\n\t// Returns `true` if the element's class attribute contains `name`.\r\n\thasClass: function (el, name) {\r\n\t\tif (el.classList !== undefined) {\r\n\t\t\treturn el.classList.contains(name);\r\n\t\t}\r\n\t\tvar className = L.DomUtil.getClass(el);\r\n\t\treturn className.length > 0 && new RegExp('(^|\\\\s)' + name + '(\\\\s|$)').test(className);\r\n\t},\r\n\r\n\t// @function addClass(el: HTMLElement, name: String)\r\n\t// Adds `name` to the element's class attribute.\r\n\taddClass: function (el, name) {\r\n\t\tif (el.classList !== undefined) {\r\n\t\t\tvar classes = L.Util.splitWords(name);\r\n\t\t\tfor (var i = 0, len = classes.length; i < len; i++) {\r\n\t\t\t\tel.classList.add(classes[i]);\r\n\t\t\t}\r\n\t\t} else if (!L.DomUtil.hasClass(el, name)) {\r\n\t\t\tvar className = L.DomUtil.getClass(el);\r\n\t\t\tL.DomUtil.setClass(el, (className ? className + ' ' : '') + name);\r\n\t\t}\r\n\t},\r\n\r\n\t// @function removeClass(el: HTMLElement, name: String)\r\n\t// Removes `name` from the element's class attribute.\r\n\tremoveClass: function (el, name) {\r\n\t\tif (el.classList !== undefined) {\r\n\t\t\tel.classList.remove(name);\r\n\t\t} else {\r\n\t\t\tL.DomUtil.setClass(el, L.Util.trim((' ' + L.DomUtil.getClass(el) + ' ').replace(' ' + name + ' ', ' ')));\r\n\t\t}\r\n\t},\r\n\r\n\t// @function setClass(el: HTMLElement, name: String)\r\n\t// Sets the element's class.\r\n\tsetClass: function (el, name) {\r\n\t\tif (el.className.baseVal === undefined) {\r\n\t\t\tel.className = name;\r\n\t\t} else {\r\n\t\t\t// in case of SVG element\r\n\t\t\tel.className.baseVal = name;\r\n\t\t}\r\n\t},\r\n\r\n\t// @function getClass(el: HTMLElement): String\r\n\t// Returns the element's class.\r\n\tgetClass: function (el) {\r\n\t\treturn el.className.baseVal === undefined ? el.className : el.className.baseVal;\r\n\t},\r\n\r\n\t// @function setOpacity(el: HTMLElement, opacity: Number)\r\n\t// Set the opacity of an element (including old IE support).\r\n\t// `opacity` must be a number from `0` to `1`.\r\n\tsetOpacity: function (el, value) {\r\n\r\n\t\tif ('opacity' in el.style) {\r\n\t\t\tel.style.opacity = value;\r\n\r\n\t\t} else if ('filter' in el.style) {\r\n\t\t\tL.DomUtil._setOpacityIE(el, value);\r\n\t\t}\r\n\t},\r\n\r\n\t_setOpacityIE: function (el, value) {\r\n\t\tvar filter = false,\r\n\t\t    filterName = 'DXImageTransform.Microsoft.Alpha';\r\n\r\n\t\t// filters collection throws an error if we try to retrieve a filter that doesn't exist\r\n\t\ttry {\r\n\t\t\tfilter = el.filters.item(filterName);\r\n\t\t} catch (e) {\r\n\t\t\t// don't set opacity to 1 if we haven't already set an opacity,\r\n\t\t\t// it isn't needed and breaks transparent pngs.\r\n\t\t\tif (value === 1) { return; }\r\n\t\t}\r\n\r\n\t\tvalue = Math.round(value * 100);\r\n\r\n\t\tif (filter) {\r\n\t\t\tfilter.Enabled = (value !== 100);\r\n\t\t\tfilter.Opacity = value;\r\n\t\t} else {\r\n\t\t\tel.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';\r\n\t\t}\r\n\t},\r\n\r\n\t// @function testProp(props: String[]): String|false\r\n\t// Goes through the array of style names and returns the first name\r\n\t// that is a valid style name for an element. If no such name is found,\r\n\t// it returns false. Useful for vendor-prefixed styles like `transform`.\r\n\ttestProp: function (props) {\r\n\r\n\t\tvar style = document.documentElement.style;\r\n\r\n\t\tfor (var i = 0; i < props.length; i++) {\r\n\t\t\tif (props[i] in style) {\r\n\t\t\t\treturn props[i];\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn false;\r\n\t},\r\n\r\n\t// @function setTransform(el: HTMLElement, offset: Point, scale?: Number)\r\n\t// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels\r\n\t// and optionally scaled by `scale`. Does not have an effect if the\r\n\t// browser doesn't support 3D CSS transforms.\r\n\tsetTransform: function (el, offset, scale) {\r\n\t\tvar pos = offset || new L.Point(0, 0);\r\n\r\n\t\tel.style[L.DomUtil.TRANSFORM] =\r\n\t\t\t(L.Browser.ie3d ?\r\n\t\t\t\t'translate(' + pos.x + 'px,' + pos.y + 'px)' :\r\n\t\t\t\t'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +\r\n\t\t\t(scale ? ' scale(' + scale + ')' : '');\r\n\t},\r\n\r\n\t// @function setPosition(el: HTMLElement, position: Point)\r\n\t// Sets the position of `el` to coordinates specified by `position`,\r\n\t// using CSS translate or top/left positioning depending on the browser\r\n\t// (used by Leaflet internally to position its layers).\r\n\tsetPosition: function (el, point) { // (HTMLElement, Point[, Boolean])\r\n\r\n\t\t/*eslint-disable */\r\n\t\tel._leaflet_pos = point;\r\n\t\t/*eslint-enable */\r\n\r\n\t\tif (L.Browser.any3d) {\r\n\t\t\tL.DomUtil.setTransform(el, point);\r\n\t\t} else {\r\n\t\t\tel.style.left = point.x + 'px';\r\n\t\t\tel.style.top = point.y + 'px';\r\n\t\t}\r\n\t},\r\n\r\n\t// @function getPosition(el: HTMLElement): Point\r\n\t// Returns the coordinates of an element previously positioned with setPosition.\r\n\tgetPosition: function (el) {\r\n\t\t// this method is only used for elements previously positioned using setPosition,\r\n\t\t// so it's safe to cache the position for performance\r\n\r\n\t\treturn el._leaflet_pos || new L.Point(0, 0);\r\n\t}\r\n};\r\n\r\n\r\n(function () {\r\n\t// prefix style property names\r\n\r\n\t// @property TRANSFORM: String\r\n\t// Vendor-prefixed fransform style name (e.g. `'webkitTransform'` for WebKit).\r\n\tL.DomUtil.TRANSFORM = L.DomUtil.testProp(\r\n\t\t\t['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);\r\n\r\n\r\n\t// webkitTransition comes first because some browser versions that drop vendor prefix don't do\r\n\t// the same for the transitionend event, in particular the Android 4.1 stock browser\r\n\r\n\t// @property TRANSITION: String\r\n\t// Vendor-prefixed transform style name.\r\n\tvar transition = L.DomUtil.TRANSITION = L.DomUtil.testProp(\r\n\t\t\t['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);\r\n\r\n\tL.DomUtil.TRANSITION_END =\r\n\t\t\ttransition === 'webkitTransition' || transition === 'OTransition' ? transition + 'End' : 'transitionend';\r\n\r\n\t// @function disableTextSelection()\r\n\t// Prevents the user from generating `selectstart` DOM events, usually generated\r\n\t// when the user drags the mouse through a page with text. Used internally\r\n\t// by Leaflet to override the behaviour of any click-and-drag interaction on\r\n\t// the map. Affects drag interactions on the whole document.\r\n\r\n\t// @function enableTextSelection()\r\n\t// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).\r\n\tif ('onselectstart' in document) {\r\n\t\tL.DomUtil.disableTextSelection = function () {\r\n\t\t\tL.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);\r\n\t\t};\r\n\t\tL.DomUtil.enableTextSelection = function () {\r\n\t\t\tL.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);\r\n\t\t};\r\n\r\n\t} else {\r\n\t\tvar userSelectProperty = L.DomUtil.testProp(\r\n\t\t\t['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);\r\n\r\n\t\tL.DomUtil.disableTextSelection = function () {\r\n\t\t\tif (userSelectProperty) {\r\n\t\t\t\tvar style = document.documentElement.style;\r\n\t\t\t\tthis._userSelect = style[userSelectProperty];\r\n\t\t\t\tstyle[userSelectProperty] = 'none';\r\n\t\t\t}\r\n\t\t};\r\n\t\tL.DomUtil.enableTextSelection = function () {\r\n\t\t\tif (userSelectProperty) {\r\n\t\t\t\tdocument.documentElement.style[userSelectProperty] = this._userSelect;\r\n\t\t\t\tdelete this._userSelect;\r\n\t\t\t}\r\n\t\t};\r\n\t}\r\n\r\n\t// @function disableImageDrag()\r\n\t// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but\r\n\t// for `dragstart` DOM events, usually generated when the user drags an image.\r\n\tL.DomUtil.disableImageDrag = function () {\r\n\t\tL.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);\r\n\t};\r\n\r\n\t// @function enableImageDrag()\r\n\t// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).\r\n\tL.DomUtil.enableImageDrag = function () {\r\n\t\tL.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);\r\n\t};\r\n\r\n\t// @function preventOutline(el: HTMLElement)\r\n\t// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)\r\n\t// of the element `el` invisible. Used internally by Leaflet to prevent\r\n\t// focusable elements from displaying an outline when the user performs a\r\n\t// drag interaction on them.\r\n\tL.DomUtil.preventOutline = function (element) {\r\n\t\twhile (element.tabIndex === -1) {\r\n\t\t\telement = element.parentNode;\r\n\t\t}\r\n\t\tif (!element || !element.style) { return; }\r\n\t\tL.DomUtil.restoreOutline();\r\n\t\tthis._outlineElement = element;\r\n\t\tthis._outlineStyle = element.style.outline;\r\n\t\telement.style.outline = 'none';\r\n\t\tL.DomEvent.on(window, 'keydown', L.DomUtil.restoreOutline, this);\r\n\t};\r\n\r\n\t// @function restoreOutline()\r\n\t// Cancels the effects of a previous [`L.DomUtil.preventOutline`]().\r\n\tL.DomUtil.restoreOutline = function () {\r\n\t\tif (!this._outlineElement) { return; }\r\n\t\tthis._outlineElement.style.outline = this._outlineStyle;\r\n\t\tdelete this._outlineElement;\r\n\t\tdelete this._outlineStyle;\r\n\t\tL.DomEvent.off(window, 'keydown', L.DomUtil.restoreOutline, this);\r\n\t};\r\n})();\r\n","/* @class LatLng\r\n * @aka L.LatLng\r\n *\r\n * Represents a geographical point with a certain latitude and longitude.\r\n *\r\n * @example\r\n *\r\n * ```\r\n * var latlng = L.latLng(50.5, 30.5);\r\n * ```\r\n *\r\n * 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:\r\n *\r\n * ```\r\n * map.panTo([50, 30]);\r\n * map.panTo({lon: 30, lat: 50});\r\n * map.panTo({lat: 50, lng: 30});\r\n * map.panTo(L.latLng(50, 30));\r\n * ```\r\n */\r\n\r\nL.LatLng = function (lat, lng, alt) {\r\n\tif (isNaN(lat) || isNaN(lng)) {\r\n\t\tthrow new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');\r\n\t}\r\n\r\n\t// @property lat: Number\r\n\t// Latitude in degrees\r\n\tthis.lat = +lat;\r\n\r\n\t// @property lng: Number\r\n\t// Longitude in degrees\r\n\tthis.lng = +lng;\r\n\r\n\t// @property alt: Number\r\n\t// Altitude in meters (optional)\r\n\tif (alt !== undefined) {\r\n\t\tthis.alt = +alt;\r\n\t}\r\n};\r\n\r\nL.LatLng.prototype = {\r\n\t// @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean\r\n\t// Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overriden by setting `maxMargin` to a small number.\r\n\tequals: function (obj, maxMargin) {\r\n\t\tif (!obj) { return false; }\r\n\r\n\t\tobj = L.latLng(obj);\r\n\r\n\t\tvar margin = Math.max(\r\n\t\t        Math.abs(this.lat - obj.lat),\r\n\t\t        Math.abs(this.lng - obj.lng));\r\n\r\n\t\treturn margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);\r\n\t},\r\n\r\n\t// @method toString(): String\r\n\t// Returns a string representation of the point (for debugging purposes).\r\n\ttoString: function (precision) {\r\n\t\treturn 'LatLng(' +\r\n\t\t        L.Util.formatNum(this.lat, precision) + ', ' +\r\n\t\t        L.Util.formatNum(this.lng, precision) + ')';\r\n\t},\r\n\r\n\t// @method distanceTo(otherLatLng: LatLng): Number\r\n\t// Returns the distance (in meters) to the given `LatLng` calculated using the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula).\r\n\tdistanceTo: function (other) {\r\n\t\treturn L.CRS.Earth.distance(this, L.latLng(other));\r\n\t},\r\n\r\n\t// @method wrap(): LatLng\r\n\t// Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.\r\n\twrap: function () {\r\n\t\treturn L.CRS.Earth.wrapLatLng(this);\r\n\t},\r\n\r\n\t// @method toBounds(sizeInMeters: Number): LatLngBounds\r\n\t// Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`.\r\n\ttoBounds: function (sizeInMeters) {\r\n\t\tvar latAccuracy = 180 * sizeInMeters / 40075017,\r\n\t\t    lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);\r\n\r\n\t\treturn L.latLngBounds(\r\n\t\t        [this.lat - latAccuracy, this.lng - lngAccuracy],\r\n\t\t        [this.lat + latAccuracy, this.lng + lngAccuracy]);\r\n\t},\r\n\r\n\tclone: function () {\r\n\t\treturn new L.LatLng(this.lat, this.lng, this.alt);\r\n\t}\r\n};\r\n\r\n\r\n\r\n// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng\r\n// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Array): LatLng\r\n// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.\r\n\r\n// @alternative\r\n// @factory L.latLng(coords: Object): LatLng\r\n// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.\r\n\r\nL.latLng = function (a, b, c) {\r\n\tif (a instanceof L.LatLng) {\r\n\t\treturn a;\r\n\t}\r\n\tif (L.Util.isArray(a) && typeof a[0] !== 'object') {\r\n\t\tif (a.length === 3) {\r\n\t\t\treturn new L.LatLng(a[0], a[1], a[2]);\r\n\t\t}\r\n\t\tif (a.length === 2) {\r\n\t\t\treturn new L.LatLng(a[0], a[1]);\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\tif (a === undefined || a === null) {\r\n\t\treturn a;\r\n\t}\r\n\tif (typeof a === 'object' && 'lat' in a) {\r\n\t\treturn new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);\r\n\t}\r\n\tif (b === undefined) {\r\n\t\treturn null;\r\n\t}\r\n\treturn new L.LatLng(a, b, c);\r\n};\r\n","/*\r\n * @class LatLngBounds\r\n * @aka L.LatLngBounds\r\n *\r\n * Represents a rectangular geographical area on a map.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var corner1 = L.latLng(40.712, -74.227),\r\n * corner2 = L.latLng(40.774, -74.125),\r\n * bounds = L.latLngBounds(corner1, corner2);\r\n * ```\r\n *\r\n * 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:\r\n *\r\n * ```js\r\n * map.fitBounds([\r\n * \t[40.712, -74.227],\r\n * \t[40.774, -74.125]\r\n * ]);\r\n * ```\r\n *\r\n * 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.\r\n */\r\n\r\nL.LatLngBounds = function (corner1, corner2) { // (LatLng, LatLng) or (LatLng[])\r\n\tif (!corner1) { return; }\r\n\r\n\tvar latlngs = corner2 ? [corner1, corner2] : corner1;\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\tthis.extend(latlngs[i]);\r\n\t}\r\n};\r\n\r\nL.LatLngBounds.prototype = {\r\n\r\n\t// @method extend(latlng: LatLng): this\r\n\t// Extend the bounds to contain the given point\r\n\r\n\t// @alternative\r\n\t// @method extend(otherBounds: LatLngBounds): this\r\n\t// Extend the bounds to contain the given bounds\r\n\textend: function (obj) {\r\n\t\tvar sw = this._southWest,\r\n\t\t    ne = this._northEast,\r\n\t\t    sw2, ne2;\r\n\r\n\t\tif (obj instanceof L.LatLng) {\r\n\t\t\tsw2 = obj;\r\n\t\t\tne2 = obj;\r\n\r\n\t\t} else if (obj instanceof L.LatLngBounds) {\r\n\t\t\tsw2 = obj._southWest;\r\n\t\t\tne2 = obj._northEast;\r\n\r\n\t\t\tif (!sw2 || !ne2) { return this; }\r\n\r\n\t\t} else {\r\n\t\t\treturn obj ? this.extend(L.latLng(obj) || L.latLngBounds(obj)) : this;\r\n\t\t}\r\n\r\n\t\tif (!sw && !ne) {\r\n\t\t\tthis._southWest = new L.LatLng(sw2.lat, sw2.lng);\r\n\t\t\tthis._northEast = new L.LatLng(ne2.lat, ne2.lng);\r\n\t\t} else {\r\n\t\t\tsw.lat = Math.min(sw2.lat, sw.lat);\r\n\t\t\tsw.lng = Math.min(sw2.lng, sw.lng);\r\n\t\t\tne.lat = Math.max(ne2.lat, ne.lat);\r\n\t\t\tne.lng = Math.max(ne2.lng, ne.lng);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method pad(bufferRatio: Number): LatLngBounds\r\n\t// Returns bigger bounds created by extending the current bounds by a given percentage in each direction.\r\n\tpad: function (bufferRatio) {\r\n\t\tvar sw = this._southWest,\r\n\t\t    ne = this._northEast,\r\n\t\t    heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,\r\n\t\t    widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;\r\n\r\n\t\treturn new L.LatLngBounds(\r\n\t\t        new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),\r\n\t\t        new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));\r\n\t},\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the center point of the bounds.\r\n\tgetCenter: function () {\r\n\t\treturn new L.LatLng(\r\n\t\t        (this._southWest.lat + this._northEast.lat) / 2,\r\n\t\t        (this._southWest.lng + this._northEast.lng) / 2);\r\n\t},\r\n\r\n\t// @method getSouthWest(): LatLng\r\n\t// Returns the south-west point of the bounds.\r\n\tgetSouthWest: function () {\r\n\t\treturn this._southWest;\r\n\t},\r\n\r\n\t// @method getNorthEast(): LatLng\r\n\t// Returns the north-east point of the bounds.\r\n\tgetNorthEast: function () {\r\n\t\treturn this._northEast;\r\n\t},\r\n\r\n\t// @method getNorthWest(): LatLng\r\n\t// Returns the north-west point of the bounds.\r\n\tgetNorthWest: function () {\r\n\t\treturn new L.LatLng(this.getNorth(), this.getWest());\r\n\t},\r\n\r\n\t// @method getSouthEast(): LatLng\r\n\t// Returns the south-east point of the bounds.\r\n\tgetSouthEast: function () {\r\n\t\treturn new L.LatLng(this.getSouth(), this.getEast());\r\n\t},\r\n\r\n\t// @method getWest(): Number\r\n\t// Returns the west longitude of the bounds\r\n\tgetWest: function () {\r\n\t\treturn this._southWest.lng;\r\n\t},\r\n\r\n\t// @method getSouth(): Number\r\n\t// Returns the south latitude of the bounds\r\n\tgetSouth: function () {\r\n\t\treturn this._southWest.lat;\r\n\t},\r\n\r\n\t// @method getEast(): Number\r\n\t// Returns the east longitude of the bounds\r\n\tgetEast: function () {\r\n\t\treturn this._northEast.lng;\r\n\t},\r\n\r\n\t// @method getNorth(): Number\r\n\t// Returns the north latitude of the bounds\r\n\tgetNorth: function () {\r\n\t\treturn this._northEast.lat;\r\n\t},\r\n\r\n\t// @method contains(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle contains the given one.\r\n\r\n\t// @alternative\r\n\t// @method contains (latlng: LatLng): Boolean\r\n\t// Returns `true` if the rectangle contains the given point.\r\n\tcontains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean\r\n\t\tif (typeof obj[0] === 'number' || obj instanceof L.LatLng || 'lat' in obj) {\r\n\t\t\tobj = L.latLng(obj);\r\n\t\t} else {\r\n\t\t\tobj = L.latLngBounds(obj);\r\n\t\t}\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t    ne = this._northEast,\r\n\t\t    sw2, ne2;\r\n\r\n\t\tif (obj instanceof L.LatLngBounds) {\r\n\t\t\tsw2 = obj.getSouthWest();\r\n\t\t\tne2 = obj.getNorthEast();\r\n\t\t} else {\r\n\t\t\tsw2 = ne2 = obj;\r\n\t\t}\r\n\r\n\t\treturn (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&\r\n\t\t       (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);\r\n\t},\r\n\r\n\t// @method intersects(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.\r\n\tintersects: function (bounds) {\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t    ne = this._northEast,\r\n\t\t    sw2 = bounds.getSouthWest(),\r\n\t\t    ne2 = bounds.getNorthEast(),\r\n\r\n\t\t    latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),\r\n\t\t    lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);\r\n\r\n\t\treturn latIntersects && lngIntersects;\r\n\t},\r\n\r\n\t// @method overlaps(otherBounds: Bounds): Boolean\r\n\t// Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.\r\n\toverlaps: function (bounds) {\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\r\n\t\tvar sw = this._southWest,\r\n\t\t    ne = this._northEast,\r\n\t\t    sw2 = bounds.getSouthWest(),\r\n\t\t    ne2 = bounds.getNorthEast(),\r\n\r\n\t\t    latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),\r\n\t\t    lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);\r\n\r\n\t\treturn latOverlaps && lngOverlaps;\r\n\t},\r\n\r\n\t// @method toBBoxString(): String\r\n\t// 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.\r\n\ttoBBoxString: function () {\r\n\t\treturn [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');\r\n\t},\r\n\r\n\t// @method equals(otherBounds: LatLngBounds): Boolean\r\n\t// Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds.\r\n\tequals: function (bounds) {\r\n\t\tif (!bounds) { return false; }\r\n\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\r\n\t\treturn this._southWest.equals(bounds.getSouthWest()) &&\r\n\t\t       this._northEast.equals(bounds.getNorthEast());\r\n\t},\r\n\r\n\t// @method isValid(): Boolean\r\n\t// Returns `true` if the bounds are properly initialized.\r\n\tisValid: function () {\r\n\t\treturn !!(this._southWest && this._northEast);\r\n\t}\r\n};\r\n\r\n// TODO International date line?\r\n\r\n// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)\r\n// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.\r\n\r\n// @alternative\r\n// @factory L.latLngBounds(latlngs: LatLng[])\r\n// 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).\r\nL.latLngBounds = function (a, b) {\r\n\tif (a instanceof L.LatLngBounds) {\r\n\t\treturn a;\r\n\t}\r\n\treturn new L.LatLngBounds(a, b);\r\n};\r\n","/*\r\n * @namespace Projection\r\n * @section\r\n * Leaflet comes with a set of already defined Projections out of the box:\r\n *\r\n * @projection L.Projection.LonLat\r\n *\r\n * Equirectangular, or Plate Carree projection — the most simple projection,\r\n * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as\r\n * latitude. Also suitable for flat worlds, e.g. game maps. Used by the\r\n * `EPSG:3395` and `Simple` CRS.\r\n */\r\n\r\nL.Projection = {};\r\n\r\nL.Projection.LonLat = {\r\n\tproject: function (latlng) {\r\n\t\treturn new L.Point(latlng.lng, latlng.lat);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\treturn new L.LatLng(point.y, point.x);\r\n\t},\r\n\r\n\tbounds: L.bounds([-180, -90], [180, 90])\r\n};\r\n","/*\r\n * @namespace Projection\r\n * @projection L.Projection.SphericalMercator\r\n *\r\n * Spherical Mercator projection — the most common projection for online maps,\r\n * used by almost all free and commercial tile providers. Assumes that Earth is\r\n * a sphere. Used by the `EPSG:3857` CRS.\r\n */\r\n\r\nL.Projection.SphericalMercator = {\r\n\r\n\tR: 6378137,\r\n\tMAX_LATITUDE: 85.0511287798,\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t    max = this.MAX_LATITUDE,\r\n\t\t    lat = Math.max(Math.min(max, latlng.lat), -max),\r\n\t\t    sin = Math.sin(lat * d);\r\n\r\n\t\treturn new L.Point(\r\n\t\t\t\tthis.R * latlng.lng * d,\r\n\t\t\t\tthis.R * Math.log((1 + sin) / (1 - sin)) / 2);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI;\r\n\r\n\t\treturn new L.LatLng(\r\n\t\t\t(2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,\r\n\t\t\tpoint.x * d / this.R);\r\n\t},\r\n\r\n\tbounds: (function () {\r\n\t\tvar d = 6378137 * Math.PI;\r\n\t\treturn L.bounds([-d, -d], [d, d]);\r\n\t})()\r\n};\r\n","/*\r\n * @class CRS\r\n * @aka L.CRS\r\n * Abstract class that defines coordinate reference systems for projecting\r\n * geographical points into pixel (screen) coordinates and back (and to\r\n * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See\r\n * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).\r\n *\r\n * Leaflet defines the most usual CRSs by default. If you want to use a\r\n * CRS not defined by default, take a look at the\r\n * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.\r\n */\r\n\r\nL.CRS = {\r\n\t// @method latLngToPoint(latlng: LatLng, zoom: Number): Point\r\n\t// Projects geographical coordinates into pixel coordinates for a given zoom.\r\n\tlatLngToPoint: function (latlng, zoom) {\r\n\t\tvar projectedPoint = this.projection.project(latlng),\r\n\t\t    scale = this.scale(zoom);\r\n\r\n\t\treturn this.transformation._transform(projectedPoint, scale);\r\n\t},\r\n\r\n\t// @method pointToLatLng(point: Point, zoom: Number): LatLng\r\n\t// The inverse of `latLngToPoint`. Projects pixel coordinates on a given\r\n\t// zoom into geographical coordinates.\r\n\tpointToLatLng: function (point, zoom) {\r\n\t\tvar scale = this.scale(zoom),\r\n\t\t    untransformedPoint = this.transformation.untransform(point, scale);\r\n\r\n\t\treturn this.projection.unproject(untransformedPoint);\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng): Point\r\n\t// Projects geographical coordinates into coordinates in units accepted for\r\n\t// this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).\r\n\tproject: function (latlng) {\r\n\t\treturn this.projection.project(latlng);\r\n\t},\r\n\r\n\t// @method unproject(point: Point): LatLng\r\n\t// Given a projected coordinate returns the corresponding LatLng.\r\n\t// The inverse of `project`.\r\n\tunproject: function (point) {\r\n\t\treturn this.projection.unproject(point);\r\n\t},\r\n\r\n\t// @method scale(zoom: Number): Number\r\n\t// Returns the scale used when transforming projected coordinates into\r\n\t// pixel coordinates for a particular zoom. For example, it returns\r\n\t// `256 * 2^zoom` for Mercator-based CRS.\r\n\tscale: function (zoom) {\r\n\t\treturn 256 * Math.pow(2, zoom);\r\n\t},\r\n\r\n\t// @method zoom(scale: Number): Number\r\n\t// Inverse of `scale()`, returns the zoom level corresponding to a scale\r\n\t// factor of `scale`.\r\n\tzoom: function (scale) {\r\n\t\treturn Math.log(scale / 256) / Math.LN2;\r\n\t},\r\n\r\n\t// @method getProjectedBounds(zoom: Number): Bounds\r\n\t// Returns the projection's bounds scaled and transformed for the provided `zoom`.\r\n\tgetProjectedBounds: function (zoom) {\r\n\t\tif (this.infinite) { return null; }\r\n\r\n\t\tvar b = this.projection.bounds,\r\n\t\t    s = this.scale(zoom),\r\n\t\t    min = this.transformation.transform(b.min, s),\r\n\t\t    max = this.transformation.transform(b.max, s);\r\n\r\n\t\treturn L.bounds(min, max);\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates.\r\n\r\n\t// @property code: String\r\n\t// Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)\r\n\t//\r\n\t// @property wrapLng: Number[]\r\n\t// An array of two numbers defining whether the longitude (horizontal) coordinate\r\n\t// axis wraps around a given range and how. Defaults to `[-180, 180]` in most\r\n\t// geographical CRSs. If `undefined`, the longitude axis does not wrap around.\r\n\t//\r\n\t// @property wrapLat: Number[]\r\n\t// Like `wrapLng`, but for the latitude (vertical) axis.\r\n\r\n\t// wrapLng: [min, max],\r\n\t// wrapLat: [min, max],\r\n\r\n\t// @property infinite: Boolean\r\n\t// If true, the coordinate space will be unbounded (infinite in both axes)\r\n\tinfinite: false,\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where lat and lng has been wrapped according to the\r\n\t// CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.\r\n\t// Only accepts actual `L.LatLng` instances, not arrays.\r\n\twrapLatLng: function (latlng) {\r\n\t\tvar lng = this.wrapLng ? L.Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,\r\n\t\t    lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,\r\n\t\t    alt = latlng.alt;\r\n\r\n\t\treturn L.latLng(lat, lng, alt);\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring\r\n\t// that its center is within the CRS's bounds.\r\n\t// Only accepts actual `L.LatLngBounds` instances, not arrays.\r\n\twrapLatLngBounds: function (bounds) {\r\n\t\tvar center = bounds.getCenter(),\r\n\t\t    newCenter = this.wrapLatLng(center),\r\n\t\t    latShift = center.lat - newCenter.lat,\r\n\t\t    lngShift = center.lng - newCenter.lng;\r\n\r\n\t\tif (latShift === 0 && lngShift === 0) {\r\n\t\t\treturn bounds;\r\n\t\t}\r\n\r\n\t\tvar sw = bounds.getSouthWest(),\r\n\t\t    ne = bounds.getNorthEast(),\r\n\t\t    newSw = L.latLng({lat: sw.lat - latShift, lng: sw.lng - lngShift}),\r\n\t\t    newNe = L.latLng({lat: ne.lat - latShift, lng: ne.lng - lngShift});\r\n\r\n\t\treturn new L.LatLngBounds(newSw, newNe);\r\n\t}\r\n};\r\n","/*\n * @namespace CRS\n * @crs L.CRS.Simple\n *\n * A simple CRS that maps longitude and latitude into `x` and `y` directly.\n * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`\n * axis should still be inverted (going from bottom to top). `distance()` returns\n * simple euclidean distance.\n */\n\nL.CRS.Simple = L.extend({}, L.CRS, {\n\tprojection: L.Projection.LonLat,\n\ttransformation: new L.Transformation(1, 0, -1, 0),\n\n\tscale: function (zoom) {\n\t\treturn Math.pow(2, zoom);\n\t},\n\n\tzoom: function (scale) {\n\t\treturn Math.log(scale) / Math.LN2;\n\t},\n\n\tdistance: function (latlng1, latlng2) {\n\t\tvar dx = latlng2.lng - latlng1.lng,\n\t\t    dy = latlng2.lat - latlng1.lat;\n\n\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t},\n\n\tinfinite: true\n});\n","/*\n * @namespace CRS\n * @crs L.CRS.Earth\n *\n * Serves as the base for CRS that are global such that they cover the earth.\n * Can only be used as the base for other CRS and cannot be used directly,\n * since it does not have a `code`, `projection` or `transformation`. `distance()` returns\n * meters.\n */\n\nL.CRS.Earth = L.extend({}, L.CRS, {\n\twrapLng: [-180, 180],\n\n\t// Mean Earth Radius, as recommended for use by\n\t// the International Union of Geodesy and Geophysics,\n\t// see http://rosettacode.org/wiki/Haversine_formula\n\tR: 6371000,\n\n\t// distance between two geographical points using spherical law of cosines approximation\n\tdistance: function (latlng1, latlng2) {\n\t\tvar rad = Math.PI / 180,\n\t\t    lat1 = latlng1.lat * rad,\n\t\t    lat2 = latlng2.lat * rad,\n\t\t    a = Math.sin(lat1) * Math.sin(lat2) +\n\t\t        Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);\n\n\t\treturn this.R * Math.acos(Math.min(a, 1));\n\t}\n});\n","/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3857\r\n *\r\n * The most common CRS for online maps, used by almost all free and commercial\r\n * tile providers. Uses Spherical Mercator projection. Set in by default in\r\n * Map's `crs` option.\r\n */\r\n\r\nL.CRS.EPSG3857 = L.extend({}, L.CRS.Earth, {\r\n\tcode: 'EPSG:3857',\r\n\tprojection: L.Projection.SphericalMercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * L.Projection.SphericalMercator.R);\r\n\t\treturn new L.Transformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n\r\nL.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {\r\n\tcode: 'EPSG:900913'\r\n});\r\n","/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG4326\r\n *\r\n * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.\r\n *\r\n * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),\r\n * which is a breaking change from 0.7.x behaviour.  If you are using a `TileLayer`\r\n * with this CRS, ensure that there are two 256x256 pixel tiles covering the\r\n * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),\r\n * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.\r\n */\r\n\r\nL.CRS.EPSG4326 = L.extend({}, L.CRS.Earth, {\r\n\tcode: 'EPSG:4326',\r\n\tprojection: L.Projection.LonLat,\r\n\ttransformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5)\r\n});\r\n","/*\r\n * @class Map\r\n * @aka L.Map\r\n * @inherits Evented\r\n *\r\n * The central class of the API — it is used to create a map on a page and manipulate it.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * // initialize the map on the \"map\" div with a given center and zoom\r\n * var map = L.map('map', {\r\n * \tcenter: [51.505, -0.09],\r\n * \tzoom: 13\r\n * });\r\n * ```\r\n *\r\n */\r\n\r\nL.Map = L.Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section Map State Options\r\n\t\t// @option crs: CRS = L.CRS.EPSG3857\r\n\t\t// The [Coordinate Reference System](#crs) to use. Don't change this if you're not\r\n\t\t// sure what it means.\r\n\t\tcrs: L.CRS.EPSG3857,\r\n\r\n\t\t// @option center: LatLng = undefined\r\n\t\t// Initial geographic center of the map\r\n\t\tcenter: undefined,\r\n\r\n\t\t// @option zoom: Number = undefined\r\n\t\t// Initial map zoom level\r\n\t\tzoom: undefined,\r\n\r\n\t\t// @option minZoom: Number = undefined\r\n\t\t// Minimum zoom level of the map. Overrides any `minZoom` option set on map layers.\r\n\t\tminZoom: undefined,\r\n\r\n\t\t// @option maxZoom: Number = undefined\r\n\t\t// Maximum zoom level of the map. Overrides any `maxZoom` option set on map layers.\r\n\t\tmaxZoom: undefined,\r\n\r\n\t\t// @option layers: Layer[] = []\r\n\t\t// Array of layers that will be added to the map initially\r\n\t\tlayers: [],\r\n\r\n\t\t// @option maxBounds: LatLngBounds = null\r\n\t\t// When this option is set, the map restricts the view to the given\r\n\t\t// geographical bounds, bouncing the user back if the user tries to pan\r\n\t\t// outside the view. To set the restriction dynamically, use\r\n\t\t// [`setMaxBounds`](#map-setmaxbounds) method.\r\n\t\tmaxBounds: undefined,\r\n\r\n\t\t// @option renderer: Renderer = *\r\n\t\t// The default method for drawing vector layers on the map. `L.SVG`\r\n\t\t// or `L.Canvas` by default depending on browser support.\r\n\t\trenderer: undefined,\r\n\r\n\r\n\t\t// @section Animation Options\r\n\t\t// @option zoomAnimation: Boolean = true\r\n\t\t// Whether the map zoom animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tzoomAnimation: true,\r\n\r\n\t\t// @option zoomAnimationThreshold: Number = 4\r\n\t\t// Won't animate zoom if the zoom difference exceeds this value.\r\n\t\tzoomAnimationThreshold: 4,\r\n\r\n\t\t// @option fadeAnimation: Boolean = true\r\n\t\t// Whether the tile fade animation is enabled. By default it's enabled\r\n\t\t// in all browsers that support CSS3 Transitions except Android.\r\n\t\tfadeAnimation: true,\r\n\r\n\t\t// @option markerZoomAnimation: Boolean = true\r\n\t\t// Whether markers animate their zoom with the zoom animation, if disabled\r\n\t\t// they will disappear for the length of the animation. By default it's\r\n\t\t// enabled in all browsers that support CSS3 Transitions except Android.\r\n\t\tmarkerZoomAnimation: true,\r\n\r\n\t\t// @option transform3DLimit: Number = 2^23\r\n\t\t// Defines the maximum size of a CSS translation transform. The default\r\n\t\t// value should not be changed unless a web browser positions layers in\r\n\t\t// the wrong place after doing a large `panBy`.\r\n\t\ttransform3DLimit: 8388608, // Precision limit of a 32-bit float\r\n\r\n\t\t// @section Interaction Options\r\n\t\t// @option zoomSnap: Number = 1\r\n\t\t// Forces the map's zoom level to always be a multiple of this, particularly\r\n\t\t// right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.\r\n\t\t// By default, the zoom level snaps to the nearest integer; lower values\r\n\t\t// (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`\r\n\t\t// means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.\r\n\t\tzoomSnap: 1,\r\n\r\n\t\t// @option zoomDelta: Number = 1\r\n\t\t// Controls how much the map's zoom level will change after a\r\n\t\t// [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`\r\n\t\t// or `-` on the keyboard, or using the [zoom controls](#control-zoom).\r\n\t\t// Values smaller than `1` (e.g. `0.5`) allow for greater granularity.\r\n\t\tzoomDelta: 1,\r\n\r\n\t\t// @option trackResize: Boolean = true\r\n\t\t// Whether the map automatically handles browser window resize to update itself.\r\n\t\ttrackResize: true\r\n\t},\r\n\r\n\tinitialize: function (id, options) { // (HTMLElement or String, Object)\r\n\t\toptions = L.setOptions(this, options);\r\n\r\n\t\tthis._initContainer(id);\r\n\t\tthis._initLayout();\r\n\r\n\t\t// hack for https://github.com/Leaflet/Leaflet/issues/1980\r\n\t\tthis._onResize = L.bind(this._onResize, this);\r\n\r\n\t\tthis._initEvents();\r\n\r\n\t\tif (options.maxBounds) {\r\n\t\t\tthis.setMaxBounds(options.maxBounds);\r\n\t\t}\r\n\r\n\t\tif (options.zoom !== undefined) {\r\n\t\t\tthis._zoom = this._limitZoom(options.zoom);\r\n\t\t}\r\n\r\n\t\tif (options.center && options.zoom !== undefined) {\r\n\t\t\tthis.setView(L.latLng(options.center), options.zoom, {reset: true});\r\n\t\t}\r\n\r\n\t\tthis._handlers = [];\r\n\t\tthis._layers = {};\r\n\t\tthis._zoomBoundLayers = {};\r\n\t\tthis._sizeChanged = true;\r\n\r\n\t\tthis.callInitHooks();\r\n\r\n\t\t// don't animate on browsers without hardware-accelerated transitions or old Android/Opera\r\n\t\tthis._zoomAnimated = L.DomUtil.TRANSITION && L.Browser.any3d && !L.Browser.mobileOpera &&\r\n\t\t\t\tthis.options.zoomAnimation;\r\n\r\n\t\t// zoom transitions run with the same duration for all layers, so if one of transitionend events\r\n\t\t// happens after starting zoom animation (propagating to the map pane), we know that it ended globally\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tthis._createAnimProxy();\r\n\t\t\tL.DomEvent.on(this._proxy, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);\r\n\t\t}\r\n\r\n\t\tthis._addLayers(this.options.layers);\r\n\t},\r\n\r\n\r\n\t// @section Methods for modifying map state\r\n\r\n\t// @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) with the given\r\n\t// animation options.\r\n\tsetView: function (center, zoom, options) {\r\n\r\n\t\tzoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);\r\n\t\tcenter = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);\r\n\t\toptions = options || {};\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tif (this._loaded && !options.reset && options !== true) {\r\n\r\n\t\t\tif (options.animate !== undefined) {\r\n\t\t\t\toptions.zoom = L.extend({animate: options.animate}, options.zoom);\r\n\t\t\t\toptions.pan = L.extend({animate: options.animate, duration: options.duration}, options.pan);\r\n\t\t\t}\r\n\r\n\t\t\t// try animating pan or zoom\r\n\t\t\tvar moved = (this._zoom !== zoom) ?\r\n\t\t\t\tthis._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :\r\n\t\t\t\tthis._tryAnimatedPan(center, options.pan);\r\n\r\n\t\t\tif (moved) {\r\n\t\t\t\t// prevent resize handler call, the view will refresh after animation anyway\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\treturn this;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// animation didn't start, just reset the map view\r\n\t\tthis._resetView(center, zoom);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setZoom(zoom: Number, options: Zoom/pan options): this\r\n\t// Sets the zoom of the map.\r\n\tsetZoom: function (zoom, options) {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthis._zoom = zoom;\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\treturn this.setView(this.getCenter(), zoom, {zoom: options});\r\n\t},\r\n\r\n\t// @method zoomIn(delta?: Number, options?: Zoom options): this\r\n\t// Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomIn: function (delta, options) {\r\n\t\tdelta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom + delta, options);\r\n\t},\r\n\r\n\t// @method zoomOut(delta?: Number, options?: Zoom options): this\r\n\t// Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).\r\n\tzoomOut: function (delta, options) {\r\n\t\tdelta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);\r\n\t\treturn this.setZoom(this._zoom - delta, options);\r\n\t},\r\n\r\n\t// @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified geographical point on the map\r\n\t// stationary (e.g. used internally for scroll zoom and double-click zoom).\r\n\t// @alternative\r\n\t// @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this\r\n\t// Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.\r\n\tsetZoomAround: function (latlng, zoom, options) {\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t    viewHalf = this.getSize().divideBy(2),\r\n\t\t    containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),\r\n\r\n\t\t    centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),\r\n\t\t    newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));\r\n\r\n\t\treturn this.setView(newCenter, zoom, {zoom: options});\r\n\t},\r\n\r\n\t_getBoundsCenterZoom: function (bounds, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tbounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);\r\n\r\n\t\tvar paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),\r\n\t\t    paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),\r\n\r\n\t\t    zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));\r\n\r\n\t\tzoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;\r\n\r\n\t\tvar paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),\r\n\r\n\t\t    swPoint = this.project(bounds.getSouthWest(), zoom),\r\n\t\t    nePoint = this.project(bounds.getNorthEast(), zoom),\r\n\t\t    center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);\r\n\r\n\t\treturn {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom\r\n\t\t};\r\n\t},\r\n\r\n\t// @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets a map view that contains the given geographical bounds with the\r\n\t// maximum zoom level possible.\r\n\tfitBounds: function (bounds, options) {\r\n\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthrow new Error('Bounds are not valid.');\r\n\t\t}\r\n\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.setView(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method fitWorld(options?: fitBounds options): this\r\n\t// Sets a map view that mostly contains the whole world with the maximum\r\n\t// zoom level possible.\r\n\tfitWorld: function (options) {\r\n\t\treturn this.fitBounds([[-90, -180], [90, 180]], options);\r\n\t},\r\n\r\n\t// @method panTo(latlng: LatLng, options?: Pan options): this\r\n\t// Pans the map to a given center.\r\n\tpanTo: function (center, options) { // (LatLng)\r\n\t\treturn this.setView(center, this._zoom, {pan: options});\r\n\t},\r\n\r\n\t// @method panBy(offset: Point): this\r\n\t// Pans the map by a given number of pixels (animated).\r\n\tpanBy: function (offset, options) {\r\n\t\toffset = L.point(offset).round();\r\n\t\toptions = options || {};\r\n\r\n\t\tif (!offset.x && !offset.y) {\r\n\t\t\treturn this.fire('moveend');\r\n\t\t}\r\n\t\t// If we pan too far, Chrome gets issues with tiles\r\n\t\t// and makes them disappear or appear in the wrong place (slightly offset) #2602\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) {\r\n\t\t\tthis._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tif (!this._panAnim) {\r\n\t\t\tthis._panAnim = new L.PosAnimation();\r\n\r\n\t\t\tthis._panAnim.on({\r\n\t\t\t\t'step': this._onPanTransitionStep,\r\n\t\t\t\t'end': this._onPanTransitionEnd\r\n\t\t\t}, this);\r\n\t\t}\r\n\r\n\t\t// don't fire movestart if animating inertia\r\n\t\tif (!options.noMoveStart) {\r\n\t\t\tthis.fire('movestart');\r\n\t\t}\r\n\r\n\t\t// animate pan unless animate: false specified\r\n\t\tif (options.animate !== false) {\r\n\t\t\tL.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');\r\n\r\n\t\t\tvar newPos = this._getMapPanePos().subtract(offset).round();\r\n\t\t\tthis._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);\r\n\t\t} else {\r\n\t\t\tthis._rawPanBy(offset);\r\n\t\t\tthis.fire('move').fire('moveend');\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this\r\n\t// Sets the view of the map (geographical center and zoom) performing a smooth\r\n\t// pan-zoom animation.\r\n\tflyTo: function (targetCenter, targetZoom, options) {\r\n\r\n\t\toptions = options || {};\r\n\t\tif (options.animate === false || !L.Browser.any3d) {\r\n\t\t\treturn this.setView(targetCenter, targetZoom, options);\r\n\t\t}\r\n\r\n\t\tthis._stop();\r\n\r\n\t\tvar from = this.project(this.getCenter()),\r\n\t\t    to = this.project(targetCenter),\r\n\t\t    size = this.getSize(),\r\n\t\t    startZoom = this._zoom;\r\n\r\n\t\ttargetCenter = L.latLng(targetCenter);\r\n\t\ttargetZoom = targetZoom === undefined ? startZoom : targetZoom;\r\n\r\n\t\tvar w0 = Math.max(size.x, size.y),\r\n\t\t    w1 = w0 * this.getZoomScale(startZoom, targetZoom),\r\n\t\t    u1 = (to.distanceTo(from)) || 1,\r\n\t\t    rho = 1.42,\r\n\t\t    rho2 = rho * rho;\r\n\r\n\t\tfunction r(i) {\r\n\t\t\tvar s1 = i ? -1 : 1,\r\n\t\t\t    s2 = i ? w1 : w0,\r\n\t\t\t    t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,\r\n\t\t\t    b1 = 2 * s2 * rho2 * u1,\r\n\t\t\t    b = t1 / b1,\r\n\t\t\t    sq = Math.sqrt(b * b + 1) - b;\r\n\r\n\t\t\t    // workaround for floating point precision bug when sq = 0, log = -Infinite,\r\n\t\t\t    // thus triggering an infinite loop in flyTo\r\n\t\t\t    var log = sq < 0.000000001 ? -18 : Math.log(sq);\r\n\r\n\t\t\treturn log;\r\n\t\t}\r\n\r\n\t\tfunction sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }\r\n\t\tfunction cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }\r\n\t\tfunction tanh(n) { return sinh(n) / cosh(n); }\r\n\r\n\t\tvar r0 = r(0);\r\n\r\n\t\tfunction w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }\r\n\t\tfunction u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }\r\n\r\n\t\tfunction easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }\r\n\r\n\t\tvar start = Date.now(),\r\n\t\t    S = (r(1) - r0) / rho,\r\n\t\t    duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;\r\n\r\n\t\tfunction frame() {\r\n\t\t\tvar t = (Date.now() - start) / duration,\r\n\t\t\t    s = easeOut(t) * S;\r\n\r\n\t\t\tif (t <= 1) {\r\n\t\t\t\tthis._flyToFrame = L.Util.requestAnimFrame(frame, this);\r\n\r\n\t\t\t\tthis._move(\r\n\t\t\t\t\tthis.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),\r\n\t\t\t\t\tthis.getScaleZoom(w0 / w(s), startZoom),\r\n\t\t\t\t\t{flyTo: true});\r\n\r\n\t\t\t} else {\r\n\t\t\t\tthis\r\n\t\t\t\t\t._move(targetCenter, targetZoom)\r\n\t\t\t\t\t._moveEnd(true);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._moveStart(true);\r\n\r\n\t\tframe.call(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this\r\n\t// Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),\r\n\t// but takes a bounds parameter like [`fitBounds`](#map-fitbounds).\r\n\tflyToBounds: function (bounds, options) {\r\n\t\tvar target = this._getBoundsCenterZoom(bounds, options);\r\n\t\treturn this.flyTo(target.center, target.zoom, options);\r\n\t},\r\n\r\n\t// @method setMaxBounds(bounds: Bounds): this\r\n\t// Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).\r\n\tsetMaxBounds: function (bounds) {\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\r\n\t\tif (!bounds.isValid()) {\r\n\t\t\tthis.options.maxBounds = null;\r\n\t\t\treturn this.off('moveend', this._panInsideMaxBounds);\r\n\t\t} else if (this.options.maxBounds) {\r\n\t\t\tthis.off('moveend', this._panInsideMaxBounds);\r\n\t\t}\r\n\r\n\t\tthis.options.maxBounds = bounds;\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\tthis._panInsideMaxBounds();\r\n\t\t}\r\n\r\n\t\treturn this.on('moveend', this._panInsideMaxBounds);\r\n\t},\r\n\r\n\t// @method setMinZoom(zoom: Number): this\r\n\t// Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).\r\n\tsetMinZoom: function (zoom) {\r\n\t\tthis.options.minZoom = zoom;\r\n\r\n\t\tif (this._loaded && this.getZoom() < this.options.minZoom) {\r\n\t\t\treturn this.setZoom(zoom);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setMaxZoom(zoom: Number): this\r\n\t// Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).\r\n\tsetMaxZoom: function (zoom) {\r\n\t\tthis.options.maxZoom = zoom;\r\n\r\n\t\tif (this._loaded && (this.getZoom() > this.options.maxZoom)) {\r\n\t\t\treturn this.setZoom(zoom);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this\r\n\t// 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.\r\n\tpanInsideBounds: function (bounds, options) {\r\n\t\tthis._enforcingBounds = true;\r\n\t\tvar center = this.getCenter(),\r\n\t\t    newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));\r\n\r\n\t\tif (!center.equals(newCenter)) {\r\n\t\t\tthis.panTo(newCenter, options);\r\n\t\t}\r\n\r\n\t\tthis._enforcingBounds = false;\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method invalidateSize(options: Zoom/Pan options): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default. If `options.pan` is `false`, panning will not occur.\r\n\t// If `options.debounceMoveend` is `true`, it will delay `moveend` event so\r\n\t// that it doesn't happen often even if the method is called many\r\n\t// times in a row.\r\n\r\n\t// @alternative\r\n\t// @method invalidateSize(animate: Boolean): this\r\n\t// Checks if the map container size changed and updates the map if so —\r\n\t// call it after you've changed the map size dynamically, also animating\r\n\t// pan by default.\r\n\tinvalidateSize: function (options) {\r\n\t\tif (!this._loaded) { return this; }\r\n\r\n\t\toptions = L.extend({\r\n\t\t\tanimate: false,\r\n\t\t\tpan: true\r\n\t\t}, options === true ? {animate: true} : options);\r\n\r\n\t\tvar oldSize = this.getSize();\r\n\t\tthis._sizeChanged = true;\r\n\t\tthis._lastCenter = null;\r\n\r\n\t\tvar newSize = this.getSize(),\r\n\t\t    oldCenter = oldSize.divideBy(2).round(),\r\n\t\t    newCenter = newSize.divideBy(2).round(),\r\n\t\t    offset = oldCenter.subtract(newCenter);\r\n\r\n\t\tif (!offset.x && !offset.y) { return this; }\r\n\r\n\t\tif (options.animate && options.pan) {\r\n\t\t\tthis.panBy(offset);\r\n\r\n\t\t} else {\r\n\t\t\tif (options.pan) {\r\n\t\t\t\tthis._rawPanBy(offset);\r\n\t\t\t}\r\n\r\n\t\t\tthis.fire('move');\r\n\r\n\t\t\tif (options.debounceMoveend) {\r\n\t\t\t\tclearTimeout(this._sizeTimer);\r\n\t\t\t\tthis._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);\r\n\t\t\t} else {\r\n\t\t\t\tthis.fire('moveend');\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @section Map state change events\r\n\t\t// @event resize: ResizeEvent\r\n\t\t// Fired when the map is resized.\r\n\t\treturn this.fire('resize', {\r\n\t\t\toldSize: oldSize,\r\n\t\t\tnewSize: newSize\r\n\t\t});\r\n\t},\r\n\r\n\t// @section Methods for modifying map state\r\n\t// @method stop(): this\r\n\t// Stops the currently running `panTo` or `flyTo` animation, if any.\r\n\tstop: function () {\r\n\t\tthis.setZoom(this._limitZoom(this._zoom));\r\n\t\tif (!this.options.zoomSnap) {\r\n\t\t\tthis.fire('viewreset');\r\n\t\t}\r\n\t\treturn this._stop();\r\n\t},\r\n\r\n\t// @section Geolocation methods\r\n\t// @method locate(options?: Locate options): this\r\n\t// Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)\r\n\t// event with location data on success or a [`locationerror`](#map-locationerror) event on failure,\r\n\t// and optionally sets the map view to the user's location with respect to\r\n\t// detection accuracy (or to the world view if geolocation failed).\r\n\t// Note that, if your page doesn't use HTTPS, this method will fail in\r\n\t// modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))\r\n\t// See `Locate options` for more details.\r\n\tlocate: function (options) {\r\n\r\n\t\toptions = this._locateOptions = L.extend({\r\n\t\t\ttimeout: 10000,\r\n\t\t\twatch: false\r\n\t\t\t// setView: false\r\n\t\t\t// maxZoom: <Number>\r\n\t\t\t// maximumAge: 0\r\n\t\t\t// enableHighAccuracy: false\r\n\t\t}, options);\r\n\r\n\t\tif (!('geolocation' in navigator)) {\r\n\t\t\tthis._handleGeolocationError({\r\n\t\t\t\tcode: 0,\r\n\t\t\t\tmessage: 'Geolocation not supported.'\r\n\t\t\t});\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar onResponse = L.bind(this._handleGeolocationResponse, this),\r\n\t\t    onError = L.bind(this._handleGeolocationError, this);\r\n\r\n\t\tif (options.watch) {\r\n\t\t\tthis._locationWatchId =\r\n\t\t\t        navigator.geolocation.watchPosition(onResponse, onError, options);\r\n\t\t} else {\r\n\t\t\tnavigator.geolocation.getCurrentPosition(onResponse, onError, options);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method stopLocate(): this\r\n\t// Stops watching location previously initiated by `map.locate({watch: true})`\r\n\t// and aborts resetting the map view if map.locate was called with\r\n\t// `{setView: true}`.\r\n\tstopLocate: function () {\r\n\t\tif (navigator.geolocation && navigator.geolocation.clearWatch) {\r\n\t\t\tnavigator.geolocation.clearWatch(this._locationWatchId);\r\n\t\t}\r\n\t\tif (this._locateOptions) {\r\n\t\t\tthis._locateOptions.setView = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_handleGeolocationError: function (error) {\r\n\t\tvar c = error.code,\r\n\t\t    message = error.message ||\r\n\t\t            (c === 1 ? 'permission denied' :\r\n\t\t            (c === 2 ? 'position unavailable' : 'timeout'));\r\n\r\n\t\tif (this._locateOptions.setView && !this._loaded) {\r\n\t\t\tthis.fitWorld();\r\n\t\t}\r\n\r\n\t\t// @section Location events\r\n\t\t// @event locationerror: ErrorEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method) failed.\r\n\t\tthis.fire('locationerror', {\r\n\t\t\tcode: c,\r\n\t\t\tmessage: 'Geolocation error: ' + message + '.'\r\n\t\t});\r\n\t},\r\n\r\n\t_handleGeolocationResponse: function (pos) {\r\n\t\tvar lat = pos.coords.latitude,\r\n\t\t    lng = pos.coords.longitude,\r\n\t\t    latlng = new L.LatLng(lat, lng),\r\n\t\t    bounds = latlng.toBounds(pos.coords.accuracy),\r\n\t\t    options = this._locateOptions;\r\n\r\n\t\tif (options.setView) {\r\n\t\t\tvar zoom = this.getBoundsZoom(bounds);\r\n\t\t\tthis.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);\r\n\t\t}\r\n\r\n\t\tvar data = {\r\n\t\t\tlatlng: latlng,\r\n\t\t\tbounds: bounds,\r\n\t\t\ttimestamp: pos.timestamp\r\n\t\t};\r\n\r\n\t\tfor (var i in pos.coords) {\r\n\t\t\tif (typeof pos.coords[i] === 'number') {\r\n\t\t\t\tdata[i] = pos.coords[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// @event locationfound: LocationEvent\r\n\t\t// Fired when geolocation (using the [`locate`](#map-locate) method)\r\n\t\t// went successfully.\r\n\t\tthis.fire('locationfound', data);\r\n\t},\r\n\r\n\t// TODO handler.addTo\r\n\t// TODO Appropiate docs section?\r\n\t// @section Other Methods\r\n\t// @method addHandler(name: String, HandlerClass: Function): this\r\n\t// Adds a new `Handler` to the map, given its name and constructor function.\r\n\taddHandler: function (name, HandlerClass) {\r\n\t\tif (!HandlerClass) { return this; }\r\n\r\n\t\tvar handler = this[name] = new HandlerClass(this);\r\n\r\n\t\tthis._handlers.push(handler);\r\n\r\n\t\tif (this.options[name]) {\r\n\t\t\thandler.enable();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove(): this\r\n\t// Destroys the map and clears all related event listeners.\r\n\tremove: function () {\r\n\r\n\t\tthis._initEvents(true);\r\n\r\n\t\tif (this._containerId !== this._container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is being reused by another instance');\r\n\t\t}\r\n\r\n\t\ttry {\r\n\t\t\t// throws error in IE6-8\r\n\t\t\tdelete this._container._leaflet_id;\r\n\t\t\tdelete this._containerId;\r\n\t\t} catch (e) {\r\n\t\t\t/*eslint-disable */\r\n\t\t\tthis._container._leaflet_id = undefined;\r\n\t\t\t/*eslint-enable */\r\n\t\t\tthis._containerId = undefined;\r\n\t\t}\r\n\r\n\t\tL.DomUtil.remove(this._mapPane);\r\n\r\n\t\tif (this._clearControlPos) {\r\n\t\t\tthis._clearControlPos();\r\n\t\t}\r\n\r\n\t\tthis._clearHandlers();\r\n\r\n\t\tif (this._loaded) {\r\n\t\t\t// @section Map state change events\r\n\t\t\t// @event unload: Event\r\n\t\t\t// Fired when the map is destroyed with [remove](#map-remove) method.\r\n\t\t\tthis.fire('unload');\r\n\t\t}\r\n\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tthis._layers[i].remove();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\t// @method createPane(name: String, container?: HTMLElement): HTMLElement\r\n\t// Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,\r\n\t// then returns it. The pane is created as a children of `container`, or\r\n\t// as a children of the main map pane if not set.\r\n\tcreatePane: function (name, container) {\r\n\t\tvar className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),\r\n\t\t    pane = L.DomUtil.create('div', className, container || this._mapPane);\r\n\r\n\t\tif (name) {\r\n\t\t\tthis._panes[name] = pane;\r\n\t\t}\r\n\t\treturn pane;\r\n\t},\r\n\r\n\t// @section Methods for Getting Map State\r\n\r\n\t// @method getCenter(): LatLng\r\n\t// Returns the geographical center of the map view\r\n\tgetCenter: function () {\r\n\t\tthis._checkIfLoaded();\r\n\r\n\t\tif (this._lastCenter && !this._moved()) {\r\n\t\t\treturn this._lastCenter;\r\n\t\t}\r\n\t\treturn this.layerPointToLatLng(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// @method getZoom(): Number\r\n\t// Returns the current zoom level of the map view\r\n\tgetZoom: function () {\r\n\t\treturn this._zoom;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the geographical bounds visible in the current map view\r\n\tgetBounds: function () {\r\n\t\tvar bounds = this.getPixelBounds(),\r\n\t\t    sw = this.unproject(bounds.getBottomLeft()),\r\n\t\t    ne = this.unproject(bounds.getTopRight());\r\n\r\n\t\treturn new L.LatLngBounds(sw, ne);\r\n\t},\r\n\r\n\t// @method getMinZoom(): Number\r\n\t// 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.\r\n\tgetMinZoom: function () {\r\n\t\treturn this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;\r\n\t},\r\n\r\n\t// @method getMaxZoom(): Number\r\n\t// Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).\r\n\tgetMaxZoom: function () {\r\n\t\treturn this.options.maxZoom === undefined ?\r\n\t\t\t(this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :\r\n\t\t\tthis.options.maxZoom;\r\n\t},\r\n\r\n\t// @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean): Number\r\n\t// Returns the maximum zoom level on which the given bounds fit to the map\r\n\t// view in its entirety. If `inside` (optional) is set to `true`, the method\r\n\t// instead returns the minimum zoom level on which the map view fits into\r\n\t// the given bounds in its entirety.\r\n\tgetBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number\r\n\t\tbounds = L.latLngBounds(bounds);\r\n\t\tpadding = L.point(padding || [0, 0]);\r\n\r\n\t\tvar zoom = this.getZoom() || 0,\r\n\t\t    min = this.getMinZoom(),\r\n\t\t    max = this.getMaxZoom(),\r\n\t\t    nw = bounds.getNorthWest(),\r\n\t\t    se = bounds.getSouthEast(),\r\n\t\t    size = this.getSize().subtract(padding),\r\n\t\t    boundsSize = L.bounds(this.project(se, zoom), this.project(nw, zoom)).getSize(),\r\n\t\t    snap = L.Browser.any3d ? this.options.zoomSnap : 1;\r\n\r\n\t\tvar scale = Math.min(size.x / boundsSize.x, size.y / boundsSize.y);\r\n\t\tzoom = this.getScaleZoom(scale, zoom);\r\n\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level\r\n\t\t\tzoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;\r\n\t\t}\r\n\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t// @method getSize(): Point\r\n\t// Returns the current size of the map container (in pixels).\r\n\tgetSize: function () {\r\n\t\tif (!this._size || this._sizeChanged) {\r\n\t\t\tthis._size = new L.Point(\r\n\t\t\t\tthis._container.clientWidth || 0,\r\n\t\t\t\tthis._container.clientHeight || 0);\r\n\r\n\t\t\tthis._sizeChanged = false;\r\n\t\t}\r\n\t\treturn this._size.clone();\r\n\t},\r\n\r\n\t// @method getPixelBounds(): Bounds\r\n\t// Returns the bounds of the current map view in projected pixel\r\n\t// coordinates (sometimes useful in layer and overlay implementations).\r\n\tgetPixelBounds: function (center, zoom) {\r\n\t\tvar topLeftPoint = this._getTopLeftPoint(center, zoom);\r\n\t\treturn new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));\r\n\t},\r\n\r\n\t// TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to\r\n\t// the map pane? \"left point of the map layer\" can be confusing, specially\r\n\t// since there can be negative offsets.\r\n\t// @method getPixelOrigin(): Point\r\n\t// Returns the projected pixel coordinates of the top left point of\r\n\t// the map layer (useful in custom layer and overlay implementations).\r\n\tgetPixelOrigin: function () {\r\n\t\tthis._checkIfLoaded();\r\n\t\treturn this._pixelOrigin;\r\n\t},\r\n\r\n\t// @method getPixelWorldBounds(zoom?: Number): Bounds\r\n\t// Returns the world's bounds in pixel coordinates for zoom level `zoom`.\r\n\t// If `zoom` is omitted, the map's current zoom level is used.\r\n\tgetPixelWorldBounds: function (zoom) {\r\n\t\treturn this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method getPane(pane: String|HTMLElement): HTMLElement\r\n\t// Returns a [map pane](#map-pane), given its name or its HTML element (its identity).\r\n\tgetPane: function (pane) {\r\n\t\treturn typeof pane === 'string' ? this._panes[pane] : pane;\r\n\t},\r\n\r\n\t// @method getPanes(): Object\r\n\t// Returns a plain object containing the names of all [panes](#map-pane) as keys and\r\n\t// the panes as values.\r\n\tgetPanes: function () {\r\n\t\treturn this._panes;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTML element that contains the map.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\r\n\t// @section Conversion Methods\r\n\r\n\t// @method getZoomScale(toZoom: Number, fromZoom: Number): Number\r\n\t// Returns the scale factor to be applied to a map transition from zoom level\r\n\t// `fromZoom` to `toZoom`. Used internally to help with zoom animations.\r\n\tgetZoomScale: function (toZoom, fromZoom) {\r\n\t\t// TODO replace with universal implementation after refactoring projections\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\treturn crs.scale(toZoom) / crs.scale(fromZoom);\r\n\t},\r\n\r\n\t// @method getScaleZoom(scale: Number, fromZoom: Number): Number\r\n\t// Returns the zoom level that the map would end up at, if it is at `fromZoom`\r\n\t// level and everything is scaled by a factor of `scale`. Inverse of\r\n\t// [`getZoomScale`](#map-getZoomScale).\r\n\tgetScaleZoom: function (scale, fromZoom) {\r\n\t\tvar crs = this.options.crs;\r\n\t\tfromZoom = fromZoom === undefined ? this._zoom : fromZoom;\r\n\t\tvar zoom = crs.zoom(scale * crs.scale(fromZoom));\r\n\t\treturn isNaN(zoom) ? Infinity : zoom;\r\n\t},\r\n\r\n\t// @method project(latlng: LatLng, zoom: Number): Point\r\n\t// Projects a geographical coordinate `LatLng` according to the projection\r\n\t// of the map's CRS, then scales it according to `zoom` and the CRS's\r\n\t// `Transformation`. The result is pixel coordinate relative to\r\n\t// the CRS origin.\r\n\tproject: function (latlng, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.latLngToPoint(L.latLng(latlng), zoom);\r\n\t},\r\n\r\n\t// @method unproject(point: Point, zoom: Number): LatLng\r\n\t// Inverse of [`project`](#map-project).\r\n\tunproject: function (point, zoom) {\r\n\t\tzoom = zoom === undefined ? this._zoom : zoom;\r\n\t\treturn this.options.crs.pointToLatLng(L.point(point), zoom);\r\n\t},\r\n\r\n\t// @method layerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding geographical coordinate (for the current zoom level).\r\n\tlayerPointToLatLng: function (point) {\r\n\t\tvar projectedPoint = L.point(point).add(this.getPixelOrigin());\r\n\t\treturn this.unproject(projectedPoint);\r\n\t},\r\n\r\n\t// @method latLngToLayerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the [origin pixel](#map-getpixelorigin).\r\n\tlatLngToLayerPoint: function (latlng) {\r\n\t\tvar projectedPoint = this.project(L.latLng(latlng))._round();\r\n\t\treturn projectedPoint._subtract(this.getPixelOrigin());\r\n\t},\r\n\r\n\t// @method wrapLatLng(latlng: LatLng): LatLng\r\n\t// Returns a `LatLng` where `lat` and `lng` has been wrapped according to the\r\n\t// map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the\r\n\t// CRS's bounds.\r\n\t// By default this means longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees.\r\n\twrapLatLng: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLng(L.latLng(latlng));\r\n\t},\r\n\r\n\t// @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds\r\n\t// Returns a `LatLngBounds` with the same size as the given one, ensuring that\r\n\t// its center is within the CRS's bounds.\r\n\t// By default this means the center longitude is wrapped around the dateline so its\r\n\t// value is between -180 and +180 degrees, and the majority of the bounds\r\n\t// overlaps the CRS's bounds.\r\n\twrapLatLngBounds: function (latlng) {\r\n\t\treturn this.options.crs.wrapLatLngBounds(L.latLngBounds(latlng));\r\n\t},\r\n\r\n\t// @method distance(latlng1: LatLng, latlng2: LatLng): Number\r\n\t// Returns the distance between two geographical coordinates according to\r\n\t// the map's CRS. By default this measures distance in meters.\r\n\tdistance: function (latlng1, latlng2) {\r\n\t\treturn this.options.crs.distance(L.latLng(latlng1), L.latLng(latlng2));\r\n\t},\r\n\r\n\t// @method containerPointToLayerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the map container, returns the corresponding\r\n\t// pixel coordinate relative to the [origin pixel](#map-getpixelorigin).\r\n\tcontainerPointToLayerPoint: function (point) { // (Point)\r\n\t\treturn L.point(point).subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method layerPointToContainerPoint(point: Point): Point\r\n\t// Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),\r\n\t// returns the corresponding pixel coordinate relative to the map container.\r\n\tlayerPointToContainerPoint: function (point) { // (Point)\r\n\t\treturn L.point(point).add(this._getMapPanePos());\r\n\t},\r\n\r\n\t// @method containerPointToLatLng(point: Point): LatLng\r\n\t// Given a pixel coordinate relative to the map container, returns\r\n\t// the corresponding geographical coordinate (for the current zoom level).\r\n\tcontainerPointToLatLng: function (point) {\r\n\t\tvar layerPoint = this.containerPointToLayerPoint(L.point(point));\r\n\t\treturn this.layerPointToLatLng(layerPoint);\r\n\t},\r\n\r\n\t// @method latLngToContainerPoint(latlng: LatLng): Point\r\n\t// Given a geographical coordinate, returns the corresponding pixel coordinate\r\n\t// relative to the map container.\r\n\tlatLngToContainerPoint: function (latlng) {\r\n\t\treturn this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));\r\n\t},\r\n\r\n\t// @method mouseEventToContainerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to the\r\n\t// map container where the event took place.\r\n\tmouseEventToContainerPoint: function (e) {\r\n\t\treturn L.DomEvent.getMousePosition(e, this._container);\r\n\t},\r\n\r\n\t// @method mouseEventToLayerPoint(ev: MouseEvent): Point\r\n\t// Given a MouseEvent object, returns the pixel coordinate relative to\r\n\t// the [origin pixel](#map-getpixelorigin) where the event took place.\r\n\tmouseEventToLayerPoint: function (e) {\r\n\t\treturn this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));\r\n\t},\r\n\r\n\t// @method mouseEventToLatLng(ev: MouseEvent): LatLng\r\n\t// Given a MouseEvent object, returns geographical coordinate where the\r\n\t// event took place.\r\n\tmouseEventToLatLng: function (e) { // (MouseEvent)\r\n\t\treturn this.layerPointToLatLng(this.mouseEventToLayerPoint(e));\r\n\t},\r\n\r\n\r\n\t// map initialization methods\r\n\r\n\t_initContainer: function (id) {\r\n\t\tvar container = this._container = L.DomUtil.get(id);\r\n\r\n\t\tif (!container) {\r\n\t\t\tthrow new Error('Map container not found.');\r\n\t\t} else if (container._leaflet_id) {\r\n\t\t\tthrow new Error('Map container is already initialized.');\r\n\t\t}\r\n\r\n\t\tL.DomEvent.addListener(container, 'scroll', this._onScroll, this);\r\n\t\tthis._containerId = L.Util.stamp(container);\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar container = this._container;\r\n\r\n\t\tthis._fadeAnimated = this.options.fadeAnimation && L.Browser.any3d;\r\n\r\n\t\tL.DomUtil.addClass(container, 'leaflet-container' +\r\n\t\t\t(L.Browser.touch ? ' leaflet-touch' : '') +\r\n\t\t\t(L.Browser.retina ? ' leaflet-retina' : '') +\r\n\t\t\t(L.Browser.ielt9 ? ' leaflet-oldie' : '') +\r\n\t\t\t(L.Browser.safari ? ' leaflet-safari' : '') +\r\n\t\t\t(this._fadeAnimated ? ' leaflet-fade-anim' : ''));\r\n\r\n\t\tvar position = L.DomUtil.getStyle(container, 'position');\r\n\r\n\t\tif (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {\r\n\t\t\tcontainer.style.position = 'relative';\r\n\t\t}\r\n\r\n\t\tthis._initPanes();\r\n\r\n\t\tif (this._initControlPos) {\r\n\t\t\tthis._initControlPos();\r\n\t\t}\r\n\t},\r\n\r\n\t_initPanes: function () {\r\n\t\tvar panes = this._panes = {};\r\n\t\tthis._paneRenderers = {};\r\n\r\n\t\t// @section\r\n\t\t//\r\n\t\t// Panes are DOM elements used to control the ordering of layers on the map. You\r\n\t\t// can access panes with [`map.getPane`](#map-getpane) or\r\n\t\t// [`map.getPanes`](#map-getpanes) methods. New panes can be created with the\r\n\t\t// [`map.createPane`](#map-createpane) method.\r\n\t\t//\r\n\t\t// Every map has the following default panes that differ only in zIndex.\r\n\t\t//\r\n\t\t// @pane mapPane: HTMLElement = 'auto'\r\n\t\t// Pane that contains all other map panes\r\n\r\n\t\tthis._mapPane = this.createPane('mapPane', this._container);\r\n\t\tL.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));\r\n\r\n\t\t// @pane tilePane: HTMLElement = 200\r\n\t\t// Pane for `GridLayer`s and `TileLayer`s\r\n\t\tthis.createPane('tilePane');\r\n\t\t// @pane overlayPane: HTMLElement = 400\r\n\t\t// Pane for vector overlays (`Path`s), like `Polyline`s and `Polygon`s\r\n\t\tthis.createPane('shadowPane');\r\n\t\t// @pane shadowPane: HTMLElement = 500\r\n\t\t// Pane for overlay shadows (e.g. `Marker` shadows)\r\n\t\tthis.createPane('overlayPane');\r\n\t\t// @pane markerPane: HTMLElement = 600\r\n\t\t// Pane for `Icon`s of `Marker`s\r\n\t\tthis.createPane('markerPane');\r\n\t\t// @pane tooltipPane: HTMLElement = 650\r\n\t\t// Pane for tooltip.\r\n\t\tthis.createPane('tooltipPane');\r\n\t\t// @pane popupPane: HTMLElement = 700\r\n\t\t// Pane for `Popup`s.\r\n\t\tthis.createPane('popupPane');\r\n\r\n\t\tif (!this.options.markerZoomAnimation) {\r\n\t\t\tL.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');\r\n\t\t\tL.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');\r\n\t\t}\r\n\t},\r\n\r\n\r\n\t// private methods that modify map state\r\n\r\n\t// @section Map state change events\r\n\t_resetView: function (center, zoom) {\r\n\t\tL.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));\r\n\r\n\t\tvar loading = !this._loaded;\r\n\t\tthis._loaded = true;\r\n\t\tzoom = this._limitZoom(zoom);\r\n\r\n\t\tthis.fire('viewprereset');\r\n\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\t\tthis\r\n\t\t\t._moveStart(zoomChanged)\r\n\t\t\t._move(center, zoom)\r\n\t\t\t._moveEnd(zoomChanged);\r\n\r\n\t\t// @event viewreset: Event\r\n\t\t// Fired when the map needs to redraw its content (this usually happens\r\n\t\t// on map zoom or load). Very useful for creating custom overlays.\r\n\t\tthis.fire('viewreset');\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the map is initialized (when its center and zoom are set\r\n\t\t// for the first time).\r\n\t\tif (loading) {\r\n\t\t\tthis.fire('load');\r\n\t\t}\r\n\t},\r\n\r\n\t_moveStart: function (zoomChanged) {\r\n\t\t// @event zoomstart: Event\r\n\t\t// Fired when the map zoom is about to change (e.g. before zoom animation).\r\n\t\t// @event movestart: Event\r\n\t\t// Fired when the view of the map starts changing (e.g. user starts dragging the map).\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomstart');\r\n\t\t}\r\n\t\treturn this.fire('movestart');\r\n\t},\r\n\r\n\t_move: function (center, zoom, data) {\r\n\t\tif (zoom === undefined) {\r\n\t\t\tzoom = this._zoom;\r\n\t\t}\r\n\t\tvar zoomChanged = this._zoom !== zoom;\r\n\r\n\t\tthis._zoom = zoom;\r\n\t\tthis._lastCenter = center;\r\n\t\tthis._pixelOrigin = this._getNewPixelOrigin(center);\r\n\r\n\t\t// @event zoom: Event\r\n\t\t// Fired repeatedly during any change in zoom level, including zoom\r\n\t\t// and fly animations.\r\n\t\tif (zoomChanged || (data && data.pinch)) {\t// Always fire 'zoom' if pinching because #3530\r\n\t\t\tthis.fire('zoom', data);\r\n\t\t}\r\n\r\n\t\t// @event move: Event\r\n\t\t// Fired repeatedly during any movement of the map, including pan and\r\n\t\t// fly animations.\r\n\t\treturn this.fire('move', data);\r\n\t},\r\n\r\n\t_moveEnd: function (zoomChanged) {\r\n\t\t// @event zoomend: Event\r\n\t\t// Fired when the map has changed, after any animations.\r\n\t\tif (zoomChanged) {\r\n\t\t\tthis.fire('zoomend');\r\n\t\t}\r\n\r\n\t\t// @event moveend: Event\r\n\t\t// Fired when the center of the map stops changing (e.g. user stopped\r\n\t\t// dragging the map).\r\n\t\treturn this.fire('moveend');\r\n\t},\r\n\r\n\t_stop: function () {\r\n\t\tL.Util.cancelAnimFrame(this._flyToFrame);\r\n\t\tif (this._panAnim) {\r\n\t\t\tthis._panAnim.stop();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_rawPanBy: function (offset) {\r\n\t\tL.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));\r\n\t},\r\n\r\n\t_getZoomSpan: function () {\r\n\t\treturn this.getMaxZoom() - this.getMinZoom();\r\n\t},\r\n\r\n\t_panInsideMaxBounds: function () {\r\n\t\tif (!this._enforcingBounds) {\r\n\t\t\tthis.panInsideBounds(this.options.maxBounds);\r\n\t\t}\r\n\t},\r\n\r\n\t_checkIfLoaded: function () {\r\n\t\tif (!this._loaded) {\r\n\t\t\tthrow new Error('Set map center and zoom first.');\r\n\t\t}\r\n\t},\r\n\r\n\t// DOM event handling\r\n\r\n\t// @section Interaction events\r\n\t_initEvents: function (remove) {\r\n\t\tif (!L.DomEvent) { return; }\r\n\r\n\t\tthis._targets = {};\r\n\t\tthis._targets[L.stamp(this._container)] = this;\r\n\r\n\t\tvar onOff = remove ? 'off' : 'on';\r\n\r\n\t\t// @event click: MouseEvent\r\n\t\t// Fired when the user clicks (or taps) the map.\r\n\t\t// @event dblclick: MouseEvent\r\n\t\t// Fired when the user double-clicks (or double-taps) the map.\r\n\t\t// @event mousedown: MouseEvent\r\n\t\t// Fired when the user pushes the mouse button on the map.\r\n\t\t// @event mouseup: MouseEvent\r\n\t\t// Fired when the user releases the mouse button on the map.\r\n\t\t// @event mouseover: MouseEvent\r\n\t\t// Fired when the mouse enters the map.\r\n\t\t// @event mouseout: MouseEvent\r\n\t\t// Fired when the mouse leaves the map.\r\n\t\t// @event mousemove: MouseEvent\r\n\t\t// Fired while the mouse moves over the map.\r\n\t\t// @event contextmenu: MouseEvent\r\n\t\t// Fired when the user pushes the right mouse button on the map, prevents\r\n\t\t// default browser context menu from showing if there are listeners on\r\n\t\t// this event. Also fired on mobile when the user holds a single touch\r\n\t\t// for a second (also called long press).\r\n\t\t// @event keypress: KeyboardEvent\r\n\t\t// Fired when the user presses a key from the keyboard while the map is focused.\r\n\t\tL.DomEvent[onOff](this._container, 'click dblclick mousedown mouseup ' +\r\n\t\t\t'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this);\r\n\r\n\t\tif (this.options.trackResize) {\r\n\t\t\tL.DomEvent[onOff](window, 'resize', this._onResize, this);\r\n\t\t}\r\n\r\n\t\tif (L.Browser.any3d && this.options.transform3DLimit) {\r\n\t\t\tthis[onOff]('moveend', this._onMoveEnd);\r\n\t\t}\r\n\t},\r\n\r\n\t_onResize: function () {\r\n\t\tL.Util.cancelAnimFrame(this._resizeRequest);\r\n\t\tthis._resizeRequest = L.Util.requestAnimFrame(\r\n\t\t        function () { this.invalidateSize({debounceMoveend: true}); }, this);\r\n\t},\r\n\r\n\t_onScroll: function () {\r\n\t\tthis._container.scrollTop  = 0;\r\n\t\tthis._container.scrollLeft = 0;\r\n\t},\r\n\r\n\t_onMoveEnd: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\tif (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {\r\n\t\t\t// https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have\r\n\t\t\t// a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/\r\n\t\t\tthis._resetView(this.getCenter(), this.getZoom());\r\n\t\t}\r\n\t},\r\n\r\n\t_findEventTargets: function (e, type) {\r\n\t\tvar targets = [],\r\n\t\t    target,\r\n\t\t    isHover = type === 'mouseout' || type === 'mouseover',\r\n\t\t    src = e.target || e.srcElement,\r\n\t\t    dragging = false;\r\n\r\n\t\twhile (src) {\r\n\t\t\ttarget = this._targets[L.stamp(src)];\r\n\t\t\tif (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {\r\n\t\t\t\t// Prevent firing click after you just dragged an object.\r\n\t\t\t\tdragging = true;\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t\tif (target && target.listens(type, true)) {\r\n\t\t\t\tif (isHover && !L.DomEvent._isExternalTarget(src, e)) { break; }\r\n\t\t\t\ttargets.push(target);\r\n\t\t\t\tif (isHover) { break; }\r\n\t\t\t}\r\n\t\t\tif (src === this._container) { break; }\r\n\t\t\tsrc = src.parentNode;\r\n\t\t}\r\n\t\tif (!targets.length && !dragging && !isHover && L.DomEvent._isExternalTarget(src, e)) {\r\n\t\t\ttargets = [this];\r\n\t\t}\r\n\t\treturn targets;\r\n\t},\r\n\r\n\t_handleDOMEvent: function (e) {\r\n\t\tif (!this._loaded || L.DomEvent._skipped(e)) { return; }\r\n\r\n\t\tvar type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;\r\n\r\n\t\tif (type === 'mousedown') {\r\n\t\t\t// prevents outline when clicking on keyboard-focusable element\r\n\t\t\tL.DomUtil.preventOutline(e.target || e.srcElement);\r\n\t\t}\r\n\r\n\t\tthis._fireDOMEvent(e, type);\r\n\t},\r\n\r\n\t_fireDOMEvent: function (e, type, targets) {\r\n\r\n\t\tif (e.type === 'click') {\r\n\t\t\t// Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).\r\n\t\t\t// @event preclick: MouseEvent\r\n\t\t\t// Fired before mouse click on the map (sometimes useful when you\r\n\t\t\t// want something to happen on click before any existing click\r\n\t\t\t// handlers start running).\r\n\t\t\tvar synth = L.Util.extend({}, e);\r\n\t\t\tsynth.type = 'preclick';\r\n\t\t\tthis._fireDOMEvent(synth, synth.type, targets);\r\n\t\t}\r\n\r\n\t\tif (e._stopped) { return; }\r\n\r\n\t\t// Find the layer the event is propagating from and its parents.\r\n\t\ttargets = (targets || []).concat(this._findEventTargets(e, type));\r\n\r\n\t\tif (!targets.length) { return; }\r\n\r\n\t\tvar target = targets[0];\r\n\t\tif (type === 'contextmenu' && target.listens(type, true)) {\r\n\t\t\tL.DomEvent.preventDefault(e);\r\n\t\t}\r\n\r\n\t\tvar data = {\r\n\t\t\toriginalEvent: e\r\n\t\t};\r\n\r\n\t\tif (e.type !== 'keypress') {\r\n\t\t\tvar isMarker = target instanceof L.Marker;\r\n\t\t\tdata.containerPoint = isMarker ?\r\n\t\t\t\t\tthis.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);\r\n\t\t\tdata.layerPoint = this.containerPointToLayerPoint(data.containerPoint);\r\n\t\t\tdata.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);\r\n\t\t}\r\n\r\n\t\tfor (var i = 0; i < targets.length; i++) {\r\n\t\t\ttargets[i].fire(type, data, true);\r\n\t\t\tif (data.originalEvent._stopped ||\r\n\t\t\t\t(targets[i].options.nonBubblingEvents && L.Util.indexOf(targets[i].options.nonBubblingEvents, type) !== -1)) { return; }\r\n\t\t}\r\n\t},\r\n\r\n\t_draggableMoved: function (obj) {\r\n\t\tobj = obj.dragging && obj.dragging.enabled() ? obj : this;\r\n\t\treturn (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());\r\n\t},\r\n\r\n\t_clearHandlers: function () {\r\n\t\tfor (var i = 0, len = this._handlers.length; i < len; i++) {\r\n\t\t\tthis._handlers[i].disable();\r\n\t\t}\r\n\t},\r\n\r\n\t// @section Other Methods\r\n\r\n\t// @method whenReady(fn: Function, context?: Object): this\r\n\t// Runs the given function `fn` when the map gets initialized with\r\n\t// a view (center and zoom) and at least one layer, or immediately\r\n\t// if it's already initialized, optionally passing a function context.\r\n\twhenReady: function (callback, context) {\r\n\t\tif (this._loaded) {\r\n\t\t\tcallback.call(context || this, {target: this});\r\n\t\t} else {\r\n\t\t\tthis.on('load', callback, context);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\r\n\t// private methods for getting map state\r\n\r\n\t_getMapPanePos: function () {\r\n\t\treturn L.DomUtil.getPosition(this._mapPane) || new L.Point(0, 0);\r\n\t},\r\n\r\n\t_moved: function () {\r\n\t\tvar pos = this._getMapPanePos();\r\n\t\treturn pos && !pos.equals([0, 0]);\r\n\t},\r\n\r\n\t_getTopLeftPoint: function (center, zoom) {\r\n\t\tvar pixelOrigin = center && zoom !== undefined ?\r\n\t\t\tthis._getNewPixelOrigin(center, zoom) :\r\n\t\t\tthis.getPixelOrigin();\r\n\t\treturn pixelOrigin.subtract(this._getMapPanePos());\r\n\t},\r\n\r\n\t_getNewPixelOrigin: function (center, zoom) {\r\n\t\tvar viewHalf = this.getSize()._divideBy(2);\r\n\t\treturn this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();\r\n\t},\r\n\r\n\t_latLngToNewLayerPoint: function (latlng, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn this.project(latlng, zoom)._subtract(topLeft);\r\n\t},\r\n\r\n\t_latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {\r\n\t\tvar topLeft = this._getNewPixelOrigin(center, zoom);\r\n\t\treturn L.bounds([\r\n\t\t\tthis.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),\r\n\t\t\tthis.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)\r\n\t\t]);\r\n\t},\r\n\r\n\t// layer point of the current center\r\n\t_getCenterLayerPoint: function () {\r\n\t\treturn this.containerPointToLayerPoint(this.getSize()._divideBy(2));\r\n\t},\r\n\r\n\t// offset of the specified place to the current center in pixels\r\n\t_getCenterOffset: function (latlng) {\r\n\t\treturn this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());\r\n\t},\r\n\r\n\t// adjust center for view to get inside bounds\r\n\t_limitCenter: function (center, zoom, bounds) {\r\n\r\n\t\tif (!bounds) { return center; }\r\n\r\n\t\tvar centerPoint = this.project(center, zoom),\r\n\t\t    viewHalf = this.getSize().divideBy(2),\r\n\t\t    viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),\r\n\t\t    offset = this._getBoundsOffset(viewBounds, bounds, zoom);\r\n\r\n\t\t// If offset is less than a pixel, ignore.\r\n\t\t// This prevents unstable projections from getting into\r\n\t\t// an infinite loop of tiny offsets.\r\n\t\tif (offset.round().equals([0, 0])) {\r\n\t\t\treturn center;\r\n\t\t}\r\n\r\n\t\treturn this.unproject(centerPoint.add(offset), zoom);\r\n\t},\r\n\r\n\t// adjust offset for view to get inside bounds\r\n\t_limitOffset: function (offset, bounds) {\r\n\t\tif (!bounds) { return offset; }\r\n\r\n\t\tvar viewBounds = this.getPixelBounds(),\r\n\t\t    newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));\r\n\r\n\t\treturn offset.add(this._getBoundsOffset(newBounds, bounds));\r\n\t},\r\n\r\n\t// returns offset needed for pxBounds to get inside maxBounds at a specified zoom\r\n\t_getBoundsOffset: function (pxBounds, maxBounds, zoom) {\r\n\t\tvar projectedMaxBounds = L.bounds(\r\n\t\t        this.project(maxBounds.getNorthEast(), zoom),\r\n\t\t        this.project(maxBounds.getSouthWest(), zoom)\r\n\t\t    ),\r\n\t\t    minOffset = projectedMaxBounds.min.subtract(pxBounds.min),\r\n\t\t    maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),\r\n\r\n\t\t    dx = this._rebound(minOffset.x, -maxOffset.x),\r\n\t\t    dy = this._rebound(minOffset.y, -maxOffset.y);\r\n\r\n\t\treturn new L.Point(dx, dy);\r\n\t},\r\n\r\n\t_rebound: function (left, right) {\r\n\t\treturn left + right > 0 ?\r\n\t\t\tMath.round(left - right) / 2 :\r\n\t\t\tMath.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));\r\n\t},\r\n\r\n\t_limitZoom: function (zoom) {\r\n\t\tvar min = this.getMinZoom(),\r\n\t\t    max = this.getMaxZoom(),\r\n\t\t    snap = L.Browser.any3d ? this.options.zoomSnap : 1;\r\n\t\tif (snap) {\r\n\t\t\tzoom = Math.round(zoom / snap) * snap;\r\n\t\t}\r\n\t\treturn Math.max(min, Math.min(max, zoom));\r\n\t},\r\n\r\n\t_onPanTransitionStep: function () {\r\n\t\tthis.fire('move');\r\n\t},\r\n\r\n\t_onPanTransitionEnd: function () {\r\n\t\tL.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');\r\n\t\tthis.fire('moveend');\r\n\t},\r\n\r\n\t_tryAnimatedPan: function (center, options) {\r\n\t\t// difference between the new and current centers in pixels\r\n\t\tvar offset = this._getCenterOffset(center)._floor();\r\n\r\n\t\t// don't animate too far unless animate: true specified in options\r\n\t\tif ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tthis.panBy(offset, options);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_createAnimProxy: function () {\r\n\r\n\t\tvar proxy = this._proxy = L.DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');\r\n\t\tthis._panes.mapPane.appendChild(proxy);\r\n\r\n\t\tthis.on('zoomanim', function (e) {\r\n\t\t\tvar prop = L.DomUtil.TRANSFORM,\r\n\t\t\t    transform = proxy.style[prop];\r\n\r\n\t\t\tL.DomUtil.setTransform(proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));\r\n\r\n\t\t\t// workaround for case when transform is the same and so transitionend event is not fired\r\n\t\t\tif (transform === proxy.style[prop] && this._animatingZoom) {\r\n\t\t\t\tthis._onZoomTransitionEnd();\r\n\t\t\t}\r\n\t\t}, this);\r\n\r\n\t\tthis.on('load moveend', function () {\r\n\t\t\tvar c = this.getCenter(),\r\n\t\t\t    z = this.getZoom();\r\n\t\t\tL.DomUtil.setTransform(proxy, this.project(c, z), this.getZoomScale(z, 1));\r\n\t\t}, this);\r\n\t},\r\n\r\n\t_catchTransitionEnd: function (e) {\r\n\t\tif (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {\r\n\t\t\tthis._onZoomTransitionEnd();\r\n\t\t}\r\n\t},\r\n\r\n\t_nothingToAnimate: function () {\r\n\t\treturn !this._container.getElementsByClassName('leaflet-zoom-animated').length;\r\n\t},\r\n\r\n\t_tryAnimatedZoom: function (center, zoom, options) {\r\n\r\n\t\tif (this._animatingZoom) { return true; }\r\n\r\n\t\toptions = options || {};\r\n\r\n\t\t// don't animate if disabled, not supported or zoom difference is too large\r\n\t\tif (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||\r\n\t\t        Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }\r\n\r\n\t\t// offset is the pixel coords of the zoom origin relative to the current center\r\n\t\tvar scale = this.getZoomScale(zoom),\r\n\t\t    offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);\r\n\r\n\t\t// don't animate if the zoom origin isn't within one screen from the current center, unless forced\r\n\t\tif (options.animate !== true && !this.getSize().contains(offset)) { return false; }\r\n\r\n\t\tL.Util.requestAnimFrame(function () {\r\n\t\t\tthis\r\n\t\t\t    ._moveStart(true)\r\n\t\t\t    ._animateZoom(center, zoom, true);\r\n\t\t}, this);\r\n\r\n\t\treturn true;\r\n\t},\r\n\r\n\t_animateZoom: function (center, zoom, startAnim, noUpdate) {\r\n\t\tif (startAnim) {\r\n\t\t\tthis._animatingZoom = true;\r\n\r\n\t\t\t// remember what center/zoom to set after animation\r\n\t\t\tthis._animateToCenter = center;\r\n\t\t\tthis._animateToZoom = zoom;\r\n\r\n\t\t\tL.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');\r\n\t\t}\r\n\r\n\t\t// @event zoomanim: ZoomAnimEvent\r\n\t\t// Fired on every frame of a zoom animation\r\n\t\tthis.fire('zoomanim', {\r\n\t\t\tcenter: center,\r\n\t\t\tzoom: zoom,\r\n\t\t\tnoUpdate: noUpdate\r\n\t\t});\r\n\r\n\t\t// Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693\r\n\t\tsetTimeout(L.bind(this._onZoomTransitionEnd, this), 250);\r\n\t},\r\n\r\n\t_onZoomTransitionEnd: function () {\r\n\t\tif (!this._animatingZoom) { return; }\r\n\r\n\t\tL.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');\r\n\r\n\t\tthis._animatingZoom = false;\r\n\r\n\t\tthis._move(this._animateToCenter, this._animateToZoom);\r\n\r\n\t\t// This anim frame should prevent an obscure iOS webkit tile loading race condition.\r\n\t\tL.Util.requestAnimFrame(function () {\r\n\t\t\tthis._moveEnd(true);\r\n\t\t}, this);\r\n\t}\r\n});\r\n\r\n// @section\r\n\r\n// @factory L.map(id: String, options?: Map options)\r\n// Instantiates a map object given the DOM ID of a `<div>` element\r\n// and optionally an object literal with `Map options`.\r\n//\r\n// @alternative\r\n// @factory L.map(el: HTMLElement, options?: Map options)\r\n// Instantiates a map object given an instance of a `<div>` HTML element\r\n// and optionally an object literal with `Map options`.\r\nL.map = function (id, options) {\r\n\treturn new L.Map(id, options);\r\n};\r\n","\n/*\n * @class Layer\n * @inherits Evented\n * @aka L.Layer\n * @aka ILayer\n *\n * A set of methods from the Layer base class that all Leaflet layers use.\n * Inherits all methods, options and events from `L.Evented`.\n *\n * @example\n *\n * ```js\n * var layer = L.Marker(latlng).addTo(map);\n * layer.addTo(map);\n * layer.remove();\n * ```\n *\n * @event add: Event\n * Fired after the layer is added to a map\n *\n * @event remove: Event\n * Fired after the layer is removed from a map\n */\n\n\nL.Layer = L.Evented.extend({\n\n\t// Classes extending `L.Layer` will inherit the following options:\n\toptions: {\n\t\t// @option pane: String = 'overlayPane'\n\t\t// 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.\n\t\tpane: 'overlayPane',\n\t\tnonBubblingEvents: [],  // Array of events that should not be bubbled to DOM parents (like the map),\n\n\t\t// @option attribution: String = null\n\t\t// String to be shown in the attribution control, describes the layer data, e.g. \"© Mapbox\".\n\t\tattribution: null\n\t},\n\n\t/* @section\n\t * Classes extending `L.Layer` will inherit the following methods:\n\t *\n\t * @method addTo(map: Map): this\n\t * Adds the layer to the given map\n\t */\n\taddTo: function (map) {\n\t\tmap.addLayer(this);\n\t\treturn this;\n\t},\n\n\t// @method remove: this\n\t// Removes the layer from the map it is currently active on.\n\tremove: function () {\n\t\treturn this.removeFrom(this._map || this._mapToAdd);\n\t},\n\n\t// @method removeFrom(map: Map): this\n\t// Removes the layer from the given map\n\tremoveFrom: function (obj) {\n\t\tif (obj) {\n\t\t\tobj.removeLayer(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getPane(name? : String): HTMLElement\n\t// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.\n\tgetPane: function (name) {\n\t\treturn this._map.getPane(name ? (this.options[name] || name) : this.options.pane);\n\t},\n\n\taddInteractiveTarget: function (targetEl) {\n\t\tthis._map._targets[L.stamp(targetEl)] = this;\n\t\treturn this;\n\t},\n\n\tremoveInteractiveTarget: function (targetEl) {\n\t\tdelete this._map._targets[L.stamp(targetEl)];\n\t\treturn this;\n\t},\n\n\t// @method getAttribution: String\n\t// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).\n\tgetAttribution: function () {\n\t\treturn this.options.attribution;\n\t},\n\n\t_layerAdd: function (e) {\n\t\tvar map = e.target;\n\n\t\t// check in case layer gets added and then removed before the map is ready\n\t\tif (!map.hasLayer(this)) { return; }\n\n\t\tthis._map = map;\n\t\tthis._zoomAnimated = map._zoomAnimated;\n\n\t\tif (this.getEvents) {\n\t\t\tvar events = this.getEvents();\n\t\t\tmap.on(events, this);\n\t\t\tthis.once('remove', function () {\n\t\t\t\tmap.off(events, this);\n\t\t\t}, this);\n\t\t}\n\n\t\tthis.onAdd(map);\n\n\t\tif (this.getAttribution && map.attributionControl) {\n\t\t\tmap.attributionControl.addAttribution(this.getAttribution());\n\t\t}\n\n\t\tthis.fire('add');\n\t\tmap.fire('layeradd', {layer: this});\n\t}\n});\n\n/* @section Extension methods\n * @uninheritable\n *\n * Every layer should extend from `L.Layer` and (re-)implement the following methods.\n *\n * @method onAdd(map: Map): this\n * 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).\n *\n * @method onRemove(map: Map): this\n * 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).\n *\n * @method getEvents(): Object\n * 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.\n *\n * @method getAttribution(): String\n * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.\n *\n * @method beforeAdd(map: Map): this\n * 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.\n */\n\n\n/* @namespace Map\n * @section Layer events\n *\n * @event layeradd: LayerEvent\n * Fired when a new layer is added to the map.\n *\n * @event layerremove: LayerEvent\n * Fired when some layer is removed from the map\n *\n * @section Methods for Layers and Controls\n */\nL.Map.include({\n\t// @method addLayer(layer: Layer): this\n\t// Adds the given layer to the map\n\taddLayer: function (layer) {\n\t\tvar id = L.stamp(layer);\n\t\tif (this._layers[id]) { return this; }\n\t\tthis._layers[id] = layer;\n\n\t\tlayer._mapToAdd = this;\n\n\t\tif (layer.beforeAdd) {\n\t\t\tlayer.beforeAdd(this);\n\t\t}\n\n\t\tthis.whenReady(layer._layerAdd, layer);\n\n\t\treturn this;\n\t},\n\n\t// @method removeLayer(layer: Layer): this\n\t// Removes the given layer from the map.\n\tremoveLayer: function (layer) {\n\t\tvar id = L.stamp(layer);\n\n\t\tif (!this._layers[id]) { return this; }\n\n\t\tif (this._loaded) {\n\t\t\tlayer.onRemove(this);\n\t\t}\n\n\t\tif (layer.getAttribution && this.attributionControl) {\n\t\t\tthis.attributionControl.removeAttribution(layer.getAttribution());\n\t\t}\n\n\t\tdelete this._layers[id];\n\n\t\tif (this._loaded) {\n\t\t\tthis.fire('layerremove', {layer: layer});\n\t\t\tlayer.fire('remove');\n\t\t}\n\n\t\tlayer._map = layer._mapToAdd = null;\n\n\t\treturn this;\n\t},\n\n\t// @method hasLayer(layer: Layer): Boolean\n\t// Returns `true` if the given layer is currently added to the map\n\thasLayer: function (layer) {\n\t\treturn !!layer && (L.stamp(layer) in this._layers);\n\t},\n\n\t/* @method eachLayer(fn: Function, context?: Object): this\n\t * Iterates over the layers of the map, optionally specifying context of the iterator function.\n\t * ```\n\t * map.eachLayer(function(layer){\n\t *     layer.bindPopup('Hello');\n\t * });\n\t * ```\n\t */\n\teachLayer: function (method, context) {\n\t\tfor (var i in this._layers) {\n\t\t\tmethod.call(context, this._layers[i]);\n\t\t}\n\t\treturn this;\n\t},\n\n\t_addLayers: function (layers) {\n\t\tlayers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];\n\n\t\tfor (var i = 0, len = layers.length; i < len; i++) {\n\t\t\tthis.addLayer(layers[i]);\n\t\t}\n\t},\n\n\t_addZoomLimit: function (layer) {\n\t\tif (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {\n\t\t\tthis._zoomBoundLayers[L.stamp(layer)] = layer;\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_removeZoomLimit: function (layer) {\n\t\tvar id = L.stamp(layer);\n\n\t\tif (this._zoomBoundLayers[id]) {\n\t\t\tdelete this._zoomBoundLayers[id];\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_updateZoomLevels: function () {\n\t\tvar minZoom = Infinity,\n\t\t    maxZoom = -Infinity,\n\t\t    oldZoomSpan = this._getZoomSpan();\n\n\t\tfor (var i in this._zoomBoundLayers) {\n\t\t\tvar options = this._zoomBoundLayers[i].options;\n\n\t\t\tminZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);\n\t\t\tmaxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);\n\t\t}\n\n\t\tthis._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;\n\t\tthis._layersMinZoom = minZoom === Infinity ? undefined : minZoom;\n\n\t\t// @section Map state change events\n\t\t// @event zoomlevelschange: Event\n\t\t// Fired when the number of zoomlevels on the map is changed due\n\t\t// to adding or removing a layer.\n\t\tif (oldZoomSpan !== this._getZoomSpan()) {\n\t\t\tthis.fire('zoomlevelschange');\n\t\t}\n\n\t\tif (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {\n\t\t\tthis.setZoom(this._layersMaxZoom);\n\t\t}\n\t\tif (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {\n\t\t\tthis.setZoom(this._layersMinZoom);\n\t\t}\n\t}\n});\n","/*\r\n * @namespace DomEvent\r\n * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.\r\n */\r\n\r\n// Inspired by John Resig, Dean Edwards and YUI addEvent implementations.\r\n\r\n\r\n\r\nvar eventsKey = '_leaflet_events';\r\n\r\nL.DomEvent = {\r\n\r\n\t// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n\t// Adds a listener function (`fn`) to a particular DOM event type of the\r\n\t// element `el`. You can optionally specify the context of the listener\r\n\t// (object the `this` keyword will point to). You can also pass several\r\n\t// space-separated types (e.g. `'click dblclick'`).\r\n\r\n\t// @alternative\r\n\t// @function on(el: HTMLElement, eventMap: Object, context?: Object): this\r\n\t// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\ton: function (obj, types, fn, context) {\r\n\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis._on(obj, type, types[type], fn);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\ttypes = L.Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._on(obj, types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this\r\n\t// Removes a previously added listener function. If no function is specified,\r\n\t// it will remove all the listeners of that particular DOM event from the element.\r\n\t// Note that if you passed a custom context to on, you must pass the same\r\n\t// context to `off` in order to remove the listener.\r\n\r\n\t// @alternative\r\n\t// @function off(el: HTMLElement, eventMap: Object, context?: Object): this\r\n\t// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`\r\n\toff: function (obj, types, fn, context) {\r\n\r\n\t\tif (typeof types === 'object') {\r\n\t\t\tfor (var type in types) {\r\n\t\t\t\tthis._off(obj, type, types[type], fn);\r\n\t\t\t}\r\n\t\t} else {\r\n\t\t\ttypes = L.Util.splitWords(types);\r\n\r\n\t\t\tfor (var i = 0, len = types.length; i < len; i++) {\r\n\t\t\t\tthis._off(obj, types[i], fn, context);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_on: function (obj, type, fn, context) {\r\n\t\tvar id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : '');\r\n\r\n\t\tif (obj[eventsKey] && obj[eventsKey][id]) { return this; }\r\n\r\n\t\tvar handler = function (e) {\r\n\t\t\treturn fn.call(context || obj, e || window.event);\r\n\t\t};\r\n\r\n\t\tvar originalHandler = handler;\r\n\r\n\t\tif (L.Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\t\tthis.addPointerListener(obj, type, handler, id);\r\n\r\n\t\t} else if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener &&\r\n\t\t           !(L.Browser.pointer && L.Browser.chrome)) {\r\n\t\t\t// Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener\r\n\t\t\t// See #5180\r\n\t\t\tthis.addDoubleTapListener(obj, handler, id);\r\n\r\n\t\t} else if ('addEventListener' in obj) {\r\n\r\n\t\t\tif (type === 'mousewheel') {\r\n\t\t\t\tobj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);\r\n\r\n\t\t\t} else if ((type === 'mouseenter') || (type === 'mouseleave')) {\r\n\t\t\t\thandler = function (e) {\r\n\t\t\t\t\te = e || window.event;\r\n\t\t\t\t\tif (L.DomEvent._isExternalTarget(obj, e)) {\r\n\t\t\t\t\t\toriginalHandler(e);\r\n\t\t\t\t\t}\r\n\t\t\t\t};\r\n\t\t\t\tobj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false);\r\n\r\n\t\t\t} else {\r\n\t\t\t\tif (type === 'click' && L.Browser.android) {\r\n\t\t\t\t\thandler = function (e) {\r\n\t\t\t\t\t\treturn L.DomEvent._filterClick(e, originalHandler);\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\t\t\t\tobj.addEventListener(type, handler, false);\r\n\t\t\t}\r\n\r\n\t\t} else if ('attachEvent' in obj) {\r\n\t\t\tobj.attachEvent('on' + type, handler);\r\n\t\t}\r\n\r\n\t\tobj[eventsKey] = obj[eventsKey] || {};\r\n\t\tobj[eventsKey][id] = handler;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_off: function (obj, type, fn, context) {\r\n\r\n\t\tvar id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : ''),\r\n\t\t    handler = obj[eventsKey] && obj[eventsKey][id];\r\n\r\n\t\tif (!handler) { return this; }\r\n\r\n\t\tif (L.Browser.pointer && type.indexOf('touch') === 0) {\r\n\t\t\tthis.removePointerListener(obj, type, id);\r\n\r\n\t\t} else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {\r\n\t\t\tthis.removeDoubleTapListener(obj, id);\r\n\r\n\t\t} else if ('removeEventListener' in obj) {\r\n\r\n\t\t\tif (type === 'mousewheel') {\r\n\t\t\t\tobj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);\r\n\r\n\t\t\t} else {\r\n\t\t\t\tobj.removeEventListener(\r\n\t\t\t\t\ttype === 'mouseenter' ? 'mouseover' :\r\n\t\t\t\t\ttype === 'mouseleave' ? 'mouseout' : type, handler, false);\r\n\t\t\t}\r\n\r\n\t\t} else if ('detachEvent' in obj) {\r\n\t\t\tobj.detachEvent('on' + type, handler);\r\n\t\t}\r\n\r\n\t\tobj[eventsKey][id] = null;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @function stopPropagation(ev: DOMEvent): this\r\n\t// Stop the given event from propagation to parent elements. Used inside the listener functions:\r\n\t// ```js\r\n\t// L.DomEvent.on(div, 'click', function (ev) {\r\n\t// \tL.DomEvent.stopPropagation(ev);\r\n\t// });\r\n\t// ```\r\n\tstopPropagation: function (e) {\r\n\r\n\t\tif (e.stopPropagation) {\r\n\t\t\te.stopPropagation();\r\n\t\t} else if (e.originalEvent) {  // In case of Leaflet event.\r\n\t\t\te.originalEvent._stopped = true;\r\n\t\t} else {\r\n\t\t\te.cancelBubble = true;\r\n\t\t}\r\n\t\tL.DomEvent._skipped(e);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @function disableScrollPropagation(el: HTMLElement): this\r\n\t// Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants).\r\n\tdisableScrollPropagation: function (el) {\r\n\t\treturn L.DomEvent.on(el, 'mousewheel', L.DomEvent.stopPropagation);\r\n\t},\r\n\r\n\t// @function disableClickPropagation(el: HTMLElement): this\r\n\t// Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,\r\n\t// `'mousedown'` and `'touchstart'` events (plus browser variants).\r\n\tdisableClickPropagation: function (el) {\r\n\t\tvar stop = L.DomEvent.stopPropagation;\r\n\r\n\t\tL.DomEvent.on(el, L.Draggable.START.join(' '), stop);\r\n\r\n\t\treturn L.DomEvent.on(el, {\r\n\t\t\tclick: L.DomEvent._fakeStop,\r\n\t\t\tdblclick: stop\r\n\t\t});\r\n\t},\r\n\r\n\t// @function preventDefault(ev: DOMEvent): this\r\n\t// Prevents the default action of the DOM Event `ev` from happening (such as\r\n\t// following a link in the href of the a element, or doing a POST request\r\n\t// with page reload when a `<form>` is submitted).\r\n\t// Use it inside listener functions.\r\n\tpreventDefault: function (e) {\r\n\r\n\t\tif (e.preventDefault) {\r\n\t\t\te.preventDefault();\r\n\t\t} else {\r\n\t\t\te.returnValue = false;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @function stop(ev): this\r\n\t// Does `stopPropagation` and `preventDefault` at the same time.\r\n\tstop: function (e) {\r\n\t\treturn L.DomEvent\r\n\t\t\t.preventDefault(e)\r\n\t\t\t.stopPropagation(e);\r\n\t},\r\n\r\n\t// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point\r\n\t// Gets normalized mouse position from a DOM event relative to the\r\n\t// `container` or to the whole page if not specified.\r\n\tgetMousePosition: function (e, container) {\r\n\t\tif (!container) {\r\n\t\t\treturn new L.Point(e.clientX, e.clientY);\r\n\t\t}\r\n\r\n\t\tvar rect = container.getBoundingClientRect();\r\n\r\n\t\treturn new L.Point(\r\n\t\t\te.clientX - rect.left - container.clientLeft,\r\n\t\t\te.clientY - rect.top - container.clientTop);\r\n\t},\r\n\r\n\t// Chrome on Win scrolls double the pixels as in other platforms (see #4538),\r\n\t// and Firefox scrolls device pixels, not CSS pixels\r\n\t_wheelPxFactor: (L.Browser.win && L.Browser.chrome) ? 2 :\r\n\t                L.Browser.gecko ? window.devicePixelRatio :\r\n\t                1,\r\n\r\n\t// @function getWheelDelta(ev: DOMEvent): Number\r\n\t// Gets normalized wheel delta from a mousewheel DOM event, in vertical\r\n\t// pixels scrolled (negative if scrolling down).\r\n\t// Events from pointing devices without precise scrolling are mapped to\r\n\t// a best guess of 60 pixels.\r\n\tgetWheelDelta: function (e) {\r\n\t\treturn (L.Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta\r\n\t\t       (e.deltaY && e.deltaMode === 0) ? -e.deltaY / L.DomEvent._wheelPxFactor : // Pixels\r\n\t\t       (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines\r\n\t\t       (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages\r\n\t\t       (e.deltaX || e.deltaZ) ? 0 :\t// Skip horizontal/depth wheel events\r\n\t\t       e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels\r\n\t\t       (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines\r\n\t\t       e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages\r\n\t\t       0;\r\n\t},\r\n\r\n\t_skipEvents: {},\r\n\r\n\t_fakeStop: function (e) {\r\n\t\t// fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)\r\n\t\tL.DomEvent._skipEvents[e.type] = true;\r\n\t},\r\n\r\n\t_skipped: function (e) {\r\n\t\tvar skipped = this._skipEvents[e.type];\r\n\t\t// reset when checking, as it's only used in map container and propagates outside of the map\r\n\t\tthis._skipEvents[e.type] = false;\r\n\t\treturn skipped;\r\n\t},\r\n\r\n\t// check if element really left/entered the event target (for mouseenter/mouseleave)\r\n\t_isExternalTarget: function (el, e) {\r\n\r\n\t\tvar related = e.relatedTarget;\r\n\r\n\t\tif (!related) { return true; }\r\n\r\n\t\ttry {\r\n\t\t\twhile (related && (related !== el)) {\r\n\t\t\t\trelated = related.parentNode;\r\n\t\t\t}\r\n\t\t} catch (err) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\t\treturn (related !== el);\r\n\t},\r\n\r\n\t// this is a horrible workaround for a bug in Android where a single touch triggers two click events\r\n\t_filterClick: function (e, handler) {\r\n\t\tvar timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)),\r\n\t\t    elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);\r\n\r\n\t\t// are they closer together than 500ms yet more than 100ms?\r\n\t\t// Android typically triggers them ~300ms apart while multiple listeners\r\n\t\t// on the same event should be triggered far faster;\r\n\t\t// or check if click is simulated on the element, and if it is, reject any non-simulated events\r\n\r\n\t\tif ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {\r\n\t\t\tL.DomEvent.stop(e);\r\n\t\t\treturn;\r\n\t\t}\r\n\t\tL.DomEvent._lastClick = timeStamp;\r\n\r\n\t\thandler(e);\r\n\t}\r\n};\r\n\r\n// @function addListener(…): this\r\n// Alias to [`L.DomEvent.on`](#domevent-on)\r\nL.DomEvent.addListener = L.DomEvent.on;\r\n\r\n// @function removeListener(…): this\r\n// Alias to [`L.DomEvent.off`](#domevent-off)\r\nL.DomEvent.removeListener = L.DomEvent.off;\r\n","/*\n * @class PosAnimation\n * @aka L.PosAnimation\n * @inherits Evented\n * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.\n *\n * @example\n * ```js\n * var fx = new L.PosAnimation();\n * fx.run(el, [300, 500], 0.5);\n * ```\n *\n * @constructor L.PosAnimation()\n * Creates a `PosAnimation` object.\n *\n */\n\nL.PosAnimation = L.Evented.extend({\n\n\t// @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)\n\t// Run an animation of a given element to a new position, optionally setting\n\t// duration in seconds (`0.25` by default) and easing linearity factor (3rd\n\t// argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),\n\t// `0.5` by default).\n\trun: function (el, newPos, duration, easeLinearity) {\n\t\tthis.stop();\n\n\t\tthis._el = el;\n\t\tthis._inProgress = true;\n\t\tthis._duration = duration || 0.25;\n\t\tthis._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);\n\n\t\tthis._startPos = L.DomUtil.getPosition(el);\n\t\tthis._offset = newPos.subtract(this._startPos);\n\t\tthis._startTime = +new Date();\n\n\t\t// @event start: Event\n\t\t// Fired when the animation starts\n\t\tthis.fire('start');\n\n\t\tthis._animate();\n\t},\n\n\t// @method stop()\n\t// Stops the animation (if currently running).\n\tstop: function () {\n\t\tif (!this._inProgress) { return; }\n\n\t\tthis._step(true);\n\t\tthis._complete();\n\t},\n\n\t_animate: function () {\n\t\t// animation loop\n\t\tthis._animId = L.Util.requestAnimFrame(this._animate, this);\n\t\tthis._step();\n\t},\n\n\t_step: function (round) {\n\t\tvar elapsed = (+new Date()) - this._startTime,\n\t\t    duration = this._duration * 1000;\n\n\t\tif (elapsed < duration) {\n\t\t\tthis._runFrame(this._easeOut(elapsed / duration), round);\n\t\t} else {\n\t\t\tthis._runFrame(1);\n\t\t\tthis._complete();\n\t\t}\n\t},\n\n\t_runFrame: function (progress, round) {\n\t\tvar pos = this._startPos.add(this._offset.multiplyBy(progress));\n\t\tif (round) {\n\t\t\tpos._round();\n\t\t}\n\t\tL.DomUtil.setPosition(this._el, pos);\n\n\t\t// @event step: Event\n\t\t// Fired continuously during the animation.\n\t\tthis.fire('step');\n\t},\n\n\t_complete: function () {\n\t\tL.Util.cancelAnimFrame(this._animId);\n\n\t\tthis._inProgress = false;\n\t\t// @event end: Event\n\t\t// Fired when the animation ends.\n\t\tthis.fire('end');\n\t},\n\n\t_easeOut: function (t) {\n\t\treturn 1 - Math.pow(1 - t, this._easeOutPower);\n\t}\n});\n","/*\r\n * @namespace Projection\r\n * @projection L.Projection.Mercator\r\n *\r\n * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.\r\n */\r\n\r\nL.Projection.Mercator = {\r\n\tR: 6378137,\r\n\tR_MINOR: 6356752.314245179,\r\n\r\n\tbounds: L.bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t    r = this.R,\r\n\t\t    y = latlng.lat * d,\r\n\t\t    tmp = this.R_MINOR / r,\r\n\t\t    e = Math.sqrt(1 - tmp * tmp),\r\n\t\t    con = e * Math.sin(y);\r\n\r\n\t\tvar ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\ty = -r * Math.log(Math.max(ts, 1E-10));\r\n\r\n\t\treturn new L.Point(latlng.lng * d * r, y);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI,\r\n\t\t    r = this.R,\r\n\t\t    tmp = this.R_MINOR / r,\r\n\t\t    e = Math.sqrt(1 - tmp * tmp),\r\n\t\t    ts = Math.exp(-point.y / r),\r\n\t\t    phi = Math.PI / 2 - 2 * Math.atan(ts);\r\n\r\n\t\tfor (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {\r\n\t\t\tcon = e * Math.sin(phi);\r\n\t\t\tcon = Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\t\tdphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;\r\n\t\t\tphi += dphi;\r\n\t\t}\r\n\r\n\t\treturn new L.LatLng(phi * d, point.x * d / r);\r\n\t}\r\n};\r\n","/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3395\r\n *\r\n * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.\r\n */\r\n\r\nL.CRS.EPSG3395 = L.extend({}, L.CRS.Earth, {\r\n\tcode: 'EPSG:3395',\r\n\tprojection: L.Projection.Mercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * L.Projection.Mercator.R);\r\n\t\treturn new L.Transformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\r\n","/*\n * @class GridLayer\n * @inherits Layer\n * @aka L.GridLayer\n *\n * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.\n * 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.\n *\n *\n * @section Synchronous usage\n * @example\n *\n * 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.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n *     createTile: function(coords){\n *         // create a <canvas> element for drawing\n *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n *         // setup tile width and height according to the options\n *         var size = this.getTileSize();\n *         tile.width = size.x;\n *         tile.height = size.y;\n *\n *         // get a canvas context and draw something on it using coords.x, coords.y and coords.z\n *         var ctx = tile.getContext('2d');\n *\n *         // return the tile so it can be rendered on screen\n *         return tile;\n *     }\n * });\n * ```\n *\n * @section Asynchronous usage\n * @example\n *\n * 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.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n *     createTile: function(coords, done){\n *         var error;\n *\n *         // create a <canvas> element for drawing\n *         var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n *         // setup tile width and height according to the options\n *         var size = this.getTileSize();\n *         tile.width = size.x;\n *         tile.height = size.y;\n *\n *         // draw something asynchronously and pass the tile to the done() callback\n *         setTimeout(function() {\n *             done(error, tile);\n *         }, 1000);\n *\n *         return tile;\n *     }\n * });\n * ```\n *\n * @section\n */\n\n\nL.GridLayer = L.Layer.extend({\n\n\t// @section\n\t// @aka GridLayer options\n\toptions: {\n\t\t// @option tileSize: Number|Point = 256\n\t\t// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.\n\t\ttileSize: 256,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Opacity of the tiles. Can be used in the `createTile()` function.\n\t\topacity: 1,\n\n\t\t// @option updateWhenIdle: Boolean = depends\n\t\t// If `false`, new tiles are loaded during panning, otherwise only after it (for better performance). `true` by default on mobile browsers, otherwise `false`.\n\t\tupdateWhenIdle: L.Browser.mobile,\n\n\t\t// @option updateWhenZooming: Boolean = true\n\t\t// 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.\n\t\tupdateWhenZooming: true,\n\n\t\t// @option updateInterval: Number = 200\n\t\t// Tiles will not update more than once every `updateInterval` milliseconds when panning.\n\t\tupdateInterval: 200,\n\n\t\t// @option zIndex: Number = 1\n\t\t// The explicit zIndex of the tile layer.\n\t\tzIndex: 1,\n\n\t\t// @option bounds: LatLngBounds = undefined\n\t\t// If set, tiles will only be loaded inside the set `LatLngBounds`.\n\t\tbounds: null,\n\n\t\t// @option minZoom: Number = 0\n\t\t// The minimum zoom level that tiles will be loaded at. By default the entire map.\n\t\tminZoom: 0,\n\n\t\t// @option maxZoom: Number = undefined\n\t\t// The maximum zoom level that tiles will be loaded at.\n\t\tmaxZoom: undefined,\n\n\t\t// @option noWrap: Boolean = false\n\t\t// Whether the layer is wrapped around the antimeridian. If `true`, the\n\t\t// GridLayer will only be displayed once at low zoom levels. Has no\n\t\t// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used\n\t\t// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting\n\t\t// tiles outside the CRS limits.\n\t\tnoWrap: false,\n\n\t\t// @option pane: String = 'tilePane'\n\t\t// `Map pane` where the grid layer will be added.\n\t\tpane: 'tilePane',\n\n\t\t// @option className: String = ''\n\t\t// A custom class name to assign to the tile layer. Empty by default.\n\t\tclassName: '',\n\n\t\t// @option keepBuffer: Number = 2\n\t\t// When panning the map, keep this many rows and columns of tiles before unloading them.\n\t\tkeepBuffer: 2\n\t},\n\n\tinitialize: function (options) {\n\t\tL.setOptions(this, options);\n\t},\n\n\tonAdd: function () {\n\t\tthis._initContainer();\n\n\t\tthis._levels = {};\n\t\tthis._tiles = {};\n\n\t\tthis._resetView();\n\t\tthis._update();\n\t},\n\n\tbeforeAdd: function (map) {\n\t\tmap._addZoomLimit(this);\n\t},\n\n\tonRemove: function (map) {\n\t\tthis._removeAllTiles();\n\t\tL.DomUtil.remove(this._container);\n\t\tmap._removeZoomLimit(this);\n\t\tthis._container = null;\n\t\tthis._tileZoom = null;\n\t},\n\n\t// @method bringToFront: this\n\t// Brings the tile layer to the top of all tile layers.\n\tbringToFront: function () {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.toFront(this._container);\n\t\t\tthis._setAutoZIndex(Math.max);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack: this\n\t// Brings the tile layer to the bottom of all tile layers.\n\tbringToBack: function () {\n\t\tif (this._map) {\n\t\t\tL.DomUtil.toBack(this._container);\n\t\t\tthis._setAutoZIndex(Math.min);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getContainer: HTMLElement\n\t// Returns the HTML element that contains the tiles for this layer.\n\tgetContainer: function () {\n\t\treturn this._container;\n\t},\n\n\t// @method setOpacity(opacity: Number): this\n\t// Changes the [opacity](#gridlayer-opacity) of the grid layer.\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\t\tthis._updateOpacity();\n\t\treturn this;\n\t},\n\n\t// @method setZIndex(zIndex: Number): this\n\t// Changes the [zIndex](#gridlayer-zindex) of the grid layer.\n\tsetZIndex: function (zIndex) {\n\t\tthis.options.zIndex = zIndex;\n\t\tthis._updateZIndex();\n\n\t\treturn this;\n\t},\n\n\t// @method isLoading: Boolean\n\t// Returns `true` if any tile in the grid layer has not finished loading.\n\tisLoading: function () {\n\t\treturn this._loading;\n\t},\n\n\t// @method redraw: this\n\t// Causes the layer to clear all the tiles and request them again.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._removeAllTiles();\n\t\t\tthis._update();\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewprereset: this._invalidateAll,\n\t\t\tviewreset: this._resetView,\n\t\t\tzoom: this._resetView,\n\t\t\tmoveend: this._onMoveEnd\n\t\t};\n\n\t\tif (!this.options.updateWhenIdle) {\n\t\t\t// update tiles on move, but not more often than once per given interval\n\t\t\tif (!this._onMove) {\n\t\t\t\tthis._onMove = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);\n\t\t\t}\n\n\t\t\tevents.move = this._onMove;\n\t\t}\n\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._animateZoom;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t// @section Extension methods\n\t// Layers extending `GridLayer` shall reimplement the following method.\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\n\t// Called only internally, must be overriden by classes extending `GridLayer`.\n\t// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback\n\t// is specified, it must be called when the tile has finished loading and drawing.\n\tcreateTile: function () {\n\t\treturn document.createElement('div');\n\t},\n\n\t// @section\n\t// @method getTileSize: Point\n\t// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.\n\tgetTileSize: function () {\n\t\tvar s = this.options.tileSize;\n\t\treturn s instanceof L.Point ? s : new L.Point(s, s);\n\t},\n\n\t_updateZIndex: function () {\n\t\tif (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {\n\t\t\tthis._container.style.zIndex = this.options.zIndex;\n\t\t}\n\t},\n\n\t_setAutoZIndex: function (compare) {\n\t\t// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)\n\n\t\tvar layers = this.getPane().children,\n\t\t    edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min\n\n\t\tfor (var i = 0, len = layers.length, zIndex; i < len; i++) {\n\n\t\t\tzIndex = layers[i].style.zIndex;\n\n\t\t\tif (layers[i] !== this._container && zIndex) {\n\t\t\t\tedgeZIndex = compare(edgeZIndex, +zIndex);\n\t\t\t}\n\t\t}\n\n\t\tif (isFinite(edgeZIndex)) {\n\t\t\tthis.options.zIndex = edgeZIndex + compare(-1, 1);\n\t\t\tthis._updateZIndex();\n\t\t}\n\t},\n\n\t_updateOpacity: function () {\n\t\tif (!this._map) { return; }\n\n\t\t// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles\n\t\tif (L.Browser.ielt9) { return; }\n\n\t\tL.DomUtil.setOpacity(this._container, this.options.opacity);\n\n\t\tvar now = +new Date(),\n\t\t    nextFrame = false,\n\t\t    willPrune = false;\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar tile = this._tiles[key];\n\t\t\tif (!tile.current || !tile.loaded) { continue; }\n\n\t\t\tvar fade = Math.min(1, (now - tile.loaded) / 200);\n\n\t\t\tL.DomUtil.setOpacity(tile.el, fade);\n\t\t\tif (fade < 1) {\n\t\t\t\tnextFrame = true;\n\t\t\t} else {\n\t\t\t\tif (tile.active) { willPrune = true; }\n\t\t\t\ttile.active = true;\n\t\t\t}\n\t\t}\n\n\t\tif (willPrune && !this._noPrune) { this._pruneTiles(); }\n\n\t\tif (nextFrame) {\n\t\t\tL.Util.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);\n\t\t}\n\t},\n\n\t_initContainer: function () {\n\t\tif (this._container) { return; }\n\n\t\tthis._container = L.DomUtil.create('div', 'leaflet-layer ' + (this.options.className || ''));\n\t\tthis._updateZIndex();\n\n\t\tif (this.options.opacity < 1) {\n\t\t\tthis._updateOpacity();\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t},\n\n\t_updateLevels: function () {\n\n\t\tvar zoom = this._tileZoom,\n\t\t    maxZoom = this.options.maxZoom;\n\n\t\tif (zoom === undefined) { return undefined; }\n\n\t\tfor (var z in this._levels) {\n\t\t\tif (this._levels[z].el.children.length || z === zoom) {\n\t\t\t\tthis._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);\n\t\t\t} else {\n\t\t\t\tL.DomUtil.remove(this._levels[z].el);\n\t\t\t\tthis._removeTilesAtZoom(z);\n\t\t\t\tdelete this._levels[z];\n\t\t\t}\n\t\t}\n\n\t\tvar level = this._levels[zoom],\n\t\t    map = this._map;\n\n\t\tif (!level) {\n\t\t\tlevel = this._levels[zoom] = {};\n\n\t\t\tlevel.el = L.DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);\n\t\t\tlevel.el.style.zIndex = maxZoom;\n\n\t\t\tlevel.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();\n\t\t\tlevel.zoom = zoom;\n\n\t\t\tthis._setZoomTransform(level, map.getCenter(), map.getZoom());\n\n\t\t\t// force the browser to consider the newly added element for transition\n\t\t\tL.Util.falseFn(level.el.offsetWidth);\n\t\t}\n\n\t\tthis._level = level;\n\n\t\treturn level;\n\t},\n\n\t_pruneTiles: function () {\n\t\tif (!this._map) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar key, tile;\n\n\t\tvar zoom = this._map.getZoom();\n\t\tif (zoom > this.options.maxZoom ||\n\t\t\tzoom < this.options.minZoom) {\n\t\t\tthis._removeAllTiles();\n\t\t\treturn;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\ttile.retain = tile.current;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\tif (tile.current && !tile.active) {\n\t\t\t\tvar coords = tile.coords;\n\t\t\t\tif (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {\n\t\t\t\t\tthis._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\tif (!this._tiles[key].retain) {\n\t\t\t\tthis._removeTile(key);\n\t\t\t}\n\t\t}\n\t},\n\n\t_removeTilesAtZoom: function (zoom) {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (this._tiles[key].coords.z !== zoom) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_removeAllTiles: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_invalidateAll: function () {\n\t\tfor (var z in this._levels) {\n\t\t\tL.DomUtil.remove(this._levels[z].el);\n\t\t\tdelete this._levels[z];\n\t\t}\n\t\tthis._removeAllTiles();\n\n\t\tthis._tileZoom = null;\n\t},\n\n\t_retainParent: function (x, y, z, minZoom) {\n\t\tvar x2 = Math.floor(x / 2),\n\t\t    y2 = Math.floor(y / 2),\n\t\t    z2 = z - 1,\n\t\t    coords2 = new L.Point(+x2, +y2);\n\t\tcoords2.z = +z2;\n\n\t\tvar key = this._tileCoordsToKey(coords2),\n\t\t    tile = this._tiles[key];\n\n\t\tif (tile && tile.active) {\n\t\t\ttile.retain = true;\n\t\t\treturn true;\n\n\t\t} else if (tile && tile.loaded) {\n\t\t\ttile.retain = true;\n\t\t}\n\n\t\tif (z2 > minZoom) {\n\t\t\treturn this._retainParent(x2, y2, z2, minZoom);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_retainChildren: function (x, y, z, maxZoom) {\n\n\t\tfor (var i = 2 * x; i < 2 * x + 2; i++) {\n\t\t\tfor (var j = 2 * y; j < 2 * y + 2; j++) {\n\n\t\t\t\tvar coords = new L.Point(i, j);\n\t\t\t\tcoords.z = z + 1;\n\n\t\t\t\tvar key = this._tileCoordsToKey(coords),\n\t\t\t\t    tile = this._tiles[key];\n\n\t\t\t\tif (tile && tile.active) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t\tcontinue;\n\n\t\t\t\t} else if (tile && tile.loaded) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t}\n\n\t\t\t\tif (z + 1 < maxZoom) {\n\t\t\t\t\tthis._retainChildren(i, j, z + 1, maxZoom);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetView: function (e) {\n\t\tvar animating = e && (e.pinch || e.flyTo);\n\t\tthis._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);\n\t},\n\n\t_animateZoom: function (e) {\n\t\tthis._setView(e.center, e.zoom, true, e.noUpdate);\n\t},\n\n\t_setView: function (center, zoom, noPrune, noUpdate) {\n\t\tvar tileZoom = Math.round(zoom);\n\t\tif ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||\n\t\t    (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {\n\t\t\ttileZoom = undefined;\n\t\t}\n\n\t\tvar tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);\n\n\t\tif (!noUpdate || tileZoomChanged) {\n\n\t\t\tthis._tileZoom = tileZoom;\n\n\t\t\tif (this._abortLoading) {\n\t\t\t\tthis._abortLoading();\n\t\t\t}\n\n\t\t\tthis._updateLevels();\n\t\t\tthis._resetGrid();\n\n\t\t\tif (tileZoom !== undefined) {\n\t\t\t\tthis._update(center);\n\t\t\t}\n\n\t\t\tif (!noPrune) {\n\t\t\t\tthis._pruneTiles();\n\t\t\t}\n\n\t\t\t// Flag to prevent _updateOpacity from pruning tiles during\n\t\t\t// a zoom anim or a pinch gesture\n\t\t\tthis._noPrune = !!noPrune;\n\t\t}\n\n\t\tthis._setZoomTransforms(center, zoom);\n\t},\n\n\t_setZoomTransforms: function (center, zoom) {\n\t\tfor (var i in this._levels) {\n\t\t\tthis._setZoomTransform(this._levels[i], center, zoom);\n\t\t}\n\t},\n\n\t_setZoomTransform: function (level, center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, level.zoom),\n\t\t    translate = level.origin.multiplyBy(scale)\n\t\t        .subtract(this._map._getNewPixelOrigin(center, zoom)).round();\n\n\t\tif (L.Browser.any3d) {\n\t\t\tL.DomUtil.setTransform(level.el, translate, scale);\n\t\t} else {\n\t\t\tL.DomUtil.setPosition(level.el, translate);\n\t\t}\n\t},\n\n\t_resetGrid: function () {\n\t\tvar map = this._map,\n\t\t    crs = map.options.crs,\n\t\t    tileSize = this._tileSize = this.getTileSize(),\n\t\t    tileZoom = this._tileZoom;\n\n\t\tvar bounds = this._map.getPixelWorldBounds(this._tileZoom);\n\t\tif (bounds) {\n\t\t\tthis._globalTileRange = this._pxBoundsToTileRange(bounds);\n\t\t}\n\n\t\tthis._wrapX = crs.wrapLng && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),\n\t\t\tMath.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)\n\t\t];\n\t\tthis._wrapY = crs.wrapLat && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),\n\t\t\tMath.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)\n\t\t];\n\t},\n\n\t_onMoveEnd: function () {\n\t\tif (!this._map || this._map._animatingZoom) { return; }\n\n\t\tthis._update();\n\t},\n\n\t_getTiledPixelBounds: function (center) {\n\t\tvar map = this._map,\n\t\t    mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),\n\t\t    scale = map.getZoomScale(mapZoom, this._tileZoom),\n\t\t    pixelCenter = map.project(center, this._tileZoom).floor(),\n\t\t    halfSize = map.getSize().divideBy(scale * 2);\n\n\t\treturn new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));\n\t},\n\n\t// Private method to load tiles in the grid's active zoom level according to map bounds\n\t_update: function (center) {\n\t\tvar map = this._map;\n\t\tif (!map) { return; }\n\t\tvar zoom = map.getZoom();\n\n\t\tif (center === undefined) { center = map.getCenter(); }\n\t\tif (this._tileZoom === undefined) { return; }\t// if out of minzoom/maxzoom\n\n\t\tvar pixelBounds = this._getTiledPixelBounds(center),\n\t\t    tileRange = this._pxBoundsToTileRange(pixelBounds),\n\t\t    tileCenter = tileRange.getCenter(),\n\t\t    queue = [],\n\t\t    margin = this.options.keepBuffer,\n\t\t    noPruneRange = new L.Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),\n\t\t                              tileRange.getTopRight().add([margin, -margin]));\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar c = this._tiles[key].coords;\n\t\t\tif (c.z !== this._tileZoom || !noPruneRange.contains(L.point(c.x, c.y))) {\n\t\t\t\tthis._tiles[key].current = false;\n\t\t\t}\n\t\t}\n\n\t\t// _update just loads more tiles. If the tile zoom level differs too much\n\t\t// from the map's, let _setView reset levels and prune old tiles.\n\t\tif (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }\n\n\t\t// create a queue of coordinates to load tiles from\n\t\tfor (var j = tileRange.min.y; j <= tileRange.max.y; j++) {\n\t\t\tfor (var i = tileRange.min.x; i <= tileRange.max.x; i++) {\n\t\t\t\tvar coords = new L.Point(i, j);\n\t\t\t\tcoords.z = this._tileZoom;\n\n\t\t\t\tif (!this._isValidTile(coords)) { continue; }\n\n\t\t\t\tvar tile = this._tiles[this._tileCoordsToKey(coords)];\n\t\t\t\tif (tile) {\n\t\t\t\t\ttile.current = true;\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push(coords);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sort tile queue to load tiles in order of their distance to center\n\t\tqueue.sort(function (a, b) {\n\t\t\treturn a.distanceTo(tileCenter) - b.distanceTo(tileCenter);\n\t\t});\n\n\t\tif (queue.length !== 0) {\n\t\t\t// if it's the first batch of tiles to load\n\t\t\tif (!this._loading) {\n\t\t\t\tthis._loading = true;\n\t\t\t\t// @event loading: Event\n\t\t\t\t// Fired when the grid layer starts loading tiles.\n\t\t\t\tthis.fire('loading');\n\t\t\t}\n\n\t\t\t// create DOM fragment to append tiles in one batch\n\t\t\tvar fragment = document.createDocumentFragment();\n\n\t\t\tfor (i = 0; i < queue.length; i++) {\n\t\t\t\tthis._addTile(queue[i], fragment);\n\t\t\t}\n\n\t\t\tthis._level.el.appendChild(fragment);\n\t\t}\n\t},\n\n\t_isValidTile: function (coords) {\n\t\tvar crs = this._map.options.crs;\n\n\t\tif (!crs.infinite) {\n\t\t\t// don't load tile if it's out of bounds and not wrapped\n\t\t\tvar bounds = this._globalTileRange;\n\t\t\tif ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||\n\t\t\t    (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }\n\t\t}\n\n\t\tif (!this.options.bounds) { return true; }\n\n\t\t// don't load tile if it doesn't intersect the bounds in options\n\t\tvar tileBounds = this._tileCoordsToBounds(coords);\n\t\treturn L.latLngBounds(this.options.bounds).overlaps(tileBounds);\n\t},\n\n\t_keyToBounds: function (key) {\n\t\treturn this._tileCoordsToBounds(this._keyToTileCoords(key));\n\t},\n\n\t// converts tile coordinates to its geographical bounds\n\t_tileCoordsToBounds: function (coords) {\n\n\t\tvar map = this._map,\n\t\t    tileSize = this.getTileSize(),\n\n\t\t    nwPoint = coords.scaleBy(tileSize),\n\t\t    sePoint = nwPoint.add(tileSize),\n\n\t\t    nw = map.unproject(nwPoint, coords.z),\n\t\t    se = map.unproject(sePoint, coords.z),\n\t\t    bounds = new L.LatLngBounds(nw, se);\n\n\t\tif (!this.options.noWrap) {\n\t\t\tmap.wrapLatLngBounds(bounds);\n\t\t}\n\n\t\treturn bounds;\n\t},\n\n\t// converts tile coordinates to key for the tile cache\n\t_tileCoordsToKey: function (coords) {\n\t\treturn coords.x + ':' + coords.y + ':' + coords.z;\n\t},\n\n\t// converts tile cache key to coordinates\n\t_keyToTileCoords: function (key) {\n\t\tvar k = key.split(':'),\n\t\t    coords = new L.Point(+k[0], +k[1]);\n\t\tcoords.z = +k[2];\n\t\treturn coords;\n\t},\n\n\t_removeTile: function (key) {\n\t\tvar tile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\tL.DomUtil.remove(tile.el);\n\n\t\tdelete this._tiles[key];\n\n\t\t// @event tileunload: TileEvent\n\t\t// Fired when a tile is removed (e.g. when a tile goes off the screen).\n\t\tthis.fire('tileunload', {\n\t\t\ttile: tile.el,\n\t\t\tcoords: this._keyToTileCoords(key)\n\t\t});\n\t},\n\n\t_initTile: function (tile) {\n\t\tL.DomUtil.addClass(tile, 'leaflet-tile');\n\n\t\tvar tileSize = this.getTileSize();\n\t\ttile.style.width = tileSize.x + 'px';\n\t\ttile.style.height = tileSize.y + 'px';\n\n\t\ttile.onselectstart = L.Util.falseFn;\n\t\ttile.onmousemove = L.Util.falseFn;\n\n\t\t// update opacity on tiles in IE7-8 because of filter inheritance problems\n\t\tif (L.Browser.ielt9 && this.options.opacity < 1) {\n\t\t\tL.DomUtil.setOpacity(tile, this.options.opacity);\n\t\t}\n\n\t\t// without this hack, tiles disappear after zoom on Chrome for Android\n\t\t// https://github.com/Leaflet/Leaflet/issues/2078\n\t\tif (L.Browser.android && !L.Browser.android23) {\n\t\t\ttile.style.WebkitBackfaceVisibility = 'hidden';\n\t\t}\n\t},\n\n\t_addTile: function (coords, container) {\n\t\tvar tilePos = this._getTilePos(coords),\n\t\t    key = this._tileCoordsToKey(coords);\n\n\t\tvar tile = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords));\n\n\t\tthis._initTile(tile);\n\n\t\t// if createTile is defined with a second argument (\"done\" callback),\n\t\t// we know that tile is async and will be ready later; otherwise\n\t\tif (this.createTile.length < 2) {\n\t\t\t// mark tile as ready, but delay one frame for opacity animation to happen\n\t\t\tL.Util.requestAnimFrame(L.bind(this._tileReady, this, coords, null, tile));\n\t\t}\n\n\t\tL.DomUtil.setPosition(tile, tilePos);\n\n\t\t// save tile in cache\n\t\tthis._tiles[key] = {\n\t\t\tel: tile,\n\t\t\tcoords: coords,\n\t\t\tcurrent: true\n\t\t};\n\n\t\tcontainer.appendChild(tile);\n\t\t// @event tileloadstart: TileEvent\n\t\t// Fired when a tile is requested and starts loading.\n\t\tthis.fire('tileloadstart', {\n\t\t\ttile: tile,\n\t\t\tcoords: coords\n\t\t});\n\t},\n\n\t_tileReady: function (coords, err, tile) {\n\t\tif (!this._map) { return; }\n\n\t\tif (err) {\n\t\t\t// @event tileerror: TileErrorEvent\n\t\t\t// Fired when there is an error loading a tile.\n\t\t\tthis.fire('tileerror', {\n\t\t\t\terror: err,\n\t\t\t\ttile: tile,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tvar key = this._tileCoordsToKey(coords);\n\n\t\ttile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\ttile.loaded = +new Date();\n\t\tif (this._map._fadeAnimated) {\n\t\t\tL.DomUtil.setOpacity(tile.el, 0);\n\t\t\tL.Util.cancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);\n\t\t} else {\n\t\t\ttile.active = true;\n\t\t\tthis._pruneTiles();\n\t\t}\n\n\t\tif (!err) {\n\t\t\tL.DomUtil.addClass(tile.el, 'leaflet-tile-loaded');\n\n\t\t\t// @event tileload: TileEvent\n\t\t\t// Fired when a tile loads.\n\t\t\tthis.fire('tileload', {\n\t\t\t\ttile: tile.el,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tif (this._noTilesToLoad()) {\n\t\t\tthis._loading = false;\n\t\t\t// @event load: Event\n\t\t\t// Fired when the grid layer loaded all visible tiles.\n\t\t\tthis.fire('load');\n\n\t\t\tif (L.Browser.ielt9 || !this._map._fadeAnimated) {\n\t\t\t\tL.Util.requestAnimFrame(this._pruneTiles, this);\n\t\t\t} else {\n\t\t\t\t// Wait a bit more than 0.2 secs (the duration of the tile fade-in)\n\t\t\t\t// to trigger a pruning.\n\t\t\t\tsetTimeout(L.bind(this._pruneTiles, this), 250);\n\t\t\t}\n\t\t}\n\t},\n\n\t_getTilePos: function (coords) {\n\t\treturn coords.scaleBy(this.getTileSize()).subtract(this._level.origin);\n\t},\n\n\t_wrapCoords: function (coords) {\n\t\tvar newCoords = new L.Point(\n\t\t\tthis._wrapX ? L.Util.wrapNum(coords.x, this._wrapX) : coords.x,\n\t\t\tthis._wrapY ? L.Util.wrapNum(coords.y, this._wrapY) : coords.y);\n\t\tnewCoords.z = coords.z;\n\t\treturn newCoords;\n\t},\n\n\t_pxBoundsToTileRange: function (bounds) {\n\t\tvar tileSize = this.getTileSize();\n\t\treturn new L.Bounds(\n\t\t\tbounds.min.unscaleBy(tileSize).floor(),\n\t\t\tbounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));\n\t},\n\n\t_noTilesToLoad: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (!this._tiles[key].loaded) { return false; }\n\t\t}\n\t\treturn true;\n\t}\n});\n\n// @factory L.gridLayer(options?: GridLayer options)\n// Creates a new instance of GridLayer with the supplied options.\nL.gridLayer = function (options) {\n\treturn new L.GridLayer(options);\n};\n","/*\r\n * @class TileLayer\r\n * @inherits GridLayer\r\n * @aka L.TileLayer\r\n * Used to load and display tile layers on the map. Extends `GridLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);\r\n * ```\r\n *\r\n * @section URL template\r\n * @example\r\n *\r\n * A string of the following form:\r\n *\r\n * ```\r\n * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\r\n * ```\r\n *\r\n * `{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 @2x to the URL to load retina tiles.\r\n *\r\n * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:\r\n *\r\n * ```\r\n * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\r\n * ```\r\n */\r\n\r\n\r\nL.TileLayer = L.GridLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer options\r\n\toptions: {\r\n\t\t// @option minZoom: Number = 0\r\n\t\t// Minimum zoom number.\r\n\t\tminZoom: 0,\r\n\r\n\t\t// @option maxZoom: Number = 18\r\n\t\t// Maximum zoom number.\r\n\t\tmaxZoom: 18,\r\n\r\n\t\t// @option maxNativeZoom: Number = null\r\n\t\t// Maximum zoom number the tile source has available. If it is specified,\r\n\t\t// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded\r\n\t\t// from `maxNativeZoom` level and auto-scaled.\r\n\t\tmaxNativeZoom: null,\r\n\r\n\t\t// @option minNativeZoom: Number = null\r\n\t\t// Minimum zoom number the tile source has available. If it is specified,\r\n\t\t// the tiles on all zoom levels lower than `minNativeZoom` will be loaded\r\n\t\t// from `minNativeZoom` level and auto-scaled.\r\n\t\tminNativeZoom: null,\r\n\r\n\t\t// @option subdomains: String|String[] = 'abc'\r\n\t\t// 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.\r\n\t\tsubdomains: 'abc',\r\n\r\n\t\t// @option errorTileUrl: String = ''\r\n\t\t// URL to the tile image to show in place of the tile that failed to load.\r\n\t\terrorTileUrl: '',\r\n\r\n\t\t// @option zoomOffset: Number = 0\r\n\t\t// The zoom number used in tile URLs will be offset with this value.\r\n\t\tzoomOffset: 0,\r\n\r\n\t\t// @option tms: Boolean = false\r\n\t\t// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).\r\n\t\ttms: false,\r\n\r\n\t\t// @option zoomReverse: Boolean = false\r\n\t\t// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)\r\n\t\tzoomReverse: false,\r\n\r\n\t\t// @option detectRetina: Boolean = false\r\n\t\t// 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.\r\n\t\tdetectRetina: false,\r\n\r\n\t\t// @option crossOrigin: Boolean = false\r\n\t\t// If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data.\r\n\t\tcrossOrigin: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\toptions = L.setOptions(this, options);\r\n\r\n\t\t// detecting retina displays, adjusting tileSize and zoom levels\r\n\t\tif (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {\r\n\r\n\t\t\toptions.tileSize = Math.floor(options.tileSize / 2);\r\n\r\n\t\t\tif (!options.zoomReverse) {\r\n\t\t\t\toptions.zoomOffset++;\r\n\t\t\t\toptions.maxZoom--;\r\n\t\t\t} else {\r\n\t\t\t\toptions.zoomOffset--;\r\n\t\t\t\toptions.minZoom++;\r\n\t\t\t}\r\n\r\n\t\t\toptions.minZoom = Math.max(0, options.minZoom);\r\n\t\t}\r\n\r\n\t\tif (typeof options.subdomains === 'string') {\r\n\t\t\toptions.subdomains = options.subdomains.split('');\r\n\t\t}\r\n\r\n\t\t// for https://github.com/Leaflet/Leaflet/issues/137\r\n\t\tif (!L.Browser.android) {\r\n\t\t\tthis.on('tileunload', this._onTileRemove);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setUrl(url: String, noRedraw?: Boolean): this\r\n\t// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).\r\n\tsetUrl: function (url, noRedraw) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\r\n\t// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)\r\n\t// to return an `<img>` HTML element with the appropiate image URL given `coords`. The `done`\r\n\t// callback is called when the tile has been loaded.\r\n\tcreateTile: function (coords, done) {\r\n\t\tvar tile = document.createElement('img');\r\n\r\n\t\tL.DomEvent.on(tile, 'load', L.bind(this._tileOnLoad, this, done, tile));\r\n\t\tL.DomEvent.on(tile, 'error', L.bind(this._tileOnError, this, done, tile));\r\n\r\n\t\tif (this.options.crossOrigin) {\r\n\t\t\ttile.crossOrigin = '';\r\n\t\t}\r\n\r\n\t\t/*\r\n\t\t Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons\r\n\t\t http://www.w3.org/TR/WCAG20-TECHS/H67\r\n\t\t*/\r\n\t\ttile.alt = '';\r\n\r\n\t\t/*\r\n\t\t Set role=\"presentation\" to force screen readers to ignore this\r\n\t\t https://www.w3.org/TR/wai-aria/roles#textalternativecomputation\r\n\t\t*/\r\n\t\ttile.setAttribute('role', 'presentation');\r\n\r\n\t\ttile.src = this.getTileUrl(coords);\r\n\r\n\t\treturn tile;\r\n\t},\r\n\r\n\t// @section Extension methods\r\n\t// @uninheritable\r\n\t// Layers extending `TileLayer` might reimplement the following method.\r\n\t// @method getTileUrl(coords: Object): String\r\n\t// Called only internally, returns the URL for a tile given its coordinates.\r\n\t// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.\r\n\tgetTileUrl: function (coords) {\r\n\t\tvar data = {\r\n\t\t\tr: L.Browser.retina ? '@2x' : '',\r\n\t\t\ts: this._getSubdomain(coords),\r\n\t\t\tx: coords.x,\r\n\t\t\ty: coords.y,\r\n\t\t\tz: this._getZoomForUrl()\r\n\t\t};\r\n\t\tif (this._map && !this._map.options.crs.infinite) {\r\n\t\t\tvar invertedY = this._globalTileRange.max.y - coords.y;\r\n\t\t\tif (this.options.tms) {\r\n\t\t\t\tdata['y'] = invertedY;\r\n\t\t\t}\r\n\t\t\tdata['-y'] = invertedY;\r\n\t\t}\r\n\r\n\t\treturn L.Util.template(this._url, L.extend(data, this.options));\r\n\t},\r\n\r\n\t_tileOnLoad: function (done, tile) {\r\n\t\t// For https://github.com/Leaflet/Leaflet/issues/3332\r\n\t\tif (L.Browser.ielt9) {\r\n\t\t\tsetTimeout(L.bind(done, this, null, tile), 0);\r\n\t\t} else {\r\n\t\t\tdone(null, tile);\r\n\t\t}\r\n\t},\r\n\r\n\t_tileOnError: function (done, tile, e) {\r\n\t\tvar errorUrl = this.options.errorTileUrl;\r\n\t\tif (errorUrl && tile.src !== errorUrl) {\r\n\t\t\ttile.src = errorUrl;\r\n\t\t}\r\n\t\tdone(e, tile);\r\n\t},\r\n\r\n\tgetTileSize: function () {\r\n\t\tvar map = this._map,\r\n\t\ttileSize = L.GridLayer.prototype.getTileSize.call(this),\r\n\t\tzoom = this._tileZoom + this.options.zoomOffset,\r\n\t\tminNativeZoom = this.options.minNativeZoom,\r\n\t\tmaxNativeZoom = this.options.maxNativeZoom;\r\n\r\n\t\t// decrease tile size when scaling below minNativeZoom\r\n\t\tif (minNativeZoom !== null && zoom < minNativeZoom) {\r\n\t\t\treturn tileSize.divideBy(map.getZoomScale(minNativeZoom, zoom)).round();\r\n\t\t}\r\n\r\n\t\t// increase tile size when scaling above maxNativeZoom\r\n\t\tif (maxNativeZoom !== null && zoom > maxNativeZoom) {\r\n\t\t\treturn tileSize.divideBy(map.getZoomScale(maxNativeZoom, zoom)).round();\r\n\t\t}\r\n\r\n\t\treturn tileSize;\r\n\t},\r\n\r\n\t_onTileRemove: function (e) {\r\n\t\te.tile.onload = null;\r\n\t},\r\n\r\n\t_getZoomForUrl: function () {\r\n\t\tvar zoom = this._tileZoom,\r\n\t\tmaxZoom = this.options.maxZoom,\r\n\t\tzoomReverse = this.options.zoomReverse,\r\n\t\tzoomOffset = this.options.zoomOffset,\r\n\t\tminNativeZoom = this.options.minNativeZoom,\r\n\t\tmaxNativeZoom = this.options.maxNativeZoom;\r\n\r\n\t\tif (zoomReverse) {\r\n\t\t\tzoom = maxZoom - zoom;\r\n\t\t}\r\n\r\n\t\tzoom += zoomOffset;\r\n\r\n\t\tif (minNativeZoom !== null && zoom < minNativeZoom) {\r\n\t\t\treturn minNativeZoom;\r\n\t\t}\r\n\r\n\t\tif (maxNativeZoom !== null && zoom > maxNativeZoom) {\r\n\t\t\treturn maxNativeZoom;\r\n\t\t}\r\n\r\n\t\treturn zoom;\r\n\t},\r\n\r\n\t_getSubdomain: function (tilePoint) {\r\n\t\tvar index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;\r\n\t\treturn this.options.subdomains[index];\r\n\t},\r\n\r\n\t// stops loading all tiles in the background layer\r\n\t_abortLoading: function () {\r\n\t\tvar i, tile;\r\n\t\tfor (i in this._tiles) {\r\n\t\t\tif (this._tiles[i].coords.z !== this._tileZoom) {\r\n\t\t\t\ttile = this._tiles[i].el;\r\n\r\n\t\t\t\ttile.onload = L.Util.falseFn;\r\n\t\t\t\ttile.onerror = L.Util.falseFn;\r\n\r\n\t\t\t\tif (!tile.complete) {\r\n\t\t\t\t\ttile.src = L.Util.emptyImageUrl;\r\n\t\t\t\t\tL.DomUtil.remove(tile);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)\r\n// Instantiates a tile layer object given a `URL template` and optionally an options object.\r\n\r\nL.tileLayer = function (url, options) {\r\n\treturn new L.TileLayer(url, options);\r\n};\r\n","/*\r\n * @class TileLayer.WMS\r\n * @inherits TileLayer\r\n * @aka L.TileLayer.WMS\r\n * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var nexrad = L.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\r\n * \tlayers: 'nexrad-n0r-900913',\r\n * \tformat: 'image/png',\r\n * \ttransparent: true,\r\n * \tattribution: \"Weather data © 2012 IEM Nexrad\"\r\n * });\r\n * ```\r\n */\r\n\r\nL.TileLayer.WMS = L.TileLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer.WMS options\r\n\t// If any custom options not documented here are used, they will be sent to the\r\n\t// WMS server as extra parameters in each request URL. This can be useful for\r\n\t// [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).\r\n\tdefaultWmsParams: {\r\n\t\tservice: 'WMS',\r\n\t\trequest: 'GetMap',\r\n\r\n\t\t// @option layers: String = ''\r\n\t\t// **(required)** Comma-separated list of WMS layers to show.\r\n\t\tlayers: '',\r\n\r\n\t\t// @option styles: String = ''\r\n\t\t// Comma-separated list of WMS styles.\r\n\t\tstyles: '',\r\n\r\n\t\t// @option format: String = 'image/jpeg'\r\n\t\t// WMS image format (use `'image/png'` for layers with transparency).\r\n\t\tformat: 'image/jpeg',\r\n\r\n\t\t// @option transparent: Boolean = false\r\n\t\t// If `true`, the WMS service will return images with transparency.\r\n\t\ttransparent: false,\r\n\r\n\t\t// @option version: String = '1.1.1'\r\n\t\t// Version of the WMS service to use\r\n\t\tversion: '1.1.1'\r\n\t},\r\n\r\n\toptions: {\r\n\t\t// @option crs: CRS = null\r\n\t\t// Coordinate Reference System to use for the WMS requests, defaults to\r\n\t\t// map CRS. Don't change this if you're not sure what it means.\r\n\t\tcrs: null,\r\n\r\n\t\t// @option uppercase: Boolean = false\r\n\t\t// If `true`, WMS request parameter keys will be uppercase.\r\n\t\tuppercase: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tvar wmsParams = L.extend({}, this.defaultWmsParams);\r\n\r\n\t\t// all keys that are not TileLayer options go to WMS params\r\n\t\tfor (var i in options) {\r\n\t\t\tif (!(i in this.options)) {\r\n\t\t\t\twmsParams[i] = options[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions = L.setOptions(this, options);\r\n\r\n\t\twmsParams.width = wmsParams.height = options.tileSize * (options.detectRetina && L.Browser.retina ? 2 : 1);\r\n\r\n\t\tthis.wmsParams = wmsParams;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\r\n\t\tthis._crs = this.options.crs || map.options.crs;\r\n\t\tthis._wmsVersion = parseFloat(this.wmsParams.version);\r\n\r\n\t\tvar projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';\r\n\t\tthis.wmsParams[projectionKey] = this._crs.code;\r\n\r\n\t\tL.TileLayer.prototype.onAdd.call(this, map);\r\n\t},\r\n\r\n\tgetTileUrl: function (coords) {\r\n\r\n\t\tvar tileBounds = this._tileCoordsToBounds(coords),\r\n\t\t    nw = this._crs.project(tileBounds.getNorthWest()),\r\n\t\t    se = this._crs.project(tileBounds.getSouthEast()),\r\n\r\n\t\t    bbox = (this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?\r\n\t\t\t    [se.y, nw.x, nw.y, se.x] :\r\n\t\t\t    [nw.x, se.y, se.x, nw.y]).join(','),\r\n\r\n\t\t    url = L.TileLayer.prototype.getTileUrl.call(this, coords);\r\n\r\n\t\treturn url +\r\n\t\t\tL.Util.getParamString(this.wmsParams, url, this.options.uppercase) +\r\n\t\t\t(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;\r\n\t},\r\n\r\n\t// @method setParams(params: Object, noRedraw?: Boolean): this\r\n\t// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).\r\n\tsetParams: function (params, noRedraw) {\r\n\r\n\t\tL.extend(this.wmsParams, params);\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)\r\n// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.\r\nL.tileLayer.wms = function (url, options) {\r\n\treturn new L.TileLayer.WMS(url, options);\r\n};\r\n","/*\r\n * @class ImageOverlay\r\n * @aka L.ImageOverlay\r\n * @inherits Interactive layer\r\n *\r\n * Used to load and display a single image over specific bounds of the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\r\n * \timageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\r\n * L.imageOverlay(imageUrl, imageBounds).addTo(map);\r\n * ```\r\n */\r\n\r\nL.ImageOverlay = L.Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka ImageOverlay options\r\n\toptions: {\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the image overlay.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option crossOrigin: Boolean = false\r\n\t\t// If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data.\r\n\t\tcrossOrigin: false\r\n\t},\r\n\r\n\tinitialize: function (url, bounds, options) { // (String, LatLngBounds, Object)\r\n\t\tthis._url = url;\r\n\t\tthis._bounds = L.latLngBounds(bounds);\r\n\r\n\t\tL.setOptions(this, options);\r\n\t},\r\n\r\n\tonAdd: function () {\r\n\t\tif (!this._image) {\r\n\t\t\tthis._initImage();\r\n\r\n\t\t\tif (this.options.opacity < 1) {\r\n\t\t\t\tthis._updateOpacity();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\tL.DomUtil.addClass(this._image, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._image);\r\n\t\t}\r\n\r\n\t\tthis.getPane().appendChild(this._image);\r\n\t\tthis._reset();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tL.DomUtil.remove(this._image);\r\n\t\tif (this.options.interactive) {\r\n\t\t\tthis.removeInteractiveTarget(this._image);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Sets the opacity of the overlay.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetStyle: function (styleOpts) {\r\n\t\tif (styleOpts.opacity) {\r\n\t\t\tthis.setOpacity(styleOpts.opacity);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer to the top of all overlays.\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tL.DomUtil.toFront(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer to the bottom of all overlays.\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tL.DomUtil.toBack(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setUrl(url: String): this\r\n\t// Changes the URL of the image.\r\n\tsetUrl: function (url) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._image.src = url;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setBounds(bounds: LatLngBounds): this\r\n\t// Update the bounds that this ImageOverlay covers\r\n\tsetBounds: function (bounds) {\r\n\t\tthis._bounds = bounds;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._reset();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._reset,\r\n\t\t\tviewreset: this._reset\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Get the bounds that this ImageOverlay covers\r\n\tgetBounds: function () {\r\n\t\treturn this._bounds;\r\n\t},\r\n\r\n\t// @method getElement(): HTMLElement\r\n\t// Get the img element that represents the ImageOverlay on the map\r\n\tgetElement: function () {\r\n\t\treturn this._image;\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar img = this._image = L.DomUtil.create('img',\r\n\t\t\t\t'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : ''));\r\n\r\n\t\timg.onselectstart = L.Util.falseFn;\r\n\t\timg.onmousemove = L.Util.falseFn;\r\n\r\n\t\timg.onload = L.bind(this.fire, this, 'load');\r\n\r\n\t\tif (this.options.crossOrigin) {\r\n\t\t\timg.crossOrigin = '';\r\n\t\t}\r\n\r\n\t\timg.src = this._url;\r\n\t\timg.alt = this.options.alt;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar scale = this._map.getZoomScale(e.zoom),\r\n\t\t    offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;\r\n\r\n\t\tL.DomUtil.setTransform(this._image, offset, scale);\r\n\t},\r\n\r\n\t_reset: function () {\r\n\t\tvar image = this._image,\r\n\t\t    bounds = new L.Bounds(\r\n\t\t        this._map.latLngToLayerPoint(this._bounds.getNorthWest()),\r\n\t\t        this._map.latLngToLayerPoint(this._bounds.getSouthEast())),\r\n\t\t    size = bounds.getSize();\r\n\r\n\t\tL.DomUtil.setPosition(image, bounds.min);\r\n\r\n\t\timage.style.width  = size.x + 'px';\r\n\t\timage.style.height = size.y + 'px';\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tL.DomUtil.setOpacity(this._image, this.options.opacity);\r\n\t}\r\n});\r\n\r\n// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)\r\n// Instantiates an image overlay object given the URL of the image and the\r\n// geographical bounds it is tied to.\r\nL.imageOverlay = function (url, bounds, options) {\r\n\treturn new L.ImageOverlay(url, bounds, options);\r\n};\r\n","/*\r\n * @class Icon\r\n * @aka L.Icon\r\n * @inherits Layer\r\n *\r\n * Represents an icon to provide when creating a marker.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var myIcon = L.icon({\r\n *     iconUrl: 'my-icon.png',\r\n *     iconRetinaUrl: 'my-icon@2x.png',\r\n *     iconSize: [38, 95],\r\n *     iconAnchor: [22, 94],\r\n *     popupAnchor: [-3, -76],\r\n *     shadowUrl: 'my-icon-shadow.png',\r\n *     shadowRetinaUrl: 'my-icon-shadow@2x.png',\r\n *     shadowSize: [68, 95],\r\n *     shadowAnchor: [22, 94]\r\n * });\r\n *\r\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\r\n * ```\r\n *\r\n * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.\r\n *\r\n */\r\n\r\nL.Icon = L.Class.extend({\r\n\r\n\t/* @section\r\n\t * @aka Icon options\r\n\t *\r\n\t * @option iconUrl: String = null\r\n\t * **(required)** The URL to the icon image (absolute or relative to your script path).\r\n\t *\r\n\t * @option iconRetinaUrl: String = null\r\n\t * The URL to a retina sized version of the icon image (absolute or relative to your\r\n\t * script path). Used for Retina screen devices.\r\n\t *\r\n\t * @option iconSize: Point = null\r\n\t * Size of the icon image in pixels.\r\n\t *\r\n\t * @option iconAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the icon (relative to its top left corner). The icon\r\n\t * will be aligned so that this point is at the marker's geographical location. Centered\r\n\t * by default if size is specified, also can be set in CSS with negative margins.\r\n\t *\r\n\t * @option popupAnchor: Point = null\r\n\t * The coordinates of the point from which popups will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option shadowUrl: String = null\r\n\t * The URL to the icon shadow image. If not specified, no shadow image will be created.\r\n\t *\r\n\t * @option shadowRetinaUrl: String = null\r\n\t *\r\n\t * @option shadowSize: Point = null\r\n\t * Size of the shadow image in pixels.\r\n\t *\r\n\t * @option shadowAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the shadow (relative to its top left corner) (the same\r\n\t * as iconAnchor if not specified).\r\n\t *\r\n\t * @option className: String = ''\r\n\t * A custom class name to assign to both icon and shadow images. Empty by default.\r\n\t */\r\n\r\n\tinitialize: function (options) {\r\n\t\tL.setOptions(this, options);\r\n\t},\r\n\r\n\t// @method createIcon(oldIcon?: HTMLElement): HTMLElement\r\n\t// Called internally when the icon has to be shown, returns a `<img>` HTML element\r\n\t// styled according to the options.\r\n\tcreateIcon: function (oldIcon) {\r\n\t\treturn this._createIcon('icon', oldIcon);\r\n\t},\r\n\r\n\t// @method createShadow(oldIcon?: HTMLElement): HTMLElement\r\n\t// As `createIcon`, but for the shadow beneath it.\r\n\tcreateShadow: function (oldIcon) {\r\n\t\treturn this._createIcon('shadow', oldIcon);\r\n\t},\r\n\r\n\t_createIcon: function (name, oldIcon) {\r\n\t\tvar src = this._getIconUrl(name);\r\n\r\n\t\tif (!src) {\r\n\t\t\tif (name === 'icon') {\r\n\t\t\t\tthrow new Error('iconUrl not set in Icon options (see the docs).');\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tvar img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);\r\n\t\tthis._setIconStyles(img, name);\r\n\r\n\t\treturn img;\r\n\t},\r\n\r\n\t_setIconStyles: function (img, name) {\r\n\t\tvar options = this.options;\r\n\t\tvar sizeOption = options[name + 'Size'];\r\n\r\n\t\tif (typeof sizeOption === 'number') {\r\n\t\t\tsizeOption = [sizeOption, sizeOption];\r\n\t\t}\r\n\r\n\t\tvar size = L.point(sizeOption),\r\n\t\t    anchor = L.point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||\r\n\t\t            size && size.divideBy(2, true));\r\n\r\n\t\timg.className = 'leaflet-marker-' + name + ' ' + (options.className || '');\r\n\r\n\t\tif (anchor) {\r\n\t\t\timg.style.marginLeft = (-anchor.x) + 'px';\r\n\t\t\timg.style.marginTop  = (-anchor.y) + 'px';\r\n\t\t}\r\n\r\n\t\tif (size) {\r\n\t\t\timg.style.width  = size.x + 'px';\r\n\t\t\timg.style.height = size.y + 'px';\r\n\t\t}\r\n\t},\r\n\r\n\t_createImg: function (src, el) {\r\n\t\tel = el || document.createElement('img');\r\n\t\tel.src = src;\r\n\t\treturn el;\r\n\t},\r\n\r\n\t_getIconUrl: function (name) {\r\n\t\treturn L.Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.icon(options: Icon options)\r\n// Creates an icon instance with the given options.\r\nL.icon = function (options) {\r\n\treturn new L.Icon(options);\r\n};\r\n","/*\n * @miniclass Icon.Default (Icon)\n * @aka L.Icon.Default\n * @section\n *\n * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when\n * no icon is specified. Points to the blue marker image distributed with Leaflet\n * releases.\n *\n * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`\n * (which is a set of `Icon options`).\n *\n * If you want to _completely_ replace the default icon, override the\n * `L.Marker.prototype.options.icon` with your own icon instead.\n */\n\nL.Icon.Default = L.Icon.extend({\n\n\toptions: {\n\t\ticonUrl:       'marker-icon.png',\n\t\ticonRetinaUrl: 'marker-icon-2x.png',\n\t\tshadowUrl:     'marker-shadow.png',\n\t\ticonSize:    [25, 41],\n\t\ticonAnchor:  [12, 41],\n\t\tpopupAnchor: [1, -34],\n\t\ttooltipAnchor: [16, -28],\n\t\tshadowSize:  [41, 41]\n\t},\n\n\t_getIconUrl: function (name) {\n\t\tif (!L.Icon.Default.imagePath) {\t// Deprecated, backwards-compatibility only\n\t\t\tL.Icon.Default.imagePath = this._detectIconPath();\n\t\t}\n\n\t\t// @option imagePath: String\n\t\t// `L.Icon.Default` will try to auto-detect the absolute location of the\n\t\t// blue icon images. If you are placing these images in a non-standard\n\t\t// way, set this option to point to the right absolute path.\n\t\treturn (this.options.imagePath || L.Icon.Default.imagePath) + L.Icon.prototype._getIconUrl.call(this, name);\n\t},\n\n\t_detectIconPath: function () {\n\t\tvar el = L.DomUtil.create('div',  'leaflet-default-icon-path', document.body);\n\t\tvar path = L.DomUtil.getStyle(el, 'background-image') ||\n\t\t           L.DomUtil.getStyle(el, 'backgroundImage');\t// IE8\n\n\t\tdocument.body.removeChild(el);\n\n\t\treturn path.indexOf('url') === 0 ?\n\t\t\tpath.replace(/^url\\([\\\"\\']?/, '').replace(/marker-icon\\.png[\\\"\\']?\\)$/, '') : '';\n\t}\n});\n","/*\r\n * @class Marker\r\n * @inherits Interactive layer\r\n * @aka L.Marker\r\n * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.marker([50.5, 30.5]).addTo(map);\r\n * ```\r\n */\r\n\r\nL.Marker = L.Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka Marker options\r\n\toptions: {\r\n\t\t// @option icon: Icon = *\r\n\t\t// Icon class to use for rendering the marker. See [Icon documentation](#L.Icon) for details on how to customize the marker icon. If not specified, a new `L.Icon.Default` is used.\r\n\t\ticon: new L.Icon.Default(),\r\n\r\n\t\t// Option inherited from \"Interactive layer\" abstract class\r\n\t\tinteractive: true,\r\n\r\n\t\t// @option draggable: Boolean = false\r\n\t\t// Whether the marker is draggable with mouse/touch or not.\r\n\t\tdraggable: false,\r\n\r\n\t\t// @option keyboard: Boolean = true\r\n\t\t// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.\r\n\t\tkeyboard: true,\r\n\r\n\t\t// @option title: String = ''\r\n\t\t// Text for the browser tooltip that appear on marker hover (no tooltip by default).\r\n\t\ttitle: '',\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the icon image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option zIndexOffset: Number = 0\r\n\t\t// 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).\r\n\t\tzIndexOffset: 0,\r\n\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the marker.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option riseOnHover: Boolean = false\r\n\t\t// If `true`, the marker will get on top of others when you hover the mouse over it.\r\n\t\triseOnHover: false,\r\n\r\n\t\t// @option riseOffset: Number = 250\r\n\t\t// The z-index offset used for the `riseOnHover` feature.\r\n\t\triseOffset: 250,\r\n\r\n\t\t// @option pane: String = 'markerPane'\r\n\t\t// `Map pane` where the markers icon will be added.\r\n\t\tpane: 'markerPane',\r\n\r\n\t\t// FIXME: shadowPane is no longer a valid option\r\n\t\tnonBubblingEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu']\r\n\t},\r\n\r\n\t/* @section\r\n\t *\r\n\t * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:\r\n\t */\r\n\r\n\tinitialize: function (latlng, options) {\r\n\t\tL.setOptions(this, options);\r\n\t\tthis._latlng = L.latLng(latlng);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.on('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._initIcon();\r\n\t\tthis.update();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (this.dragging && this.dragging.enabled()) {\r\n\t\t\tthis.options.draggable = true;\r\n\t\t\tthis.dragging.removeHooks();\r\n\t\t}\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.off('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._removeIcon();\r\n\t\tthis._removeShadow();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\treturn {\r\n\t\t\tzoom: this.update,\r\n\t\t\tviewreset: this.update\r\n\t\t};\r\n\t},\r\n\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the current geographical position of the marker.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Changes the marker position to the given point.\r\n\tsetLatLng: function (latlng) {\r\n\t\tvar oldLatLng = this._latlng;\r\n\t\tthis._latlng = L.latLng(latlng);\r\n\t\tthis.update();\r\n\r\n\t\t// @event move: Event\r\n\t\t// 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`.\r\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\r\n\t},\r\n\r\n\t// @method setZIndexOffset(offset: Number): this\r\n\t// Changes the [zIndex offset](#marker-zindexoffset) of the marker.\r\n\tsetZIndexOffset: function (offset) {\r\n\t\tthis.options.zIndexOffset = offset;\r\n\t\treturn this.update();\r\n\t},\r\n\r\n\t// @method setIcon(icon: Icon): this\r\n\t// Changes the marker icon.\r\n\tsetIcon: function (icon) {\r\n\r\n\t\tthis.options.icon = icon;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._initIcon();\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\tif (this._popup) {\r\n\t\t\tthis.bindPopup(this._popup, this._popup.options);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetElement: function () {\r\n\t\treturn this._icon;\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tif (this._icon) {\r\n\t\t\tvar pos = this._map.latLngToLayerPoint(this._latlng).round();\r\n\t\t\tthis._setPos(pos);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initIcon: function () {\r\n\t\tvar options = this.options,\r\n\t\t    classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\r\n\r\n\t\tvar icon = options.icon.createIcon(this._icon),\r\n\t\t    addIcon = false;\r\n\r\n\t\t// if we're not reusing the icon, remove the old one and init new one\r\n\t\tif (icon !== this._icon) {\r\n\t\t\tif (this._icon) {\r\n\t\t\t\tthis._removeIcon();\r\n\t\t\t}\r\n\t\t\taddIcon = true;\r\n\r\n\t\t\tif (options.title) {\r\n\t\t\t\ticon.title = options.title;\r\n\t\t\t}\r\n\t\t\tif (options.alt) {\r\n\t\t\t\ticon.alt = options.alt;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tL.DomUtil.addClass(icon, classToAdd);\r\n\r\n\t\tif (options.keyboard) {\r\n\t\t\ticon.tabIndex = '0';\r\n\t\t}\r\n\r\n\t\tthis._icon = icon;\r\n\r\n\t\tif (options.riseOnHover) {\r\n\t\t\tthis.on({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tvar newShadow = options.icon.createShadow(this._shadow),\r\n\t\t    addShadow = false;\r\n\r\n\t\tif (newShadow !== this._shadow) {\r\n\t\t\tthis._removeShadow();\r\n\t\t\taddShadow = true;\r\n\t\t}\r\n\r\n\t\tif (newShadow) {\r\n\t\t\tL.DomUtil.addClass(newShadow, classToAdd);\r\n\t\t\tnewShadow.alt = '';\r\n\t\t}\r\n\t\tthis._shadow = newShadow;\r\n\r\n\r\n\t\tif (options.opacity < 1) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\r\n\t\tif (addIcon) {\r\n\t\t\tthis.getPane().appendChild(this._icon);\r\n\t\t}\r\n\t\tthis._initInteraction();\r\n\t\tif (newShadow && addShadow) {\r\n\t\t\tthis.getPane('shadowPane').appendChild(this._shadow);\r\n\t\t}\r\n\t},\r\n\r\n\t_removeIcon: function () {\r\n\t\tif (this.options.riseOnHover) {\r\n\t\t\tthis.off({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tL.DomUtil.remove(this._icon);\r\n\t\tthis.removeInteractiveTarget(this._icon);\r\n\r\n\t\tthis._icon = null;\r\n\t},\r\n\r\n\t_removeShadow: function () {\r\n\t\tif (this._shadow) {\r\n\t\t\tL.DomUtil.remove(this._shadow);\r\n\t\t}\r\n\t\tthis._shadow = null;\r\n\t},\r\n\r\n\t_setPos: function (pos) {\r\n\t\tL.DomUtil.setPosition(this._icon, pos);\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tL.DomUtil.setPosition(this._shadow, pos);\r\n\t\t}\r\n\r\n\t\tthis._zIndex = pos.y + this.options.zIndexOffset;\r\n\r\n\t\tthis._resetZIndex();\r\n\t},\r\n\r\n\t_updateZIndex: function (offset) {\r\n\t\tthis._icon.style.zIndex = this._zIndex + offset;\r\n\t},\r\n\r\n\t_animateZoom: function (opt) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();\r\n\r\n\t\tthis._setPos(pos);\r\n\t},\r\n\r\n\t_initInteraction: function () {\r\n\r\n\t\tif (!this.options.interactive) { return; }\r\n\r\n\t\tL.DomUtil.addClass(this._icon, 'leaflet-interactive');\r\n\r\n\t\tthis.addInteractiveTarget(this._icon);\r\n\r\n\t\tif (L.Handler.MarkerDrag) {\r\n\t\t\tvar draggable = this.options.draggable;\r\n\t\t\tif (this.dragging) {\r\n\t\t\t\tdraggable = this.dragging.enabled();\r\n\t\t\t\tthis.dragging.disable();\r\n\t\t\t}\r\n\r\n\t\t\tthis.dragging = new L.Handler.MarkerDrag(this);\r\n\r\n\t\t\tif (draggable) {\r\n\t\t\t\tthis.dragging.enable();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Changes the opacity of the marker.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\t\tif (this._map) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tvar opacity = this.options.opacity;\r\n\r\n\t\tL.DomUtil.setOpacity(this._icon, opacity);\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tL.DomUtil.setOpacity(this._shadow, opacity);\r\n\t\t}\r\n\t},\r\n\r\n\t_bringToFront: function () {\r\n\t\tthis._updateZIndex(this.options.riseOffset);\r\n\t},\r\n\r\n\t_resetZIndex: function () {\r\n\t\tthis._updateZIndex(0);\r\n\t},\r\n\r\n\t_getPopupAnchor: function () {\r\n\t\treturn this.options.icon.options.popupAnchor || [0, 0];\r\n\t},\r\n\r\n\t_getTooltipAnchor: function () {\r\n\t\treturn this.options.icon.options.tooltipAnchor || [0, 0];\r\n\t}\r\n});\r\n\r\n\r\n// factory L.marker(latlng: LatLng, options? : Marker options)\r\n\r\n// @factory L.marker(latlng: LatLng, options? : Marker options)\r\n// Instantiates a Marker object given a geographical point and optionally an options object.\r\nL.marker = function (latlng, options) {\r\n\treturn new L.Marker(latlng, options);\r\n};\r\n","/*\n * @class DivIcon\n * @aka L.DivIcon\n * @inherits Icon\n *\n * Represents a lightweight icon for markers that uses a simple `<div>`\n * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.\n *\n * @example\n * ```js\n * var myIcon = L.divIcon({className: 'my-div-icon'});\n * // you can set .my-div-icon styles in CSS\n *\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n * ```\n *\n * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.\n */\n\nL.DivIcon = L.Icon.extend({\n\toptions: {\n\t\t// @section\n\t\t// @aka DivIcon options\n\t\ticonSize: [12, 12], // also can be set through CSS\n\n\t\t// iconAnchor: (Point),\n\t\t// popupAnchor: (Point),\n\n\t\t// @option html: String = ''\n\t\t// Custom HTML code to put inside the div element, empty by default.\n\t\thtml: false,\n\n\t\t// @option bgPos: Point = [0, 0]\n\t\t// Optional relative position of the background, in pixels\n\t\tbgPos: null,\n\n\t\tclassName: 'leaflet-div-icon'\n\t},\n\n\tcreateIcon: function (oldIcon) {\n\t\tvar div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),\n\t\t    options = this.options;\n\n\t\tdiv.innerHTML = options.html !== false ? options.html : '';\n\n\t\tif (options.bgPos) {\n\t\t\tvar bgPos = L.point(options.bgPos);\n\t\t\tdiv.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';\n\t\t}\n\t\tthis._setIconStyles(div, 'icon');\n\n\t\treturn div;\n\t},\n\n\tcreateShadow: function () {\n\t\treturn null;\n\t}\n});\n\n// @factory L.divIcon(options: DivIcon options)\n// Creates a `DivIcon` instance with the given options.\nL.divIcon = function (options) {\n\treturn new L.DivIcon(options);\n};\n","/*\r\n * @class DivOverlay\r\n * @inherits Layer\r\n * @aka L.DivOverlay\r\n * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.\r\n */\r\n\r\n// @namespace DivOverlay\r\nL.DivOverlay = L.Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka DivOverlay options\r\n\toptions: {\r\n\t\t// @option offset: Point = Point(0, 7)\r\n\t\t// The offset of the popup position. Useful to control the anchor\r\n\t\t// of the popup when opening it on some overlays.\r\n\t\toffset: [0, 7],\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: '',\r\n\r\n\t\t// @option pane: String = 'popupPane'\r\n\t\t// `Map pane` where the popup will be added.\r\n\t\tpane: 'popupPane'\r\n\t},\r\n\r\n\tinitialize: function (options, source) {\r\n\t\tL.setOptions(this, options);\r\n\r\n\t\tthis._source = source;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = map._zoomAnimated;\r\n\r\n\t\tif (!this._container) {\r\n\t\t\tthis._initLayout();\r\n\t\t}\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tL.DomUtil.setOpacity(this._container, 0);\r\n\t\t}\r\n\r\n\t\tclearTimeout(this._removeTimeout);\r\n\t\tthis.getPane().appendChild(this._container);\r\n\t\tthis.update();\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tL.DomUtil.setOpacity(this._container, 1);\r\n\t\t}\r\n\r\n\t\tthis.bringToFront();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tL.DomUtil.setOpacity(this._container, 0);\r\n\t\t\tthis._removeTimeout = setTimeout(L.bind(L.DomUtil.remove, L.DomUtil, this._container), 200);\r\n\t\t} else {\r\n\t\t\tL.DomUtil.remove(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the geographical point of popup.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Sets the geographical point where the popup will open.\r\n\tsetLatLng: function (latlng) {\r\n\t\tthis._latlng = L.latLng(latlng);\r\n\t\tif (this._map) {\r\n\t\t\tthis._updatePosition();\r\n\t\t\tthis._adjustPan();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContent: String|HTMLElement\r\n\t// Returns the content of the popup.\r\n\tgetContent: function () {\r\n\t\treturn this._content;\r\n\t},\r\n\r\n\t// @method setContent(htmlContent: String|HTMLElement|Function): this\r\n\t// Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.\r\n\tsetContent: function (content) {\r\n\t\tthis._content = content;\r\n\t\tthis.update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getElement: String|HTMLElement\r\n\t// Alias for [getContent()](#popup-getcontent)\r\n\tgetElement: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method update: null\r\n\t// Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.\r\n\tupdate: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tthis._container.style.visibility = 'hidden';\r\n\r\n\t\tthis._updateContent();\r\n\t\tthis._updateLayout();\r\n\t\tthis._updatePosition();\r\n\r\n\t\tthis._container.style.visibility = '';\r\n\r\n\t\tthis._adjustPan();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._updatePosition,\r\n\t\t\tviewreset: this._updatePosition\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method isOpen: Boolean\r\n\t// Returns `true` when the popup is visible on the map.\r\n\tisOpen: function () {\r\n\t\treturn !!this._map && this._map.hasLayer(this);\r\n\t},\r\n\r\n\t// @method bringToFront: this\r\n\t// Brings this popup in front of other popups (in the same map pane).\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\tL.DomUtil.toFront(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack: this\r\n\t// Brings this popup to the back of other popups (in the same map pane).\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\tL.DomUtil.toBack(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateContent: function () {\r\n\t\tif (!this._content) { return; }\r\n\r\n\t\tvar node = this._contentNode;\r\n\t\tvar content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;\r\n\r\n\t\tif (typeof content === 'string') {\r\n\t\t\tnode.innerHTML = content;\r\n\t\t} else {\r\n\t\t\twhile (node.hasChildNodes()) {\r\n\t\t\t\tnode.removeChild(node.firstChild);\r\n\t\t\t}\r\n\t\t\tnode.appendChild(content);\r\n\t\t}\r\n\t\tthis.fire('contentupdate');\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng),\r\n\t\t    offset = L.point(this.options.offset),\r\n\t\t    anchor = this._getAnchor();\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tL.DomUtil.setPosition(this._container, pos.add(anchor));\r\n\t\t} else {\r\n\t\t\toffset = offset.add(pos).add(anchor);\r\n\t\t}\r\n\r\n\t\tvar bottom = this._containerBottom = -offset.y,\r\n\t\t    left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;\r\n\r\n\t\t// bottom position the popup in case the height of the popup changes (images loading etc)\r\n\t\tthis._container.style.bottom = bottom + 'px';\r\n\t\tthis._container.style.left = left + 'px';\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\treturn [0, 0];\r\n\t}\r\n\r\n});\r\n","/*\r\n * @class Popup\r\n * @inherits DivOverlay\r\n * @aka L.Popup\r\n * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to\r\n * open popups while making sure that only one popup is open at one time\r\n * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.\r\n *\r\n * @example\r\n *\r\n * If you want to just bind a popup to marker click and then open it, it's really easy:\r\n *\r\n * ```js\r\n * marker.bindPopup(popupContent).openPopup();\r\n * ```\r\n * Path overlays like polylines also have a `bindPopup` method.\r\n * Here's a more complicated way to open a popup on a map:\r\n *\r\n * ```js\r\n * var popup = L.popup()\r\n * \t.setLatLng(latlng)\r\n * \t.setContent('<p>Hello world!<br />This is a nice popup.</p>')\r\n * \t.openOn(map);\r\n * ```\r\n */\r\n\r\n\r\n// @namespace Popup\r\nL.Popup = L.DivOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka Popup options\r\n\toptions: {\r\n\t\t// @option maxWidth: Number = 300\r\n\t\t// Max width of the popup, in pixels.\r\n\t\tmaxWidth: 300,\r\n\r\n\t\t// @option minWidth: Number = 50\r\n\t\t// Min width of the popup, in pixels.\r\n\t\tminWidth: 50,\r\n\r\n\t\t// @option maxHeight: Number = null\r\n\t\t// If set, creates a scrollable container of the given height\r\n\t\t// inside a popup if its content exceeds it.\r\n\t\tmaxHeight: null,\r\n\r\n\t\t// @option autoPan: Boolean = true\r\n\t\t// Set it to `false` if you don't want the map to do panning animation\r\n\t\t// to fit the opened popup.\r\n\t\tautoPan: true,\r\n\r\n\t\t// @option autoPanPaddingTopLeft: Point = null\r\n\t\t// The margin between the popup and the top left corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingTopLeft: null,\r\n\r\n\t\t// @option autoPanPaddingBottomRight: Point = null\r\n\t\t// The margin between the popup and the bottom right corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingBottomRight: null,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(5, 5)\r\n\t\t// Equivalent of setting both top left and bottom right autopan padding to the same value.\r\n\t\tautoPanPadding: [5, 5],\r\n\r\n\t\t// @option keepInView: Boolean = false\r\n\t\t// Set it to `true` if you want to prevent users from panning the popup\r\n\t\t// off of the screen while it is open.\r\n\t\tkeepInView: false,\r\n\r\n\t\t// @option closeButton: Boolean = true\r\n\t\t// Controls the presence of a close button in the popup.\r\n\t\tcloseButton: true,\r\n\r\n\t\t// @option autoClose: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the popup closing when user clicks the map (set globally by\r\n\t\t// the Map's [closePopupOnClick](#map-closepopuponclick) option).\r\n\t\tautoClose: true,\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method openOn(map: Map): this\r\n\t// Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.\r\n\topenOn: function (map) {\r\n\t\tmap.openPopup(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tL.DivOverlay.prototype.onAdd.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupopen: PopupEvent\r\n\t\t// Fired when a popup is opened in the map\r\n\t\tmap.fire('popupopen', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupopen: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is opened\r\n\t\t\tthis._source.fire('popupopen', {popup: this}, true);\r\n\t\t\t// For non-path layers, we toggle the popup when clicking\r\n\t\t\t// again the layer, so prevent the map to reopen it.\r\n\t\t\tif (!(this._source instanceof L.Path)) {\r\n\t\t\t\tthis._source.on('preclick', L.DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tL.DivOverlay.prototype.onRemove.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupclose: PopupEvent\r\n\t\t// Fired when a popup in the map is closed\r\n\t\tmap.fire('popupclose', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupclose: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is closed\r\n\t\t\tthis._source.fire('popupclose', {popup: this}, true);\r\n\t\t\tif (!(this._source instanceof L.Path)) {\r\n\t\t\t\tthis._source.off('preclick', L.DomEvent.stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = L.DivOverlay.prototype.getEvents.call(this);\r\n\r\n\t\tif ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {\r\n\t\t\tevents.preclick = this._close;\r\n\t\t}\r\n\r\n\t\tif (this.options.keepInView) {\r\n\t\t\tevents.moveend = this._adjustPan;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t_close: function () {\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.closePopup(this);\r\n\t\t}\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar prefix = 'leaflet-popup',\r\n\t\t    container = this._container = L.DomUtil.create('div',\r\n\t\t\tprefix + ' ' + (this.options.className || '') +\r\n\t\t\t' leaflet-zoom-animated');\r\n\r\n\t\tif (this.options.closeButton) {\r\n\t\t\tvar closeButton = this._closeButton = L.DomUtil.create('a', prefix + '-close-button', container);\r\n\t\t\tcloseButton.href = '#close';\r\n\t\t\tcloseButton.innerHTML = '&#215;';\r\n\r\n\t\t\tL.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this);\r\n\t\t}\r\n\r\n\t\tvar wrapper = this._wrapper = L.DomUtil.create('div', prefix + '-content-wrapper', container);\r\n\t\tthis._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);\r\n\r\n\t\tL.DomEvent\r\n\t\t\t.disableClickPropagation(wrapper)\r\n\t\t\t.disableScrollPropagation(this._contentNode)\r\n\t\t\t.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);\r\n\r\n\t\tthis._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);\r\n\t\tthis._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);\r\n\t},\r\n\r\n\t_updateLayout: function () {\r\n\t\tvar container = this._contentNode,\r\n\t\t    style = container.style;\r\n\r\n\t\tstyle.width = '';\r\n\t\tstyle.whiteSpace = 'nowrap';\r\n\r\n\t\tvar width = container.offsetWidth;\r\n\t\twidth = Math.min(width, this.options.maxWidth);\r\n\t\twidth = Math.max(width, this.options.minWidth);\r\n\r\n\t\tstyle.width = (width + 1) + 'px';\r\n\t\tstyle.whiteSpace = '';\r\n\r\n\t\tstyle.height = '';\r\n\r\n\t\tvar height = container.offsetHeight,\r\n\t\t    maxHeight = this.options.maxHeight,\r\n\t\t    scrolledClass = 'leaflet-popup-scrolled';\r\n\r\n\t\tif (maxHeight && height > maxHeight) {\r\n\t\t\tstyle.height = maxHeight + 'px';\r\n\t\t\tL.DomUtil.addClass(container, scrolledClass);\r\n\t\t} else {\r\n\t\t\tL.DomUtil.removeClass(container, scrolledClass);\r\n\t\t}\r\n\r\n\t\tthis._containerWidth = this._container.offsetWidth;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),\r\n\t\t    anchor = this._getAnchor();\r\n\t\tL.DomUtil.setPosition(this._container, pos.add(anchor));\r\n\t},\r\n\r\n\t_adjustPan: function () {\r\n\t\tif (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }\r\n\r\n\t\tvar map = this._map,\r\n\t\t    marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,\r\n\t\t    containerHeight = this._container.offsetHeight + marginBottom,\r\n\t\t    containerWidth = this._containerWidth,\r\n\t\t    layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);\r\n\r\n\t\tlayerPos._add(L.DomUtil.getPosition(this._container));\r\n\r\n\t\tvar containerPos = map.layerPointToContainerPoint(layerPos),\r\n\t\t    padding = L.point(this.options.autoPanPadding),\r\n\t\t    paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),\r\n\t\t    paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),\r\n\t\t    size = map.getSize(),\r\n\t\t    dx = 0,\r\n\t\t    dy = 0;\r\n\r\n\t\tif (containerPos.x + containerWidth + paddingBR.x > size.x) { // right\r\n\t\t\tdx = containerPos.x + containerWidth - size.x + paddingBR.x;\r\n\t\t}\r\n\t\tif (containerPos.x - dx - paddingTL.x < 0) { // left\r\n\t\t\tdx = containerPos.x - paddingTL.x;\r\n\t\t}\r\n\t\tif (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom\r\n\t\t\tdy = containerPos.y + containerHeight - size.y + paddingBR.y;\r\n\t\t}\r\n\t\tif (containerPos.y - dy - paddingTL.y < 0) { // top\r\n\t\t\tdy = containerPos.y - paddingTL.y;\r\n\t\t}\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event autopanstart: Event\r\n\t\t// Fired when the map starts autopanning when opening a popup.\r\n\t\tif (dx || dy) {\r\n\t\t\tmap\r\n\t\t\t    .fire('autopanstart')\r\n\t\t\t    .panBy([dx, dy]);\r\n\t\t}\r\n\t},\r\n\r\n\t_onCloseButtonClick: function (e) {\r\n\t\tthis._close();\r\n\t\tL.DomEvent.stop(e);\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\t// Where should we anchor the popup on the source layer?\r\n\t\treturn L.point(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);\r\n\t}\r\n\r\n});\r\n\r\n// @namespace Popup\r\n// @factory L.popup(options?: Popup options, source?: Layer)\r\n// 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.\r\nL.popup = function (options, source) {\r\n\treturn new L.Popup(options, source);\r\n};\r\n\r\n\r\n/* @namespace Map\r\n * @section Interaction Options\r\n * @option closePopupOnClick: Boolean = true\r\n * Set it to `false` if you don't want popups to close when user clicks the map.\r\n */\r\nL.Map.mergeOptions({\r\n\tclosePopupOnClick: true\r\n});\r\n\r\n\r\n// @namespace Map\r\n// @section Methods for Layers and Controls\r\nL.Map.include({\r\n\t// @method openPopup(popup: Popup): this\r\n\t// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).\r\n\t// @alternative\r\n\t// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this\r\n\t// Creates a popup with the specified content and options and opens it in the given point on a map.\r\n\topenPopup: function (popup, latlng, options) {\r\n\t\tif (!(popup instanceof L.Popup)) {\r\n\t\t\tpopup = new L.Popup(options).setContent(popup);\r\n\t\t}\r\n\r\n\t\tif (latlng) {\r\n\t\t\tpopup.setLatLng(latlng);\r\n\t\t}\r\n\r\n\t\tif (this.hasLayer(popup)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tif (this._popup && this._popup.options.autoClose) {\r\n\t\t\tthis.closePopup();\r\n\t\t}\r\n\r\n\t\tthis._popup = popup;\r\n\t\treturn this.addLayer(popup);\r\n\t},\r\n\r\n\t// @method closePopup(popup?: Popup): this\r\n\t// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).\r\n\tclosePopup: function (popup) {\r\n\t\tif (!popup || popup === this._popup) {\r\n\t\t\tpopup = this._popup;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\tif (popup) {\r\n\t\t\tthis.removeLayer(popup);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n/*\r\n * @namespace Layer\r\n * @section Popup methods example\r\n *\r\n * All layers share a set of methods convenient for binding popups to it.\r\n *\r\n * ```js\r\n * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\r\n * layer.openPopup();\r\n * layer.closePopup();\r\n * ```\r\n *\r\n * 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.\r\n */\r\n\r\n// @section Popup methods\r\nL.Layer.include({\r\n\r\n\t// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this\r\n\t// Binds a popup to the layer with the passed `content` and sets up the\r\n\t// neccessary event listeners. If a `Function` is passed it will receive\r\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\r\n\tbindPopup: function (content, options) {\r\n\r\n\t\tif (content instanceof L.Popup) {\r\n\t\t\tL.setOptions(content, options);\r\n\t\t\tthis._popup = content;\r\n\t\t\tcontent._source = this;\r\n\t\t} else {\r\n\t\t\tif (!this._popup || options) {\r\n\t\t\t\tthis._popup = new L.Popup(options, this);\r\n\t\t\t}\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\r\n\t\tif (!this._popupHandlersAdded) {\r\n\t\t\tthis.on({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = true;\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method unbindPopup(): this\r\n\t// Removes the popup previously bound with `bindPopup`.\r\n\tunbindPopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis.off({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = false;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method openPopup(latlng?: LatLng): this\r\n\t// Opens the bound popup at the specificed `latlng` or at the default popup anchor if no `latlng` is passed.\r\n\topenPopup: function (layer, latlng) {\r\n\t\tif (!(layer instanceof L.Layer)) {\r\n\t\t\tlatlng = layer;\r\n\t\t\tlayer = this;\r\n\t\t}\r\n\r\n\t\tif (layer instanceof L.FeatureGroup) {\r\n\t\t\tfor (var id in this._layers) {\r\n\t\t\t\tlayer = this._layers[id];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!latlng) {\r\n\t\t\tlatlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();\r\n\t\t}\r\n\r\n\t\tif (this._popup && this._map) {\r\n\t\t\t// set popup source to this layer\r\n\t\t\tthis._popup._source = layer;\r\n\r\n\t\t\t// update the popup (content, layout, ect...)\r\n\t\t\tthis._popup.update();\r\n\r\n\t\t\t// open the popup on the map\r\n\t\t\tthis._map.openPopup(this._popup, latlng);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(): this\r\n\t// Closes the popup bound to this layer if it is open.\r\n\tclosePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup._close();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method togglePopup(): this\r\n\t// Opens or closes the popup bound to this layer depending on its current state.\r\n\ttogglePopup: function (target) {\r\n\t\tif (this._popup) {\r\n\t\t\tif (this._popup._map) {\r\n\t\t\t\tthis.closePopup();\r\n\t\t\t} else {\r\n\t\t\t\tthis.openPopup(target);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method isPopupOpen(): boolean\r\n\t// Returns `true` if the popup bound to this layer is currently open.\r\n\tisPopupOpen: function () {\r\n\t\treturn (this._popup ? this._popup.isOpen() : false);\r\n\t},\r\n\r\n\t// @method setPopupContent(content: String|HTMLElement|Popup): this\r\n\t// Sets the content of the popup bound to this layer.\r\n\tsetPopupContent: function (content) {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getPopup(): Popup\r\n\t// Returns the popup bound to this layer.\r\n\tgetPopup: function () {\r\n\t\treturn this._popup;\r\n\t},\r\n\r\n\t_openPopup: function (e) {\r\n\t\tvar layer = e.layer || e.target;\r\n\r\n\t\tif (!this._popup) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._map) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// prevent map click\r\n\t\tL.DomEvent.stop(e);\r\n\r\n\t\t// if this inherits from Path its a vector and we can just\r\n\t\t// open the popup at the new location\r\n\t\tif (layer instanceof L.Path) {\r\n\t\t\tthis.openPopup(e.layer || e.target, e.latlng);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// otherwise treat it like a marker and figure out\r\n\t\t// if we should toggle it open/closed\r\n\t\tif (this._map.hasLayer(this._popup) && this._popup._source === layer) {\r\n\t\t\tthis.closePopup();\r\n\t\t} else {\r\n\t\t\tthis.openPopup(layer, e.latlng);\r\n\t\t}\r\n\t},\r\n\r\n\t_movePopup: function (e) {\r\n\t\tthis._popup.setLatLng(e.latlng);\r\n\t}\r\n});\r\n","/*\n * @class Tooltip\n * @inherits DivOverlay\n * @aka L.Tooltip\n * Used to display small texts on top of map layers.\n *\n * @example\n *\n * ```js\n * marker.bindTooltip(\"my tooltip text\").openTooltip();\n * ```\n * Note about tooltip offset. Leaflet takes two options in consideration\n * for computing tooltip offseting:\n * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.\n *   Add a positive x offset to move the tooltip to the right, and a positive y offset to\n *   move it to the bottom. Negatives will move to the left and top.\n * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You\n *   should adapt this value if you use a custom icon.\n */\n\n\n// @namespace Tooltip\nL.Tooltip = L.DivOverlay.extend({\n\n\t// @section\n\t// @aka Tooltip options\n\toptions: {\n\t\t// @option pane: String = 'tooltipPane'\n\t\t// `Map pane` where the tooltip will be added.\n\t\tpane: 'tooltipPane',\n\n\t\t// @option offset: Point = Point(0, 0)\n\t\t// Optional offset of the tooltip position.\n\t\toffset: [0, 0],\n\n\t\t// @option direction: String = 'auto'\n\t\t// Direction where to open the tooltip. Possible values are: `right`, `left`,\n\t\t// `top`, `bottom`, `center`, `auto`.\n\t\t// `auto` will dynamicaly switch between `right` and `left` according to the tooltip\n\t\t// position on the map.\n\t\tdirection: 'auto',\n\n\t\t// @option permanent: Boolean = false\n\t\t// Whether to open the tooltip permanently or only on mouseover.\n\t\tpermanent: false,\n\n\t\t// @option sticky: Boolean = false\n\t\t// If true, the tooltip will follow the mouse instead of being fixed at the feature center.\n\t\tsticky: false,\n\n\t\t// @option interactive: Boolean = false\n\t\t// If true, the tooltip will listen to the feature events.\n\t\tinteractive: false,\n\n\t\t// @option opacity: Number = 0.9\n\t\t// Tooltip container opacity.\n\t\topacity: 0.9\n\t},\n\n\tonAdd: function (map) {\n\t\tL.DivOverlay.prototype.onAdd.call(this, map);\n\t\tthis.setOpacity(this.options.opacity);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipopen: TooltipEvent\n\t\t// Fired when a tooltip is opened in the map.\n\t\tmap.fire('tooltipopen', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipopen: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is opened.\n\t\t\tthis._source.fire('tooltipopen', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tonRemove: function (map) {\n\t\tL.DivOverlay.prototype.onRemove.call(this, map);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipclose: TooltipEvent\n\t\t// Fired when a tooltip in the map is closed.\n\t\tmap.fire('tooltipclose', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipclose: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is closed.\n\t\t\tthis._source.fire('tooltipclose', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = L.DivOverlay.prototype.getEvents.call(this);\n\n\t\tif (L.Browser.touch && !this.options.permanent) {\n\t\t\tevents.preclick = this._close;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t_close: function () {\n\t\tif (this._map) {\n\t\t\tthis._map.closeTooltip(this);\n\t\t}\n\t},\n\n\t_initLayout: function () {\n\t\tvar prefix = 'leaflet-tooltip',\n\t\t    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\n\n\t\tthis._contentNode = this._container = L.DomUtil.create('div', className);\n\t},\n\n\t_updateLayout: function () {},\n\n\t_adjustPan: function () {},\n\n\t_setPosition: function (pos) {\n\t\tvar map = this._map,\n\t\t    container = this._container,\n\t\t    centerPoint = map.latLngToContainerPoint(map.getCenter()),\n\t\t    tooltipPoint = map.layerPointToContainerPoint(pos),\n\t\t    direction = this.options.direction,\n\t\t    tooltipWidth = container.offsetWidth,\n\t\t    tooltipHeight = container.offsetHeight,\n\t\t    offset = L.point(this.options.offset),\n\t\t    anchor = this._getAnchor();\n\n\t\tif (direction === 'top') {\n\t\t\tpos = pos.add(L.point(-tooltipWidth / 2 + offset.x, -tooltipHeight + offset.y + anchor.y, true));\n\t\t} else if (direction === 'bottom') {\n\t\t\tpos = pos.subtract(L.point(tooltipWidth / 2 - offset.x, -offset.y, true));\n\t\t} else if (direction === 'center') {\n\t\t\tpos = pos.subtract(L.point(tooltipWidth / 2 + offset.x, tooltipHeight / 2 - anchor.y + offset.y, true));\n\t\t} else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {\n\t\t\tdirection = 'right';\n\t\t\tpos = pos.add(L.point(offset.x + anchor.x, anchor.y - tooltipHeight / 2 + offset.y, true));\n\t\t} else {\n\t\t\tdirection = 'left';\n\t\t\tpos = pos.subtract(L.point(tooltipWidth + anchor.x - offset.x, tooltipHeight / 2 - anchor.y - offset.y, true));\n\t\t}\n\n\t\tL.DomUtil.removeClass(container, 'leaflet-tooltip-right');\n\t\tL.DomUtil.removeClass(container, 'leaflet-tooltip-left');\n\t\tL.DomUtil.removeClass(container, 'leaflet-tooltip-top');\n\t\tL.DomUtil.removeClass(container, 'leaflet-tooltip-bottom');\n\t\tL.DomUtil.addClass(container, 'leaflet-tooltip-' + direction);\n\t\tL.DomUtil.setPosition(container, pos);\n\t},\n\n\t_updatePosition: function () {\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._setPosition(pos);\n\t},\n\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\n\t\tif (this._container) {\n\t\t\tL.DomUtil.setOpacity(this._container, opacity);\n\t\t}\n\t},\n\n\t_animateZoom: function (e) {\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);\n\t\tthis._setPosition(pos);\n\t},\n\n\t_getAnchor: function () {\n\t\t// Where should we anchor the tooltip on the source layer?\n\t\treturn L.point(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);\n\t}\n\n});\n\n// @namespace Tooltip\n// @factory L.tooltip(options?: Tooltip options, source?: Layer)\n// 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.\nL.tooltip = function (options, source) {\n\treturn new L.Tooltip(options, source);\n};\n\n// @namespace Map\n// @section Methods for Layers and Controls\nL.Map.include({\n\n\t// @method openTooltip(tooltip: Tooltip): this\n\t// Opens the specified tooltip.\n\t// @alternative\n\t// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this\n\t// Creates a tooltip with the specified content and options and open it.\n\topenTooltip: function (tooltip, latlng, options) {\n\t\tif (!(tooltip instanceof L.Tooltip)) {\n\t\t\ttooltip = new L.Tooltip(options).setContent(tooltip);\n\t\t}\n\n\t\tif (latlng) {\n\t\t\ttooltip.setLatLng(latlng);\n\t\t}\n\n\t\tif (this.hasLayer(tooltip)) {\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.addLayer(tooltip);\n\t},\n\n\t// @method closeTooltip(tooltip?: Tooltip): this\n\t// Closes the tooltip given as parameter.\n\tcloseTooltip: function (tooltip) {\n\t\tif (tooltip) {\n\t\t\tthis.removeLayer(tooltip);\n\t\t}\n\t\treturn this;\n\t}\n\n});\n\n/*\n * @namespace Layer\n * @section Tooltip methods example\n *\n * All layers share a set of methods convenient for binding tooltips to it.\n *\n * ```js\n * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);\n * layer.openTooltip();\n * layer.closeTooltip();\n * ```\n */\n\n// @section Tooltip methods\nL.Layer.include({\n\n\t// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this\n\t// Binds a tooltip to the layer with the passed `content` and sets up the\n\t// neccessary event listeners. If a `Function` is passed it will receive\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\n\tbindTooltip: function (content, options) {\n\n\t\tif (content instanceof L.Tooltip) {\n\t\t\tL.setOptions(content, options);\n\t\t\tthis._tooltip = content;\n\t\t\tcontent._source = this;\n\t\t} else {\n\t\t\tif (!this._tooltip || options) {\n\t\t\t\tthis._tooltip = L.tooltip(options, this);\n\t\t\t}\n\t\t\tthis._tooltip.setContent(content);\n\n\t\t}\n\n\t\tthis._initTooltipInteractions();\n\n\t\tif (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {\n\t\t\tthis.openTooltip();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method unbindTooltip(): this\n\t// Removes the tooltip previously bound with `bindTooltip`.\n\tunbindTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._initTooltipInteractions(true);\n\t\t\tthis.closeTooltip();\n\t\t\tthis._tooltip = null;\n\t\t}\n\t\treturn this;\n\t},\n\n\t_initTooltipInteractions: function (remove) {\n\t\tif (!remove && this._tooltipHandlersAdded) { return; }\n\t\tvar onOff = remove ? 'off' : 'on',\n\t\t    events = {\n\t\t\tremove: this.closeTooltip,\n\t\t\tmove: this._moveTooltip\n\t\t    };\n\t\tif (!this._tooltip.options.permanent) {\n\t\t\tevents.mouseover = this._openTooltip;\n\t\t\tevents.mouseout = this.closeTooltip;\n\t\t\tif (this._tooltip.options.sticky) {\n\t\t\t\tevents.mousemove = this._moveTooltip;\n\t\t\t}\n\t\t\tif (L.Browser.touch) {\n\t\t\t\tevents.click = this._openTooltip;\n\t\t\t}\n\t\t} else {\n\t\t\tevents.add = this._openTooltip;\n\t\t}\n\t\tthis[onOff](events);\n\t\tthis._tooltipHandlersAdded = !remove;\n\t},\n\n\t// @method openTooltip(latlng?: LatLng): this\n\t// Opens the bound tooltip at the specificed `latlng` or at the default tooltip anchor if no `latlng` is passed.\n\topenTooltip: function (layer, latlng) {\n\t\tif (!(layer instanceof L.Layer)) {\n\t\t\tlatlng = layer;\n\t\t\tlayer = this;\n\t\t}\n\n\t\tif (layer instanceof L.FeatureGroup) {\n\t\t\tfor (var id in this._layers) {\n\t\t\t\tlayer = this._layers[id];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!latlng) {\n\t\t\tlatlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();\n\t\t}\n\n\t\tif (this._tooltip && this._map) {\n\n\t\t\t// set tooltip source to this layer\n\t\t\tthis._tooltip._source = layer;\n\n\t\t\t// update the tooltip (content, layout, ect...)\n\t\t\tthis._tooltip.update();\n\n\t\t\t// open the tooltip on the map\n\t\t\tthis._map.openTooltip(this._tooltip, latlng);\n\n\t\t\t// Tooltip container may not be defined if not permanent and never\n\t\t\t// opened.\n\t\t\tif (this._tooltip.options.interactive && this._tooltip._container) {\n\t\t\t\tL.DomUtil.addClass(this._tooltip._container, 'leaflet-clickable');\n\t\t\t\tthis.addInteractiveTarget(this._tooltip._container);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(): this\n\t// Closes the tooltip bound to this layer if it is open.\n\tcloseTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip._close();\n\t\t\tif (this._tooltip.options.interactive && this._tooltip._container) {\n\t\t\t\tL.DomUtil.removeClass(this._tooltip._container, 'leaflet-clickable');\n\t\t\t\tthis.removeInteractiveTarget(this._tooltip._container);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method toggleTooltip(): this\n\t// Opens or closes the tooltip bound to this layer depending on its current state.\n\ttoggleTooltip: function (target) {\n\t\tif (this._tooltip) {\n\t\t\tif (this._tooltip._map) {\n\t\t\t\tthis.closeTooltip();\n\t\t\t} else {\n\t\t\t\tthis.openTooltip(target);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method isTooltipOpen(): boolean\n\t// Returns `true` if the tooltip bound to this layer is currently open.\n\tisTooltipOpen: function () {\n\t\treturn this._tooltip.isOpen();\n\t},\n\n\t// @method setTooltipContent(content: String|HTMLElement|Tooltip): this\n\t// Sets the content of the tooltip bound to this layer.\n\tsetTooltipContent: function (content) {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.setContent(content);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getTooltip(): Tooltip\n\t// Returns the tooltip bound to this layer.\n\tgetTooltip: function () {\n\t\treturn this._tooltip;\n\t},\n\n\t_openTooltip: function (e) {\n\t\tvar layer = e.layer || e.target;\n\n\t\tif (!this._tooltip || !this._map) {\n\t\t\treturn;\n\t\t}\n\t\tthis.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);\n\t},\n\n\t_moveTooltip: function (e) {\n\t\tvar latlng = e.latlng, containerPoint, layerPoint;\n\t\tif (this._tooltip.options.sticky && e.originalEvent) {\n\t\t\tcontainerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);\n\t\t\tlayerPoint = this._map.containerPointToLayerPoint(containerPoint);\n\t\t\tlatlng = this._map.layerPointToLatLng(layerPoint);\n\t\t}\n\t\tthis._tooltip.setLatLng(latlng);\n\t}\n});\n","/*\r\n * @class LayerGroup\r\n * @aka L.LayerGroup\r\n * @inherits Layer\r\n *\r\n * Used to group several layers and handle them as one. If you add it to the map,\r\n * any layers added or removed from the group will be added/removed on the map as\r\n * well. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.layerGroup([marker1, marker2])\r\n * \t.addLayer(polyline)\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nL.LayerGroup = L.Layer.extend({\r\n\r\n\tinitialize: function (layers) {\r\n\t\tthis._layers = {};\r\n\r\n\t\tvar i, len;\r\n\r\n\t\tif (layers) {\r\n\t\t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n\t\t\t\tthis.addLayer(layers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addLayer(layer: Layer): this\r\n\t// Adds the given layer to the group.\r\n\taddLayer: function (layer) {\r\n\t\tvar id = this.getLayerId(layer);\r\n\r\n\t\tthis._layers[id] = layer;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.addLayer(layer);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Removes the given layer from the group.\r\n\t// @alternative\r\n\t// @method removeLayer(id: Number): this\r\n\t// Removes the layer with the given internal ID from the group.\r\n\tremoveLayer: function (layer) {\r\n\t\tvar id = layer in this._layers ? layer : this.getLayerId(layer);\r\n\r\n\t\tif (this._map && this._layers[id]) {\r\n\t\t\tthis._map.removeLayer(this._layers[id]);\r\n\t\t}\r\n\r\n\t\tdelete this._layers[id];\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method hasLayer(layer: Layer): Boolean\r\n\t// Returns `true` if the given layer is currently added to the group.\r\n\thasLayer: function (layer) {\r\n\t\treturn !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers);\r\n\t},\r\n\r\n\t// @method clearLayers(): this\r\n\t// Removes all the layers from the group.\r\n\tclearLayers: function () {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tthis.removeLayer(this._layers[i]);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method invoke(methodName: String, …): this\r\n\t// Calls `methodName` on every layer contained in this group, passing any\r\n\t// additional parameters. Has no effect if the layers contained do not\r\n\t// implement `methodName`.\r\n\tinvoke: function (methodName) {\r\n\t\tvar args = Array.prototype.slice.call(arguments, 1),\r\n\t\t    i, layer;\r\n\r\n\t\tfor (i in this._layers) {\r\n\t\t\tlayer = this._layers[i];\r\n\r\n\t\t\tif (layer[methodName]) {\r\n\t\t\t\tlayer[methodName].apply(layer, args);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmap.addLayer(this._layers[i]);\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmap.removeLayer(this._layers[i]);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method eachLayer(fn: Function, context?: Object): this\r\n\t// Iterates over the layers of the group, optionally specifying context of the iterator function.\r\n\t// ```js\r\n\t// group.eachLayer(function (layer) {\r\n\t// \tlayer.bindPopup('Hello');\r\n\t// });\r\n\t// ```\r\n\teachLayer: function (method, context) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmethod.call(context, this._layers[i]);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getLayer(id: Number): Layer\r\n\t// Returns the layer with the given internal ID.\r\n\tgetLayer: function (id) {\r\n\t\treturn this._layers[id];\r\n\t},\r\n\r\n\t// @method getLayers(): Layer[]\r\n\t// Returns an array of all the layers added to the group.\r\n\tgetLayers: function () {\r\n\t\tvar layers = [];\r\n\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tlayers.push(this._layers[i]);\r\n\t\t}\r\n\t\treturn layers;\r\n\t},\r\n\r\n\t// @method setZIndex(zIndex: Number): this\r\n\t// Calls `setZIndex` on every layer contained in this group, passing the z-index.\r\n\tsetZIndex: function (zIndex) {\r\n\t\treturn this.invoke('setZIndex', zIndex);\r\n\t},\r\n\r\n\t// @method getLayerId(layer: Layer): Number\r\n\t// Returns the internal ID for a layer\r\n\tgetLayerId: function (layer) {\r\n\t\treturn L.stamp(layer);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.layerGroup(layers: Layer[])\r\n// Create a layer group, optionally given an initial set of layers.\r\nL.layerGroup = function (layers) {\r\n\treturn new L.LayerGroup(layers);\r\n};\r\n","/*\r\n * @class FeatureGroup\r\n * @aka L.FeatureGroup\r\n * @inherits LayerGroup\r\n *\r\n * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:\r\n *  * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))\r\n *  * Events are propagated to the `FeatureGroup`, so if the group has an event\r\n * handler, it will handle events from any of the layers. This includes mouse events\r\n * and custom events.\r\n *  * Has `layeradd` and `layerremove` events\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.featureGroup([marker1, marker2, polyline])\r\n * \t.bindPopup('Hello world!')\r\n * \t.on('click', function() { alert('Clicked on a member of the group!'); })\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nL.FeatureGroup = L.LayerGroup.extend({\r\n\r\n\taddLayer: function (layer) {\r\n\t\tif (this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlayer.addEventParent(this);\r\n\r\n\t\tL.LayerGroup.prototype.addLayer.call(this, layer);\r\n\r\n\t\t// @event layeradd: LayerEvent\r\n\t\t// Fired when a layer is added to this `FeatureGroup`\r\n\t\treturn this.fire('layeradd', {layer: layer});\r\n\t},\r\n\r\n\tremoveLayer: function (layer) {\r\n\t\tif (!this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tif (layer in this._layers) {\r\n\t\t\tlayer = this._layers[layer];\r\n\t\t}\r\n\r\n\t\tlayer.removeEventParent(this);\r\n\r\n\t\tL.LayerGroup.prototype.removeLayer.call(this, layer);\r\n\r\n\t\t// @event layerremove: LayerEvent\r\n\t\t// Fired when a layer is removed from this `FeatureGroup`\r\n\t\treturn this.fire('layerremove', {layer: layer});\r\n\t},\r\n\r\n\t// @method setStyle(style: Path options): this\r\n\t// Sets the given path options to each layer of the group that has a `setStyle` method.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.invoke('setStyle', style);\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer group to the top of all other layers\r\n\tbringToFront: function () {\r\n\t\treturn this.invoke('bringToFront');\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer group to the top of all other layers\r\n\tbringToBack: function () {\r\n\t\treturn this.invoke('bringToBack');\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).\r\n\tgetBounds: function () {\r\n\t\tvar bounds = new L.LatLngBounds();\r\n\r\n\t\tfor (var id in this._layers) {\r\n\t\t\tvar layer = this._layers[id];\r\n\t\t\tbounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());\r\n\t\t}\r\n\t\treturn bounds;\r\n\t}\r\n});\r\n\r\n// @factory L.featureGroup(layers: Layer[])\r\n// Create a feature group, optionally given an initial set of layers.\r\nL.featureGroup = function (layers) {\r\n\treturn new L.FeatureGroup(layers);\r\n};\r\n","/*\n * @class Renderer\n * @inherits Layer\n * @aka L.Renderer\n *\n * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the\n * DOM container of the renderer, its bounds, and its zoom animation.\n *\n * A `Renderer` works as an implicit layer group for all `Path`s - the renderer\n * itself can be added or removed to the map. All paths use a renderer, which can\n * be implicit (the map will decide the type of renderer and use it automatically)\n * or explicit (using the [`renderer`](#path-renderer) option of the path).\n *\n * Do not use this class directly, use `SVG` and `Canvas` instead.\n *\n * @event update: Event\n * Fired when the renderer updates its bounds, center and zoom, for example when\n * its map has moved\n */\n\nL.Renderer = L.Layer.extend({\n\n\t// @section\n\t// @aka Renderer options\n\toptions: {\n\t\t// @option padding: Number = 0.1\n\t\t// How much to extend the clip area around the map view (relative to its size)\n\t\t// e.g. 0.1 would be 10% of map view in each direction\n\t\tpadding: 0.1\n\t},\n\n\tinitialize: function (options) {\n\t\tL.setOptions(this, options);\n\t\tL.stamp(this);\n\t\tthis._layers = this._layers || {};\n\t},\n\n\tonAdd: function () {\n\t\tif (!this._container) {\n\t\t\tthis._initContainer(); // defined by renderer implementations\n\n\t\t\tif (this._zoomAnimated) {\n\t\t\t\tL.DomUtil.addClass(this._container, 'leaflet-zoom-animated');\n\t\t\t}\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t\tthis._update();\n\t\tthis.on('update', this._updatePaths, this);\n\t},\n\n\tonRemove: function () {\n\t\tL.DomUtil.remove(this._container);\n\t\tthis.off('update', this._updatePaths, this);\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewreset: this._reset,\n\t\t\tzoom: this._onZoom,\n\t\t\tmoveend: this._update,\n\t\t\tzoomend: this._onZoomEnd\n\t\t};\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._onAnimZoom;\n\t\t}\n\t\treturn events;\n\t},\n\n\t_onAnimZoom: function (ev) {\n\t\tthis._updateTransform(ev.center, ev.zoom);\n\t},\n\n\t_onZoom: function () {\n\t\tthis._updateTransform(this._map.getCenter(), this._map.getZoom());\n\t},\n\n\t_updateTransform: function (center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, this._zoom),\n\t\t    position = L.DomUtil.getPosition(this._container),\n\t\t    viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),\n\t\t    currentCenterPoint = this._map.project(this._center, zoom),\n\t\t    destCenterPoint = this._map.project(center, zoom),\n\t\t    centerOffset = destCenterPoint.subtract(currentCenterPoint),\n\n\t\t    topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);\n\n\t\tif (L.Browser.any3d) {\n\t\t\tL.DomUtil.setTransform(this._container, topLeftOffset, scale);\n\t\t} else {\n\t\t\tL.DomUtil.setPosition(this._container, topLeftOffset);\n\t\t}\n\t},\n\n\t_reset: function () {\n\t\tthis._update();\n\t\tthis._updateTransform(this._center, this._zoom);\n\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._reset();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._project();\n\t\t}\n\t},\n\n\t_updatePaths: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._update();\n\t\t}\n\t},\n\n\t_update: function () {\n\t\t// Update pixel bounds of renderer container (for positioning/sizing/clipping later)\n\t\t// Subclasses are responsible of firing the 'update' event.\n\t\tvar p = this.options.padding,\n\t\t    size = this._map.getSize(),\n\t\t    min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();\n\n\t\tthis._bounds = new L.Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());\n\n\t\tthis._center = this._map.getCenter();\n\t\tthis._zoom = this._map.getZoom();\n\t}\n});\n\n\nL.Map.include({\n\t// @namespace Map; @method getRenderer(layer: Path): Renderer\n\t// Returns the instance of `Renderer` that should be used to render the given\n\t// `Path`. It will ensure that the `renderer` options of the map and paths\n\t// are respected, and that the renderers do exist on the map.\n\tgetRenderer: function (layer) {\n\t\t// @namespace Path; @option renderer: Renderer\n\t\t// Use this specific instance of `Renderer` for this path. Takes\n\t\t// precedence over the map's [default renderer](#map-renderer).\n\t\tvar renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;\n\n\t\tif (!renderer) {\n\t\t\t// @namespace Map; @option preferCanvas: Boolean = false\n\t\t\t// Whether `Path`s should be rendered on a `Canvas` renderer.\n\t\t\t// By default, all `Path`s are rendered in a `SVG` renderer.\n\t\t\trenderer = this._renderer = (this.options.preferCanvas && L.canvas()) || L.svg();\n\t\t}\n\n\t\tif (!this.hasLayer(renderer)) {\n\t\t\tthis.addLayer(renderer);\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_getPaneRenderer: function (name) {\n\t\tif (name === 'overlayPane' || name === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar renderer = this._paneRenderers[name];\n\t\tif (renderer === undefined) {\n\t\t\trenderer = (L.SVG && L.svg({pane: name})) || (L.Canvas && L.canvas({pane: name}));\n\t\t\tthis._paneRenderers[name] = renderer;\n\t\t}\n\t\treturn renderer;\n\t}\n});\n","/*\n * @class Path\n * @aka L.Path\n * @inherits Interactive layer\n *\n * An abstract class that contains options and constants shared between vector\n * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.\n */\n\nL.Path = L.Layer.extend({\n\n\t// @section\n\t// @aka Path options\n\toptions: {\n\t\t// @option stroke: Boolean = true\n\t\t// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.\n\t\tstroke: true,\n\n\t\t// @option color: String = '#3388ff'\n\t\t// Stroke color\n\t\tcolor: '#3388ff',\n\n\t\t// @option weight: Number = 3\n\t\t// Stroke width in pixels\n\t\tweight: 3,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Stroke opacity\n\t\topacity: 1,\n\n\t\t// @option lineCap: String= 'round'\n\t\t// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.\n\t\tlineCap: 'round',\n\n\t\t// @option lineJoin: String = 'round'\n\t\t// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.\n\t\tlineJoin: 'round',\n\n\t\t// @option dashArray: String = null\n\t\t// 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).\n\t\tdashArray: null,\n\n\t\t// @option dashOffset: String = null\n\t\t// 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).\n\t\tdashOffset: null,\n\n\t\t// @option fill: Boolean = depends\n\t\t// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.\n\t\tfill: false,\n\n\t\t// @option fillColor: String = *\n\t\t// Fill color. Defaults to the value of the [`color`](#path-color) option\n\t\tfillColor: null,\n\n\t\t// @option fillOpacity: Number = 0.2\n\t\t// Fill opacity.\n\t\tfillOpacity: 0.2,\n\n\t\t// @option fillRule: String = 'evenodd'\n\t\t// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.\n\t\tfillRule: 'evenodd',\n\n\t\t// className: '',\n\n\t\t// Option inherited from \"Interactive layer\" abstract class\n\t\tinteractive: true\n\t},\n\n\tbeforeAdd: function (map) {\n\t\t// Renderer is set here because we need to call renderer.getEvents\n\t\t// before this.getEvents.\n\t\tthis._renderer = map.getRenderer(this);\n\t},\n\n\tonAdd: function () {\n\t\tthis._renderer._initPath(this);\n\t\tthis._reset();\n\t\tthis._renderer._addPath(this);\n\t},\n\n\tonRemove: function () {\n\t\tthis._renderer._removePath(this);\n\t},\n\n\t// @method redraw(): this\n\t// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._renderer._updatePath(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method setStyle(style: Path options): this\n\t// Changes the appearance of a Path based on the options in the `Path options` object.\n\tsetStyle: function (style) {\n\t\tL.setOptions(this, style);\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._updateStyle(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToFront(): this\n\t// Brings the layer to the top of all path layers.\n\tbringToFront: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToFront(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack(): this\n\t// Brings the layer to the bottom of all path layers.\n\tbringToBack: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToBack(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetElement: function () {\n\t\treturn this._path;\n\t},\n\n\t_reset: function () {\n\t\t// defined in children classes\n\t\tthis._project();\n\t\tthis._update();\n\t},\n\n\t_clickTolerance: function () {\n\t\t// used when doing hit detection for Canvas layers\n\t\treturn (this.options.stroke ? this.options.weight / 2 : 0) + (L.Browser.touch ? 10 : 0);\n\t}\n});\n","/*\r\n * @namespace LineUtil\r\n *\r\n * Various utility functions for polyine points processing, used by Leaflet internally to make polylines lightning-fast.\r\n */\r\n\r\nL.LineUtil = {\r\n\r\n\t// Simplify polyline with vertex reduction and Douglas-Peucker simplification.\r\n\t// Improves rendering performance dramatically by lessening the number of points to draw.\r\n\r\n\t// @function simplify(points: Point[], tolerance: Number): Point[]\r\n\t// Dramatically reduces the number of points in a polyline while retaining\r\n\t// its shape and returns a new array of simplified points, using the\r\n\t// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).\r\n\t// Used for a huge performance boost when processing/displaying Leaflet polylines for\r\n\t// each zoom level and also reducing visual noise. tolerance affects the amount of\r\n\t// simplification (lesser value means higher quality but slower and with more points).\r\n\t// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).\r\n\tsimplify: function (points, tolerance) {\r\n\t\tif (!tolerance || !points.length) {\r\n\t\t\treturn points.slice();\r\n\t\t}\r\n\r\n\t\tvar sqTolerance = tolerance * tolerance;\r\n\r\n\t\t// stage 1: vertex reduction\r\n\t\tpoints = this._reducePoints(points, sqTolerance);\r\n\r\n\t\t// stage 2: Douglas-Peucker simplification\r\n\t\tpoints = this._simplifyDP(points, sqTolerance);\r\n\r\n\t\treturn points;\r\n\t},\r\n\r\n\t// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number\r\n\t// Returns the distance between point `p` and segment `p1` to `p2`.\r\n\tpointToSegmentDistance:  function (p, p1, p2) {\r\n\t\treturn Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true));\r\n\t},\r\n\r\n\t// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number\r\n\t// Returns the closest point from a point `p` on a segment `p1` to `p2`.\r\n\tclosestPointOnSegment: function (p, p1, p2) {\r\n\t\treturn this._sqClosestPointOnSegment(p, p1, p2);\r\n\t},\r\n\r\n\t// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm\r\n\t_simplifyDP: function (points, sqTolerance) {\r\n\r\n\t\tvar len = points.length,\r\n\t\t    ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,\r\n\t\t    markers = new ArrayConstructor(len);\r\n\r\n\t\tmarkers[0] = markers[len - 1] = 1;\r\n\r\n\t\tthis._simplifyDPStep(points, markers, sqTolerance, 0, len - 1);\r\n\r\n\t\tvar i,\r\n\t\t    newPoints = [];\r\n\r\n\t\tfor (i = 0; i < len; i++) {\r\n\t\t\tif (markers[i]) {\r\n\t\t\t\tnewPoints.push(points[i]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn newPoints;\r\n\t},\r\n\r\n\t_simplifyDPStep: function (points, markers, sqTolerance, first, last) {\r\n\r\n\t\tvar maxSqDist = 0,\r\n\t\t    index, i, sqDist;\r\n\r\n\t\tfor (i = first + 1; i <= last - 1; i++) {\r\n\t\t\tsqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true);\r\n\r\n\t\t\tif (sqDist > maxSqDist) {\r\n\t\t\t\tindex = i;\r\n\t\t\t\tmaxSqDist = sqDist;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (maxSqDist > sqTolerance) {\r\n\t\t\tmarkers[index] = 1;\r\n\r\n\t\t\tthis._simplifyDPStep(points, markers, sqTolerance, first, index);\r\n\t\t\tthis._simplifyDPStep(points, markers, sqTolerance, index, last);\r\n\t\t}\r\n\t},\r\n\r\n\t// reduce points that are too close to each other to a single point\r\n\t_reducePoints: function (points, sqTolerance) {\r\n\t\tvar reducedPoints = [points[0]];\r\n\r\n\t\tfor (var i = 1, prev = 0, len = points.length; i < len; i++) {\r\n\t\t\tif (this._sqDist(points[i], points[prev]) > sqTolerance) {\r\n\t\t\t\treducedPoints.push(points[i]);\r\n\t\t\t\tprev = i;\r\n\t\t\t}\r\n\t\t}\r\n\t\tif (prev < len - 1) {\r\n\t\t\treducedPoints.push(points[len - 1]);\r\n\t\t}\r\n\t\treturn reducedPoints;\r\n\t},\r\n\r\n\r\n\t// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean\r\n\t// Clips the segment a to b by rectangular bounds with the\r\n\t// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)\r\n\t// (modifying the segment points directly!). Used by Leaflet to only show polyline\r\n\t// points that are on the screen or near, increasing performance.\r\n\tclipSegment: function (a, b, bounds, useLastCode, round) {\r\n\t\tvar codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds),\r\n\t\t    codeB = this._getBitCode(b, bounds),\r\n\r\n\t\t    codeOut, p, newCode;\r\n\r\n\t\t// save 2nd code to avoid calculating it on the next segment\r\n\t\tthis._lastCode = codeB;\r\n\r\n\t\twhile (true) {\r\n\t\t\t// if a,b is inside the clip window (trivial accept)\r\n\t\t\tif (!(codeA | codeB)) {\r\n\t\t\t\treturn [a, b];\r\n\t\t\t}\r\n\r\n\t\t\t// if a,b is outside the clip window (trivial reject)\r\n\t\t\tif (codeA & codeB) {\r\n\t\t\t\treturn false;\r\n\t\t\t}\r\n\r\n\t\t\t// other cases\r\n\t\t\tcodeOut = codeA || codeB;\r\n\t\t\tp = this._getEdgeIntersection(a, b, codeOut, bounds, round);\r\n\t\t\tnewCode = this._getBitCode(p, bounds);\r\n\r\n\t\t\tif (codeOut === codeA) {\r\n\t\t\t\ta = p;\r\n\t\t\t\tcodeA = newCode;\r\n\t\t\t} else {\r\n\t\t\t\tb = p;\r\n\t\t\t\tcodeB = newCode;\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_getEdgeIntersection: function (a, b, code, bounds, round) {\r\n\t\tvar dx = b.x - a.x,\r\n\t\t    dy = b.y - a.y,\r\n\t\t    min = bounds.min,\r\n\t\t    max = bounds.max,\r\n\t\t    x, y;\r\n\r\n\t\tif (code & 8) { // top\r\n\t\t\tx = a.x + dx * (max.y - a.y) / dy;\r\n\t\t\ty = max.y;\r\n\r\n\t\t} else if (code & 4) { // bottom\r\n\t\t\tx = a.x + dx * (min.y - a.y) / dy;\r\n\t\t\ty = min.y;\r\n\r\n\t\t} else if (code & 2) { // right\r\n\t\t\tx = max.x;\r\n\t\t\ty = a.y + dy * (max.x - a.x) / dx;\r\n\r\n\t\t} else if (code & 1) { // left\r\n\t\t\tx = min.x;\r\n\t\t\ty = a.y + dy * (min.x - a.x) / dx;\r\n\t\t}\r\n\r\n\t\treturn new L.Point(x, y, round);\r\n\t},\r\n\r\n\t_getBitCode: function (p, bounds) {\r\n\t\tvar code = 0;\r\n\r\n\t\tif (p.x < bounds.min.x) { // left\r\n\t\t\tcode |= 1;\r\n\t\t} else if (p.x > bounds.max.x) { // right\r\n\t\t\tcode |= 2;\r\n\t\t}\r\n\r\n\t\tif (p.y < bounds.min.y) { // bottom\r\n\t\t\tcode |= 4;\r\n\t\t} else if (p.y > bounds.max.y) { // top\r\n\t\t\tcode |= 8;\r\n\t\t}\r\n\r\n\t\treturn code;\r\n\t},\r\n\r\n\t// square distance (to avoid unnecessary Math.sqrt calls)\r\n\t_sqDist: function (p1, p2) {\r\n\t\tvar dx = p2.x - p1.x,\r\n\t\t    dy = p2.y - p1.y;\r\n\t\treturn dx * dx + dy * dy;\r\n\t},\r\n\r\n\t// return closest point on segment or distance to that point\r\n\t_sqClosestPointOnSegment: function (p, p1, p2, sqDist) {\r\n\t\tvar x = p1.x,\r\n\t\t    y = p1.y,\r\n\t\t    dx = p2.x - x,\r\n\t\t    dy = p2.y - y,\r\n\t\t    dot = dx * dx + dy * dy,\r\n\t\t    t;\r\n\r\n\t\tif (dot > 0) {\r\n\t\t\tt = ((p.x - x) * dx + (p.y - y) * dy) / dot;\r\n\r\n\t\t\tif (t > 1) {\r\n\t\t\t\tx = p2.x;\r\n\t\t\t\ty = p2.y;\r\n\t\t\t} else if (t > 0) {\r\n\t\t\t\tx += dx * t;\r\n\t\t\t\ty += dy * t;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tdx = p.x - x;\r\n\t\tdy = p.y - y;\r\n\r\n\t\treturn sqDist ? dx * dx + dy * dy : new L.Point(x, y);\r\n\t}\r\n};\r\n","/*\n * @class Polyline\n * @aka L.Polyline\n * @inherits Path\n *\n * A class for drawing polyline overlays on a map. Extends `Path`.\n *\n * @example\n *\n * ```js\n * // create a red polyline from an array of LatLng points\n * var latlngs = [\n * \t[45.51, -122.68],\n * \t[37.77, -122.43],\n * \t[34.04, -118.2]\n * ];\n *\n * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polyline\n * map.fitBounds(polyline.getBounds());\n * ```\n *\n * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:\n *\n * ```js\n * // create a red polyline from an array of arrays of LatLng points\n * var latlngs = [\n * \t[[45.51, -122.68],\n * \t [37.77, -122.43],\n * \t [34.04, -118.2]],\n * \t[[40.78, -73.91],\n * \t [41.83, -87.62],\n * \t [32.76, -96.72]]\n * ];\n * ```\n */\n\nL.Polyline = L.Path.extend({\n\n\t// @section\n\t// @aka Polyline options\n\toptions: {\n\t\t// @option smoothFactor: Number = 1.0\n\t\t// How much to simplify the polyline on each zoom level. More means\n\t\t// better performance and smoother look, and less means more accurate representation.\n\t\tsmoothFactor: 1.0,\n\n\t\t// @option noClip: Boolean = false\n\t\t// Disable polyline clipping.\n\t\tnoClip: false\n\t},\n\n\tinitialize: function (latlngs, options) {\n\t\tL.setOptions(this, options);\n\t\tthis._setLatLngs(latlngs);\n\t},\n\n\t// @method getLatLngs(): LatLng[]\n\t// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.\n\tgetLatLngs: function () {\n\t\treturn this._latlngs;\n\t},\n\n\t// @method setLatLngs(latlngs: LatLng[]): this\n\t// Replaces all the points in the polyline with the given array of geographical points.\n\tsetLatLngs: function (latlngs) {\n\t\tthis._setLatLngs(latlngs);\n\t\treturn this.redraw();\n\t},\n\n\t// @method isEmpty(): Boolean\n\t// Returns `true` if the Polyline has no LatLngs.\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length;\n\t},\n\n\tclosestLayerPoint: function (p) {\n\t\tvar minDistance = Infinity,\n\t\t    minPoint = null,\n\t\t    closest = L.LineUtil._sqClosestPointOnSegment,\n\t\t    p1, p2;\n\n\t\tfor (var j = 0, jLen = this._parts.length; j < jLen; j++) {\n\t\t\tvar points = this._parts[j];\n\n\t\t\tfor (var i = 1, len = points.length; i < len; i++) {\n\t\t\t\tp1 = points[i - 1];\n\t\t\t\tp2 = points[i];\n\n\t\t\t\tvar sqDist = closest(p, p1, p2, true);\n\n\t\t\t\tif (sqDist < minDistance) {\n\t\t\t\t\tminDistance = sqDist;\n\t\t\t\t\tminPoint = closest(p, p1, p2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (minPoint) {\n\t\t\tminPoint.distance = Math.sqrt(minDistance);\n\t\t}\n\t\treturn minPoint;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\n\t\tvar i, halfDist, segDist, dist, p1, p2, ratio,\n\t\t    points = this._rings[0],\n\t\t    len = points.length;\n\n\t\tif (!len) { return null; }\n\n\t\t// polyline centroid algorithm; only uses the first ring if there are multiple\n\n\t\tfor (i = 0, halfDist = 0; i < len - 1; i++) {\n\t\t\thalfDist += points[i].distanceTo(points[i + 1]) / 2;\n\t\t}\n\n\t\t// The line is so small in the current view that all points are on the same pixel.\n\t\tif (halfDist === 0) {\n\t\t\treturn this._map.layerPointToLatLng(points[0]);\n\t\t}\n\n\t\tfor (i = 0, dist = 0; i < len - 1; i++) {\n\t\t\tp1 = points[i];\n\t\t\tp2 = points[i + 1];\n\t\t\tsegDist = p1.distanceTo(p2);\n\t\t\tdist += segDist;\n\n\t\t\tif (dist > halfDist) {\n\t\t\t\tratio = (dist - halfDist) / segDist;\n\t\t\t\treturn this._map.layerPointToLatLng([\n\t\t\t\t\tp2.x - ratio * (p2.x - p1.x),\n\t\t\t\t\tp2.y - ratio * (p2.y - p1.y)\n\t\t\t\t]);\n\t\t\t}\n\t\t}\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\treturn this._bounds;\n\t},\n\n\t// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this\n\t// Adds a given point to the polyline. By default, adds to the first ring of\n\t// the polyline in case of a multi-polyline, but can be overridden by passing\n\t// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).\n\taddLatLng: function (latlng, latlngs) {\n\t\tlatlngs = latlngs || this._defaultShape();\n\t\tlatlng = L.latLng(latlng);\n\t\tlatlngs.push(latlng);\n\t\tthis._bounds.extend(latlng);\n\t\treturn this.redraw();\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tthis._bounds = new L.LatLngBounds();\n\t\tthis._latlngs = this._convertLatLngs(latlngs);\n\t},\n\n\t_defaultShape: function () {\n\t\treturn L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];\n\t},\n\n\t// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = [],\n\t\t    flat = L.Polyline._flat(latlngs);\n\n\t\tfor (var i = 0, len = latlngs.length; i < len; i++) {\n\t\t\tif (flat) {\n\t\t\t\tresult[i] = L.latLng(latlngs[i]);\n\t\t\t\tthis._bounds.extend(result[i]);\n\t\t\t} else {\n\t\t\t\tresult[i] = this._convertLatLngs(latlngs[i]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t},\n\n\t_project: function () {\n\t\tvar pxBounds = new L.Bounds();\n\t\tthis._rings = [];\n\t\tthis._projectLatlngs(this._latlngs, this._rings, pxBounds);\n\n\t\tvar w = this._clickTolerance(),\n\t\t    p = new L.Point(w, w);\n\n\t\tif (this._bounds.isValid() && pxBounds.isValid()) {\n\t\t\tpxBounds.min._subtract(p);\n\t\t\tpxBounds.max._add(p);\n\t\t\tthis._pxBounds = pxBounds;\n\t\t}\n\t},\n\n\t// recursively turns latlngs into a set of rings with projected coordinates\n\t_projectLatlngs: function (latlngs, result, projectedBounds) {\n\t\tvar flat = latlngs[0] instanceof L.LatLng,\n\t\t    len = latlngs.length,\n\t\t    i, ring;\n\n\t\tif (flat) {\n\t\t\tring = [];\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tring[i] = this._map.latLngToLayerPoint(latlngs[i]);\n\t\t\t\tprojectedBounds.extend(ring[i]);\n\t\t\t}\n\t\t\tresult.push(ring);\n\t\t} else {\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tthis._projectLatlngs(latlngs[i], result, projectedBounds);\n\t\t\t}\n\t\t}\n\t},\n\n\t// clip polyline by renderer bounds so that we have less to render for performance\n\t_clipPoints: function () {\n\t\tvar bounds = this._renderer._bounds;\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tvar parts = this._parts,\n\t\t    i, j, k, len, len2, segment, points;\n\n\t\tfor (i = 0, k = 0, len = this._rings.length; i < len; i++) {\n\t\t\tpoints = this._rings[i];\n\n\t\t\tfor (j = 0, len2 = points.length; j < len2 - 1; j++) {\n\t\t\t\tsegment = L.LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);\n\n\t\t\t\tif (!segment) { continue; }\n\n\t\t\t\tparts[k] = parts[k] || [];\n\t\t\t\tparts[k].push(segment[0]);\n\n\t\t\t\t// if segment goes out of screen, or it's the last one, it's the end of the line part\n\t\t\t\tif ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {\n\t\t\t\t\tparts[k].push(segment[1]);\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// simplify each clipped part of the polyline for performance\n\t_simplifyPoints: function () {\n\t\tvar parts = this._parts,\n\t\t    tolerance = this.options.smoothFactor;\n\n\t\tfor (var i = 0, len = parts.length; i < len; i++) {\n\t\t\tparts[i] = L.LineUtil.simplify(parts[i], tolerance);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tif (!this._map) { return; }\n\n\t\tthis._clipPoints();\n\t\tthis._simplifyPoints();\n\t\tthis._updatePath();\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this);\n\t}\n});\n\n// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)\n// Instantiates a polyline object given an array of geographical points and\n// optionally an options object. You can create a `Polyline` object with\n// multiple separate lines (`MultiPolyline`) by passing an array of arrays\n// of geographic points.\nL.polyline = function (latlngs, options) {\n\treturn new L.Polyline(latlngs, options);\n};\n\nL.Polyline._flat = function (latlngs) {\n\t// true if it's a flat array of latlngs; false if nested\n\treturn !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');\n};\n","/*\r\n * @namespace PolyUtil\r\n * Various utility functions for polygon geometries.\r\n */\r\n\r\nL.PolyUtil = {};\r\n\r\n/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]\r\n * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgeman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).\r\n * Used by Leaflet to only show polygon points that are on the screen or near, increasing\r\n * performance. Note that polygon points needs different algorithm for clipping\r\n * than polyline, so there's a seperate method for it.\r\n */\r\nL.PolyUtil.clipPolygon = function (points, bounds, round) {\r\n\tvar clippedPoints,\r\n\t    edges = [1, 4, 2, 8],\r\n\t    i, j, k,\r\n\t    a, b,\r\n\t    len, edge, p,\r\n\t    lu = L.LineUtil;\r\n\r\n\tfor (i = 0, len = points.length; i < len; i++) {\r\n\t\tpoints[i]._code = lu._getBitCode(points[i], bounds);\r\n\t}\r\n\r\n\t// for each edge (left, bottom, right, top)\r\n\tfor (k = 0; k < 4; k++) {\r\n\t\tedge = edges[k];\r\n\t\tclippedPoints = [];\r\n\r\n\t\tfor (i = 0, len = points.length, j = len - 1; i < len; j = i++) {\r\n\t\t\ta = points[i];\r\n\t\t\tb = points[j];\r\n\r\n\t\t\t// if a is inside the clip window\r\n\t\t\tif (!(a._code & edge)) {\r\n\t\t\t\t// if b is outside the clip window (a->b goes out of screen)\r\n\t\t\t\tif (b._code & edge) {\r\n\t\t\t\t\tp = lu._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\t\tp._code = lu._getBitCode(p, bounds);\r\n\t\t\t\t\tclippedPoints.push(p);\r\n\t\t\t\t}\r\n\t\t\t\tclippedPoints.push(a);\r\n\r\n\t\t\t// else if b is inside the clip window (a->b enters the screen)\r\n\t\t\t} else if (!(b._code & edge)) {\r\n\t\t\t\tp = lu._getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\tp._code = lu._getBitCode(p, bounds);\r\n\t\t\t\tclippedPoints.push(p);\r\n\t\t\t}\r\n\t\t}\r\n\t\tpoints = clippedPoints;\r\n\t}\r\n\r\n\treturn points;\r\n};\r\n","/*\n * @class Polygon\n * @aka L.Polygon\n * @inherits Polyline\n *\n * A class for drawing polygon overlays on a map. Extends `Polyline`.\n *\n * 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.\n *\n *\n * @example\n *\n * ```js\n * // create a red polygon from an array of LatLng points\n * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];\n *\n * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polygon\n * map.fitBounds(polygon.getBounds());\n * ```\n *\n * 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:\n *\n * ```js\n * var latlngs = [\n *   [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n *   [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ];\n * ```\n *\n * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.\n *\n * ```js\n * var latlngs = [\n *   [ // first polygon\n *     [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n *     [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n *   ],\n *   [ // second polygon\n *     [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]\n *   ]\n * ];\n * ```\n */\n\nL.Polygon = L.Polyline.extend({\n\n\toptions: {\n\t\tfill: true\n\t},\n\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length || !this._latlngs[0].length;\n\t},\n\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\n\t\tvar i, j, p1, p2, f, area, x, y, center,\n\t\t    points = this._rings[0],\n\t\t    len = points.length;\n\n\t\tif (!len) { return null; }\n\n\t\t// polygon centroid algorithm; only uses the first ring if there are multiple\n\n\t\tarea = x = y = 0;\n\n\t\tfor (i = 0, j = len - 1; i < len; j = i++) {\n\t\t\tp1 = points[i];\n\t\t\tp2 = points[j];\n\n\t\t\tf = p1.y * p2.x - p2.y * p1.x;\n\t\t\tx += (p1.x + p2.x) * f;\n\t\t\ty += (p1.y + p2.y) * f;\n\t\t\tarea += f * 3;\n\t\t}\n\n\t\tif (area === 0) {\n\t\t\t// Polygon is so small that all points are on same pixel.\n\t\t\tcenter = points[0];\n\t\t} else {\n\t\t\tcenter = [x / area, y / area];\n\t\t}\n\t\treturn this._map.layerPointToLatLng(center);\n\t},\n\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = L.Polyline.prototype._convertLatLngs.call(this, latlngs),\n\t\t    len = result.length;\n\n\t\t// remove last point if it equals first one\n\t\tif (len >= 2 && result[0] instanceof L.LatLng && result[0].equals(result[len - 1])) {\n\t\t\tresult.pop();\n\t\t}\n\t\treturn result;\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tL.Polyline.prototype._setLatLngs.call(this, latlngs);\n\t\tif (L.Polyline._flat(this._latlngs)) {\n\t\t\tthis._latlngs = [this._latlngs];\n\t\t}\n\t},\n\n\t_defaultShape: function () {\n\t\treturn L.Polyline._flat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];\n\t},\n\n\t_clipPoints: function () {\n\t\t// polygons need a different clipping algorithm so we redefine that\n\n\t\tvar bounds = this._renderer._bounds,\n\t\t    w = this.options.weight,\n\t\t    p = new L.Point(w, w);\n\n\t\t// increase clip padding by stroke width to avoid stroke on clip edges\n\t\tbounds = new L.Bounds(bounds.min.subtract(p), bounds.max.add(p));\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tfor (var i = 0, len = this._rings.length, clipped; i < len; i++) {\n\t\t\tclipped = L.PolyUtil.clipPolygon(this._rings[i], bounds, true);\n\t\t\tif (clipped.length) {\n\t\t\t\tthis._parts.push(clipped);\n\t\t\t}\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this, true);\n\t}\n});\n\n\n// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)\nL.polygon = function (latlngs, options) {\n\treturn new L.Polygon(latlngs, options);\n};\n","/*\n * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.\n */\n\n/*\n * @class Rectangle\n * @aka L.Retangle\n * @inherits Polygon\n *\n * A class for drawing rectangle overlays on a map. Extends `Polygon`.\n *\n * @example\n *\n * ```js\n * // define rectangle geographical bounds\n * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n *\n * // create an orange rectangle\n * L.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n *\n * // zoom the map to the rectangle bounds\n * map.fitBounds(bounds);\n * ```\n *\n */\n\n\nL.Rectangle = L.Polygon.extend({\n\tinitialize: function (latLngBounds, options) {\n\t\tL.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);\n\t},\n\n\t// @method setBounds(latLngBounds: LatLngBounds): this\n\t// Redraws the rectangle with the passed bounds.\n\tsetBounds: function (latLngBounds) {\n\t\treturn this.setLatLngs(this._boundsToLatLngs(latLngBounds));\n\t},\n\n\t_boundsToLatLngs: function (latLngBounds) {\n\t\tlatLngBounds = L.latLngBounds(latLngBounds);\n\t\treturn [\n\t\t\tlatLngBounds.getSouthWest(),\n\t\t\tlatLngBounds.getNorthWest(),\n\t\t\tlatLngBounds.getNorthEast(),\n\t\t\tlatLngBounds.getSouthEast()\n\t\t];\n\t}\n});\n\n\n// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)\nL.rectangle = function (latLngBounds, options) {\n\treturn new L.Rectangle(latLngBounds, options);\n};\n","/*\n * @class CircleMarker\n * @aka L.CircleMarker\n * @inherits Path\n *\n * A circle of a fixed size with radius specified in pixels. Extends `Path`.\n */\n\nL.CircleMarker = L.Path.extend({\n\n\t// @section\n\t// @aka CircleMarker options\n\toptions: {\n\t\tfill: true,\n\n\t\t// @option radius: Number = 10\n\t\t// Radius of the circle marker, in pixels\n\t\tradius: 10\n\t},\n\n\tinitialize: function (latlng, options) {\n\t\tL.setOptions(this, options);\n\t\tthis._latlng = L.latLng(latlng);\n\t\tthis._radius = this.options.radius;\n\t},\n\n\t// @method setLatLng(latLng: LatLng): this\n\t// Sets the position of a circle marker to a new location.\n\tsetLatLng: function (latlng) {\n\t\tthis._latlng = L.latLng(latlng);\n\t\tthis.redraw();\n\t\treturn this.fire('move', {latlng: this._latlng});\n\t},\n\n\t// @method getLatLng(): LatLng\n\t// Returns the current geographical position of the circle marker\n\tgetLatLng: function () {\n\t\treturn this._latlng;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle marker. Units are in pixels.\n\tsetRadius: function (radius) {\n\t\tthis.options.radius = this._radius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of the circle\n\tgetRadius: function () {\n\t\treturn this._radius;\n\t},\n\n\tsetStyle : function (options) {\n\t\tvar radius = options && options.radius || this._radius;\n\t\tL.Path.prototype.setStyle.call(this, options);\n\t\tthis.setRadius(radius);\n\t\treturn this;\n\t},\n\n\t_project: function () {\n\t\tthis._point = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._updateBounds();\n\t},\n\n\t_updateBounds: function () {\n\t\tvar r = this._radius,\n\t\t    r2 = this._radiusY || r,\n\t\t    w = this._clickTolerance(),\n\t\t    p = [r + w, r2 + w];\n\t\tthis._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));\n\t},\n\n\t_update: function () {\n\t\tif (this._map) {\n\t\t\tthis._updatePath();\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updateCircle(this);\n\t},\n\n\t_empty: function () {\n\t\treturn this._radius && !this._renderer._bounds.intersects(this._pxBounds);\n\t}\n});\n\n\n// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)\n// Instantiates a circle marker object given a geographical point, and an optional options object.\nL.circleMarker = function (latlng, options) {\n\treturn new L.CircleMarker(latlng, options);\n};\n","/*\n * @class Circle\n * @aka L.Circle\n * @inherits CircleMarker\n *\n * A class for drawing circle overlays on a map. Extends `CircleMarker`.\n *\n * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).\n *\n * @example\n *\n * ```js\n * L.circle([50.5, 30.5], {radius: 200}).addTo(map);\n * ```\n */\n\nL.Circle = L.CircleMarker.extend({\n\n\tinitialize: function (latlng, options, legacyOptions) {\n\t\tif (typeof options === 'number') {\n\t\t\t// Backwards compatibility with 0.7.x factory (latlng, radius, options?)\n\t\t\toptions = L.extend({}, legacyOptions, {radius: options});\n\t\t}\n\t\tL.setOptions(this, options);\n\t\tthis._latlng = L.latLng(latlng);\n\n\t\tif (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }\n\n\t\t// @section\n\t\t// @aka Circle options\n\t\t// @option radius: Number; Radius of the circle, in meters.\n\t\tthis._mRadius = this.options.radius;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle. Units are in meters.\n\tsetRadius: function (radius) {\n\t\tthis._mRadius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of a circle. Units are in meters.\n\tgetRadius: function () {\n\t\treturn this._mRadius;\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\tvar half = [this._radius, this._radiusY || this._radius];\n\n\t\treturn new L.LatLngBounds(\n\t\t\tthis._map.layerPointToLatLng(this._point.subtract(half)),\n\t\t\tthis._map.layerPointToLatLng(this._point.add(half)));\n\t},\n\n\tsetStyle: L.Path.prototype.setStyle,\n\n\t_project: function () {\n\n\t\tvar lng = this._latlng.lng,\n\t\t    lat = this._latlng.lat,\n\t\t    map = this._map,\n\t\t    crs = map.options.crs;\n\n\t\tif (crs.distance === L.CRS.Earth.distance) {\n\t\t\tvar d = Math.PI / 180,\n\t\t\t    latR = (this._mRadius / L.CRS.Earth.R) / d,\n\t\t\t    top = map.project([lat + latR, lng]),\n\t\t\t    bottom = map.project([lat - latR, lng]),\n\t\t\t    p = top.add(bottom).divideBy(2),\n\t\t\t    lat2 = map.unproject(p).lat,\n\t\t\t    lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /\n\t\t\t            (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;\n\n\t\t\tif (isNaN(lngR) || lngR === 0) {\n\t\t\t\tlngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425\n\t\t\t}\n\n\t\t\tthis._point = p.subtract(map.getPixelOrigin());\n\t\t\tthis._radius = isNaN(lngR) ? 0 : Math.max(Math.round(p.x - map.project([lat2, lng - lngR]).x), 1);\n\t\t\tthis._radiusY = Math.max(Math.round(p.y - top.y), 1);\n\n\t\t} else {\n\t\t\tvar latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));\n\n\t\t\tthis._point = map.latLngToLayerPoint(this._latlng);\n\t\t\tthis._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;\n\t\t}\n\n\t\tthis._updateBounds();\n\t}\n});\n\n// @factory L.circle(latlng: LatLng, options?: Circle options)\n// Instantiates a circle object given a geographical point, and an options object\n// which contains the circle radius.\n// @alternative\n// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)\n// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.\n// Do not use in new applications or plugins.\nL.circle = function (latlng, options, legacyOptions) {\n\treturn new L.Circle(latlng, options, legacyOptions);\n};\n","/*\n * @class SVG\n * @inherits Renderer\n * @aka L.SVG\n *\n * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not\n * available in all web browsers, notably Android 2.x and 3.x.\n *\n * Although SVG is not available on IE7 and IE8, these browsers support\n * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)\n * (a now deprecated technology), and the SVG renderer will fall back to VML in\n * this case.\n *\n * @example\n *\n * Use SVG by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.svg()\n * });\n * ```\n *\n * Use a SVG renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.svg({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nL.SVG = L.Renderer.extend({\n\n\tgetEvents: function () {\n\t\tvar events = L.Renderer.prototype.getEvents.call(this);\n\t\tevents.zoomstart = this._onZoomStart;\n\t\treturn events;\n\t},\n\n\t_initContainer: function () {\n\t\tthis._container = L.SVG.create('svg');\n\n\t\t// makes it possible to click through svg root; we'll reset it back in individual paths\n\t\tthis._container.setAttribute('pointer-events', 'none');\n\n\t\tthis._rootGroup = L.SVG.create('g');\n\t\tthis._container.appendChild(this._rootGroup);\n\t},\n\n\t_onZoomStart: function () {\n\t\t// Drag-then-pinch interactions might mess up the center and zoom.\n\t\t// In this case, the easiest way to prevent this is re-do the renderer\n\t\t//   bounds and padding when the zooming starts.\n\t\tthis._update();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tL.Renderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t    size = b.getSize(),\n\t\t    container = this._container;\n\n\t\t// set size of svg-container if changed\n\t\tif (!this._svgSize || !this._svgSize.equals(size)) {\n\t\t\tthis._svgSize = size;\n\t\t\tcontainer.setAttribute('width', size.x);\n\t\t\tcontainer.setAttribute('height', size.y);\n\t\t}\n\n\t\t// movement: update container viewBox so that we don't have to change coordinates of individual layers\n\t\tL.DomUtil.setPosition(container, b.min);\n\t\tcontainer.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));\n\n\t\tthis.fire('update');\n\t},\n\n\t// methods below are called by vector layers implementations\n\n\t_initPath: function (layer) {\n\t\tvar path = layer._path = L.SVG.create('path');\n\n\t\t// @namespace Path\n\t\t// @option className: String = null\n\t\t// Custom class name set on an element. Only for SVG renderer.\n\t\tif (layer.options.className) {\n\t\t\tL.DomUtil.addClass(path, layer.options.className);\n\t\t}\n\n\t\tif (layer.options.interactive) {\n\t\t\tL.DomUtil.addClass(path, 'leaflet-interactive');\n\t\t}\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[L.stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tthis._rootGroup.appendChild(layer._path);\n\t\tlayer.addInteractiveTarget(layer._path);\n\t},\n\n\t_removePath: function (layer) {\n\t\tL.DomUtil.remove(layer._path);\n\t\tlayer.removeInteractiveTarget(layer._path);\n\t\tdelete this._layers[L.stamp(layer)];\n\t},\n\n\t_updatePath: function (layer) {\n\t\tlayer._project();\n\t\tlayer._update();\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar path = layer._path,\n\t\t    options = layer.options;\n\n\t\tif (!path) { return; }\n\n\t\tif (options.stroke) {\n\t\t\tpath.setAttribute('stroke', options.color);\n\t\t\tpath.setAttribute('stroke-opacity', options.opacity);\n\t\t\tpath.setAttribute('stroke-width', options.weight);\n\t\t\tpath.setAttribute('stroke-linecap', options.lineCap);\n\t\t\tpath.setAttribute('stroke-linejoin', options.lineJoin);\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tpath.setAttribute('stroke-dasharray', options.dashArray);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dasharray');\n\t\t\t}\n\n\t\t\tif (options.dashOffset) {\n\t\t\t\tpath.setAttribute('stroke-dashoffset', options.dashOffset);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dashoffset');\n\t\t\t}\n\t\t} else {\n\t\t\tpath.setAttribute('stroke', 'none');\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tpath.setAttribute('fill', options.fillColor || options.color);\n\t\t\tpath.setAttribute('fill-opacity', options.fillOpacity);\n\t\t\tpath.setAttribute('fill-rule', options.fillRule || 'evenodd');\n\t\t} else {\n\t\t\tpath.setAttribute('fill', 'none');\n\t\t}\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tthis._setPath(layer, L.SVG.pointsToPath(layer._parts, closed));\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point,\n\t\t    r = layer._radius,\n\t\t    r2 = layer._radiusY || r,\n\t\t    arc = 'a' + r + ',' + r2 + ' 0 1,0 ';\n\n\t\t// drawing a circle with two half-arcs\n\t\tvar d = layer._empty() ? 'M0 0' :\n\t\t\t\t'M' + (p.x - r) + ',' + p.y +\n\t\t\t\tarc + (r * 2) + ',0 ' +\n\t\t\t\tarc + (-r * 2) + ',0 ';\n\n\t\tthis._setPath(layer, d);\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.setAttribute('d', path);\n\t},\n\n\t// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements\n\t_bringToFront: function (layer) {\n\t\tL.DomUtil.toFront(layer._path);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tL.DomUtil.toBack(layer._path);\n\t}\n});\n\n\n// @namespace SVG; @section\n// There are several static functions which can be called without instantiating L.SVG:\nL.extend(L.SVG, {\n\t// @function create(name: String): SVGElement\n\t// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),\n\t// corresponding to the class name passed. For example, using 'line' will return\n\t// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).\n\tcreate: function (name) {\n\t\treturn document.createElementNS('http://www.w3.org/2000/svg', name);\n\t},\n\n\t// @function pointsToPath(rings: Point[], closed: Boolean): String\n\t// Generates a SVG path string for multiple rings, with each ring turning\n\t// into \"M..L..L..\" instructions\n\tpointsToPath: function (rings, closed) {\n\t\tvar str = '',\n\t\t    i, j, len, len2, points, p;\n\n\t\tfor (i = 0, len = rings.length; i < len; i++) {\n\t\t\tpoints = rings[i];\n\n\t\t\tfor (j = 0, len2 = points.length; j < len2; j++) {\n\t\t\t\tp = points[j];\n\t\t\t\tstr += (j ? 'L' : 'M') + p.x + ' ' + p.y;\n\t\t\t}\n\n\t\t\t// closes the ring for polygons; \"x\" is VML syntax\n\t\t\tstr += closed ? (L.Browser.svg ? 'z' : 'x') : '';\n\t\t}\n\n\t\t// SVG complains about empty path strings\n\t\treturn str || 'M0 0';\n\t}\n});\n\n// @namespace Browser; @property svg: Boolean\n// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).\nL.Browser.svg = !!(document.createElementNS && L.SVG.create('svg').createSVGRect);\n\n\n// @namespace SVG\n// @factory L.svg(options?: Renderer options)\n// Creates a SVG renderer with the given options.\nL.svg = function (options) {\n\treturn L.Browser.svg || L.Browser.vml ? new L.SVG(options) : null;\n};\n","/*\n * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!\n */\n\n/*\n * @class SVG\n *\n * Although SVG is not available on IE7 and IE8, these browsers support [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language), and the SVG renderer will fall back to VML in this case.\n *\n * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility\n * with old versions of Internet Explorer.\n */\n\n// @namespace Browser; @property vml: Boolean\n// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).\nL.Browser.vml = !L.Browser.svg && (function () {\n\ttry {\n\t\tvar div = document.createElement('div');\n\t\tdiv.innerHTML = '<v:shape adj=\"1\"/>';\n\n\t\tvar shape = div.firstChild;\n\t\tshape.style.behavior = 'url(#default#VML)';\n\n\t\treturn shape && (typeof shape.adj === 'object');\n\n\t} catch (e) {\n\t\treturn false;\n\t}\n}());\n\n// redefine some SVG methods to handle VML syntax which is similar but with some differences\nL.SVG.include(!L.Browser.vml ? {} : {\n\n\t_initContainer: function () {\n\t\tthis._container = L.DomUtil.create('div', 'leaflet-vml-container');\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom) { return; }\n\t\tL.Renderer.prototype._update.call(this);\n\t\tthis.fire('update');\n\t},\n\n\t_initPath: function (layer) {\n\t\tvar container = layer._container = L.SVG.create('shape');\n\n\t\tL.DomUtil.addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));\n\n\t\tcontainer.coordsize = '1 1';\n\n\t\tlayer._path = L.SVG.create('path');\n\t\tcontainer.appendChild(layer._path);\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[L.stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tvar container = layer._container;\n\t\tthis._container.appendChild(container);\n\n\t\tif (layer.options.interactive) {\n\t\t\tlayer.addInteractiveTarget(container);\n\t\t}\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar container = layer._container;\n\t\tL.DomUtil.remove(container);\n\t\tlayer.removeInteractiveTarget(container);\n\t\tdelete this._layers[L.stamp(layer)];\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar stroke = layer._stroke,\n\t\t    fill = layer._fill,\n\t\t    options = layer.options,\n\t\t    container = layer._container;\n\n\t\tcontainer.stroked = !!options.stroke;\n\t\tcontainer.filled = !!options.fill;\n\n\t\tif (options.stroke) {\n\t\t\tif (!stroke) {\n\t\t\t\tstroke = layer._stroke = L.SVG.create('stroke');\n\t\t\t}\n\t\t\tcontainer.appendChild(stroke);\n\t\t\tstroke.weight = options.weight + 'px';\n\t\t\tstroke.color = options.color;\n\t\t\tstroke.opacity = options.opacity;\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tstroke.dashStyle = L.Util.isArray(options.dashArray) ?\n\t\t\t\t    options.dashArray.join(' ') :\n\t\t\t\t    options.dashArray.replace(/( *, *)/g, ' ');\n\t\t\t} else {\n\t\t\t\tstroke.dashStyle = '';\n\t\t\t}\n\t\t\tstroke.endcap = options.lineCap.replace('butt', 'flat');\n\t\t\tstroke.joinstyle = options.lineJoin;\n\n\t\t} else if (stroke) {\n\t\t\tcontainer.removeChild(stroke);\n\t\t\tlayer._stroke = null;\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tif (!fill) {\n\t\t\t\tfill = layer._fill = L.SVG.create('fill');\n\t\t\t}\n\t\t\tcontainer.appendChild(fill);\n\t\t\tfill.color = options.fillColor || options.color;\n\t\t\tfill.opacity = options.fillOpacity;\n\n\t\t} else if (fill) {\n\t\t\tcontainer.removeChild(fill);\n\t\t\tlayer._fill = null;\n\t\t}\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point.round(),\n\t\t    r = Math.round(layer._radius),\n\t\t    r2 = Math.round(layer._radiusY || r);\n\n\t\tthis._setPath(layer, layer._empty() ? 'M0 0' :\n\t\t\t\t'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.v = path;\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tL.DomUtil.toFront(layer._container);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tL.DomUtil.toBack(layer._container);\n\t}\n});\n\nif (L.Browser.vml) {\n\tL.SVG.create = (function () {\n\t\ttry {\n\t\t\tdocument.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');\n\t\t\treturn function (name) {\n\t\t\t\treturn document.createElement('<lvml:' + name + ' class=\"lvml\">');\n\t\t\t};\n\t\t} catch (e) {\n\t\t\treturn function (name) {\n\t\t\t\treturn document.createElement('<' + name + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">');\n\t\t\t};\n\t\t}\n\t})();\n}\n","/*\n * @class Canvas\n * @inherits Renderer\n * @aka L.Canvas\n *\n * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not\n * available in all web browsers, notably IE8, and overlapping geometries might\n * not display properly in some edge cases.\n *\n * @example\n *\n * Use Canvas by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.canvas()\n * });\n * ```\n *\n * Use a Canvas renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.canvas({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nL.Canvas = L.Renderer.extend({\n\tgetEvents: function () {\n\t\tvar events = L.Renderer.prototype.getEvents.call(this);\n\t\tevents.viewprereset = this._onViewPreReset;\n\t\treturn events;\n\t},\n\n\t_onViewPreReset: function () {\n\t\t// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once\n\t\tthis._postponeUpdatePaths = true;\n\t},\n\n\tonAdd: function () {\n\t\tL.Renderer.prototype.onAdd.call(this);\n\n\t\t// Redraw vectors since canvas is cleared upon removal,\n\t\t// in case of removing the renderer itself from the map.\n\t\tthis._draw();\n\t},\n\n\t_initContainer: function () {\n\t\tvar container = this._container = document.createElement('canvas');\n\n\t\tL.DomEvent\n\t\t\t.on(container, 'mousemove', L.Util.throttle(this._onMouseMove, 32, this), this)\n\t\t\t.on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)\n\t\t\t.on(container, 'mouseout', this._handleMouseOut, this);\n\n\t\tthis._ctx = container.getContext('2d');\n\t},\n\n\t_updatePaths: function () {\n\t\tif (this._postponeUpdatePaths) { return; }\n\n\t\tvar layer;\n\t\tthis._redrawBounds = null;\n\t\tfor (var id in this._layers) {\n\t\t\tlayer = this._layers[id];\n\t\t\tlayer._update();\n\t\t}\n\t\tthis._redraw();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tthis._drawnLayers = {};\n\n\t\tL.Renderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t    container = this._container,\n\t\t    size = b.getSize(),\n\t\t    m = L.Browser.retina ? 2 : 1;\n\n\t\tL.DomUtil.setPosition(container, b.min);\n\n\t\t// set canvas size (also clearing it); use double size on retina\n\t\tcontainer.width = m * size.x;\n\t\tcontainer.height = m * size.y;\n\t\tcontainer.style.width = size.x + 'px';\n\t\tcontainer.style.height = size.y + 'px';\n\n\t\tif (L.Browser.retina) {\n\t\t\tthis._ctx.scale(2, 2);\n\t\t}\n\n\t\t// translate so we use the same path coordinates after canvas element moves\n\t\tthis._ctx.translate(-b.min.x, -b.min.y);\n\n\t\t// Tell paths to redraw themselves\n\t\tthis.fire('update');\n\t},\n\n\t_reset: function () {\n\t\tL.Renderer.prototype._reset.call(this);\n\n\t\tif (this._postponeUpdatePaths) {\n\t\t\tthis._postponeUpdatePaths = false;\n\t\t\tthis._updatePaths();\n\t\t}\n\t},\n\n\t_initPath: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._layers[L.stamp(layer)] = layer;\n\n\t\tvar order = layer._order = {\n\t\t\tlayer: layer,\n\t\t\tprev: this._drawLast,\n\t\t\tnext: null\n\t\t};\n\t\tif (this._drawLast) { this._drawLast.next = order; }\n\t\tthis._drawLast = order;\n\t\tthis._drawFirst = this._drawFirst || this._drawLast;\n\t},\n\n\t_addPath: function (layer) {\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\tthis._drawLast = prev;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\tdelete layer._order;\n\n\t\tdelete this._layers[L.stamp(layer)];\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updatePath: function (layer) {\n\t\t// Redraw the union of the layer's old pixel\n\t\t// bounds and the new pixel bounds.\n\t\tthis._extendRedrawBounds(layer);\n\t\tlayer._project();\n\t\tlayer._update();\n\t\t// The redraw will extend the redraw bounds\n\t\t// with the new pixel bounds.\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateDashArray: function (layer) {\n\t\tif (layer.options.dashArray) {\n\t\t\tvar parts = layer.options.dashArray.split(','),\n\t\t\t    dashArray = [],\n\t\t\t    i;\n\t\t\tfor (i = 0; i < parts.length; i++) {\n\t\t\t\tdashArray.push(Number(parts[i]));\n\t\t\t}\n\t\t\tlayer.options._dashArray = dashArray;\n\t\t}\n\t},\n\n\t_requestRedraw: function (layer) {\n\t\tif (!this._map) { return; }\n\n\t\tthis._extendRedrawBounds(layer);\n\t\tthis._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._redraw, this);\n\t},\n\n\t_extendRedrawBounds: function (layer) {\n\t\tvar padding = (layer.options.weight || 0) + 1;\n\t\tthis._redrawBounds = this._redrawBounds || new L.Bounds();\n\t\tthis._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));\n\t\tthis._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));\n\t},\n\n\t_redraw: function () {\n\t\tthis._redrawRequest = null;\n\n\t\tif (this._redrawBounds) {\n\t\t\tthis._redrawBounds.min._floor();\n\t\t\tthis._redrawBounds.max._ceil();\n\t\t}\n\n\t\tthis._clear(); // clear layers in redraw bounds\n\t\tthis._draw(); // draw layers\n\n\t\tthis._redrawBounds = null;\n\t},\n\n\t_clear: function () {\n\t\tvar bounds = this._redrawBounds;\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._container.width, this._container.height);\n\t\t}\n\t},\n\n\t_draw: function () {\n\t\tvar layer, bounds = this._redrawBounds;\n\t\tthis._ctx.save();\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.beginPath();\n\t\t\tthis._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t\tthis._ctx.clip();\n\t\t}\n\n\t\tthis._drawing = true;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {\n\t\t\t\tlayer._updatePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._drawing = false;\n\n\t\tthis._ctx.restore();  // Restore state before clipping.\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tif (!this._drawing) { return; }\n\n\t\tvar i, j, len2, p,\n\t\t    parts = layer._parts,\n\t\t    len = parts.length,\n\t\t    ctx = this._ctx;\n\n\t\tif (!len) { return; }\n\n\t\tthis._drawnLayers[layer._leaflet_id] = layer;\n\n\t\tctx.beginPath();\n\n\t\tif (ctx.setLineDash) {\n\t\t\tctx.setLineDash(layer.options && layer.options._dashArray || []);\n\t\t}\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tfor (j = 0, len2 = parts[i].length; j < len2; j++) {\n\t\t\t\tp = parts[i][j];\n\t\t\t\tctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);\n\t\t\t}\n\t\t\tif (closed) {\n\t\t\t\tctx.closePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\n\t\t// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature\n\t},\n\n\t_updateCircle: function (layer) {\n\n\t\tif (!this._drawing || layer._empty()) { return; }\n\n\t\tvar p = layer._point,\n\t\t    ctx = this._ctx,\n\t\t    r = layer._radius,\n\t\t    s = (layer._radiusY || r) / r;\n\n\t\tthis._drawnLayers[layer._leaflet_id] = layer;\n\n\t\tif (s !== 1) {\n\t\t\tctx.save();\n\t\t\tctx.scale(1, s);\n\t\t}\n\n\t\tctx.beginPath();\n\t\tctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);\n\n\t\tif (s !== 1) {\n\t\t\tctx.restore();\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\t},\n\n\t_fillStroke: function (ctx, layer) {\n\t\tvar options = layer.options;\n\n\t\tif (options.fill) {\n\t\t\tctx.globalAlpha = options.fillOpacity;\n\t\t\tctx.fillStyle = options.fillColor || options.color;\n\t\t\tctx.fill(options.fillRule || 'evenodd');\n\t\t}\n\n\t\tif (options.stroke && options.weight !== 0) {\n\t\t\tctx.globalAlpha = options.opacity;\n\t\t\tctx.lineWidth = options.weight;\n\t\t\tctx.strokeStyle = options.color;\n\t\t\tctx.lineCap = options.lineCap;\n\t\t\tctx.lineJoin = options.lineJoin;\n\t\t\tctx.stroke();\n\t\t}\n\t},\n\n\t// Canvas obviously doesn't have mouse events for individual drawn objects,\n\t// so we emulate that by calculating what's under the mouse on mousemove/click manually\n\n\t_onClick: function (e) {\n\t\tvar point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {\n\t\t\t\tclickedLayer = layer;\n\t\t\t}\n\t\t}\n\t\tif (clickedLayer)  {\n\t\t\tL.DomEvent._fakeStop(e);\n\t\t\tthis._fireEvent([clickedLayer], e);\n\t\t}\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }\n\n\t\tvar point = this._map.mouseEventToLayerPoint(e);\n\t\tthis._handleMouseHover(e, point);\n\t},\n\n\n\t_handleMouseOut: function (e) {\n\t\tvar layer = this._hoveredLayer;\n\t\tif (layer) {\n\t\t\t// if we're leaving the layer, fire mouseout\n\t\t\tL.DomUtil.removeClass(this._container, 'leaflet-interactive');\n\t\t\tthis._fireEvent([layer], e, 'mouseout');\n\t\t\tthis._hoveredLayer = null;\n\t\t}\n\t},\n\n\t_handleMouseHover: function (e, point) {\n\t\tvar layer, candidateHoveredLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tcandidateHoveredLayer = layer;\n\t\t\t}\n\t\t}\n\n\t\tif (candidateHoveredLayer !== this._hoveredLayer) {\n\t\t\tthis._handleMouseOut(e);\n\n\t\t\tif (candidateHoveredLayer) {\n\t\t\t\tL.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor\n\t\t\t\tthis._fireEvent([candidateHoveredLayer], e, 'mouseover');\n\t\t\t\tthis._hoveredLayer = candidateHoveredLayer;\n\t\t\t}\n\t\t}\n\n\t\tif (this._hoveredLayer) {\n\t\t\tthis._fireEvent([this._hoveredLayer], e);\n\t\t}\n\t},\n\n\t_fireEvent: function (layers, e, type) {\n\t\tthis._map._fireDOMEvent(e, type || e.type, layers);\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\t// Already last\n\t\t\treturn;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else if (next) {\n\t\t\t// Update first entry unless this is the\n\t\t\t// signle entry\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\torder.prev = this._drawLast;\n\t\tthis._drawLast.next = order;\n\n\t\torder.next = null;\n\t\tthis._drawLast = order;\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\t// Already first\n\t\t\treturn;\n\t\t}\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else if (prev) {\n\t\t\t// Update last entry unless this is the\n\t\t\t// signle entry\n\t\t\tthis._drawLast = prev;\n\t\t}\n\n\t\torder.prev = null;\n\n\t\torder.next = this._drawFirst;\n\t\tthis._drawFirst.prev = order;\n\t\tthis._drawFirst = order;\n\n\t\tthis._requestRedraw(layer);\n\t}\n});\n\n// @namespace Browser; @property canvas: Boolean\n// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).\nL.Browser.canvas = (function () {\n\treturn !!document.createElement('canvas').getContext;\n}());\n\n// @namespace Canvas\n// @factory L.canvas(options?: Renderer options)\n// Creates a Canvas renderer with the given options.\nL.canvas = function (options) {\n\treturn L.Browser.canvas ? new L.Canvas(options) : null;\n};\n\nL.Polyline.prototype._containsPoint = function (p, closed) {\n\tvar i, j, k, len, len2, part,\n\t    w = this._clickTolerance();\n\n\tif (!this._pxBounds.contains(p)) { return false; }\n\n\t// hit detection for polylines\n\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\tpart = this._parts[i];\n\n\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\tif (!closed && (j === 0)) { continue; }\n\n\t\t\tif (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\t}\n\treturn false;\n};\n\nL.Polygon.prototype._containsPoint = function (p) {\n\tvar inside = false,\n\t    part, p1, p2, i, j, k, len, len2;\n\n\tif (!this._pxBounds.contains(p)) { return false; }\n\n\t// ray casting algorithm for detecting if point is in polygon\n\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\tpart = this._parts[i];\n\n\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\tp1 = part[j];\n\t\t\tp2 = part[k];\n\n\t\t\tif (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {\n\t\t\t\tinside = !inside;\n\t\t\t}\n\t\t}\n\t}\n\n\t// also check if it's on polygon stroke\n\treturn inside || L.Polyline.prototype._containsPoint.call(this, p, true);\n};\n\nL.CircleMarker.prototype._containsPoint = function (p) {\n\treturn p.distanceTo(this._point) <= this._radius + this._clickTolerance();\n};\n","/*\r\n * @class GeoJSON\r\n * @aka L.GeoJSON\r\n * @inherits FeatureGroup\r\n *\r\n * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse\r\n * GeoJSON data and display it on the map. Extends `FeatureGroup`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.geoJSON(data, {\r\n * \tstyle: function (feature) {\r\n * \t\treturn {color: feature.properties.color};\r\n * \t}\r\n * }).bindPopup(function (layer) {\r\n * \treturn layer.feature.properties.description;\r\n * }).addTo(map);\r\n * ```\r\n */\r\n\r\nL.GeoJSON = L.FeatureGroup.extend({\r\n\r\n\t/* @section\r\n\t * @aka GeoJSON options\r\n\t *\r\n\t * @option pointToLayer: Function = *\r\n\t * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally\r\n\t * called when data is added, passing the GeoJSON point feature and its `LatLng`.\r\n\t * The default is to spawn a default `Marker`:\r\n\t * ```js\r\n\t * function(geoJsonPoint, latlng) {\r\n\t * \treturn L.marker(latlng);\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option style: Function = *\r\n\t * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,\r\n\t * called internally when data is added.\r\n\t * The default value is to not override any defaults:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn {}\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option onEachFeature: Function = *\r\n\t * A `Function` that will be called once for each created `Feature`, after it has\r\n\t * been created and styled. Useful for attaching events and popups to features.\r\n\t * The default is to do nothing with the newly created layers:\r\n\t * ```js\r\n\t * function (feature, layer) {}\r\n\t * ```\r\n\t *\r\n\t * @option filter: Function = *\r\n\t * A `Function` that will be used to decide whether to include a feature or not.\r\n\t * The default is to include all features:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn true;\r\n\t * }\r\n\t * ```\r\n\t * Note: dynamically changing the `filter` option will have effect only on newly\r\n\t * added data. It will _not_ re-evaluate already included features.\r\n\t *\r\n\t * @option coordsToLatLng: Function = *\r\n\t * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.\r\n\t * The default is the `coordsToLatLng` static method.\r\n\t */\r\n\r\n\tinitialize: function (geojson, options) {\r\n\t\tL.setOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tif (geojson) {\r\n\t\t\tthis.addData(geojson);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addData( <GeoJSON> data ): this\r\n\t// Adds a GeoJSON object to the layer.\r\n\taddData: function (geojson) {\r\n\t\tvar features = L.Util.isArray(geojson) ? geojson : geojson.features,\r\n\t\t    i, len, feature;\r\n\r\n\t\tif (features) {\r\n\t\t\tfor (i = 0, len = features.length; i < len; i++) {\r\n\t\t\t\t// only add this if geometry or geometries are set and not null\r\n\t\t\t\tfeature = features[i];\r\n\t\t\t\tif (feature.geometries || feature.geometry || feature.features || feature.coordinates) {\r\n\t\t\t\t\tthis.addData(feature);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar options = this.options;\r\n\r\n\t\tif (options.filter && !options.filter(geojson)) { return this; }\r\n\r\n\t\tvar layer = L.GeoJSON.geometryToLayer(geojson, options);\r\n\t\tif (!layer) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tlayer.feature = L.GeoJSON.asFeature(geojson);\r\n\r\n\t\tlayer.defaultOptions = layer.options;\r\n\t\tthis.resetStyle(layer);\r\n\r\n\t\tif (options.onEachFeature) {\r\n\t\t\toptions.onEachFeature(geojson, layer);\r\n\t\t}\r\n\r\n\t\treturn this.addLayer(layer);\r\n\t},\r\n\r\n\t// @method resetStyle( <Path> layer ): this\r\n\t// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.\r\n\tresetStyle: function (layer) {\r\n\t\t// reset any custom styles\r\n\t\tlayer.options = L.Util.extend({}, layer.defaultOptions);\r\n\t\tthis._setLayerStyle(layer, this.options.style);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setStyle( <Function> style ): this\r\n\t// Changes styles of GeoJSON vector layers with the given style function.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.eachLayer(function (layer) {\r\n\t\t\tthis._setLayerStyle(layer, style);\r\n\t\t}, this);\r\n\t},\r\n\r\n\t_setLayerStyle: function (layer, style) {\r\n\t\tif (typeof style === 'function') {\r\n\t\t\tstyle = style(layer.feature);\r\n\t\t}\r\n\t\tif (layer.setStyle) {\r\n\t\t\tlayer.setStyle(style);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @section\r\n// There are several static functions which can be called without instantiating L.GeoJSON:\r\nL.extend(L.GeoJSON, {\r\n\t// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer\r\n\t// Creates a `Layer` from a given GeoJSON feature. Can use a custom\r\n\t// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)\r\n\t// functions if provided as options.\r\n\tgeometryToLayer: function (geojson, options) {\r\n\r\n\t\tvar geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,\r\n\t\t    coords = geometry ? geometry.coordinates : null,\r\n\t\t    layers = [],\r\n\t\t    pointToLayer = options && options.pointToLayer,\r\n\t\t    coordsToLatLng = options && options.coordsToLatLng || this.coordsToLatLng,\r\n\t\t    latlng, latlngs, i, len;\r\n\r\n\t\tif (!coords && !geometry) {\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tswitch (geometry.type) {\r\n\t\tcase 'Point':\r\n\t\t\tlatlng = coordsToLatLng(coords);\r\n\t\t\treturn pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);\r\n\r\n\t\tcase 'MultiPoint':\r\n\t\t\tfor (i = 0, len = coords.length; i < len; i++) {\r\n\t\t\t\tlatlng = coordsToLatLng(coords[i]);\r\n\t\t\t\tlayers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));\r\n\t\t\t}\r\n\t\t\treturn new L.FeatureGroup(layers);\r\n\r\n\t\tcase 'LineString':\r\n\t\tcase 'MultiLineString':\r\n\t\t\tlatlngs = this.coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, coordsToLatLng);\r\n\t\t\treturn new L.Polyline(latlngs, options);\r\n\r\n\t\tcase 'Polygon':\r\n\t\tcase 'MultiPolygon':\r\n\t\t\tlatlngs = this.coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, coordsToLatLng);\r\n\t\t\treturn new L.Polygon(latlngs, options);\r\n\r\n\t\tcase 'GeometryCollection':\r\n\t\t\tfor (i = 0, len = geometry.geometries.length; i < len; i++) {\r\n\t\t\t\tvar layer = this.geometryToLayer({\r\n\t\t\t\t\tgeometry: geometry.geometries[i],\r\n\t\t\t\t\ttype: 'Feature',\r\n\t\t\t\t\tproperties: geojson.properties\r\n\t\t\t\t}, options);\r\n\r\n\t\t\t\tif (layer) {\r\n\t\t\t\t\tlayers.push(layer);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn new L.FeatureGroup(layers);\r\n\r\n\t\tdefault:\r\n\t\t\tthrow new Error('Invalid GeoJSON object.');\r\n\t\t}\r\n\t},\r\n\r\n\t// @function coordsToLatLng(coords: Array): LatLng\r\n\t// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)\r\n\t// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.\r\n\tcoordsToLatLng: function (coords) {\r\n\t\treturn new L.LatLng(coords[1], coords[0], coords[2]);\r\n\t},\r\n\r\n\t// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array\r\n\t// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.\r\n\t// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).\r\n\t// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.\r\n\tcoordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) {\r\n\t\tvar latlngs = [];\r\n\r\n\t\tfor (var i = 0, len = coords.length, latlng; i < len; i++) {\r\n\t\t\tlatlng = levelsDeep ?\r\n\t\t\t        this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) :\r\n\t\t\t        (coordsToLatLng || this.coordsToLatLng)(coords[i]);\r\n\r\n\t\t\tlatlngs.push(latlng);\r\n\t\t}\r\n\r\n\t\treturn latlngs;\r\n\t},\r\n\r\n\t// @function latLngToCoords(latlng: LatLng): Array\r\n\t// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)\r\n\tlatLngToCoords: function (latlng) {\r\n\t\treturn latlng.alt !== undefined ?\r\n\t\t\t\t[latlng.lng, latlng.lat, latlng.alt] :\r\n\t\t\t\t[latlng.lng, latlng.lat];\r\n\t},\r\n\r\n\t// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array\r\n\t// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)\r\n\t// `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.\r\n\tlatLngsToCoords: function (latlngs, levelsDeep, closed) {\r\n\t\tvar coords = [];\r\n\r\n\t\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\t\tcoords.push(levelsDeep ?\r\n\t\t\t\tL.GeoJSON.latLngsToCoords(latlngs[i], levelsDeep - 1, closed) :\r\n\t\t\t\tL.GeoJSON.latLngToCoords(latlngs[i]));\r\n\t\t}\r\n\r\n\t\tif (!levelsDeep && closed) {\r\n\t\t\tcoords.push(coords[0]);\r\n\t\t}\r\n\r\n\t\treturn coords;\r\n\t},\r\n\r\n\tgetFeature: function (layer, newGeometry) {\r\n\t\treturn layer.feature ?\r\n\t\t\t\tL.extend({}, layer.feature, {geometry: newGeometry}) :\r\n\t\t\t\tL.GeoJSON.asFeature(newGeometry);\r\n\t},\r\n\r\n\t// @function asFeature(geojson: Object): Object\r\n\t// Normalize GeoJSON geometries/features into GeoJSON features.\r\n\tasFeature: function (geojson) {\r\n\t\tif (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {\r\n\t\t\treturn geojson;\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'Feature',\r\n\t\t\tproperties: {},\r\n\t\t\tgeometry: geojson\r\n\t\t};\r\n\t}\r\n});\r\n\r\nvar PointToGeoJSON = {\r\n\ttoGeoJSON: function () {\r\n\t\treturn L.GeoJSON.getFeature(this, {\r\n\t\t\ttype: 'Point',\r\n\t\t\tcoordinates: L.GeoJSON.latLngToCoords(this.getLatLng())\r\n\t\t});\r\n\t}\r\n};\r\n\r\n// @namespace Marker\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).\r\nL.Marker.include(PointToGeoJSON);\r\n\r\n// @namespace CircleMarker\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).\r\nL.Circle.include(PointToGeoJSON);\r\nL.CircleMarker.include(PointToGeoJSON);\r\n\r\n\r\n// @namespace Polyline\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).\r\nL.Polyline.prototype.toGeoJSON = function () {\r\n\tvar multi = !L.Polyline._flat(this._latlngs);\r\n\r\n\tvar coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);\r\n\r\n\treturn L.GeoJSON.getFeature(this, {\r\n\t\ttype: (multi ? 'Multi' : '') + 'LineString',\r\n\t\tcoordinates: coords\r\n\t});\r\n};\r\n\r\n// @namespace Polygon\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).\r\nL.Polygon.prototype.toGeoJSON = function () {\r\n\tvar holes = !L.Polyline._flat(this._latlngs),\r\n\t    multi = holes && !L.Polyline._flat(this._latlngs[0]);\r\n\r\n\tvar coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true);\r\n\r\n\tif (!holes) {\r\n\t\tcoords = [coords];\r\n\t}\r\n\r\n\treturn L.GeoJSON.getFeature(this, {\r\n\t\ttype: (multi ? 'Multi' : '') + 'Polygon',\r\n\t\tcoordinates: coords\r\n\t});\r\n};\r\n\r\n\r\n// @namespace LayerGroup\r\nL.LayerGroup.include({\r\n\ttoMultiPoint: function () {\r\n\t\tvar coords = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tcoords.push(layer.toGeoJSON().geometry.coordinates);\r\n\t\t});\r\n\r\n\t\treturn L.GeoJSON.getFeature(this, {\r\n\t\t\ttype: 'MultiPoint',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t},\r\n\r\n\t// @method toGeoJSON(): Object\r\n\t// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `GeometryCollection`).\r\n\ttoGeoJSON: function () {\r\n\r\n\t\tvar type = this.feature && this.feature.geometry && this.feature.geometry.type;\r\n\r\n\t\tif (type === 'MultiPoint') {\r\n\t\t\treturn this.toMultiPoint();\r\n\t\t}\r\n\r\n\t\tvar isGeometryCollection = type === 'GeometryCollection',\r\n\t\t    jsons = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tif (layer.toGeoJSON) {\r\n\t\t\t\tvar json = layer.toGeoJSON();\r\n\t\t\t\tjsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (isGeometryCollection) {\r\n\t\t\treturn L.GeoJSON.getFeature(this, {\r\n\t\t\t\tgeometries: jsons,\r\n\t\t\t\ttype: 'GeometryCollection'\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'FeatureCollection',\r\n\t\t\tfeatures: jsons\r\n\t\t};\r\n\t}\r\n});\r\n\r\n// @namespace GeoJSON\r\n// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)\r\n// Creates a GeoJSON layer. Optionally accepts an object in\r\n// [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map\r\n// (you can alternatively add it later with `addData` method) and an `options` object.\r\nL.geoJSON = function (geojson, options) {\r\n\treturn new L.GeoJSON(geojson, options);\r\n};\r\n// Backward compatibility.\r\nL.geoJson = L.geoJSON;\r\n","/*\r\n * @class Draggable\r\n * @aka L.Draggable\r\n * @inherits Evented\r\n *\r\n * A class for making DOM elements draggable (including touch support).\r\n * Used internally for map and marker dragging. Only works for elements\r\n * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).\r\n *\r\n * @example\r\n * ```js\r\n * var draggable = new L.Draggable(elementToDrag);\r\n * draggable.enable();\r\n * ```\r\n */\r\n\r\nL.Draggable = L.Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @option clickTolerance: Number = 3\r\n\t\t// The max number of pixels a user can shift the mouse pointer during a click\r\n\t\t// for it to be considered a valid click (as opposed to a mouse drag).\r\n\t\tclickTolerance: 3\r\n\t},\r\n\r\n\tstatics: {\r\n\t\tSTART: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],\r\n\t\tEND: {\r\n\t\t\tmousedown: 'mouseup',\r\n\t\t\ttouchstart: 'touchend',\r\n\t\t\tpointerdown: 'touchend',\r\n\t\t\tMSPointerDown: 'touchend'\r\n\t\t},\r\n\t\tMOVE: {\r\n\t\t\tmousedown: 'mousemove',\r\n\t\t\ttouchstart: 'touchmove',\r\n\t\t\tpointerdown: 'touchmove',\r\n\t\t\tMSPointerDown: 'touchmove'\r\n\t\t}\r\n\t},\r\n\r\n\t// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline: Boolean)\r\n\t// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).\r\n\tinitialize: function (element, dragStartTarget, preventOutline) {\r\n\t\tthis._element = element;\r\n\t\tthis._dragStartTarget = dragStartTarget || element;\r\n\t\tthis._preventOutline = preventOutline;\r\n\t},\r\n\r\n\t// @method enable()\r\n\t// Enables the dragging ability\r\n\tenable: function () {\r\n\t\tif (this._enabled) { return; }\r\n\r\n\t\tL.DomEvent.on(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);\r\n\r\n\t\tthis._enabled = true;\r\n\t},\r\n\r\n\t// @method disable()\r\n\t// Disables the dragging ability\r\n\tdisable: function () {\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\t// If we're currently dragging this draggable,\r\n\t\t// disabling it counts as first ending the drag.\r\n\t\tif (L.Draggable._dragging === this) {\r\n\t\t\tthis.finishDrag();\r\n\t\t}\r\n\r\n\t\tL.DomEvent.off(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);\r\n\r\n\t\tthis._enabled = false;\r\n\t\tthis._moved = false;\r\n\t},\r\n\r\n\t_onDown: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\r\n\t\tthis._moved = false;\r\n\r\n\t\tif (L.DomUtil.hasClass(this._element, 'leaflet-zoom-anim')) { return; }\r\n\r\n\t\tif (L.Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }\r\n\t\tL.Draggable._dragging = this;  // Prevent dragging multiple objects at once.\r\n\r\n\t\tif (this._preventOutline) {\r\n\t\t\tL.DomUtil.preventOutline(this._element);\r\n\t\t}\r\n\r\n\t\tL.DomUtil.disableImageDrag();\r\n\t\tL.DomUtil.disableTextSelection();\r\n\r\n\t\tif (this._moving) { return; }\r\n\r\n\t\t// @event down: Event\r\n\t\t// Fired when a drag is about to start.\r\n\t\tthis.fire('down');\r\n\r\n\t\tvar first = e.touches ? e.touches[0] : e;\r\n\r\n\t\tthis._startPoint = new L.Point(first.clientX, first.clientY);\r\n\r\n\t\tL.DomEvent\r\n\t\t\t.on(document, L.Draggable.MOVE[e.type], this._onMove, this)\r\n\t\t\t.on(document, L.Draggable.END[e.type], this._onUp, this);\r\n\t},\r\n\r\n\t_onMove: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length > 1) {\r\n\t\t\tthis._moved = true;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\r\n\t\t    newPoint = new L.Point(first.clientX, first.clientY),\r\n\t\t    offset = newPoint.subtract(this._startPoint);\r\n\r\n\t\tif (!offset.x && !offset.y) { return; }\r\n\t\tif (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }\r\n\r\n\t\tL.DomEvent.preventDefault(e);\r\n\r\n\t\tif (!this._moved) {\r\n\t\t\t// @event dragstart: Event\r\n\t\t\t// Fired when a drag starts\r\n\t\t\tthis.fire('dragstart');\r\n\r\n\t\t\tthis._moved = true;\r\n\t\t\tthis._startPos = L.DomUtil.getPosition(this._element).subtract(offset);\r\n\r\n\t\t\tL.DomUtil.addClass(document.body, 'leaflet-dragging');\r\n\r\n\t\t\tthis._lastTarget = e.target || e.srcElement;\r\n\t\t\t// IE and Edge do not give the <use> element, so fetch it\r\n\t\t\t// if necessary\r\n\t\t\tif ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) {\r\n\t\t\t\tthis._lastTarget = this._lastTarget.correspondingUseElement;\r\n\t\t\t}\r\n\t\t\tL.DomUtil.addClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t}\r\n\r\n\t\tthis._newPos = this._startPos.add(offset);\r\n\t\tthis._moving = true;\r\n\r\n\t\tL.Util.cancelAnimFrame(this._animRequest);\r\n\t\tthis._lastEvent = e;\r\n\t\tthis._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true);\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tvar e = {originalEvent: this._lastEvent};\r\n\r\n\t\t// @event predrag: Event\r\n\t\t// Fired continuously during dragging *before* each corresponding\r\n\t\t// update of the element's position.\r\n\t\tthis.fire('predrag', e);\r\n\t\tL.DomUtil.setPosition(this._element, this._newPos);\r\n\r\n\t\t// @event drag: Event\r\n\t\t// Fired continuously during dragging.\r\n\t\tthis.fire('drag', e);\r\n\t},\r\n\r\n\t_onUp: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\t\tthis.finishDrag();\r\n\t},\r\n\r\n\tfinishDrag: function () {\r\n\t\tL.DomUtil.removeClass(document.body, 'leaflet-dragging');\r\n\r\n\t\tif (this._lastTarget) {\r\n\t\t\tL.DomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t\tthis._lastTarget = null;\r\n\t\t}\r\n\r\n\t\tfor (var i in L.Draggable.MOVE) {\r\n\t\t\tL.DomEvent\r\n\t\t\t\t.off(document, L.Draggable.MOVE[i], this._onMove, this)\r\n\t\t\t\t.off(document, L.Draggable.END[i], this._onUp, this);\r\n\t\t}\r\n\r\n\t\tL.DomUtil.enableImageDrag();\r\n\t\tL.DomUtil.enableTextSelection();\r\n\r\n\t\tif (this._moved && this._moving) {\r\n\t\t\t// ensure drag is not fired after dragend\r\n\t\t\tL.Util.cancelAnimFrame(this._animRequest);\r\n\r\n\t\t\t// @event dragend: DragEndEvent\r\n\t\t\t// Fired when the drag ends.\r\n\t\t\tthis.fire('dragend', {\r\n\t\t\t\tdistance: this._newPos.distanceTo(this._startPos)\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._moving = false;\r\n\t\tL.Draggable._dragging = false;\r\n\t}\r\n\r\n});\r\n","/*\n\tL.Handler is a base class for handler classes that are used internally to inject\n\tinteraction features like dragging to classes like Map and Marker.\n*/\n\n// @class Handler\n// @aka L.Handler\n// Abstract class for map interaction handlers\n\nL.Handler = L.Class.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t},\n\n\t// @method enable(): this\n\t// Enables the handler\n\tenable: function () {\n\t\tif (this._enabled) { return this; }\n\n\t\tthis._enabled = true;\n\t\tthis.addHooks();\n\t\treturn this;\n\t},\n\n\t// @method disable(): this\n\t// Disables the handler\n\tdisable: function () {\n\t\tif (!this._enabled) { return this; }\n\n\t\tthis._enabled = false;\n\t\tthis.removeHooks();\n\t\treturn this;\n\t},\n\n\t// @method enabled(): Boolean\n\t// Returns `true` if the handler is enabled\n\tenabled: function () {\n\t\treturn !!this._enabled;\n\t}\n\n\t// @section Extension methods\n\t// Classes inheriting from `Handler` must implement the two following methods:\n\t// @method addHooks()\n\t// Called when the handler is enabled, should add event hooks.\n\t// @method removeHooks()\n\t// Called when the handler is disabled, should remove the event hooks added previously.\n});\n","/*\n * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nL.Map.mergeOptions({\n\t// @option dragging: Boolean = true\n\t// Whether the map be draggable with mouse/touch or not.\n\tdragging: true,\n\n\t// @section Panning Inertia Options\n\t// @option inertia: Boolean = *\n\t// If enabled, panning of the map will have an inertia effect where\n\t// the map builds momentum while dragging and continues moving in\n\t// the same direction for some time. Feels especially nice on touch\n\t// devices. Enabled by default unless running on old Android devices.\n\tinertia: !L.Browser.android23,\n\n\t// @option inertiaDeceleration: Number = 3000\n\t// The rate with which the inertial movement slows down, in pixels/second².\n\tinertiaDeceleration: 3400, // px/s^2\n\n\t// @option inertiaMaxSpeed: Number = Infinity\n\t// Max speed of the inertial movement, in pixels/second.\n\tinertiaMaxSpeed: Infinity, // px/s\n\n\t// @option easeLinearity: Number = 0.2\n\teaseLinearity: 0.2,\n\n\t// TODO refactor, move to CRS\n\t// @option worldCopyJump: Boolean = false\n\t// With this option enabled, the map tracks when you pan to another \"copy\"\n\t// of the world and seamlessly jumps to the original one so that all overlays\n\t// like markers and vector layers are still visible.\n\tworldCopyJump: false,\n\n\t// @option maxBoundsViscosity: Number = 0.0\n\t// If `maxBounds` is set, this option will control how solid the bounds\n\t// are when dragging the map around. The default value of `0.0` allows the\n\t// user to drag outside the bounds at normal speed, higher values will\n\t// slow down map dragging outside bounds, and `1.0` makes the bounds fully\n\t// solid, preventing the user from dragging outside the bounds.\n\tmaxBoundsViscosity: 0.0\n});\n\nL.Map.Drag = L.Handler.extend({\n\taddHooks: function () {\n\t\tif (!this._draggable) {\n\t\t\tvar map = this._map;\n\n\t\t\tthis._draggable = new L.Draggable(map._mapPane, map._container);\n\n\t\t\tthis._draggable.on({\n\t\t\t\tdown: this._onDown,\n\t\t\t\tdragstart: this._onDragStart,\n\t\t\t\tdrag: this._onDrag,\n\t\t\t\tdragend: this._onDragEnd\n\t\t\t}, this);\n\n\t\t\tthis._draggable.on('predrag', this._onPreDragLimit, this);\n\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\tthis._draggable.on('predrag', this._onPreDragWrap, this);\n\t\t\t\tmap.on('zoomend', this._onZoomEnd, this);\n\n\t\t\t\tmap.whenReady(this._onZoomEnd, this);\n\t\t\t}\n\t\t}\n\t\tL.DomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');\n\t\tthis._draggable.enable();\n\t\tthis._positions = [];\n\t\tthis._times = [];\n\t},\n\n\tremoveHooks: function () {\n\t\tL.DomUtil.removeClass(this._map._container, 'leaflet-grab');\n\t\tL.DomUtil.removeClass(this._map._container, 'leaflet-touch-drag');\n\t\tthis._draggable.disable();\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\tmoving: function () {\n\t\treturn this._draggable && this._draggable._moving;\n\t},\n\n\t_onDown: function () {\n\t\tthis._map._stop();\n\t},\n\n\t_onDragStart: function () {\n\t\tvar map = this._map;\n\n\t\tif (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {\n\t\t\tvar bounds = L.latLngBounds(this._map.options.maxBounds);\n\n\t\t\tthis._offsetLimit = L.bounds(\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)\n\t\t\t\t\t.add(this._map.getSize()));\n\n\t\t\tthis._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));\n\t\t} else {\n\t\t\tthis._offsetLimit = null;\n\t\t}\n\n\t\tmap\n\t\t    .fire('movestart')\n\t\t    .fire('dragstart');\n\n\t\tif (map.options.inertia) {\n\t\t\tthis._positions = [];\n\t\t\tthis._times = [];\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tif (this._map.options.inertia) {\n\t\t\tvar time = this._lastTime = +new Date(),\n\t\t\t    pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;\n\n\t\t\tthis._positions.push(pos);\n\t\t\tthis._times.push(time);\n\n\t\t\tif (time - this._times[0] > 50) {\n\t\t\t\tthis._positions.shift();\n\t\t\t\tthis._times.shift();\n\t\t\t}\n\t\t}\n\n\t\tthis._map\n\t\t    .fire('move', e)\n\t\t    .fire('drag', e);\n\t},\n\n\t_onZoomEnd: function () {\n\t\tvar pxCenter = this._map.getSize().divideBy(2),\n\t\t    pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);\n\n\t\tthis._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;\n\t\tthis._worldWidth = this._map.getPixelWorldBounds().getSize().x;\n\t},\n\n\t_viscousLimit: function (value, threshold) {\n\t\treturn value - (value - threshold) * this._viscosity;\n\t},\n\n\t_onPreDragLimit: function () {\n\t\tif (!this._viscosity || !this._offsetLimit) { return; }\n\n\t\tvar offset = this._draggable._newPos.subtract(this._draggable._startPos);\n\n\t\tvar limit = this._offsetLimit;\n\t\tif (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }\n\t\tif (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }\n\t\tif (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }\n\t\tif (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }\n\n\t\tthis._draggable._newPos = this._draggable._startPos.add(offset);\n\t},\n\n\t_onPreDragWrap: function () {\n\t\t// TODO refactor to be able to adjust map pane position after zoom\n\t\tvar worldWidth = this._worldWidth,\n\t\t    halfWidth = Math.round(worldWidth / 2),\n\t\t    dx = this._initialWorldOffset,\n\t\t    x = this._draggable._newPos.x,\n\t\t    newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,\n\t\t    newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,\n\t\t    newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;\n\n\t\tthis._draggable._absPos = this._draggable._newPos.clone();\n\t\tthis._draggable._newPos.x = newX;\n\t},\n\n\t_onDragEnd: function (e) {\n\t\tvar map = this._map,\n\t\t    options = map.options,\n\n\t\t    noInertia = !options.inertia || this._times.length < 2;\n\n\t\tmap.fire('dragend', e);\n\n\t\tif (noInertia) {\n\t\t\tmap.fire('moveend');\n\n\t\t} else {\n\n\t\t\tvar direction = this._lastPos.subtract(this._positions[0]),\n\t\t\t    duration = (this._lastTime - this._times[0]) / 1000,\n\t\t\t    ease = options.easeLinearity,\n\n\t\t\t    speedVector = direction.multiplyBy(ease / duration),\n\t\t\t    speed = speedVector.distanceTo([0, 0]),\n\n\t\t\t    limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),\n\t\t\t    limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),\n\n\t\t\t    decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),\n\t\t\t    offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();\n\n\t\t\tif (!offset.x && !offset.y) {\n\t\t\t\tmap.fire('moveend');\n\n\t\t\t} else {\n\t\t\t\toffset = map._limitOffset(offset, map.options.maxBounds);\n\n\t\t\t\tL.Util.requestAnimFrame(function () {\n\t\t\t\t\tmap.panBy(offset, {\n\t\t\t\t\t\tduration: decelerationDuration,\n\t\t\t\t\t\teaseLinearity: ease,\n\t\t\t\t\t\tnoMoveStart: true,\n\t\t\t\t\t\tanimate: true\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property dragging: Handler\n// Map dragging handler (by both mouse and touch).\nL.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);\n","/*\n * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\n\nL.Map.mergeOptions({\n\t// @option doubleClickZoom: Boolean|String = true\n\t// Whether the map can be zoomed in by double clicking on it and\n\t// zoomed out by double clicking while holding shift. If passed\n\t// `'center'`, double-click zoom will zoom to the center of the\n\t//  view regardless of where the mouse was.\n\tdoubleClickZoom: true\n});\n\nL.Map.DoubleClickZoom = L.Handler.extend({\n\taddHooks: function () {\n\t\tthis._map.on('dblclick', this._onDoubleClick, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._map.off('dblclick', this._onDoubleClick, this);\n\t},\n\n\t_onDoubleClick: function (e) {\n\t\tvar map = this._map,\n\t\t    oldZoom = map.getZoom(),\n\t\t    delta = map.options.zoomDelta,\n\t\t    zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;\n\n\t\tif (map.options.doubleClickZoom === 'center') {\n\t\t\tmap.setZoom(zoom);\n\t\t} else {\n\t\t\tmap.setZoomAround(e.containerPoint, zoom);\n\t\t}\n\t}\n});\n\n// @section Handlers\n//\n// Map properties include interaction handlers that allow you to control\n// interaction behavior in runtime, enabling or disabling certain features such\n// as dragging or touch zoom (see `Handler` methods). For example:\n//\n// ```js\n// map.doubleClickZoom.disable();\n// ```\n//\n// @property doubleClickZoom: Handler\n// Double click zoom handler.\nL.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);\n","/*\n * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.\n */\n\n// @namespace Map\n// @section Interaction Options\nL.Map.mergeOptions({\n\t// @section Mousewheel options\n\t// @option scrollWheelZoom: Boolean|String = true\n\t// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,\n\t// it will zoom to the center of the view regardless of where the mouse was.\n\tscrollWheelZoom: true,\n\n\t// @option wheelDebounceTime: Number = 40\n\t// Limits the rate at which a wheel can fire (in milliseconds). By default\n\t// user can't zoom via wheel more often than once per 40 ms.\n\twheelDebounceTime: 40,\n\n\t// @option wheelPxPerZoomLevel: Number = 60\n\t// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))\n\t// mean a change of one full zoom level. Smaller values will make wheel-zooming\n\t// faster (and vice versa).\n\twheelPxPerZoomLevel: 60\n});\n\nL.Map.ScrollWheelZoom = L.Handler.extend({\n\taddHooks: function () {\n\t\tL.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);\n\n\t\tthis._delta = 0;\n\t},\n\n\tremoveHooks: function () {\n\t\tL.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll, this);\n\t},\n\n\t_onWheelScroll: function (e) {\n\t\tvar delta = L.DomEvent.getWheelDelta(e);\n\n\t\tvar debounce = this._map.options.wheelDebounceTime;\n\n\t\tthis._delta += delta;\n\t\tthis._lastMousePos = this._map.mouseEventToContainerPoint(e);\n\n\t\tif (!this._startTime) {\n\t\t\tthis._startTime = +new Date();\n\t\t}\n\n\t\tvar left = Math.max(debounce - (+new Date() - this._startTime), 0);\n\n\t\tclearTimeout(this._timer);\n\t\tthis._timer = setTimeout(L.bind(this._performZoom, this), left);\n\n\t\tL.DomEvent.stop(e);\n\t},\n\n\t_performZoom: function () {\n\t\tvar map = this._map,\n\t\t    zoom = map.getZoom(),\n\t\t    snap = this._map.options.zoomSnap || 0;\n\n\t\tmap._stop(); // stop panning and fly animations if any\n\n\t\t// map the delta with a sigmoid function to -4..4 range leaning on -1..1\n\t\tvar d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),\n\t\t    d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,\n\t\t    d4 = snap ? Math.ceil(d3 / snap) * snap : d3,\n\t\t    delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;\n\n\t\tthis._delta = 0;\n\t\tthis._startTime = null;\n\n\t\tif (!delta) { return; }\n\n\t\tif (map.options.scrollWheelZoom === 'center') {\n\t\t\tmap.setZoom(zoom + delta);\n\t\t} else {\n\t\t\tmap.setZoomAround(this._lastMousePos, zoom + delta);\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property scrollWheelZoom: Handler\n// Scroll wheel zoom handler.\nL.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);\n","/*\r\n * Extends the event handling code with double tap support for mobile browsers.\r\n */\r\n\r\nL.extend(L.DomEvent, {\r\n\r\n\t_touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',\r\n\t_touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',\r\n\r\n\t// inspired by Zepto touch code by Thomas Fuchs\r\n\taddDoubleTapListener: function (obj, handler, id) {\r\n\t\tvar last, touch,\r\n\t\t    doubleTap = false,\r\n\t\t    delay = 250;\r\n\r\n\t\tfunction onTouchStart(e) {\r\n\t\t\tvar count;\r\n\r\n\t\t\tif (L.Browser.pointer) {\r\n\t\t\t\tif ((!L.Browser.edge) || e.pointerType === 'mouse') { return; }\r\n\t\t\t\tcount = L.DomEvent._pointersCount;\r\n\t\t\t} else {\r\n\t\t\t\tcount = e.touches.length;\r\n\t\t\t}\r\n\r\n\t\t\tif (count > 1) { return; }\r\n\r\n\t\t\tvar now = Date.now(),\r\n\t\t\t    delta = now - (last || now);\r\n\r\n\t\t\ttouch = e.touches ? e.touches[0] : e;\r\n\t\t\tdoubleTap = (delta > 0 && delta <= delay);\r\n\t\t\tlast = now;\r\n\t\t}\r\n\r\n\t\tfunction onTouchEnd(e) {\r\n\t\t\tif (doubleTap && !touch.cancelBubble) {\r\n\t\t\t\tif (L.Browser.pointer) {\r\n\t\t\t\t\tif ((!L.Browser.edge) || e.pointerType === 'mouse') { return; }\r\n\r\n\t\t\t\t\t// work around .type being readonly with MSPointer* events\r\n\t\t\t\t\tvar newTouch = {},\r\n\t\t\t\t\t    prop, i;\r\n\r\n\t\t\t\t\tfor (i in touch) {\r\n\t\t\t\t\t\tprop = touch[i];\r\n\t\t\t\t\t\tnewTouch[i] = prop && prop.bind ? prop.bind(touch) : prop;\r\n\t\t\t\t\t}\r\n\t\t\t\t\ttouch = newTouch;\r\n\t\t\t\t}\r\n\t\t\t\ttouch.type = 'dblclick';\r\n\t\t\t\thandler(touch);\r\n\t\t\t\tlast = null;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar pre = '_leaflet_',\r\n\t\t    touchstart = this._touchstart,\r\n\t\t    touchend = this._touchend;\r\n\r\n\t\tobj[pre + touchstart + id] = onTouchStart;\r\n\t\tobj[pre + touchend + id] = onTouchEnd;\r\n\t\tobj[pre + 'dblclick' + id] = handler;\r\n\r\n\t\tobj.addEventListener(touchstart, onTouchStart, false);\r\n\t\tobj.addEventListener(touchend, onTouchEnd, false);\r\n\r\n\t\t// On some platforms (notably, chrome<55 on win10 + touchscreen + mouse),\r\n\t\t// the browser doesn't fire touchend/pointerup events but does fire\r\n\t\t// native dblclicks. See #4127.\r\n\t\t// Edge 14 also fires native dblclicks, but only for pointerType mouse, see #5180.\r\n\t\tobj.addEventListener('dblclick', handler, false);\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tremoveDoubleTapListener: function (obj, id) {\r\n\t\tvar pre = '_leaflet_',\r\n\t\t    touchstart = obj[pre + this._touchstart + id],\r\n\t\t    touchend = obj[pre + this._touchend + id],\r\n\t\t    dblclick = obj[pre + 'dblclick' + id];\r\n\r\n\t\tobj.removeEventListener(this._touchstart, touchstart, false);\r\n\t\tobj.removeEventListener(this._touchend, touchend, false);\r\n\t\tif (!L.Browser.edge) {\r\n\t\t\tobj.removeEventListener('dblclick', dblclick, false);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n});\r\n","/*\n * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.\n */\n\nL.extend(L.DomEvent, {\n\n\tPOINTER_DOWN:   L.Browser.msPointer ? 'MSPointerDown'   : 'pointerdown',\n\tPOINTER_MOVE:   L.Browser.msPointer ? 'MSPointerMove'   : 'pointermove',\n\tPOINTER_UP:     L.Browser.msPointer ? 'MSPointerUp'     : 'pointerup',\n\tPOINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',\n\tTAG_WHITE_LIST: ['INPUT', 'SELECT', 'OPTION'],\n\n\t_pointers: {},\n\t_pointersCount: 0,\n\n\t// Provides a touch events wrapper for (ms)pointer events.\n\t// ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890\n\n\taddPointerListener: function (obj, type, handler, id) {\n\n\t\tif (type === 'touchstart') {\n\t\t\tthis._addPointerStart(obj, handler, id);\n\n\t\t} else if (type === 'touchmove') {\n\t\t\tthis._addPointerMove(obj, handler, id);\n\n\t\t} else if (type === 'touchend') {\n\t\t\tthis._addPointerEnd(obj, handler, id);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremovePointerListener: function (obj, type, id) {\n\t\tvar handler = obj['_leaflet_' + type + id];\n\n\t\tif (type === 'touchstart') {\n\t\t\tobj.removeEventListener(this.POINTER_DOWN, handler, false);\n\n\t\t} else if (type === 'touchmove') {\n\t\t\tobj.removeEventListener(this.POINTER_MOVE, handler, false);\n\n\t\t} else if (type === 'touchend') {\n\t\t\tobj.removeEventListener(this.POINTER_UP, handler, false);\n\t\t\tobj.removeEventListener(this.POINTER_CANCEL, handler, false);\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_addPointerStart: function (obj, handler, id) {\n\t\tvar onDown = L.bind(function (e) {\n\t\t\tif (e.pointerType !== 'mouse' && e.MSPOINTER_TYPE_MOUSE && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {\n\t\t\t\t// In IE11, some touch events needs to fire for form controls, or\n\t\t\t\t// the controls will stop working. We keep a whitelist of tag names that\n\t\t\t\t// need these events. For other target tags, we prevent default on the event.\n\t\t\t\tif (this.TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) {\n\t\t\t\t\tL.DomEvent.preventDefault(e);\n\t\t\t\t} else {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._handlePointer(e, handler);\n\t\t}, this);\n\n\t\tobj['_leaflet_touchstart' + id] = onDown;\n\t\tobj.addEventListener(this.POINTER_DOWN, onDown, false);\n\n\t\t// need to keep track of what pointers and how many are active to provide e.touches emulation\n\t\tif (!this._pointerDocListener) {\n\t\t\tvar pointerUp = L.bind(this._globalPointerUp, this);\n\n\t\t\t// we listen documentElement as any drags that end by moving the touch off the screen get fired there\n\t\t\tdocument.documentElement.addEventListener(this.POINTER_DOWN, L.bind(this._globalPointerDown, this), true);\n\t\t\tdocument.documentElement.addEventListener(this.POINTER_MOVE, L.bind(this._globalPointerMove, this), true);\n\t\t\tdocument.documentElement.addEventListener(this.POINTER_UP, pointerUp, true);\n\t\t\tdocument.documentElement.addEventListener(this.POINTER_CANCEL, pointerUp, true);\n\n\t\t\tthis._pointerDocListener = true;\n\t\t}\n\t},\n\n\t_globalPointerDown: function (e) {\n\t\tthis._pointers[e.pointerId] = e;\n\t\tthis._pointersCount++;\n\t},\n\n\t_globalPointerMove: function (e) {\n\t\tif (this._pointers[e.pointerId]) {\n\t\t\tthis._pointers[e.pointerId] = e;\n\t\t}\n\t},\n\n\t_globalPointerUp: function (e) {\n\t\tdelete this._pointers[e.pointerId];\n\t\tthis._pointersCount--;\n\t},\n\n\t_handlePointer: function (e, handler) {\n\t\te.touches = [];\n\t\tfor (var i in this._pointers) {\n\t\t\te.touches.push(this._pointers[i]);\n\t\t}\n\t\te.changedTouches = [e];\n\n\t\thandler(e);\n\t},\n\n\t_addPointerMove: function (obj, handler, id) {\n\t\tvar onMove = L.bind(function (e) {\n\t\t\t// don't fire touch moves when mouse isn't down\n\t\t\tif ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }\n\n\t\t\tthis._handlePointer(e, handler);\n\t\t}, this);\n\n\t\tobj['_leaflet_touchmove' + id] = onMove;\n\t\tobj.addEventListener(this.POINTER_MOVE, onMove, false);\n\t},\n\n\t_addPointerEnd: function (obj, handler, id) {\n\t\tvar onUp = L.bind(function (e) {\n\t\t\tthis._handlePointer(e, handler);\n\t\t}, this);\n\n\t\tobj['_leaflet_touchend' + id] = onUp;\n\t\tobj.addEventListener(this.POINTER_UP, onUp, false);\n\t\tobj.addEventListener(this.POINTER_CANCEL, onUp, false);\n\t}\n});\n","/*\n * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.\n */\n\n// @namespace Map\n// @section Interaction Options\nL.Map.mergeOptions({\n\t// @section Touch interaction options\n\t// @option touchZoom: Boolean|String = *\n\t// Whether the map can be zoomed by touch-dragging with two fingers. If\n\t// passed `'center'`, it will zoom to the center of the view regardless of\n\t// where the touch events (fingers) were. Enabled for touch-capable web\n\t// browsers except for old Androids.\n\ttouchZoom: L.Browser.touch && !L.Browser.android23,\n\n\t// @option bounceAtZoomLimits: Boolean = true\n\t// Set it to false if you don't want the map to zoom beyond min/max zoom\n\t// and then bounce back when pinch-zooming.\n\tbounceAtZoomLimits: true\n});\n\nL.Map.TouchZoom = L.Handler.extend({\n\taddHooks: function () {\n\t\tL.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');\n\t\tL.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tL.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');\n\t\tL.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\t_onTouchStart: function (e) {\n\t\tvar map = this._map;\n\t\tif (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }\n\n\t\tvar p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t    p2 = map.mouseEventToContainerPoint(e.touches[1]);\n\n\t\tthis._centerPoint = map.getSize()._divideBy(2);\n\t\tthis._startLatLng = map.containerPointToLatLng(this._centerPoint);\n\t\tif (map.options.touchZoom !== 'center') {\n\t\t\tthis._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));\n\t\t}\n\n\t\tthis._startDist = p1.distanceTo(p2);\n\t\tthis._startZoom = map.getZoom();\n\n\t\tthis._moved = false;\n\t\tthis._zooming = true;\n\n\t\tmap._stop();\n\n\t\tL.DomEvent\n\t\t    .on(document, 'touchmove', this._onTouchMove, this)\n\t\t    .on(document, 'touchend', this._onTouchEnd, this);\n\n\t\tL.DomEvent.preventDefault(e);\n\t},\n\n\t_onTouchMove: function (e) {\n\t\tif (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }\n\n\t\tvar map = this._map,\n\t\t    p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t    p2 = map.mouseEventToContainerPoint(e.touches[1]),\n\t\t    scale = p1.distanceTo(p2) / this._startDist;\n\n\n\t\tthis._zoom = map.getScaleZoom(scale, this._startZoom);\n\n\t\tif (!map.options.bounceAtZoomLimits && (\n\t\t\t(this._zoom < map.getMinZoom() && scale < 1) ||\n\t\t\t(this._zoom > map.getMaxZoom() && scale > 1))) {\n\t\t\tthis._zoom = map._limitZoom(this._zoom);\n\t\t}\n\n\t\tif (map.options.touchZoom === 'center') {\n\t\t\tthis._center = this._startLatLng;\n\t\t\tif (scale === 1) { return; }\n\t\t} else {\n\t\t\t// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng\n\t\t\tvar delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);\n\t\t\tif (scale === 1 && delta.x === 0 && delta.y === 0) { return; }\n\t\t\tthis._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);\n\t\t}\n\n\t\tif (!this._moved) {\n\t\t\tmap._moveStart(true);\n\t\t\tthis._moved = true;\n\t\t}\n\n\t\tL.Util.cancelAnimFrame(this._animRequest);\n\n\t\tvar moveFn = L.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});\n\t\tthis._animRequest = L.Util.requestAnimFrame(moveFn, this, true);\n\n\t\tL.DomEvent.preventDefault(e);\n\t},\n\n\t_onTouchEnd: function () {\n\t\tif (!this._moved || !this._zooming) {\n\t\t\tthis._zooming = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._zooming = false;\n\t\tL.Util.cancelAnimFrame(this._animRequest);\n\n\t\tL.DomEvent\n\t\t    .off(document, 'touchmove', this._onTouchMove)\n\t\t    .off(document, 'touchend', this._onTouchEnd);\n\n\t\t// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.\n\t\tif (this._map.options.zoomAnimation) {\n\t\t\tthis._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);\n\t\t} else {\n\t\t\tthis._map._resetView(this._center, this._map._limitZoom(this._zoom));\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property touchZoom: Handler\n// Touch zoom handler.\nL.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);\n","/*\n * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.\n */\n\n// @namespace Map\n// @section Interaction Options\nL.Map.mergeOptions({\n\t// @section Touch interaction options\n\t// @option tap: Boolean = true\n\t// Enables mobile hacks for supporting instant taps (fixing 200ms click\n\t// delay on iOS/Android) and touch holds (fired as `contextmenu` events).\n\ttap: true,\n\n\t// @option tapTolerance: Number = 15\n\t// The max number of pixels a user can shift his finger during touch\n\t// for it to be considered a valid tap.\n\ttapTolerance: 15\n});\n\nL.Map.Tap = L.Handler.extend({\n\taddHooks: function () {\n\t\tL.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tL.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\t_onDown: function (e) {\n\t\tif (!e.touches) { return; }\n\n\t\tL.DomEvent.preventDefault(e);\n\n\t\tthis._fireClick = true;\n\n\t\t// don't simulate click or track longpress if more than 1 touch\n\t\tif (e.touches.length > 1) {\n\t\t\tthis._fireClick = false;\n\t\t\tclearTimeout(this._holdTimeout);\n\t\t\treturn;\n\t\t}\n\n\t\tvar first = e.touches[0],\n\t\t    el = first.target;\n\n\t\tthis._startPos = this._newPos = new L.Point(first.clientX, first.clientY);\n\n\t\t// if touching a link, highlight it\n\t\tif (el.tagName && el.tagName.toLowerCase() === 'a') {\n\t\t\tL.DomUtil.addClass(el, 'leaflet-active');\n\t\t}\n\n\t\t// simulate long hold but setting a timeout\n\t\tthis._holdTimeout = setTimeout(L.bind(function () {\n\t\t\tif (this._isTapValid()) {\n\t\t\t\tthis._fireClick = false;\n\t\t\t\tthis._onUp();\n\t\t\t\tthis._simulateEvent('contextmenu', first);\n\t\t\t}\n\t\t}, this), 1000);\n\n\t\tthis._simulateEvent('mousedown', first);\n\n\t\tL.DomEvent.on(document, {\n\t\t\ttouchmove: this._onMove,\n\t\t\ttouchend: this._onUp\n\t\t}, this);\n\t},\n\n\t_onUp: function (e) {\n\t\tclearTimeout(this._holdTimeout);\n\n\t\tL.DomEvent.off(document, {\n\t\t\ttouchmove: this._onMove,\n\t\t\ttouchend: this._onUp\n\t\t}, this);\n\n\t\tif (this._fireClick && e && e.changedTouches) {\n\n\t\t\tvar first = e.changedTouches[0],\n\t\t\t    el = first.target;\n\n\t\t\tif (el && el.tagName && el.tagName.toLowerCase() === 'a') {\n\t\t\t\tL.DomUtil.removeClass(el, 'leaflet-active');\n\t\t\t}\n\n\t\t\tthis._simulateEvent('mouseup', first);\n\n\t\t\t// simulate click if the touch didn't move too much\n\t\t\tif (this._isTapValid()) {\n\t\t\t\tthis._simulateEvent('click', first);\n\t\t\t}\n\t\t}\n\t},\n\n\t_isTapValid: function () {\n\t\treturn this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;\n\t},\n\n\t_onMove: function (e) {\n\t\tvar first = e.touches[0];\n\t\tthis._newPos = new L.Point(first.clientX, first.clientY);\n\t\tthis._simulateEvent('mousemove', first);\n\t},\n\n\t_simulateEvent: function (type, e) {\n\t\tvar simulatedEvent = document.createEvent('MouseEvents');\n\n\t\tsimulatedEvent._simulated = true;\n\t\te.target._simulatedClick = true;\n\n\t\tsimulatedEvent.initMouseEvent(\n\t\t        type, true, true, window, 1,\n\t\t        e.screenX, e.screenY,\n\t\t        e.clientX, e.clientY,\n\t\t        false, false, false, false, 0, null);\n\n\t\te.target.dispatchEvent(simulatedEvent);\n\t}\n});\n\n// @section Handlers\n// @property tap: Handler\n// Mobile touch hacks (quick tap and touch hold) handler.\nif (L.Browser.touch && !L.Browser.pointer) {\n\tL.Map.addInitHook('addHandler', 'tap', L.Map.Tap);\n}\n","/*\n * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map\n * (zoom to a selected bounding box), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nL.Map.mergeOptions({\n\t// @option boxZoom: Boolean = true\n\t// Whether the map can be zoomed to a rectangular area specified by\n\t// dragging the mouse while pressing the shift key.\n\tboxZoom: true\n});\n\nL.Map.BoxZoom = L.Handler.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t\tthis._container = map._container;\n\t\tthis._pane = map._panes.overlayPane;\n\t},\n\n\taddHooks: function () {\n\t\tL.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tL.DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tmoved: function () {\n\t\treturn this._moved;\n\t},\n\n\t_resetState: function () {\n\t\tthis._moved = false;\n\t},\n\n\t_onMouseDown: function (e) {\n\t\tif (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }\n\n\t\tthis._resetState();\n\n\t\tL.DomUtil.disableTextSelection();\n\t\tL.DomUtil.disableImageDrag();\n\n\t\tthis._startPoint = this._map.mouseEventToContainerPoint(e);\n\n\t\tL.DomEvent.on(document, {\n\t\t\tcontextmenu: L.DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._moved) {\n\t\t\tthis._moved = true;\n\n\t\t\tthis._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._container);\n\t\t\tL.DomUtil.addClass(this._container, 'leaflet-crosshair');\n\n\t\t\tthis._map.fire('boxzoomstart');\n\t\t}\n\n\t\tthis._point = this._map.mouseEventToContainerPoint(e);\n\n\t\tvar bounds = new L.Bounds(this._point, this._startPoint),\n\t\t    size = bounds.getSize();\n\n\t\tL.DomUtil.setPosition(this._box, bounds.min);\n\n\t\tthis._box.style.width  = size.x + 'px';\n\t\tthis._box.style.height = size.y + 'px';\n\t},\n\n\t_finish: function () {\n\t\tif (this._moved) {\n\t\t\tL.DomUtil.remove(this._box);\n\t\t\tL.DomUtil.removeClass(this._container, 'leaflet-crosshair');\n\t\t}\n\n\t\tL.DomUtil.enableTextSelection();\n\t\tL.DomUtil.enableImageDrag();\n\n\t\tL.DomEvent.off(document, {\n\t\t\tcontextmenu: L.DomEvent.stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseUp: function (e) {\n\t\tif ((e.which !== 1) && (e.button !== 1)) { return; }\n\n\t\tthis._finish();\n\n\t\tif (!this._moved) { return; }\n\t\t// Postpone to next JS tick so internal click event handling\n\t\t// still see it as \"moved\".\n\t\tsetTimeout(L.bind(this._resetState, this), 0);\n\n\t\tvar bounds = new L.LatLngBounds(\n\t\t        this._map.containerPointToLatLng(this._startPoint),\n\t\t        this._map.containerPointToLatLng(this._point));\n\n\t\tthis._map\n\t\t\t.fitBounds(bounds)\n\t\t\t.fire('boxzoomend', {boxZoomBounds: bounds});\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.keyCode === 27) {\n\t\t\tthis._finish();\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property boxZoom: Handler\n// Box (shift-drag with mouse) zoom handler.\nL.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);\n","/*\n * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.\n */\n\n// @namespace Map\n// @section Keyboard Navigation Options\nL.Map.mergeOptions({\n\t// @option keyboard: Boolean = true\n\t// Makes the map focusable and allows users to navigate the map with keyboard\n\t// arrows and `+`/`-` keys.\n\tkeyboard: true,\n\n\t// @option keyboardPanDelta: Number = 80\n\t// Amount of pixels to pan when pressing an arrow key.\n\tkeyboardPanDelta: 80\n});\n\nL.Map.Keyboard = L.Handler.extend({\n\n\tkeyCodes: {\n\t\tleft:    [37],\n\t\tright:   [39],\n\t\tdown:    [40],\n\t\tup:      [38],\n\t\tzoomIn:  [187, 107, 61, 171],\n\t\tzoomOut: [189, 109, 54, 173]\n\t},\n\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\n\t\tthis._setPanDelta(map.options.keyboardPanDelta);\n\t\tthis._setZoomDelta(map.options.zoomDelta);\n\t},\n\n\taddHooks: function () {\n\t\tvar container = this._map._container;\n\n\t\t// make the container focusable by tabbing\n\t\tif (container.tabIndex <= 0) {\n\t\t\tcontainer.tabIndex = '0';\n\t\t}\n\n\t\tL.DomEvent.on(container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.on({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._removeHooks();\n\n\t\tL.DomEvent.off(this._map._container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.off({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\t_onMouseDown: function () {\n\t\tif (this._focused) { return; }\n\n\t\tvar body = document.body,\n\t\t    docEl = document.documentElement,\n\t\t    top = body.scrollTop || docEl.scrollTop,\n\t\t    left = body.scrollLeft || docEl.scrollLeft;\n\n\t\tthis._map._container.focus();\n\n\t\twindow.scrollTo(left, top);\n\t},\n\n\t_onFocus: function () {\n\t\tthis._focused = true;\n\t\tthis._map.fire('focus');\n\t},\n\n\t_onBlur: function () {\n\t\tthis._focused = false;\n\t\tthis._map.fire('blur');\n\t},\n\n\t_setPanDelta: function (panDelta) {\n\t\tvar keys = this._panKeys = {},\n\t\t    codes = this.keyCodes,\n\t\t    i, len;\n\n\t\tfor (i = 0, len = codes.left.length; i < len; i++) {\n\t\t\tkeys[codes.left[i]] = [-1 * panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.right.length; i < len; i++) {\n\t\t\tkeys[codes.right[i]] = [panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.down.length; i < len; i++) {\n\t\t\tkeys[codes.down[i]] = [0, panDelta];\n\t\t}\n\t\tfor (i = 0, len = codes.up.length; i < len; i++) {\n\t\t\tkeys[codes.up[i]] = [0, -1 * panDelta];\n\t\t}\n\t},\n\n\t_setZoomDelta: function (zoomDelta) {\n\t\tvar keys = this._zoomKeys = {},\n\t\t    codes = this.keyCodes,\n\t\t    i, len;\n\n\t\tfor (i = 0, len = codes.zoomIn.length; i < len; i++) {\n\t\t\tkeys[codes.zoomIn[i]] = zoomDelta;\n\t\t}\n\t\tfor (i = 0, len = codes.zoomOut.length; i < len; i++) {\n\t\t\tkeys[codes.zoomOut[i]] = -zoomDelta;\n\t\t}\n\t},\n\n\t_addHooks: function () {\n\t\tL.DomEvent.on(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_removeHooks: function () {\n\t\tL.DomEvent.off(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.altKey || e.ctrlKey || e.metaKey) { return; }\n\n\t\tvar key = e.keyCode,\n\t\t    map = this._map,\n\t\t    offset;\n\n\t\tif (key in this._panKeys) {\n\n\t\t\tif (map._panAnim && map._panAnim._inProgress) { return; }\n\n\t\t\toffset = this._panKeys[key];\n\t\t\tif (e.shiftKey) {\n\t\t\t\toffset = L.point(offset).multiplyBy(3);\n\t\t\t}\n\n\t\t\tmap.panBy(offset);\n\n\t\t\tif (map.options.maxBounds) {\n\t\t\t\tmap.panInsideBounds(map.options.maxBounds);\n\t\t\t}\n\n\t\t} else if (key in this._zoomKeys) {\n\t\t\tmap.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);\n\n\t\t} else if (key === 27) {\n\t\t\tmap.closePopup();\n\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tL.DomEvent.stop(e);\n\t}\n});\n\n// @section Handlers\n// @section Handlers\n// @property keyboard: Handler\n// Keyboard navigation handler.\nL.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard);\n","/*\n * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.\n */\n\n\n/* @namespace Marker\n * @section Interaction handlers\n *\n * 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:\n *\n * ```js\n * marker.dragging.disable();\n * ```\n *\n * @property dragging: Handler\n * Marker dragging handler (by both mouse and touch).\n */\n\nL.Handler.MarkerDrag = L.Handler.extend({\n\tinitialize: function (marker) {\n\t\tthis._marker = marker;\n\t},\n\n\taddHooks: function () {\n\t\tvar icon = this._marker._icon;\n\n\t\tif (!this._draggable) {\n\t\t\tthis._draggable = new L.Draggable(icon, icon, true);\n\t\t}\n\n\t\tthis._draggable.on({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).enable();\n\n\t\tL.DomUtil.addClass(icon, 'leaflet-marker-draggable');\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._draggable.off({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).disable();\n\n\t\tif (this._marker._icon) {\n\t\t\tL.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');\n\t\t}\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\t_onDragStart: function () {\n\t\t// @section Dragging events\n\t\t// @event dragstart: Event\n\t\t// Fired when the user starts dragging the marker.\n\n\t\t// @event movestart: Event\n\t\t// Fired when the marker starts moving (because of dragging).\n\n\t\tthis._oldLatLng = this._marker.getLatLng();\n\t\tthis._marker\n\t\t    .closePopup()\n\t\t    .fire('movestart')\n\t\t    .fire('dragstart');\n\t},\n\n\t_onDrag: function (e) {\n\t\tvar marker = this._marker,\n\t\t    shadow = marker._shadow,\n\t\t    iconPos = L.DomUtil.getPosition(marker._icon),\n\t\t    latlng = marker._map.layerPointToLatLng(iconPos);\n\n\t\t// update shadow position\n\t\tif (shadow) {\n\t\t\tL.DomUtil.setPosition(shadow, iconPos);\n\t\t}\n\n\t\tmarker._latlng = latlng;\n\t\te.latlng = latlng;\n\t\te.oldLatLng = this._oldLatLng;\n\n\t\t// @event drag: Event\n\t\t// Fired repeatedly while the user drags the marker.\n\t\tmarker\n\t\t    .fire('move', e)\n\t\t    .fire('drag', e);\n\t},\n\n\t_onDragEnd: function (e) {\n\t\t// @event dragend: DragEndEvent\n\t\t// Fired when the user stops dragging the marker.\n\n\t\t// @event moveend: Event\n\t\t// Fired when the marker stops moving (because of dragging).\n\t\tdelete this._oldLatLng;\n\t\tthis._marker\n\t\t    .fire('moveend')\n\t\t    .fire('dragend', e);\n\t}\n});\n","/*\r\n * @class Control\r\n * @aka L.Control\r\n * @inherits Class\r\n *\r\n * L.Control is a base class for implementing map controls. Handles positioning.\r\n * All other controls extend from this class.\r\n */\r\n\r\nL.Control = L.Class.extend({\r\n\t// @section\r\n\t// @aka Control options\r\n\toptions: {\r\n\t\t// @option position: String = 'topright'\r\n\t\t// The position of the control (one of the map corners). Possible values are `'topleft'`,\r\n\t\t// `'topright'`, `'bottomleft'` or `'bottomright'`\r\n\t\tposition: 'topright'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tL.setOptions(this, options);\r\n\t},\r\n\r\n\t/* @section\r\n\t * Classes extending L.Control will inherit the following methods:\r\n\t *\r\n\t * @method getPosition: string\r\n\t * Returns the position of the control.\r\n\t */\r\n\tgetPosition: function () {\r\n\t\treturn this.options.position;\r\n\t},\r\n\r\n\t// @method setPosition(position: string): this\r\n\t// Sets the position of the control.\r\n\tsetPosition: function (position) {\r\n\t\tvar map = this._map;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.removeControl(this);\r\n\t\t}\r\n\r\n\t\tthis.options.position = position;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.addControl(this);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTMLElement that contains the control.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method addTo(map: Map): this\r\n\t// Adds the control to the given map.\r\n\taddTo: function (map) {\r\n\t\tthis.remove();\r\n\t\tthis._map = map;\r\n\r\n\t\tvar container = this._container = this.onAdd(map),\r\n\t\t    pos = this.getPosition(),\r\n\t\t    corner = map._controlCorners[pos];\r\n\r\n\t\tL.DomUtil.addClass(container, 'leaflet-control');\r\n\r\n\t\tif (pos.indexOf('bottom') !== -1) {\r\n\t\t\tcorner.insertBefore(container, corner.firstChild);\r\n\t\t} else {\r\n\t\t\tcorner.appendChild(container);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove: this\r\n\t// Removes the control from the map it is currently active on.\r\n\tremove: function () {\r\n\t\tif (!this._map) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tL.DomUtil.remove(this._container);\r\n\r\n\t\tif (this.onRemove) {\r\n\t\t\tthis.onRemove(this._map);\r\n\t\t}\r\n\r\n\t\tthis._map = null;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_refocusOnMap: function (e) {\r\n\t\t// if map exists and event is not a keyboard event\r\n\t\tif (this._map && e && e.screenX > 0 && e.screenY > 0) {\r\n\t\t\tthis._map.getContainer().focus();\r\n\t\t}\r\n\t}\r\n});\r\n\r\nL.control = function (options) {\r\n\treturn new L.Control(options);\r\n};\r\n\r\n/* @section Extension methods\r\n * @uninheritable\r\n *\r\n * Every control should extend from `L.Control` and (re-)implement the following methods.\r\n *\r\n * @method onAdd(map: Map): HTMLElement\r\n * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).\r\n *\r\n * @method onRemove(map: Map)\r\n * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).\r\n */\r\n\r\n/* @namespace Map\r\n * @section Methods for Layers and Controls\r\n */\r\nL.Map.include({\r\n\t// @method addControl(control: Control): this\r\n\t// Adds the given control to the map\r\n\taddControl: function (control) {\r\n\t\tcontrol.addTo(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeControl(control: Control): this\r\n\t// Removes the given control from the map\r\n\tremoveControl: function (control) {\r\n\t\tcontrol.remove();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initControlPos: function () {\r\n\t\tvar corners = this._controlCorners = {},\r\n\t\t    l = 'leaflet-',\r\n\t\t    container = this._controlContainer =\r\n\t\t            L.DomUtil.create('div', l + 'control-container', this._container);\r\n\r\n\t\tfunction createCorner(vSide, hSide) {\r\n\t\t\tvar className = l + vSide + ' ' + l + hSide;\r\n\r\n\t\t\tcorners[vSide + hSide] = L.DomUtil.create('div', className, container);\r\n\t\t}\r\n\r\n\t\tcreateCorner('top', 'left');\r\n\t\tcreateCorner('top', 'right');\r\n\t\tcreateCorner('bottom', 'left');\r\n\t\tcreateCorner('bottom', 'right');\r\n\t},\r\n\r\n\t_clearControlPos: function () {\r\n\t\tL.DomUtil.remove(this._controlContainer);\r\n\t}\r\n});\r\n","/*\r\n * @class Control.Zoom\r\n * @aka L.Control.Zoom\r\n * @inherits Control\r\n *\r\n * 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`.\r\n */\r\n\r\nL.Control.Zoom = L.Control.extend({\r\n\t// @section\r\n\t// @aka Control.Zoom options\r\n\toptions: {\r\n\t\tposition: 'topleft',\r\n\r\n\t\t// @option zoomInText: String = '+'\r\n\t\t// The text set on the 'zoom in' button.\r\n\t\tzoomInText: '+',\r\n\r\n\t\t// @option zoomInTitle: String = 'Zoom in'\r\n\t\t// The title set on the 'zoom in' button.\r\n\t\tzoomInTitle: 'Zoom in',\r\n\r\n\t\t// @option zoomOutText: String = '-'\r\n\t\t// The text set on the 'zoom out' button.\r\n\t\tzoomOutText: '-',\r\n\r\n\t\t// @option zoomOutTitle: String = 'Zoom out'\r\n\t\t// The title set on the 'zoom out' button.\r\n\t\tzoomOutTitle: 'Zoom out'\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tvar zoomName = 'leaflet-control-zoom',\r\n\t\t    container = L.DomUtil.create('div', zoomName + ' leaflet-bar'),\r\n\t\t    options = this.options;\r\n\r\n\t\tthis._zoomInButton  = this._createButton(options.zoomInText, options.zoomInTitle,\r\n\t\t        zoomName + '-in',  container, this._zoomIn);\r\n\t\tthis._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,\r\n\t\t        zoomName + '-out', container, this._zoomOut);\r\n\r\n\t\tthis._updateDisabled();\r\n\t\tmap.on('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\r\n\t\treturn container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\t},\r\n\r\n\tdisable: function () {\r\n\t\tthis._disabled = true;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\tenable: function () {\r\n\t\tthis._disabled = false;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_zoomIn: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {\r\n\t\t\tthis._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_zoomOut: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom > this._map.getMinZoom()) {\r\n\t\t\tthis._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_createButton: function (html, title, className, container, fn) {\r\n\t\tvar link = L.DomUtil.create('a', className, container);\r\n\t\tlink.innerHTML = html;\r\n\t\tlink.href = '#';\r\n\t\tlink.title = title;\r\n\r\n\t\t/*\r\n\t\t * Will force screen readers like VoiceOver to read this as \"Zoom in - button\"\r\n\t\t */\r\n\t\tlink.setAttribute('role', 'button');\r\n\t\tlink.setAttribute('aria-label', title);\r\n\r\n\t\tL.DomEvent\r\n\t\t    .on(link, 'mousedown dblclick', L.DomEvent.stopPropagation)\r\n\t\t    .on(link, 'click', L.DomEvent.stop)\r\n\t\t    .on(link, 'click', fn, this)\r\n\t\t    .on(link, 'click', this._refocusOnMap, this);\r\n\r\n\t\treturn link;\r\n\t},\r\n\r\n\t_updateDisabled: function () {\r\n\t\tvar map = this._map,\r\n\t\t    className = 'leaflet-disabled';\r\n\r\n\t\tL.DomUtil.removeClass(this._zoomInButton, className);\r\n\t\tL.DomUtil.removeClass(this._zoomOutButton, className);\r\n\r\n\t\tif (this._disabled || map._zoom === map.getMinZoom()) {\r\n\t\t\tL.DomUtil.addClass(this._zoomOutButton, className);\r\n\t\t}\r\n\t\tif (this._disabled || map._zoom === map.getMaxZoom()) {\r\n\t\t\tL.DomUtil.addClass(this._zoomInButton, className);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option zoomControl: Boolean = true\r\n// Whether a [zoom control](#control-zoom) is added to the map by default.\r\nL.Map.mergeOptions({\r\n\tzoomControl: true\r\n});\r\n\r\nL.Map.addInitHook(function () {\r\n\tif (this.options.zoomControl) {\r\n\t\tthis.zoomControl = new L.Control.Zoom();\r\n\t\tthis.addControl(this.zoomControl);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Zoom\r\n// @factory L.control.zoom(options: Control.Zoom options)\r\n// Creates a zoom control\r\nL.control.zoom = function (options) {\r\n\treturn new L.Control.Zoom(options);\r\n};\r\n","/*\r\n * @class Control.Attribution\r\n * @aka L.Control.Attribution\r\n * @inherits Control\r\n *\r\n * 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.\r\n */\r\n\r\nL.Control.Attribution = L.Control.extend({\r\n\t// @section\r\n\t// @aka Control.Attribution options\r\n\toptions: {\r\n\t\tposition: 'bottomright',\r\n\r\n\t\t// @option prefix: String = 'Leaflet'\r\n\t\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\t\tprefix: '<a href=\"http://leafletjs.com\" title=\"A JS library for interactive maps\">Leaflet</a>'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tL.setOptions(this, options);\r\n\r\n\t\tthis._attributions = {};\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tmap.attributionControl = this;\r\n\t\tthis._container = L.DomUtil.create('div', 'leaflet-control-attribution');\r\n\t\tif (L.DomEvent) {\r\n\t\t\tL.DomEvent.disableClickPropagation(this._container);\r\n\t\t}\r\n\r\n\t\t// TODO ugly, refactor\r\n\t\tfor (var i in map._layers) {\r\n\t\t\tif (map._layers[i].getAttribution) {\r\n\t\t\t\tthis.addAttribution(map._layers[i].getAttribution());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method setPrefix(prefix: String): this\r\n\t// Sets the text before the attributions.\r\n\tsetPrefix: function (prefix) {\r\n\t\tthis.options.prefix = prefix;\r\n\t\tthis._update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addAttribution(text: String): this\r\n\t// Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).\r\n\taddAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (!this._attributions[text]) {\r\n\t\t\tthis._attributions[text] = 0;\r\n\t\t}\r\n\t\tthis._attributions[text]++;\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeAttribution(text: String): this\r\n\t// Removes an attribution text.\r\n\tremoveAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (this._attributions[text]) {\r\n\t\t\tthis._attributions[text]--;\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar attribs = [];\r\n\r\n\t\tfor (var i in this._attributions) {\r\n\t\t\tif (this._attributions[i]) {\r\n\t\t\t\tattribs.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar prefixAndAttribs = [];\r\n\r\n\t\tif (this.options.prefix) {\r\n\t\t\tprefixAndAttribs.push(this.options.prefix);\r\n\t\t}\r\n\t\tif (attribs.length) {\r\n\t\t\tprefixAndAttribs.push(attribs.join(', '));\r\n\t\t}\r\n\r\n\t\tthis._container.innerHTML = prefixAndAttribs.join(' | ');\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option attributionControl: Boolean = true\r\n// Whether a [attribution control](#control-attribution) is added to the map by default.\r\nL.Map.mergeOptions({\r\n\tattributionControl: true\r\n});\r\n\r\nL.Map.addInitHook(function () {\r\n\tif (this.options.attributionControl) {\r\n\t\tnew L.Control.Attribution().addTo(this);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Attribution\r\n// @factory L.control.attribution(options: Control.Attribution options)\r\n// Creates an attribution control.\r\nL.control.attribution = function (options) {\r\n\treturn new L.Control.Attribution(options);\r\n};\r\n","/*\n * @class Control.Scale\n * @aka L.Control.Scale\n * @inherits Control\n *\n * 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`.\n *\n * @example\n *\n * ```js\n * L.control.scale().addTo(map);\n * ```\n */\n\nL.Control.Scale = L.Control.extend({\n\t// @section\n\t// @aka Control.Scale options\n\toptions: {\n\t\tposition: 'bottomleft',\n\n\t\t// @option maxWidth: Number = 100\n\t\t// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).\n\t\tmaxWidth: 100,\n\n\t\t// @option metric: Boolean = True\n\t\t// Whether to show the metric scale line (m/km).\n\t\tmetric: true,\n\n\t\t// @option imperial: Boolean = True\n\t\t// Whether to show the imperial scale line (mi/ft).\n\t\timperial: true\n\n\t\t// @option updateWhenIdle: Boolean = false\n\t\t// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).\n\t},\n\n\tonAdd: function (map) {\n\t\tvar className = 'leaflet-control-scale',\n\t\t    container = L.DomUtil.create('div', className),\n\t\t    options = this.options;\n\n\t\tthis._addScales(options, className + '-line', container);\n\n\t\tmap.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t\tmap.whenReady(this._update, this);\n\n\t\treturn container;\n\t},\n\n\tonRemove: function (map) {\n\t\tmap.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t},\n\n\t_addScales: function (options, className, container) {\n\t\tif (options.metric) {\n\t\t\tthis._mScale = L.DomUtil.create('div', className, container);\n\t\t}\n\t\tif (options.imperial) {\n\t\t\tthis._iScale = L.DomUtil.create('div', className, container);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tvar map = this._map,\n\t\t    y = map.getSize().y / 2;\n\n\t\tvar maxMeters = map.distance(\n\t\t\t\tmap.containerPointToLatLng([0, y]),\n\t\t\t\tmap.containerPointToLatLng([this.options.maxWidth, y]));\n\n\t\tthis._updateScales(maxMeters);\n\t},\n\n\t_updateScales: function (maxMeters) {\n\t\tif (this.options.metric && maxMeters) {\n\t\t\tthis._updateMetric(maxMeters);\n\t\t}\n\t\tif (this.options.imperial && maxMeters) {\n\t\t\tthis._updateImperial(maxMeters);\n\t\t}\n\t},\n\n\t_updateMetric: function (maxMeters) {\n\t\tvar meters = this._getRoundNum(maxMeters),\n\t\t    label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';\n\n\t\tthis._updateScale(this._mScale, label, meters / maxMeters);\n\t},\n\n\t_updateImperial: function (maxMeters) {\n\t\tvar maxFeet = maxMeters * 3.2808399,\n\t\t    maxMiles, miles, feet;\n\n\t\tif (maxFeet > 5280) {\n\t\t\tmaxMiles = maxFeet / 5280;\n\t\t\tmiles = this._getRoundNum(maxMiles);\n\t\t\tthis._updateScale(this._iScale, miles + ' mi', miles / maxMiles);\n\n\t\t} else {\n\t\t\tfeet = this._getRoundNum(maxFeet);\n\t\t\tthis._updateScale(this._iScale, feet + ' ft', feet / maxFeet);\n\t\t}\n\t},\n\n\t_updateScale: function (scale, text, ratio) {\n\t\tscale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';\n\t\tscale.innerHTML = text;\n\t},\n\n\t_getRoundNum: function (num) {\n\t\tvar pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),\n\t\t    d = num / pow10;\n\n\t\td = d >= 10 ? 10 :\n\t\t    d >= 5 ? 5 :\n\t\t    d >= 3 ? 3 :\n\t\t    d >= 2 ? 2 : 1;\n\n\t\treturn pow10 * d;\n\t}\n});\n\n\n// @factory L.control.scale(options?: Control.Scale options)\n// Creates an scale control with the given options.\nL.control.scale = function (options) {\n\treturn new L.Control.Scale(options);\n};\n","/*\r\n * @class Control.Layers\r\n * @aka L.Control.Layers\r\n * @inherits Control\r\n *\r\n * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control.html)). Extends `Control`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var baseLayers = {\r\n * \t\"Mapbox\": mapbox,\r\n * \t\"OpenStreetMap\": osm\r\n * };\r\n *\r\n * var overlays = {\r\n * \t\"Marker\": marker,\r\n * \t\"Roads\": roadsLayer\r\n * };\r\n *\r\n * L.control.layers(baseLayers, overlays).addTo(map);\r\n * ```\r\n *\r\n * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:\r\n *\r\n * ```js\r\n * {\r\n *     \"<someName1>\": layer1,\r\n *     \"<someName2>\": layer2\r\n * }\r\n * ```\r\n *\r\n * The layer names can contain HTML, which allows you to add additional styling to the items:\r\n *\r\n * ```js\r\n * {\"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>\": myLayer}\r\n * ```\r\n */\r\n\r\n\r\nL.Control.Layers = L.Control.extend({\r\n\t// @section\r\n\t// @aka Control.Layers options\r\n\toptions: {\r\n\t\t// @option collapsed: Boolean = true\r\n\t\t// If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.\r\n\t\tcollapsed: true,\r\n\t\tposition: 'topright',\r\n\r\n\t\t// @option autoZIndex: Boolean = true\r\n\t\t// 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.\r\n\t\tautoZIndex: true,\r\n\r\n\t\t// @option hideSingleBase: Boolean = false\r\n\t\t// If `true`, the base layers in the control will be hidden when there is only one.\r\n\t\thideSingleBase: false,\r\n\r\n\t\t// @option sortLayers: Boolean = false\r\n\t\t// Whether to sort the layers. When `false`, layers will keep the order\r\n\t\t// in which they were added to the control.\r\n\t\tsortLayers: false,\r\n\r\n\t\t// @option sortFunction: Function = *\r\n\t\t// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)\r\n\t\t// that will be used for sorting the layers, when `sortLayers` is `true`.\r\n\t\t// The function receives both the `L.Layer` instances and their names, as in\r\n\t\t// `sortFunction(layerA, layerB, nameA, nameB)`.\r\n\t\t// By default, it sorts layers alphabetically by their name.\r\n\t\tsortFunction: function (layerA, layerB, nameA, nameB) {\r\n\t\t\treturn nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);\r\n\t\t}\r\n\t},\r\n\r\n\tinitialize: function (baseLayers, overlays, options) {\r\n\t\tL.setOptions(this, options);\r\n\r\n\t\tthis._layers = [];\r\n\t\tthis._lastZIndex = 0;\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tfor (var i in baseLayers) {\r\n\t\t\tthis._addLayer(baseLayers[i], i);\r\n\t\t}\r\n\r\n\t\tfor (i in overlays) {\r\n\t\t\tthis._addLayer(overlays[i], i, true);\r\n\t\t}\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._initLayout();\r\n\t\tthis._update();\r\n\r\n\t\tthis._map = map;\r\n\t\tmap.on('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tthis._map.off('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.off('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addBaseLayer(layer: Layer, name: String): this\r\n\t// Adds a base layer (radio button entry) with the given name to the control.\r\n\taddBaseLayer: function (layer, name) {\r\n\t\tthis._addLayer(layer, name);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method addOverlay(layer: Layer, name: String): this\r\n\t// Adds an overlay (checkbox entry) with the given name to the control.\r\n\taddOverlay: function (layer, name) {\r\n\t\tthis._addLayer(layer, name, true);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Remove the given layer from the control.\r\n\tremoveLayer: function (layer) {\r\n\t\tlayer.off('add remove', this._onLayerChange, this);\r\n\r\n\t\tvar obj = this._getLayer(L.stamp(layer));\r\n\t\tif (obj) {\r\n\t\t\tthis._layers.splice(this._layers.indexOf(obj), 1);\r\n\t\t}\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method expand(): this\r\n\t// Expand the control container if collapsed.\r\n\texpand: function () {\r\n\t\tL.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\tthis._form.style.height = null;\r\n\t\tvar acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);\r\n\t\tif (acceptableHeight < this._form.clientHeight) {\r\n\t\t\tL.DomUtil.addClass(this._form, 'leaflet-control-layers-scrollbar');\r\n\t\t\tthis._form.style.height = acceptableHeight + 'px';\r\n\t\t} else {\r\n\t\t\tL.DomUtil.removeClass(this._form, 'leaflet-control-layers-scrollbar');\r\n\t\t}\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method collapse(): this\r\n\t// Collapse the control container if expanded.\r\n\tcollapse: function () {\r\n\t\tL.DomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar className = 'leaflet-control-layers',\r\n\t\t    container = this._container = L.DomUtil.create('div', className),\r\n\t\t    collapsed = this.options.collapsed;\r\n\r\n\t\t// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released\r\n\t\tcontainer.setAttribute('aria-haspopup', true);\r\n\r\n\t\tL.DomEvent.disableClickPropagation(container);\r\n\t\tif (!L.Browser.touch) {\r\n\t\t\tL.DomEvent.disableScrollPropagation(container);\r\n\t\t}\r\n\r\n\t\tvar form = this._form = L.DomUtil.create('form', className + '-list');\r\n\r\n\t\tif (collapsed) {\r\n\t\t\tthis._map.on('click', this.collapse, this);\r\n\r\n\t\t\tif (!L.Browser.android) {\r\n\t\t\t\tL.DomEvent.on(container, {\r\n\t\t\t\t\tmouseenter: this.expand,\r\n\t\t\t\t\tmouseleave: this.collapse\r\n\t\t\t\t}, this);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);\r\n\t\tlink.href = '#';\r\n\t\tlink.title = 'Layers';\r\n\r\n\t\tif (L.Browser.touch) {\r\n\t\t\tL.DomEvent\r\n\t\t\t    .on(link, 'click', L.DomEvent.stop)\r\n\t\t\t    .on(link, 'click', this.expand, this);\r\n\t\t} else {\r\n\t\t\tL.DomEvent.on(link, 'focus', this.expand, this);\r\n\t\t}\r\n\r\n\t\t// work around for Firefox Android issue https://github.com/Leaflet/Leaflet/issues/2033\r\n\t\tL.DomEvent.on(form, 'click', function () {\r\n\t\t\tsetTimeout(L.bind(this._onInputClick, this), 0);\r\n\t\t}, this);\r\n\r\n\t\t// TODO keyboard accessibility\r\n\r\n\t\tif (!collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\r\n\t\tthis._baseLayersList = L.DomUtil.create('div', className + '-base', form);\r\n\t\tthis._separator = L.DomUtil.create('div', className + '-separator', form);\r\n\t\tthis._overlaysList = L.DomUtil.create('div', className + '-overlays', form);\r\n\r\n\t\tcontainer.appendChild(form);\r\n\t},\r\n\r\n\t_getLayer: function (id) {\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\r\n\t\t\tif (this._layers[i] && L.stamp(this._layers[i].layer) === id) {\r\n\t\t\t\treturn this._layers[i];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_addLayer: function (layer, name, overlay) {\r\n\t\tlayer.on('add remove', this._onLayerChange, this);\r\n\r\n\t\tthis._layers.push({\r\n\t\t\tlayer: layer,\r\n\t\t\tname: name,\r\n\t\t\toverlay: overlay\r\n\t\t});\r\n\r\n\t\tif (this.options.sortLayers) {\r\n\t\t\tthis._layers.sort(L.bind(function (a, b) {\r\n\t\t\t\treturn this.options.sortFunction(a.layer, b.layer, a.name, b.name);\r\n\t\t\t}, this));\r\n\t\t}\r\n\r\n\t\tif (this.options.autoZIndex && layer.setZIndex) {\r\n\t\t\tthis._lastZIndex++;\r\n\t\t\tlayer.setZIndex(this._lastZIndex);\r\n\t\t}\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._container) { return this; }\r\n\r\n\t\tL.DomUtil.empty(this._baseLayersList);\r\n\t\tL.DomUtil.empty(this._overlaysList);\r\n\r\n\t\tvar baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;\r\n\r\n\t\tfor (i = 0; i < this._layers.length; i++) {\r\n\t\t\tobj = this._layers[i];\r\n\t\t\tthis._addItem(obj);\r\n\t\t\toverlaysPresent = overlaysPresent || obj.overlay;\r\n\t\t\tbaseLayersPresent = baseLayersPresent || !obj.overlay;\r\n\t\t\tbaseLayersCount += !obj.overlay ? 1 : 0;\r\n\t\t}\r\n\r\n\t\t// Hide base layers section if there's only one layer.\r\n\t\tif (this.options.hideSingleBase) {\r\n\t\t\tbaseLayersPresent = baseLayersPresent && baseLayersCount > 1;\r\n\t\t\tthis._baseLayersList.style.display = baseLayersPresent ? '' : 'none';\r\n\t\t}\r\n\r\n\t\tthis._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_onLayerChange: function (e) {\r\n\t\tif (!this._handlingClick) {\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\tvar obj = this._getLayer(L.stamp(e.target));\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Layer events\r\n\t\t// @event baselayerchange: LayersControlEvent\r\n\t\t// Fired when the base layer is changed through the [layer control](#control-layers).\r\n\t\t// @event overlayadd: LayersControlEvent\r\n\t\t// Fired when an overlay is selected through the [layer control](#control-layers).\r\n\t\t// @event overlayremove: LayersControlEvent\r\n\t\t// Fired when an overlay is deselected through the [layer control](#control-layers).\r\n\t\t// @namespace Control.Layers\r\n\t\tvar type = obj.overlay ?\r\n\t\t\t(e.type === 'add' ? 'overlayadd' : 'overlayremove') :\r\n\t\t\t(e.type === 'add' ? 'baselayerchange' : null);\r\n\r\n\t\tif (type) {\r\n\t\t\tthis._map.fire(type, obj);\r\n\t\t}\r\n\t},\r\n\r\n\t// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)\r\n\t_createRadioElement: function (name, checked) {\r\n\r\n\t\tvar radioHtml = '<input type=\"radio\" class=\"leaflet-control-layers-selector\" name=\"' +\r\n\t\t\t\tname + '\"' + (checked ? ' checked=\"checked\"' : '') + '/>';\r\n\r\n\t\tvar radioFragment = document.createElement('div');\r\n\t\tradioFragment.innerHTML = radioHtml;\r\n\r\n\t\treturn radioFragment.firstChild;\r\n\t},\r\n\r\n\t_addItem: function (obj) {\r\n\t\tvar label = document.createElement('label'),\r\n\t\t    checked = this._map.hasLayer(obj.layer),\r\n\t\t    input;\r\n\r\n\t\tif (obj.overlay) {\r\n\t\t\tinput = document.createElement('input');\r\n\t\t\tinput.type = 'checkbox';\r\n\t\t\tinput.className = 'leaflet-control-layers-selector';\r\n\t\t\tinput.defaultChecked = checked;\r\n\t\t} else {\r\n\t\t\tinput = this._createRadioElement('leaflet-base-layers', checked);\r\n\t\t}\r\n\r\n\t\tinput.layerId = L.stamp(obj.layer);\r\n\r\n\t\tL.DomEvent.on(input, 'click', this._onInputClick, this);\r\n\r\n\t\tvar name = document.createElement('span');\r\n\t\tname.innerHTML = ' ' + obj.name;\r\n\r\n\t\t// Helps from preventing layer control flicker when checkboxes are disabled\r\n\t\t// https://github.com/Leaflet/Leaflet/issues/2771\r\n\t\tvar holder = document.createElement('div');\r\n\r\n\t\tlabel.appendChild(holder);\r\n\t\tholder.appendChild(input);\r\n\t\tholder.appendChild(name);\r\n\r\n\t\tvar container = obj.overlay ? this._overlaysList : this._baseLayersList;\r\n\t\tcontainer.appendChild(label);\r\n\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn label;\r\n\t},\r\n\r\n\t_onInputClick: function () {\r\n\t\tvar inputs = this._form.getElementsByTagName('input'),\r\n\t\t    input, layer, hasLayer;\r\n\t\tvar addedLayers = [],\r\n\t\t    removedLayers = [];\r\n\r\n\t\tthis._handlingClick = true;\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\t\t\thasLayer = this._map.hasLayer(layer);\r\n\r\n\t\t\tif (input.checked && !hasLayer) {\r\n\t\t\t\taddedLayers.push(layer);\r\n\r\n\t\t\t} else if (!input.checked && hasLayer) {\r\n\t\t\t\tremovedLayers.push(layer);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Bugfix issue 2318: Should remove all old layers before readding new ones\r\n\t\tfor (i = 0; i < removedLayers.length; i++) {\r\n\t\t\tthis._map.removeLayer(removedLayers[i]);\r\n\t\t}\r\n\t\tfor (i = 0; i < addedLayers.length; i++) {\r\n\t\t\tthis._map.addLayer(addedLayers[i]);\r\n\t\t}\r\n\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tthis._refocusOnMap();\r\n\t},\r\n\r\n\t_checkDisabledLayers: function () {\r\n\t\tvar inputs = this._form.getElementsByTagName('input'),\r\n\t\t    input,\r\n\t\t    layer,\r\n\t\t    zoom = this._map.getZoom();\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\t\t\tinput.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||\r\n\t\t\t                 (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_expand: function () {\r\n\t\t// Backward compatibility, remove me in 1.1.\r\n\t\treturn this.expand();\r\n\t},\r\n\r\n\t_collapse: function () {\r\n\t\t// Backward compatibility, remove me in 1.1.\r\n\t\treturn this.collapse();\r\n\t}\r\n\r\n});\r\n\r\n\r\n// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)\r\n// Creates an attribution 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.\r\nL.control.layers = function (baseLayers, overlays, options) {\r\n\treturn new L.Control.Layers(baseLayers, overlays, options);\r\n};\r\n"]}
(-)a/koha-tmpl/intranet-tmpl/lib/leaflet/leaflet.css (+624 lines)
Line 0 Link Here
1
/* required styles */
2
3
.leaflet-pane,
4
.leaflet-tile,
5
.leaflet-marker-icon,
6
.leaflet-marker-shadow,
7
.leaflet-tile-container,
8
.leaflet-pane > svg,
9
.leaflet-pane > canvas,
10
.leaflet-zoom-box,
11
.leaflet-image-layer,
12
.leaflet-layer {
13
	position: absolute;
14
	left: 0;
15
	top: 0;
16
	}
17
.leaflet-container {
18
	overflow: hidden;
19
	}
20
.leaflet-tile,
21
.leaflet-marker-icon,
22
.leaflet-marker-shadow {
23
	-webkit-user-select: none;
24
	   -moz-user-select: none;
25
	        user-select: none;
26
	  -webkit-user-drag: none;
27
	}
28
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
29
.leaflet-safari .leaflet-tile {
30
	image-rendering: -webkit-optimize-contrast;
31
	}
32
/* hack that prevents hw layers "stretching" when loading new tiles */
33
.leaflet-safari .leaflet-tile-container {
34
	width: 1600px;
35
	height: 1600px;
36
	-webkit-transform-origin: 0 0;
37
	}
38
.leaflet-marker-icon,
39
.leaflet-marker-shadow {
40
	display: block;
41
	}
42
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
43
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
44
.leaflet-container .leaflet-overlay-pane svg,
45
.leaflet-container .leaflet-marker-pane img,
46
.leaflet-container .leaflet-shadow-pane img,
47
.leaflet-container .leaflet-tile-pane img,
48
.leaflet-container img.leaflet-image-layer {
49
	max-width: none !important;
50
	}
51
52
.leaflet-container.leaflet-touch-zoom {
53
	-ms-touch-action: pan-x pan-y;
54
	touch-action: pan-x pan-y;
55
	}
56
.leaflet-container.leaflet-touch-drag {
57
	-ms-touch-action: pinch-zoom;
58
	}
59
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
60
	-ms-touch-action: none;
61
	touch-action: none;
62
}
63
.leaflet-tile {
64
	filter: inherit;
65
	visibility: hidden;
66
	}
67
.leaflet-tile-loaded {
68
	visibility: inherit;
69
	}
70
.leaflet-zoom-box {
71
	width: 0;
72
	height: 0;
73
	-moz-box-sizing: border-box;
74
	     box-sizing: border-box;
75
	z-index: 800;
76
	}
77
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
78
.leaflet-overlay-pane svg {
79
	-moz-user-select: none;
80
	}
81
82
.leaflet-pane         { z-index: 400; }
83
84
.leaflet-tile-pane    { z-index: 200; }
85
.leaflet-overlay-pane { z-index: 400; }
86
.leaflet-shadow-pane  { z-index: 500; }
87
.leaflet-marker-pane  { z-index: 600; }
88
.leaflet-tooltip-pane   { z-index: 650; }
89
.leaflet-popup-pane   { z-index: 700; }
90
91
.leaflet-map-pane canvas { z-index: 100; }
92
.leaflet-map-pane svg    { z-index: 200; }
93
94
.leaflet-vml-shape {
95
	width: 1px;
96
	height: 1px;
97
	}
98
.lvml {
99
	behavior: url(#default#VML);
100
	display: inline-block;
101
	position: absolute;
102
	}
103
104
105
/* control positioning */
106
107
.leaflet-control {
108
	position: relative;
109
	z-index: 800;
110
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
111
	pointer-events: auto;
112
	}
113
.leaflet-top,
114
.leaflet-bottom {
115
	position: absolute;
116
	z-index: 1000;
117
	pointer-events: none;
118
	}
119
.leaflet-top {
120
	top: 0;
121
	}
122
.leaflet-right {
123
	right: 0;
124
	}
125
.leaflet-bottom {
126
	bottom: 0;
127
	}
128
.leaflet-left {
129
	left: 0;
130
	}
131
.leaflet-control {
132
	float: left;
133
	clear: both;
134
	}
135
.leaflet-right .leaflet-control {
136
	float: right;
137
	}
138
.leaflet-top .leaflet-control {
139
	margin-top: 10px;
140
	}
141
.leaflet-bottom .leaflet-control {
142
	margin-bottom: 10px;
143
	}
144
.leaflet-left .leaflet-control {
145
	margin-left: 10px;
146
	}
147
.leaflet-right .leaflet-control {
148
	margin-right: 10px;
149
	}
150
151
152
/* zoom and fade animations */
153
154
.leaflet-fade-anim .leaflet-tile {
155
	will-change: opacity;
156
	}
157
.leaflet-fade-anim .leaflet-popup {
158
	opacity: 0;
159
	-webkit-transition: opacity 0.2s linear;
160
	   -moz-transition: opacity 0.2s linear;
161
	     -o-transition: opacity 0.2s linear;
162
	        transition: opacity 0.2s linear;
163
	}
164
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
165
	opacity: 1;
166
	}
167
.leaflet-zoom-animated {
168
	-webkit-transform-origin: 0 0;
169
	    -ms-transform-origin: 0 0;
170
	        transform-origin: 0 0;
171
	}
172
.leaflet-zoom-anim .leaflet-zoom-animated {
173
	will-change: transform;
174
	}
175
.leaflet-zoom-anim .leaflet-zoom-animated {
176
	-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
177
	   -moz-transition:    -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
178
	     -o-transition:      -o-transform 0.25s cubic-bezier(0,0,0.25,1);
179
	        transition:         transform 0.25s cubic-bezier(0,0,0.25,1);
180
	}
181
.leaflet-zoom-anim .leaflet-tile,
182
.leaflet-pan-anim .leaflet-tile {
183
	-webkit-transition: none;
184
	   -moz-transition: none;
185
	     -o-transition: none;
186
	        transition: none;
187
	}
188
189
.leaflet-zoom-anim .leaflet-zoom-hide {
190
	visibility: hidden;
191
	}
192
193
194
/* cursors */
195
196
.leaflet-interactive {
197
	cursor: pointer;
198
	}
199
.leaflet-grab {
200
	cursor: -webkit-grab;
201
	cursor:    -moz-grab;
202
	}
203
.leaflet-crosshair,
204
.leaflet-crosshair .leaflet-interactive {
205
	cursor: crosshair;
206
	}
207
.leaflet-popup-pane,
208
.leaflet-control {
209
	cursor: auto;
210
	}
211
.leaflet-dragging .leaflet-grab,
212
.leaflet-dragging .leaflet-grab .leaflet-interactive,
213
.leaflet-dragging .leaflet-marker-draggable {
214
	cursor: move;
215
	cursor: -webkit-grabbing;
216
	cursor:    -moz-grabbing;
217
	}
218
219
/* marker & overlays interactivity */
220
.leaflet-marker-icon,
221
.leaflet-marker-shadow,
222
.leaflet-image-layer,
223
.leaflet-pane > svg path,
224
.leaflet-tile-container {
225
	pointer-events: none;
226
	}
227
228
.leaflet-marker-icon.leaflet-interactive,
229
.leaflet-image-layer.leaflet-interactive,
230
.leaflet-pane > svg path.leaflet-interactive {
231
	pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
232
	pointer-events: auto;
233
	}
234
235
/* visual tweaks */
236
237
.leaflet-container {
238
	background: #ddd;
239
	outline: 0;
240
	}
241
.leaflet-container a {
242
	color: #0078A8;
243
	}
244
.leaflet-container a.leaflet-active {
245
	outline: 2px solid orange;
246
	}
247
.leaflet-zoom-box {
248
	border: 2px dotted #38f;
249
	background: rgba(255,255,255,0.5);
250
	}
251
252
253
/* general typography */
254
.leaflet-container {
255
	font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
256
	}
257
258
259
/* general toolbar styles */
260
261
.leaflet-bar {
262
	box-shadow: 0 1px 5px rgba(0,0,0,0.65);
263
	border-radius: 4px;
264
	}
265
.leaflet-bar a,
266
.leaflet-bar a:hover {
267
	background-color: #fff;
268
	border-bottom: 1px solid #ccc;
269
	width: 26px;
270
	height: 26px;
271
	line-height: 26px;
272
	display: block;
273
	text-align: center;
274
	text-decoration: none;
275
	color: black;
276
	}
277
.leaflet-bar a,
278
.leaflet-control-layers-toggle {
279
	background-position: 50% 50%;
280
	background-repeat: no-repeat;
281
	display: block;
282
	}
283
.leaflet-bar a:hover {
284
	background-color: #f4f4f4;
285
	}
286
.leaflet-bar a:first-child {
287
	border-top-left-radius: 4px;
288
	border-top-right-radius: 4px;
289
	}
290
.leaflet-bar a:last-child {
291
	border-bottom-left-radius: 4px;
292
	border-bottom-right-radius: 4px;
293
	border-bottom: none;
294
	}
295
.leaflet-bar a.leaflet-disabled {
296
	cursor: default;
297
	background-color: #f4f4f4;
298
	color: #bbb;
299
	}
300
301
.leaflet-touch .leaflet-bar a {
302
	width: 30px;
303
	height: 30px;
304
	line-height: 30px;
305
	}
306
307
308
/* zoom control */
309
310
.leaflet-control-zoom-in,
311
.leaflet-control-zoom-out {
312
	font: bold 18px 'Lucida Console', Monaco, monospace;
313
	text-indent: 1px;
314
	}
315
.leaflet-control-zoom-out {
316
	font-size: 20px;
317
	}
318
319
.leaflet-touch .leaflet-control-zoom-in {
320
	font-size: 22px;
321
	}
322
.leaflet-touch .leaflet-control-zoom-out {
323
	font-size: 24px;
324
	}
325
326
327
/* layers control */
328
329
.leaflet-control-layers {
330
	box-shadow: 0 1px 5px rgba(0,0,0,0.4);
331
	background: #fff;
332
	border-radius: 5px;
333
	}
334
.leaflet-control-layers-toggle {
335
	background-image: url(images/layers.png);
336
	width: 36px;
337
	height: 36px;
338
	}
339
.leaflet-retina .leaflet-control-layers-toggle {
340
	background-image: url(images/layers-2x.png);
341
	background-size: 26px 26px;
342
	}
343
.leaflet-touch .leaflet-control-layers-toggle {
344
	width: 44px;
345
	height: 44px;
346
	}
347
.leaflet-control-layers .leaflet-control-layers-list,
348
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
349
	display: none;
350
	}
351
.leaflet-control-layers-expanded .leaflet-control-layers-list {
352
	display: block;
353
	position: relative;
354
	}
355
.leaflet-control-layers-expanded {
356
	padding: 6px 10px 6px 6px;
357
	color: #333;
358
	background: #fff;
359
	}
360
.leaflet-control-layers-scrollbar {
361
	overflow-y: scroll;
362
	padding-right: 5px;
363
	}
364
.leaflet-control-layers-selector {
365
	margin-top: 2px;
366
	position: relative;
367
	top: 1px;
368
	}
369
.leaflet-control-layers label {
370
	display: block;
371
	}
372
.leaflet-control-layers-separator {
373
	height: 0;
374
	border-top: 1px solid #ddd;
375
	margin: 5px -10px 5px -6px;
376
	}
377
378
/* Default icon URLs */
379
.leaflet-default-icon-path {
380
	background-image: url(images/marker-icon.png);
381
	}
382
383
384
/* attribution and scale controls */
385
386
.leaflet-container .leaflet-control-attribution {
387
	background: #fff;
388
	background: rgba(255, 255, 255, 0.7);
389
	margin: 0;
390
	}
391
.leaflet-control-attribution,
392
.leaflet-control-scale-line {
393
	padding: 0 5px;
394
	color: #333;
395
	}
396
.leaflet-control-attribution a {
397
	text-decoration: none;
398
	}
399
.leaflet-control-attribution a:hover {
400
	text-decoration: underline;
401
	}
402
.leaflet-container .leaflet-control-attribution,
403
.leaflet-container .leaflet-control-scale {
404
	font-size: 11px;
405
	}
406
.leaflet-left .leaflet-control-scale {
407
	margin-left: 5px;
408
	}
409
.leaflet-bottom .leaflet-control-scale {
410
	margin-bottom: 5px;
411
	}
412
.leaflet-control-scale-line {
413
	border: 2px solid #777;
414
	border-top: none;
415
	line-height: 1.1;
416
	padding: 2px 5px 1px;
417
	font-size: 11px;
418
	white-space: nowrap;
419
	overflow: hidden;
420
	-moz-box-sizing: border-box;
421
	     box-sizing: border-box;
422
423
	background: #fff;
424
	background: rgba(255, 255, 255, 0.5);
425
	}
426
.leaflet-control-scale-line:not(:first-child) {
427
	border-top: 2px solid #777;
428
	border-bottom: none;
429
	margin-top: -2px;
430
	}
431
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
432
	border-bottom: 2px solid #777;
433
	}
434
435
.leaflet-touch .leaflet-control-attribution,
436
.leaflet-touch .leaflet-control-layers,
437
.leaflet-touch .leaflet-bar {
438
	box-shadow: none;
439
	}
440
.leaflet-touch .leaflet-control-layers,
441
.leaflet-touch .leaflet-bar {
442
	border: 2px solid rgba(0,0,0,0.2);
443
	background-clip: padding-box;
444
	}
445
446
447
/* popup */
448
449
.leaflet-popup {
450
	position: absolute;
451
	text-align: center;
452
	margin-bottom: 20px;
453
	}
454
.leaflet-popup-content-wrapper {
455
	padding: 1px;
456
	text-align: left;
457
	border-radius: 12px;
458
	}
459
.leaflet-popup-content {
460
	margin: 13px 19px;
461
	line-height: 1.4;
462
	}
463
.leaflet-popup-content p {
464
	margin: 18px 0;
465
	}
466
.leaflet-popup-tip-container {
467
	width: 40px;
468
	height: 20px;
469
	position: absolute;
470
	left: 50%;
471
	margin-left: -20px;
472
	overflow: hidden;
473
	pointer-events: none;
474
	}
475
.leaflet-popup-tip {
476
	width: 17px;
477
	height: 17px;
478
	padding: 1px;
479
480
	margin: -10px auto 0;
481
482
	-webkit-transform: rotate(45deg);
483
	   -moz-transform: rotate(45deg);
484
	    -ms-transform: rotate(45deg);
485
	     -o-transform: rotate(45deg);
486
	        transform: rotate(45deg);
487
	}
488
.leaflet-popup-content-wrapper,
489
.leaflet-popup-tip {
490
	background: white;
491
	color: #333;
492
	box-shadow: 0 3px 14px rgba(0,0,0,0.4);
493
	}
494
.leaflet-container a.leaflet-popup-close-button {
495
	position: absolute;
496
	top: 0;
497
	right: 0;
498
	padding: 4px 4px 0 0;
499
	border: none;
500
	text-align: center;
501
	width: 18px;
502
	height: 14px;
503
	font: 16px/14px Tahoma, Verdana, sans-serif;
504
	color: #c3c3c3;
505
	text-decoration: none;
506
	font-weight: bold;
507
	background: transparent;
508
	}
509
.leaflet-container a.leaflet-popup-close-button:hover {
510
	color: #999;
511
	}
512
.leaflet-popup-scrolled {
513
	overflow: auto;
514
	border-bottom: 1px solid #ddd;
515
	border-top: 1px solid #ddd;
516
	}
517
518
.leaflet-oldie .leaflet-popup-content-wrapper {
519
	zoom: 1;
520
	}
521
.leaflet-oldie .leaflet-popup-tip {
522
	width: 24px;
523
	margin: 0 auto;
524
525
	-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
526
	filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
527
	}
528
.leaflet-oldie .leaflet-popup-tip-container {
529
	margin-top: -1px;
530
	}
531
532
.leaflet-oldie .leaflet-control-zoom,
533
.leaflet-oldie .leaflet-control-layers,
534
.leaflet-oldie .leaflet-popup-content-wrapper,
535
.leaflet-oldie .leaflet-popup-tip {
536
	border: 1px solid #999;
537
	}
538
539
540
/* div icon */
541
542
.leaflet-div-icon {
543
	background: #fff;
544
	border: 1px solid #666;
545
	}
546
547
548
/* Tooltip */
549
/* Base styles for the element that has a tooltip */
550
.leaflet-tooltip {
551
	position: absolute;
552
	padding: 6px;
553
	background-color: #fff;
554
	border: 1px solid #fff;
555
	border-radius: 3px;
556
	color: #222;
557
	white-space: nowrap;
558
	-webkit-user-select: none;
559
	-moz-user-select: none;
560
	-ms-user-select: none;
561
	user-select: none;
562
	pointer-events: none;
563
	box-shadow: 0 1px 3px rgba(0,0,0,0.4);
564
	}
565
.leaflet-tooltip.leaflet-clickable {
566
	cursor: pointer;
567
	pointer-events: auto;
568
	}
569
.leaflet-tooltip-top:before,
570
.leaflet-tooltip-bottom:before,
571
.leaflet-tooltip-left:before,
572
.leaflet-tooltip-right:before {
573
	position: absolute;
574
	pointer-events: none;
575
	border: 6px solid transparent;
576
	background: transparent;
577
	content: "";
578
	}
579
580
/* Directions */
581
582
.leaflet-tooltip-bottom {
583
	margin-top: 6px;
584
}
585
.leaflet-tooltip-top {
586
	margin-top: -6px;
587
}
588
.leaflet-tooltip-bottom:before,
589
.leaflet-tooltip-top:before {
590
	left: 50%;
591
	margin-left: -6px;
592
	}
593
.leaflet-tooltip-top:before {
594
	bottom: 0;
595
	margin-bottom: -12px;
596
	border-top-color: #fff;
597
	}
598
.leaflet-tooltip-bottom:before {
599
	top: 0;
600
	margin-top: -12px;
601
	margin-left: -6px;
602
	border-bottom-color: #fff;
603
	}
604
.leaflet-tooltip-left {
605
	margin-left: -6px;
606
}
607
.leaflet-tooltip-right {
608
	margin-left: 6px;
609
}
610
.leaflet-tooltip-left:before,
611
.leaflet-tooltip-right:before {
612
	top: 50%;
613
	margin-top: -6px;
614
	}
615
.leaflet-tooltip-left:before {
616
	right: 0;
617
	margin-right: -12px;
618
	border-left-color: #fff;
619
	}
620
.leaflet-tooltip-right:before {
621
	left: 0;
622
	margin-left: -12px;
623
	border-right-color: #fff;
624
	}
(-)a/koha-tmpl/intranet-tmpl/lib/leaflet/leaflet.js (-1 / +9 lines)
Line 0 Link Here
0
- 
1
/*
2
 Leaflet 1.0.3+ed36a04, a JS library for interactive maps. http://leafletjs.com
3
 (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade
4
*/
5
!function(t,e,i){function n(){var e=t.L;o.noConflict=function(){return t.L=e,this},t.L=o}var o={version:"1.0.3+ed36a04"};"object"==typeof module&&"object"==typeof module.exports?module.exports=o:"function"==typeof define&&define.amd&&define(o),"undefined"!=typeof t&&n(),o.Util={extend:function(t){var e,i,n,o;for(i=1,n=arguments.length;i<n;i++){o=arguments[i];for(e in o)t[e]=o[e]}return t},create:Object.create||function(){function t(){}return function(e){return t.prototype=e,new t}}(),bind:function(t,e){var i=Array.prototype.slice;if(t.bind)return t.bind.apply(t,i.call(arguments,1));var n=i.call(arguments,2);return function(){return t.apply(e,n.length?n.concat(i.call(arguments)):arguments)}},stamp:function(t){return t._leaflet_id=t._leaflet_id||++o.Util.lastId,t._leaflet_id},lastId:0,throttle:function(t,e,i){var n,o,s,r;return r=function(){n=!1,o&&(s.apply(i,o),o=!1)},s=function(){n?o=arguments:(t.apply(i,arguments),setTimeout(r,e),n=!0)}},wrapNum:function(t,e,i){var n=e[1],o=e[0],s=n-o;return t===n&&i?t:((t-o)%s+s)%s+o},falseFn:function(){return!1},formatNum:function(t,e){var i=Math.pow(10,e||5);return Math.round(t*i)/i},trim:function(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")},splitWords:function(t){return o.Util.trim(t).split(/\s+/)},setOptions:function(t,e){t.hasOwnProperty("options")||(t.options=t.options?o.Util.create(t.options):{});for(var i in e)t.options[i]=e[i];return t.options},getParamString:function(t,e,i){var n=[];for(var o in t)n.push(encodeURIComponent(i?o.toUpperCase():o)+"="+encodeURIComponent(t[o]));return(e&&e.indexOf("?")!==-1?"&":"?")+n.join("&")},template:function(t,e){return t.replace(o.Util.templateRe,function(t,n){var o=e[n];if(o===i)throw new Error("No value provided for variable "+t);return"function"==typeof o&&(o=o(e)),o})},templateRe:/\{ *([\w_\-]+) *\}/g,isArray:Array.isArray||function(t){return"[object Array]"===Object.prototype.toString.call(t)},indexOf:function(t,e){for(var i=0;i<t.length;i++)if(t[i]===e)return i;return-1},emptyImageUrl:"data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="},function(){function e(e){return t["webkit"+e]||t["moz"+e]||t["ms"+e]}function i(e){var i=+new Date,o=Math.max(0,16-(i-n));return n=i+o,t.setTimeout(e,o)}var n=0,s=t.requestAnimationFrame||e("RequestAnimationFrame")||i,r=t.cancelAnimationFrame||e("CancelAnimationFrame")||e("CancelRequestAnimationFrame")||function(e){t.clearTimeout(e)};o.Util.requestAnimFrame=function(e,n,r){return r&&s===i?void e.call(n):s.call(t,o.bind(e,n))},o.Util.cancelAnimFrame=function(e){e&&r.call(t,e)}}(),o.extend=o.Util.extend,o.bind=o.Util.bind,o.stamp=o.Util.stamp,o.setOptions=o.Util.setOptions,o.Class=function(){},o.Class.extend=function(t){var e=function(){this.initialize&&this.initialize.apply(this,arguments),this.callInitHooks()},i=e.__super__=this.prototype,n=o.Util.create(i);n.constructor=e,e.prototype=n;for(var s in this)this.hasOwnProperty(s)&&"prototype"!==s&&(e[s]=this[s]);return t.statics&&(o.extend(e,t.statics),delete t.statics),t.includes&&(o.Util.extend.apply(null,[n].concat(t.includes)),delete t.includes),n.options&&(t.options=o.Util.extend(o.Util.create(n.options),t.options)),o.extend(n,t),n._initHooks=[],n.callInitHooks=function(){if(!this._initHooksCalled){i.callInitHooks&&i.callInitHooks.call(this),this._initHooksCalled=!0;for(var t=0,e=n._initHooks.length;t<e;t++)n._initHooks[t].call(this)}},e},o.Class.include=function(t){return o.extend(this.prototype,t),this},o.Class.mergeOptions=function(t){return o.extend(this.prototype.options,t),this},o.Class.addInitHook=function(t){var e=Array.prototype.slice.call(arguments,1),i="function"==typeof t?t:function(){this[t].apply(this,e)};return this.prototype._initHooks=this.prototype._initHooks||[],this.prototype._initHooks.push(i),this},o.Evented=o.Class.extend({on:function(t,e,i){if("object"==typeof t)for(var n in t)this._on(n,t[n],e);else{t=o.Util.splitWords(t);for(var s=0,r=t.length;s<r;s++)this._on(t[s],e,i)}return this},off:function(t,e,i){if(t)if("object"==typeof t)for(var n in t)this._off(n,t[n],e);else{t=o.Util.splitWords(t);for(var s=0,r=t.length;s<r;s++)this._off(t[s],e,i)}else delete this._events;return this},_on:function(t,e,n){this._events=this._events||{};var o=this._events[t];o||(o=[],this._events[t]=o),n===this&&(n=i);for(var s={fn:e,ctx:n},r=o,a=0,h=r.length;a<h;a++)if(r[a].fn===e&&r[a].ctx===n)return;r.push(s)},_off:function(t,e,n){var s,r,a;if(this._events&&(s=this._events[t])){if(!e){for(r=0,a=s.length;r<a;r++)s[r].fn=o.Util.falseFn;return void delete this._events[t]}if(n===this&&(n=i),s)for(r=0,a=s.length;r<a;r++){var h=s[r];if(h.ctx===n&&h.fn===e)return h.fn=o.Util.falseFn,this._firingCount&&(this._events[t]=s=s.slice()),void s.splice(r,1)}}},fire:function(t,e,i){if(!this.listens(t,i))return this;var n=o.Util.extend({},e,{type:t,target:this});if(this._events){var s=this._events[t];if(s){this._firingCount=this._firingCount+1||1;for(var r=0,a=s.length;r<a;r++){var h=s[r];h.fn.call(h.ctx||this,n)}this._firingCount--}}return i&&this._propagateEvent(n),this},listens:function(t,e){var i=this._events&&this._events[t];if(i&&i.length)return!0;if(e)for(var n in this._eventParents)if(this._eventParents[n].listens(t,e))return!0;return!1},once:function(t,e,i){if("object"==typeof t){for(var n in t)this.once(n,t[n],e);return this}var s=o.bind(function(){this.off(t,e,i).off(t,s,i)},this);return this.on(t,e,i).on(t,s,i)},addEventParent:function(t){return this._eventParents=this._eventParents||{},this._eventParents[o.stamp(t)]=t,this},removeEventParent:function(t){return this._eventParents&&delete this._eventParents[o.stamp(t)],this},_propagateEvent:function(t){for(var e in this._eventParents)this._eventParents[e].fire(t.type,o.extend({layer:t.target},t),!0)}});var s=o.Evented.prototype;s.addEventListener=s.on,s.removeEventListener=s.clearAllEventListeners=s.off,s.addOneTimeEventListener=s.once,s.fireEvent=s.fire,s.hasEventListeners=s.listens,o.Mixin={Events:s},function(){var i=navigator.userAgent.toLowerCase(),n=e.documentElement,s="ActiveXObject"in t,r=i.indexOf("webkit")!==-1,a=i.indexOf("phantom")!==-1,h=i.search("android [23]")!==-1,l=i.indexOf("chrome")!==-1,u=i.indexOf("gecko")!==-1&&!r&&!t.opera&&!s,c=0===navigator.platform.indexOf("Win"),d="undefined"!=typeof orientation||i.indexOf("mobile")!==-1,_=!t.PointerEvent&&t.MSPointerEvent,m=t.PointerEvent||_,p=s&&"transition"in n.style,f="WebKitCSSMatrix"in t&&"m11"in new t.WebKitCSSMatrix&&!h,g="MozPerspective"in n.style,v="OTransition"in n.style,y=!t.L_NO_TOUCH&&(m||"ontouchstart"in t||t.DocumentTouch&&e instanceof t.DocumentTouch);o.Browser={ie:s,ielt9:s&&!e.addEventListener,edge:"msLaunchUri"in navigator&&!("documentMode"in e),webkit:r,gecko:u,android:i.indexOf("android")!==-1,android23:h,chrome:l,safari:!l&&i.indexOf("safari")!==-1,win:c,ie3d:p,webkit3d:f,gecko3d:g,opera12:v,any3d:!t.L_DISABLE_3D&&(p||f||g)&&!v&&!a,mobile:d,mobileWebkit:d&&r,mobileWebkit3d:d&&f,mobileOpera:d&&t.opera,mobileGecko:d&&u,touch:!!y,msPointer:!!_,pointer:!!m,retina:(t.devicePixelRatio||t.screen.deviceXDPI/t.screen.logicalXDPI)>1}}(),o.Point=function(t,e,i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},o.Point.prototype={clone:function(){return new o.Point(this.x,this.y)},add:function(t){return this.clone()._add(o.point(t))},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(o.point(t))},_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t){return this.clone()._divideBy(t)},_divideBy:function(t){return this.x/=t,this.y/=t,this},multiplyBy:function(t){return this.clone()._multiplyBy(t)},_multiplyBy:function(t){return this.x*=t,this.y*=t,this},scaleBy:function(t){return new o.Point(this.x*t.x,this.y*t.y)},unscaleBy:function(t){return new o.Point(this.x/t.x,this.y/t.y)},round:function(){return this.clone()._round()},_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},floor:function(){return this.clone()._floor()},_floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this},ceil:function(){return this.clone()._ceil()},_ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this},distanceTo:function(t){t=o.point(t);var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},equals:function(t){return t=o.point(t),t.x===this.x&&t.y===this.y},contains:function(t){return t=o.point(t),Math.abs(t.x)<=Math.abs(this.x)&&Math.abs(t.y)<=Math.abs(this.y)},toString:function(){return"Point("+o.Util.formatNum(this.x)+", "+o.Util.formatNum(this.y)+")"}},o.point=function(t,e,n){return t instanceof o.Point?t:o.Util.isArray(t)?new o.Point(t[0],t[1]):t===i||null===t?t:"object"==typeof t&&"x"in t&&"y"in t?new o.Point(t.x,t.y):new o.Point(t,e,n)},o.Bounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n<o;n++)this.extend(i[n])},o.Bounds.prototype={extend:function(t){return t=o.point(t),this.min||this.max?(this.min.x=Math.min(t.x,this.min.x),this.max.x=Math.max(t.x,this.max.x),this.min.y=Math.min(t.y,this.min.y),this.max.y=Math.max(t.y,this.max.y)):(this.min=t.clone(),this.max=t.clone()),this},getCenter:function(t){return new o.Point((this.min.x+this.max.x)/2,(this.min.y+this.max.y)/2,t)},getBottomLeft:function(){return new o.Point(this.min.x,this.max.y)},getTopRight:function(){return new o.Point(this.max.x,this.min.y)},getSize:function(){return this.max.subtract(this.min)},contains:function(t){var e,i;return t="number"==typeof t[0]||t instanceof o.Point?o.point(t):o.bounds(t),t instanceof o.Bounds?(e=t.min,i=t.max):e=i=t,e.x>=this.min.x&&i.x<=this.max.x&&e.y>=this.min.y&&i.y<=this.max.y},intersects:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>=e.x&&n.x<=i.x,a=s.y>=e.y&&n.y<=i.y;return r&&a},overlaps:function(t){t=o.bounds(t);var e=this.min,i=this.max,n=t.min,s=t.max,r=s.x>e.x&&n.x<i.x,a=s.y>e.y&&n.y<i.y;return r&&a},isValid:function(){return!(!this.min||!this.max)}},o.bounds=function(t,e){return!t||t instanceof o.Bounds?t:new o.Bounds(t,e)},o.Transformation=function(t,e,i,n){this._a=t,this._b=e,this._c=i,this._d=n},o.Transformation.prototype={transform:function(t,e){return this._transform(t.clone(),e)},_transform:function(t,e){return e=e||1,t.x=e*(this._a*t.x+this._b),t.y=e*(this._c*t.y+this._d),t},untransform:function(t,e){return e=e||1,new o.Point((t.x/e-this._b)/this._a,(t.y/e-this._d)/this._c)}},o.DomUtil={get:function(t){return"string"==typeof t?e.getElementById(t):t},getStyle:function(t,i){var n=t.style[i]||t.currentStyle&&t.currentStyle[i];if((!n||"auto"===n)&&e.defaultView){var o=e.defaultView.getComputedStyle(t,null);n=o?o[i]:null}return"auto"===n?null:n},create:function(t,i,n){var o=e.createElement(t);return o.className=i||"",n&&n.appendChild(o),o},remove:function(t){var e=t.parentNode;e&&e.removeChild(t)},empty:function(t){for(;t.firstChild;)t.removeChild(t.firstChild)},toFront:function(t){t.parentNode.appendChild(t)},toBack:function(t){var e=t.parentNode;e.insertBefore(t,e.firstChild)},hasClass:function(t,e){if(t.classList!==i)return t.classList.contains(e);var n=o.DomUtil.getClass(t);return n.length>0&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(n)},addClass:function(t,e){if(t.classList!==i)for(var n=o.Util.splitWords(e),s=0,r=n.length;s<r;s++)t.classList.add(n[s]);else if(!o.DomUtil.hasClass(t,e)){var a=o.DomUtil.getClass(t);o.DomUtil.setClass(t,(a?a+" ":"")+e)}},removeClass:function(t,e){t.classList!==i?t.classList.remove(e):o.DomUtil.setClass(t,o.Util.trim((" "+o.DomUtil.getClass(t)+" ").replace(" "+e+" "," ")))},setClass:function(t,e){t.className.baseVal===i?t.className=e:t.className.baseVal=e},getClass:function(t){return t.className.baseVal===i?t.className:t.className.baseVal},setOpacity:function(t,e){"opacity"in t.style?t.style.opacity=e:"filter"in t.style&&o.DomUtil._setOpacityIE(t,e)},_setOpacityIE:function(t,e){var i=!1,n="DXImageTransform.Microsoft.Alpha";try{i=t.filters.item(n)}catch(t){if(1===e)return}e=Math.round(100*e),i?(i.Enabled=100!==e,i.Opacity=e):t.style.filter+=" progid:"+n+"(opacity="+e+")"},testProp:function(t){for(var i=e.documentElement.style,n=0;n<t.length;n++)if(t[n]in i)return t[n];return!1},setTransform:function(t,e,i){var n=e||new o.Point(0,0);t.style[o.DomUtil.TRANSFORM]=(o.Browser.ie3d?"translate("+n.x+"px,"+n.y+"px)":"translate3d("+n.x+"px,"+n.y+"px,0)")+(i?" scale("+i+")":"")},setPosition:function(t,e){t._leaflet_pos=e,o.Browser.any3d?o.DomUtil.setTransform(t,e):(t.style.left=e.x+"px",t.style.top=e.y+"px")},getPosition:function(t){return t._leaflet_pos||new o.Point(0,0)}},function(){o.DomUtil.TRANSFORM=o.DomUtil.testProp(["transform","WebkitTransform","OTransform","MozTransform","msTransform"]);var i=o.DomUtil.TRANSITION=o.DomUtil.testProp(["webkitTransition","transition","OTransition","MozTransition","msTransition"]);if(o.DomUtil.TRANSITION_END="webkitTransition"===i||"OTransition"===i?i+"End":"transitionend","onselectstart"in e)o.DomUtil.disableTextSelection=function(){o.DomEvent.on(t,"selectstart",o.DomEvent.preventDefault)},o.DomUtil.enableTextSelection=function(){o.DomEvent.off(t,"selectstart",o.DomEvent.preventDefault)};else{var n=o.DomUtil.testProp(["userSelect","WebkitUserSelect","OUserSelect","MozUserSelect","msUserSelect"]);o.DomUtil.disableTextSelection=function(){if(n){var t=e.documentElement.style;this._userSelect=t[n],t[n]="none"}},o.DomUtil.enableTextSelection=function(){n&&(e.documentElement.style[n]=this._userSelect,delete this._userSelect)}}o.DomUtil.disableImageDrag=function(){o.DomEvent.on(t,"dragstart",o.DomEvent.preventDefault)},o.DomUtil.enableImageDrag=function(){o.DomEvent.off(t,"dragstart",o.DomEvent.preventDefault)},o.DomUtil.preventOutline=function(e){for(;e.tabIndex===-1;)e=e.parentNode;e&&e.style&&(o.DomUtil.restoreOutline(),this._outlineElement=e,this._outlineStyle=e.style.outline,e.style.outline="none",o.DomEvent.on(t,"keydown",o.DomUtil.restoreOutline,this))},o.DomUtil.restoreOutline=function(){this._outlineElement&&(this._outlineElement.style.outline=this._outlineStyle,delete this._outlineElement,delete this._outlineStyle,o.DomEvent.off(t,"keydown",o.DomUtil.restoreOutline,this))}}(),o.LatLng=function(t,e,n){if(isNaN(t)||isNaN(e))throw new Error("Invalid LatLng object: ("+t+", "+e+")");this.lat=+t,this.lng=+e,n!==i&&(this.alt=+n)},o.LatLng.prototype={equals:function(t,e){if(!t)return!1;t=o.latLng(t);var n=Math.max(Math.abs(this.lat-t.lat),Math.abs(this.lng-t.lng));return n<=(e===i?1e-9:e)},toString:function(t){return"LatLng("+o.Util.formatNum(this.lat,t)+", "+o.Util.formatNum(this.lng,t)+")"},distanceTo:function(t){return o.CRS.Earth.distance(this,o.latLng(t))},wrap:function(){return o.CRS.Earth.wrapLatLng(this)},toBounds:function(t){var e=180*t/40075017,i=e/Math.cos(Math.PI/180*this.lat);return o.latLngBounds([this.lat-e,this.lng-i],[this.lat+e,this.lng+i])},clone:function(){return new o.LatLng(this.lat,this.lng,this.alt)}},o.latLng=function(t,e,n){return t instanceof o.LatLng?t:o.Util.isArray(t)&&"object"!=typeof t[0]?3===t.length?new o.LatLng(t[0],t[1],t[2]):2===t.length?new o.LatLng(t[0],t[1]):null:t===i||null===t?t:"object"==typeof t&&"lat"in t?new o.LatLng(t.lat,"lng"in t?t.lng:t.lon,t.alt):e===i?null:new o.LatLng(t,e,n)},o.LatLngBounds=function(t,e){if(t)for(var i=e?[t,e]:t,n=0,o=i.length;n<o;n++)this.extend(i[n])},o.LatLngBounds.prototype={extend:function(t){var e,i,n=this._southWest,s=this._northEast;if(t instanceof o.LatLng)e=t,i=t;else{if(!(t instanceof o.LatLngBounds))return t?this.extend(o.latLng(t)||o.latLngBounds(t)):this;if(e=t._southWest,i=t._northEast,!e||!i)return this}return n||s?(n.lat=Math.min(e.lat,n.lat),n.lng=Math.min(e.lng,n.lng),s.lat=Math.max(i.lat,s.lat),s.lng=Math.max(i.lng,s.lng)):(this._southWest=new o.LatLng(e.lat,e.lng),this._northEast=new o.LatLng(i.lat,i.lng)),this},pad:function(t){var e=this._southWest,i=this._northEast,n=Math.abs(e.lat-i.lat)*t,s=Math.abs(e.lng-i.lng)*t;return new o.LatLngBounds(new o.LatLng(e.lat-n,e.lng-s),new o.LatLng(i.lat+n,i.lng+s))},getCenter:function(){return new o.LatLng((this._southWest.lat+this._northEast.lat)/2,(this._southWest.lng+this._northEast.lng)/2)},getSouthWest:function(){return this._southWest},getNorthEast:function(){return this._northEast},getNorthWest:function(){return new o.LatLng(this.getNorth(),this.getWest())},getSouthEast:function(){return new o.LatLng(this.getSouth(),this.getEast())},getWest:function(){return this._southWest.lng},getSouth:function(){return this._southWest.lat},getEast:function(){return this._northEast.lng},getNorth:function(){return this._northEast.lat},contains:function(t){t="number"==typeof t[0]||t instanceof o.LatLng||"lat"in t?o.latLng(t):o.latLngBounds(t);var e,i,n=this._southWest,s=this._northEast;return t instanceof o.LatLngBounds?(e=t.getSouthWest(),i=t.getNorthEast()):e=i=t,e.lat>=n.lat&&i.lat<=s.lat&&e.lng>=n.lng&&i.lng<=s.lng},intersects:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>=e.lat&&n.lat<=i.lat,a=s.lng>=e.lng&&n.lng<=i.lng;return r&&a},overlaps:function(t){t=o.latLngBounds(t);var e=this._southWest,i=this._northEast,n=t.getSouthWest(),s=t.getNorthEast(),r=s.lat>e.lat&&n.lat<i.lat,a=s.lng>e.lng&&n.lng<i.lng;return r&&a},toBBoxString:function(){return[this.getWest(),this.getSouth(),this.getEast(),this.getNorth()].join(",")},equals:function(t){return!!t&&(t=o.latLngBounds(t),this._southWest.equals(t.getSouthWest())&&this._northEast.equals(t.getNorthEast()))},isValid:function(){return!(!this._southWest||!this._northEast)}},o.latLngBounds=function(t,e){return t instanceof o.LatLngBounds?t:new o.LatLngBounds(t,e)},o.Projection={},o.Projection.LonLat={project:function(t){return new o.Point(t.lng,t.lat)},unproject:function(t){return new o.LatLng(t.y,t.x)},bounds:o.bounds([-180,-90],[180,90])},o.Projection.SphericalMercator={R:6378137,MAX_LATITUDE:85.0511287798,project:function(t){var e=Math.PI/180,i=this.MAX_LATITUDE,n=Math.max(Math.min(i,t.lat),-i),s=Math.sin(n*e);return new o.Point(this.R*t.lng*e,this.R*Math.log((1+s)/(1-s))/2)},unproject:function(t){var e=180/Math.PI;return new o.LatLng((2*Math.atan(Math.exp(t.y/this.R))-Math.PI/2)*e,t.x*e/this.R)},bounds:function(){var t=6378137*Math.PI;return o.bounds([-t,-t],[t,t])}()},o.CRS={latLngToPoint:function(t,e){var i=this.projection.project(t),n=this.scale(e);return this.transformation._transform(i,n)},pointToLatLng:function(t,e){var i=this.scale(e),n=this.transformation.untransform(t,i);return this.projection.unproject(n)},project:function(t){return this.projection.project(t)},unproject:function(t){return this.projection.unproject(t)},scale:function(t){return 256*Math.pow(2,t)},zoom:function(t){return Math.log(t/256)/Math.LN2},getProjectedBounds:function(t){if(this.infinite)return null;var e=this.projection.bounds,i=this.scale(t),n=this.transformation.transform(e.min,i),s=this.transformation.transform(e.max,i);return o.bounds(n,s)},infinite:!1,wrapLatLng:function(t){var e=this.wrapLng?o.Util.wrapNum(t.lng,this.wrapLng,!0):t.lng,i=this.wrapLat?o.Util.wrapNum(t.lat,this.wrapLat,!0):t.lat,n=t.alt;return o.latLng(i,e,n)},wrapLatLngBounds:function(t){var e=t.getCenter(),i=this.wrapLatLng(e),n=e.lat-i.lat,s=e.lng-i.lng;if(0===n&&0===s)return t;var r=t.getSouthWest(),a=t.getNorthEast(),h=o.latLng({lat:r.lat-n,lng:r.lng-s}),l=o.latLng({lat:a.lat-n,lng:a.lng-s});return new o.LatLngBounds(h,l)}},o.CRS.Simple=o.extend({},o.CRS,{projection:o.Projection.LonLat,transformation:new o.Transformation(1,0,-1,0),scale:function(t){return Math.pow(2,t)},zoom:function(t){return Math.log(t)/Math.LN2},distance:function(t,e){var i=e.lng-t.lng,n=e.lat-t.lat;return Math.sqrt(i*i+n*n)},infinite:!0}),o.CRS.Earth=o.extend({},o.CRS,{wrapLng:[-180,180],R:6371e3,distance:function(t,e){var i=Math.PI/180,n=t.lat*i,o=e.lat*i,s=Math.sin(n)*Math.sin(o)+Math.cos(n)*Math.cos(o)*Math.cos((e.lng-t.lng)*i);return this.R*Math.acos(Math.min(s,1))}}),o.CRS.EPSG3857=o.extend({},o.CRS.Earth,{code:"EPSG:3857",projection:o.Projection.SphericalMercator,transformation:function(){var t=.5/(Math.PI*o.Projection.SphericalMercator.R);return new o.Transformation(t,.5,-t,.5)}()}),o.CRS.EPSG900913=o.extend({},o.CRS.EPSG3857,{code:"EPSG:900913"}),o.CRS.EPSG4326=o.extend({},o.CRS.Earth,{code:"EPSG:4326",projection:o.Projection.LonLat,transformation:new o.Transformation(1/180,1,-1/180,.5)}),o.Map=o.Evented.extend({options:{crs:o.CRS.EPSG3857,center:i,zoom:i,minZoom:i,maxZoom:i,layers:[],maxBounds:i,renderer:i,zoomAnimation:!0,zoomAnimationThreshold:4,fadeAnimation:!0,markerZoomAnimation:!0,transform3DLimit:8388608,zoomSnap:1,zoomDelta:1,trackResize:!0},initialize:function(t,e){e=o.setOptions(this,e),this._initContainer(t),this._initLayout(),this._onResize=o.bind(this._onResize,this),this._initEvents(),e.maxBounds&&this.setMaxBounds(e.maxBounds),e.zoom!==i&&(this._zoom=this._limitZoom(e.zoom)),e.center&&e.zoom!==i&&this.setView(o.latLng(e.center),e.zoom,{reset:!0}),this._handlers=[],this._layers={},this._zoomBoundLayers={},this._sizeChanged=!0,this.callInitHooks(),this._zoomAnimated=o.DomUtil.TRANSITION&&o.Browser.any3d&&!o.Browser.mobileOpera&&this.options.zoomAnimation,this._zoomAnimated&&(this._createAnimProxy(),o.DomEvent.on(this._proxy,o.DomUtil.TRANSITION_END,this._catchTransitionEnd,this)),this._addLayers(this.options.layers)},setView:function(t,e,n){if(e=e===i?this._zoom:this._limitZoom(e),t=this._limitCenter(o.latLng(t),e,this.options.maxBounds),n=n||{},this._stop(),this._loaded&&!n.reset&&n!==!0){n.animate!==i&&(n.zoom=o.extend({animate:n.animate},n.zoom),n.pan=o.extend({animate:n.animate,duration:n.duration},n.pan));var s=this._zoom!==e?this._tryAnimatedZoom&&this._tryAnimatedZoom(t,e,n.zoom):this._tryAnimatedPan(t,n.pan);if(s)return clearTimeout(this._sizeTimer),this}return this._resetView(t,e),this},setZoom:function(t,e){return this._loaded?this.setView(this.getCenter(),t,{zoom:e}):(this._zoom=t,this)},zoomIn:function(t,e){return t=t||(o.Browser.any3d?this.options.zoomDelta:1),this.setZoom(this._zoom+t,e)},zoomOut:function(t,e){return t=t||(o.Browser.any3d?this.options.zoomDelta:1),this.setZoom(this._zoom-t,e)},setZoomAround:function(t,e,i){var n=this.getZoomScale(e),s=this.getSize().divideBy(2),r=t instanceof o.Point?t:this.latLngToContainerPoint(t),a=r.subtract(s).multiplyBy(1-1/n),h=this.containerPointToLatLng(s.add(a));return this.setView(h,e,{zoom:i})},_getBoundsCenterZoom:function(t,e){e=e||{},t=t.getBounds?t.getBounds():o.latLngBounds(t);var i=o.point(e.paddingTopLeft||e.padding||[0,0]),n=o.point(e.paddingBottomRight||e.padding||[0,0]),s=this.getBoundsZoom(t,!1,i.add(n));s="number"==typeof e.maxZoom?Math.min(e.maxZoom,s):s;var r=n.subtract(i).divideBy(2),a=this.project(t.getSouthWest(),s),h=this.project(t.getNorthEast(),s),l=this.unproject(a.add(h).divideBy(2).add(r),s);return{center:l,zoom:s}},fitBounds:function(t,e){if(t=o.latLngBounds(t),!t.isValid())throw new Error("Bounds are not valid.");var i=this._getBoundsCenterZoom(t,e);return this.setView(i.center,i.zoom,e)},fitWorld:function(t){return this.fitBounds([[-90,-180],[90,180]],t)},panTo:function(t,e){return this.setView(t,this._zoom,{pan:e})},panBy:function(t,e){if(t=o.point(t).round(),e=e||{},!t.x&&!t.y)return this.fire("moveend");if(e.animate!==!0&&!this.getSize().contains(t))return this._resetView(this.unproject(this.project(this.getCenter()).add(t)),this.getZoom()),this;if(this._panAnim||(this._panAnim=new o.PosAnimation,this._panAnim.on({step:this._onPanTransitionStep,end:this._onPanTransitionEnd},this)),e.noMoveStart||this.fire("movestart"),e.animate!==!1){o.DomUtil.addClass(this._mapPane,"leaflet-pan-anim");var i=this._getMapPanePos().subtract(t).round();this._panAnim.run(this._mapPane,i,e.duration||.25,e.easeLinearity)}else this._rawPanBy(t),this.fire("move").fire("moveend");return this},flyTo:function(t,e,n){function s(t){var e=t?-1:1,i=t?v:g,n=v*v-g*g+e*L*L*y*y,o=2*i*L*y,s=n/o,r=Math.sqrt(s*s+1)-s,a=r<1e-9?-18:Math.log(r);return a}function r(t){return(Math.exp(t)-Math.exp(-t))/2}function a(t){return(Math.exp(t)+Math.exp(-t))/2}function h(t){return r(t)/a(t)}function l(t){return g*(a(x)/a(x+P*t))}function u(t){return g*(a(x)*h(x+P*t)-r(x))/L}function c(t){return 1-Math.pow(1-t,1.5)}function d(){var i=(Date.now()-w)/T,n=c(i)*b;i<=1?(this._flyToFrame=o.Util.requestAnimFrame(d,this),this._move(this.unproject(_.add(m.subtract(_).multiplyBy(u(n)/y)),f),this.getScaleZoom(g/l(n),f),{flyTo:!0})):this._move(t,e)._moveEnd(!0)}if(n=n||{},n.animate===!1||!o.Browser.any3d)return this.setView(t,e,n);this._stop();var _=this.project(this.getCenter()),m=this.project(t),p=this.getSize(),f=this._zoom;t=o.latLng(t),e=e===i?f:e;var g=Math.max(p.x,p.y),v=g*this.getZoomScale(f,e),y=m.distanceTo(_)||1,P=1.42,L=P*P,x=s(0),w=Date.now(),b=(s(1)-x)/P,T=n.duration?1e3*n.duration:1e3*b*.8;return this._moveStart(!0),d.call(this),this},flyToBounds:function(t,e){var i=this._getBoundsCenterZoom(t,e);return this.flyTo(i.center,i.zoom,e)},setMaxBounds:function(t){return t=o.latLngBounds(t),t.isValid()?(this.options.maxBounds&&this.off("moveend",this._panInsideMaxBounds),this.options.maxBounds=t,this._loaded&&this._panInsideMaxBounds(),this.on("moveend",this._panInsideMaxBounds)):(this.options.maxBounds=null,this.off("moveend",this._panInsideMaxBounds))},setMinZoom:function(t){return this.options.minZoom=t,this._loaded&&this.getZoom()<this.options.minZoom?this.setZoom(t):this},setMaxZoom:function(t){return this.options.maxZoom=t,this._loaded&&this.getZoom()>this.options.maxZoom?this.setZoom(t):this},panInsideBounds:function(t,e){this._enforcingBounds=!0;var i=this.getCenter(),n=this._limitCenter(i,this._zoom,o.latLngBounds(t));return i.equals(n)||this.panTo(n,e),this._enforcingBounds=!1,this},invalidateSize:function(t){if(!this._loaded)return this;t=o.extend({animate:!1,pan:!0},t===!0?{animate:!0}:t);var e=this.getSize();this._sizeChanged=!0,this._lastCenter=null;var i=this.getSize(),n=e.divideBy(2).round(),s=i.divideBy(2).round(),r=n.subtract(s);return r.x||r.y?(t.animate&&t.pan?this.panBy(r):(t.pan&&this._rawPanBy(r),this.fire("move"),t.debounceMoveend?(clearTimeout(this._sizeTimer),this._sizeTimer=setTimeout(o.bind(this.fire,this,"moveend"),200)):this.fire("moveend")),this.fire("resize",{oldSize:e,newSize:i})):this},stop:function(){return this.setZoom(this._limitZoom(this._zoom)),this.options.zoomSnap||this.fire("viewreset"),this._stop()},locate:function(t){if(t=this._locateOptions=o.extend({timeout:1e4,watch:!1},t),!("geolocation"in navigator))return this._handleGeolocationError({code:0,message:"Geolocation not supported."}),this;var e=o.bind(this._handleGeolocationResponse,this),i=o.bind(this._handleGeolocationError,this);return t.watch?this._locationWatchId=navigator.geolocation.watchPosition(e,i,t):navigator.geolocation.getCurrentPosition(e,i,t),this},stopLocate:function(){return navigator.geolocation&&navigator.geolocation.clearWatch&&navigator.geolocation.clearWatch(this._locationWatchId),this._locateOptions&&(this._locateOptions.setView=!1),this},_handleGeolocationError:function(t){var e=t.code,i=t.message||(1===e?"permission denied":2===e?"position unavailable":"timeout");this._locateOptions.setView&&!this._loaded&&this.fitWorld(),this.fire("locationerror",{code:e,message:"Geolocation error: "+i+"."})},_handleGeolocationResponse:function(t){var e=t.coords.latitude,i=t.coords.longitude,n=new o.LatLng(e,i),s=n.toBounds(t.coords.accuracy),r=this._locateOptions;if(r.setView){var a=this.getBoundsZoom(s);this.setView(n,r.maxZoom?Math.min(a,r.maxZoom):a)}var h={latlng:n,bounds:s,timestamp:t.timestamp};for(var l in t.coords)"number"==typeof t.coords[l]&&(h[l]=t.coords[l]);this.fire("locationfound",h)},addHandler:function(t,e){if(!e)return this;var i=this[t]=new e(this);return this._handlers.push(i),this.options[t]&&i.enable(),this},remove:function(){if(this._initEvents(!0),this._containerId!==this._container._leaflet_id)throw new Error("Map container is being reused by another instance");try{delete this._container._leaflet_id,delete this._containerId}catch(t){this._container._leaflet_id=i,this._containerId=i}o.DomUtil.remove(this._mapPane),this._clearControlPos&&this._clearControlPos(),this._clearHandlers(),this._loaded&&this.fire("unload");for(var t in this._layers)this._layers[t].remove();return this},createPane:function(t,e){var i="leaflet-pane"+(t?" leaflet-"+t.replace("Pane","")+"-pane":""),n=o.DomUtil.create("div",i,e||this._mapPane);return t&&(this._panes[t]=n),n},getCenter:function(){return this._checkIfLoaded(),this._lastCenter&&!this._moved()?this._lastCenter:this.layerPointToLatLng(this._getCenterLayerPoint())},getZoom:function(){return this._zoom},getBounds:function(){var t=this.getPixelBounds(),e=this.unproject(t.getBottomLeft()),i=this.unproject(t.getTopRight());return new o.LatLngBounds(e,i)},getMinZoom:function(){return this.options.minZoom===i?this._layersMinZoom||0:this.options.minZoom},getMaxZoom:function(){return this.options.maxZoom===i?this._layersMaxZoom===i?1/0:this._layersMaxZoom:this.options.maxZoom},getBoundsZoom:function(t,e,i){t=o.latLngBounds(t),i=o.point(i||[0,0]);var n=this.getZoom()||0,s=this.getMinZoom(),r=this.getMaxZoom(),a=t.getNorthWest(),h=t.getSouthEast(),l=this.getSize().subtract(i),u=o.bounds(this.project(h,n),this.project(a,n)).getSize(),c=o.Browser.any3d?this.options.zoomSnap:1,d=Math.min(l.x/u.x,l.y/u.y);return n=this.getScaleZoom(d,n),c&&(n=Math.round(n/(c/100))*(c/100),n=e?Math.ceil(n/c)*c:Math.floor(n/c)*c),Math.max(s,Math.min(r,n))},getSize:function(){return this._size&&!this._sizeChanged||(this._size=new o.Point(this._container.clientWidth||0,this._container.clientHeight||0),this._sizeChanged=!1),this._size.clone()},getPixelBounds:function(t,e){var i=this._getTopLeftPoint(t,e);return new o.Bounds(i,i.add(this.getSize()))},getPixelOrigin:function(){return this._checkIfLoaded(),this._pixelOrigin},getPixelWorldBounds:function(t){return this.options.crs.getProjectedBounds(t===i?this.getZoom():t)},getPane:function(t){return"string"==typeof t?this._panes[t]:t},getPanes:function(){return this._panes},getContainer:function(){return this._container},getZoomScale:function(t,e){var n=this.options.crs;return e=e===i?this._zoom:e,n.scale(t)/n.scale(e)},getScaleZoom:function(t,e){var n=this.options.crs;e=e===i?this._zoom:e;var o=n.zoom(t*n.scale(e));return isNaN(o)?1/0:o},project:function(t,e){return e=e===i?this._zoom:e,this.options.crs.latLngToPoint(o.latLng(t),e)},unproject:function(t,e){return e=e===i?this._zoom:e,this.options.crs.pointToLatLng(o.point(t),e)},layerPointToLatLng:function(t){var e=o.point(t).add(this.getPixelOrigin());return this.unproject(e)},latLngToLayerPoint:function(t){var e=this.project(o.latLng(t))._round();return e._subtract(this.getPixelOrigin())},wrapLatLng:function(t){return this.options.crs.wrapLatLng(o.latLng(t))},wrapLatLngBounds:function(t){return this.options.crs.wrapLatLngBounds(o.latLngBounds(t))},distance:function(t,e){return this.options.crs.distance(o.latLng(t),o.latLng(e))},containerPointToLayerPoint:function(t){return o.point(t).subtract(this._getMapPanePos())},layerPointToContainerPoint:function(t){return o.point(t).add(this._getMapPanePos())},containerPointToLatLng:function(t){var e=this.containerPointToLayerPoint(o.point(t));return this.layerPointToLatLng(e)},latLngToContainerPoint:function(t){return this.layerPointToContainerPoint(this.latLngToLayerPoint(o.latLng(t)))},mouseEventToContainerPoint:function(t){return o.DomEvent.getMousePosition(t,this._container)},mouseEventToLayerPoint:function(t){return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(t))},mouseEventToLatLng:function(t){return this.layerPointToLatLng(this.mouseEventToLayerPoint(t))},_initContainer:function(t){var e=this._container=o.DomUtil.get(t);if(!e)throw new Error("Map container not found.");if(e._leaflet_id)throw new Error("Map container is already initialized.");o.DomEvent.addListener(e,"scroll",this._onScroll,this),this._containerId=o.Util.stamp(e)},_initLayout:function(){var t=this._container;this._fadeAnimated=this.options.fadeAnimation&&o.Browser.any3d,
6
o.DomUtil.addClass(t,"leaflet-container"+(o.Browser.touch?" leaflet-touch":"")+(o.Browser.retina?" leaflet-retina":"")+(o.Browser.ielt9?" leaflet-oldie":"")+(o.Browser.safari?" leaflet-safari":"")+(this._fadeAnimated?" leaflet-fade-anim":""));var e=o.DomUtil.getStyle(t,"position");"absolute"!==e&&"relative"!==e&&"fixed"!==e&&(t.style.position="relative"),this._initPanes(),this._initControlPos&&this._initControlPos()},_initPanes:function(){var t=this._panes={};this._paneRenderers={},this._mapPane=this.createPane("mapPane",this._container),o.DomUtil.setPosition(this._mapPane,new o.Point(0,0)),this.createPane("tilePane"),this.createPane("shadowPane"),this.createPane("overlayPane"),this.createPane("markerPane"),this.createPane("tooltipPane"),this.createPane("popupPane"),this.options.markerZoomAnimation||(o.DomUtil.addClass(t.markerPane,"leaflet-zoom-hide"),o.DomUtil.addClass(t.shadowPane,"leaflet-zoom-hide"))},_resetView:function(t,e){o.DomUtil.setPosition(this._mapPane,new o.Point(0,0));var i=!this._loaded;this._loaded=!0,e=this._limitZoom(e),this.fire("viewprereset");var n=this._zoom!==e;this._moveStart(n)._move(t,e)._moveEnd(n),this.fire("viewreset"),i&&this.fire("load")},_moveStart:function(t){return t&&this.fire("zoomstart"),this.fire("movestart")},_move:function(t,e,n){e===i&&(e=this._zoom);var o=this._zoom!==e;return this._zoom=e,this._lastCenter=t,this._pixelOrigin=this._getNewPixelOrigin(t),(o||n&&n.pinch)&&this.fire("zoom",n),this.fire("move",n)},_moveEnd:function(t){return t&&this.fire("zoomend"),this.fire("moveend")},_stop:function(){return o.Util.cancelAnimFrame(this._flyToFrame),this._panAnim&&this._panAnim.stop(),this},_rawPanBy:function(t){o.DomUtil.setPosition(this._mapPane,this._getMapPanePos().subtract(t))},_getZoomSpan:function(){return this.getMaxZoom()-this.getMinZoom()},_panInsideMaxBounds:function(){this._enforcingBounds||this.panInsideBounds(this.options.maxBounds)},_checkIfLoaded:function(){if(!this._loaded)throw new Error("Set map center and zoom first.")},_initEvents:function(e){if(o.DomEvent){this._targets={},this._targets[o.stamp(this._container)]=this;var i=e?"off":"on";o.DomEvent[i](this._container,"click dblclick mousedown mouseup mouseover mouseout mousemove contextmenu keypress",this._handleDOMEvent,this),this.options.trackResize&&o.DomEvent[i](t,"resize",this._onResize,this),o.Browser.any3d&&this.options.transform3DLimit&&this[i]("moveend",this._onMoveEnd)}},_onResize:function(){o.Util.cancelAnimFrame(this._resizeRequest),this._resizeRequest=o.Util.requestAnimFrame(function(){this.invalidateSize({debounceMoveend:!0})},this)},_onScroll:function(){this._container.scrollTop=0,this._container.scrollLeft=0},_onMoveEnd:function(){var t=this._getMapPanePos();Math.max(Math.abs(t.x),Math.abs(t.y))>=this.options.transform3DLimit&&this._resetView(this.getCenter(),this.getZoom())},_findEventTargets:function(t,e){for(var i,n=[],s="mouseout"===e||"mouseover"===e,r=t.target||t.srcElement,a=!1;r;){if(i=this._targets[o.stamp(r)],i&&("click"===e||"preclick"===e)&&!t._simulated&&this._draggableMoved(i)){a=!0;break}if(i&&i.listens(e,!0)){if(s&&!o.DomEvent._isExternalTarget(r,t))break;if(n.push(i),s)break}if(r===this._container)break;r=r.parentNode}return n.length||a||s||!o.DomEvent._isExternalTarget(r,t)||(n=[this]),n},_handleDOMEvent:function(t){if(this._loaded&&!o.DomEvent._skipped(t)){var e="keypress"===t.type&&13===t.keyCode?"click":t.type;"mousedown"===e&&o.DomUtil.preventOutline(t.target||t.srcElement),this._fireDOMEvent(t,e)}},_fireDOMEvent:function(t,e,i){if("click"===t.type){var n=o.Util.extend({},t);n.type="preclick",this._fireDOMEvent(n,n.type,i)}if(!t._stopped&&(i=(i||[]).concat(this._findEventTargets(t,e)),i.length)){var s=i[0];"contextmenu"===e&&s.listens(e,!0)&&o.DomEvent.preventDefault(t);var r={originalEvent:t};if("keypress"!==t.type){var a=s instanceof o.Marker;r.containerPoint=a?this.latLngToContainerPoint(s.getLatLng()):this.mouseEventToContainerPoint(t),r.layerPoint=this.containerPointToLayerPoint(r.containerPoint),r.latlng=a?s.getLatLng():this.layerPointToLatLng(r.layerPoint)}for(var h=0;h<i.length;h++)if(i[h].fire(e,r,!0),r.originalEvent._stopped||i[h].options.nonBubblingEvents&&o.Util.indexOf(i[h].options.nonBubblingEvents,e)!==-1)return}},_draggableMoved:function(t){return t=t.dragging&&t.dragging.enabled()?t:this,t.dragging&&t.dragging.moved()||this.boxZoom&&this.boxZoom.moved()},_clearHandlers:function(){for(var t=0,e=this._handlers.length;t<e;t++)this._handlers[t].disable()},whenReady:function(t,e){return this._loaded?t.call(e||this,{target:this}):this.on("load",t,e),this},_getMapPanePos:function(){return o.DomUtil.getPosition(this._mapPane)||new o.Point(0,0)},_moved:function(){var t=this._getMapPanePos();return t&&!t.equals([0,0])},_getTopLeftPoint:function(t,e){var n=t&&e!==i?this._getNewPixelOrigin(t,e):this.getPixelOrigin();return n.subtract(this._getMapPanePos())},_getNewPixelOrigin:function(t,e){var i=this.getSize()._divideBy(2);return this.project(t,e)._subtract(i)._add(this._getMapPanePos())._round()},_latLngToNewLayerPoint:function(t,e,i){var n=this._getNewPixelOrigin(i,e);return this.project(t,e)._subtract(n)},_latLngBoundsToNewLayerBounds:function(t,e,i){var n=this._getNewPixelOrigin(i,e);return o.bounds([this.project(t.getSouthWest(),e)._subtract(n),this.project(t.getNorthWest(),e)._subtract(n),this.project(t.getSouthEast(),e)._subtract(n),this.project(t.getNorthEast(),e)._subtract(n)])},_getCenterLayerPoint:function(){return this.containerPointToLayerPoint(this.getSize()._divideBy(2))},_getCenterOffset:function(t){return this.latLngToLayerPoint(t).subtract(this._getCenterLayerPoint())},_limitCenter:function(t,e,i){if(!i)return t;var n=this.project(t,e),s=this.getSize().divideBy(2),r=new o.Bounds(n.subtract(s),n.add(s)),a=this._getBoundsOffset(r,i,e);return a.round().equals([0,0])?t:this.unproject(n.add(a),e)},_limitOffset:function(t,e){if(!e)return t;var i=this.getPixelBounds(),n=new o.Bounds(i.min.add(t),i.max.add(t));return t.add(this._getBoundsOffset(n,e))},_getBoundsOffset:function(t,e,i){var n=o.bounds(this.project(e.getNorthEast(),i),this.project(e.getSouthWest(),i)),s=n.min.subtract(t.min),r=n.max.subtract(t.max),a=this._rebound(s.x,-r.x),h=this._rebound(s.y,-r.y);return new o.Point(a,h)},_rebound:function(t,e){return t+e>0?Math.round(t-e)/2:Math.max(0,Math.ceil(t))-Math.max(0,Math.floor(e))},_limitZoom:function(t){var e=this.getMinZoom(),i=this.getMaxZoom(),n=o.Browser.any3d?this.options.zoomSnap:1;return n&&(t=Math.round(t/n)*n),Math.max(e,Math.min(i,t))},_onPanTransitionStep:function(){this.fire("move")},_onPanTransitionEnd:function(){o.DomUtil.removeClass(this._mapPane,"leaflet-pan-anim"),this.fire("moveend")},_tryAnimatedPan:function(t,e){var i=this._getCenterOffset(t)._floor();return!((e&&e.animate)!==!0&&!this.getSize().contains(i))&&(this.panBy(i,e),!0)},_createAnimProxy:function(){var t=this._proxy=o.DomUtil.create("div","leaflet-proxy leaflet-zoom-animated");this._panes.mapPane.appendChild(t),this.on("zoomanim",function(e){var i=o.DomUtil.TRANSFORM,n=t.style[i];o.DomUtil.setTransform(t,this.project(e.center,e.zoom),this.getZoomScale(e.zoom,1)),n===t.style[i]&&this._animatingZoom&&this._onZoomTransitionEnd()},this),this.on("load moveend",function(){var e=this.getCenter(),i=this.getZoom();o.DomUtil.setTransform(t,this.project(e,i),this.getZoomScale(i,1))},this)},_catchTransitionEnd:function(t){this._animatingZoom&&t.propertyName.indexOf("transform")>=0&&this._onZoomTransitionEnd()},_nothingToAnimate:function(){return!this._container.getElementsByClassName("leaflet-zoom-animated").length},_tryAnimatedZoom:function(t,e,i){if(this._animatingZoom)return!0;if(i=i||{},!this._zoomAnimated||i.animate===!1||this._nothingToAnimate()||Math.abs(e-this._zoom)>this.options.zoomAnimationThreshold)return!1;var n=this.getZoomScale(e),s=this._getCenterOffset(t)._divideBy(1-1/n);return!(i.animate!==!0&&!this.getSize().contains(s))&&(o.Util.requestAnimFrame(function(){this._moveStart(!0)._animateZoom(t,e,!0)},this),!0)},_animateZoom:function(t,e,i,n){i&&(this._animatingZoom=!0,this._animateToCenter=t,this._animateToZoom=e,o.DomUtil.addClass(this._mapPane,"leaflet-zoom-anim")),this.fire("zoomanim",{center:t,zoom:e,noUpdate:n}),setTimeout(o.bind(this._onZoomTransitionEnd,this),250)},_onZoomTransitionEnd:function(){this._animatingZoom&&(o.DomUtil.removeClass(this._mapPane,"leaflet-zoom-anim"),this._animatingZoom=!1,this._move(this._animateToCenter,this._animateToZoom),o.Util.requestAnimFrame(function(){this._moveEnd(!0)},this))}}),o.map=function(t,e){return new o.Map(t,e)},o.Layer=o.Evented.extend({options:{pane:"overlayPane",nonBubblingEvents:[],attribution:null},addTo:function(t){return t.addLayer(this),this},remove:function(){return this.removeFrom(this._map||this._mapToAdd)},removeFrom:function(t){return t&&t.removeLayer(this),this},getPane:function(t){return this._map.getPane(t?this.options[t]||t:this.options.pane)},addInteractiveTarget:function(t){return this._map._targets[o.stamp(t)]=this,this},removeInteractiveTarget:function(t){return delete this._map._targets[o.stamp(t)],this},getAttribution:function(){return this.options.attribution},_layerAdd:function(t){var e=t.target;if(e.hasLayer(this)){if(this._map=e,this._zoomAnimated=e._zoomAnimated,this.getEvents){var i=this.getEvents();e.on(i,this),this.once("remove",function(){e.off(i,this)},this)}this.onAdd(e),this.getAttribution&&e.attributionControl&&e.attributionControl.addAttribution(this.getAttribution()),this.fire("add"),e.fire("layeradd",{layer:this})}}}),o.Map.include({addLayer:function(t){var e=o.stamp(t);return this._layers[e]?this:(this._layers[e]=t,t._mapToAdd=this,t.beforeAdd&&t.beforeAdd(this),this.whenReady(t._layerAdd,t),this)},removeLayer:function(t){var e=o.stamp(t);return this._layers[e]?(this._loaded&&t.onRemove(this),t.getAttribution&&this.attributionControl&&this.attributionControl.removeAttribution(t.getAttribution()),delete this._layers[e],this._loaded&&(this.fire("layerremove",{layer:t}),t.fire("remove")),t._map=t._mapToAdd=null,this):this},hasLayer:function(t){return!!t&&o.stamp(t)in this._layers},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},_addLayers:function(t){t=t?o.Util.isArray(t)?t:[t]:[];for(var e=0,i=t.length;e<i;e++)this.addLayer(t[e])},_addZoomLimit:function(t){!isNaN(t.options.maxZoom)&&isNaN(t.options.minZoom)||(this._zoomBoundLayers[o.stamp(t)]=t,this._updateZoomLevels())},_removeZoomLimit:function(t){var e=o.stamp(t);this._zoomBoundLayers[e]&&(delete this._zoomBoundLayers[e],this._updateZoomLevels())},_updateZoomLevels:function(){var t=1/0,e=-(1/0),n=this._getZoomSpan();for(var o in this._zoomBoundLayers){var s=this._zoomBoundLayers[o].options;t=s.minZoom===i?t:Math.min(t,s.minZoom),e=s.maxZoom===i?e:Math.max(e,s.maxZoom)}this._layersMaxZoom=e===-(1/0)?i:e,this._layersMinZoom=t===1/0?i:t,n!==this._getZoomSpan()&&this.fire("zoomlevelschange"),this.options.maxZoom===i&&this._layersMaxZoom&&this.getZoom()>this._layersMaxZoom&&this.setZoom(this._layersMaxZoom),this.options.minZoom===i&&this._layersMinZoom&&this.getZoom()<this._layersMinZoom&&this.setZoom(this._layersMinZoom)}});var r="_leaflet_events";o.DomEvent={on:function(t,e,i,n){if("object"==typeof e)for(var s in e)this._on(t,s,e[s],i);else{e=o.Util.splitWords(e);for(var r=0,a=e.length;r<a;r++)this._on(t,e[r],i,n)}return this},off:function(t,e,i,n){if("object"==typeof e)for(var s in e)this._off(t,s,e[s],i);else{e=o.Util.splitWords(e);for(var r=0,a=e.length;r<a;r++)this._off(t,e[r],i,n)}return this},_on:function(e,i,n,s){var a=i+o.stamp(n)+(s?"_"+o.stamp(s):"");if(e[r]&&e[r][a])return this;var h=function(i){return n.call(s||e,i||t.event)},l=h;return o.Browser.pointer&&0===i.indexOf("touch")?this.addPointerListener(e,i,h,a):!o.Browser.touch||"dblclick"!==i||!this.addDoubleTapListener||o.Browser.pointer&&o.Browser.chrome?"addEventListener"in e?"mousewheel"===i?e.addEventListener("onwheel"in e?"wheel":"mousewheel",h,!1):"mouseenter"===i||"mouseleave"===i?(h=function(i){i=i||t.event,o.DomEvent._isExternalTarget(e,i)&&l(i)},e.addEventListener("mouseenter"===i?"mouseover":"mouseout",h,!1)):("click"===i&&o.Browser.android&&(h=function(t){return o.DomEvent._filterClick(t,l)}),e.addEventListener(i,h,!1)):"attachEvent"in e&&e.attachEvent("on"+i,h):this.addDoubleTapListener(e,h,a),e[r]=e[r]||{},e[r][a]=h,this},_off:function(t,e,i,n){var s=e+o.stamp(i)+(n?"_"+o.stamp(n):""),a=t[r]&&t[r][s];return a?(o.Browser.pointer&&0===e.indexOf("touch")?this.removePointerListener(t,e,s):o.Browser.touch&&"dblclick"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,s):"removeEventListener"in t?"mousewheel"===e?t.removeEventListener("onwheel"in t?"wheel":"mousewheel",a,!1):t.removeEventListener("mouseenter"===e?"mouseover":"mouseleave"===e?"mouseout":e,a,!1):"detachEvent"in t&&t.detachEvent("on"+e,a),t[r][s]=null,this):this},stopPropagation:function(t){return t.stopPropagation?t.stopPropagation():t.originalEvent?t.originalEvent._stopped=!0:t.cancelBubble=!0,o.DomEvent._skipped(t),this},disableScrollPropagation:function(t){return o.DomEvent.on(t,"mousewheel",o.DomEvent.stopPropagation)},disableClickPropagation:function(t){var e=o.DomEvent.stopPropagation;return o.DomEvent.on(t,o.Draggable.START.join(" "),e),o.DomEvent.on(t,{click:o.DomEvent._fakeStop,dblclick:e})},preventDefault:function(t){return t.preventDefault?t.preventDefault():t.returnValue=!1,this},stop:function(t){return o.DomEvent.preventDefault(t).stopPropagation(t)},getMousePosition:function(t,e){if(!e)return new o.Point(t.clientX,t.clientY);var i=e.getBoundingClientRect();return new o.Point(t.clientX-i.left-e.clientLeft,t.clientY-i.top-e.clientTop)},_wheelPxFactor:o.Browser.win&&o.Browser.chrome?2:o.Browser.gecko?t.devicePixelRatio:1,getWheelDelta:function(t){return o.Browser.edge?t.wheelDeltaY/2:t.deltaY&&0===t.deltaMode?-t.deltaY/o.DomEvent._wheelPxFactor:t.deltaY&&1===t.deltaMode?20*-t.deltaY:t.deltaY&&2===t.deltaMode?60*-t.deltaY:t.deltaX||t.deltaZ?0:t.wheelDelta?(t.wheelDeltaY||t.wheelDelta)/2:t.detail&&Math.abs(t.detail)<32765?20*-t.detail:t.detail?t.detail/-32765*60:0},_skipEvents:{},_fakeStop:function(t){o.DomEvent._skipEvents[t.type]=!0},_skipped:function(t){var e=this._skipEvents[t.type];return this._skipEvents[t.type]=!1,e},_isExternalTarget:function(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(t){return!1}return i!==t},_filterClick:function(t,e){var i=t.timeStamp||t.originalEvent&&t.originalEvent.timeStamp,n=o.DomEvent._lastClick&&i-o.DomEvent._lastClick;return n&&n>100&&n<500||t.target._simulatedClick&&!t._simulated?void o.DomEvent.stop(t):(o.DomEvent._lastClick=i,void e(t))}},o.DomEvent.addListener=o.DomEvent.on,o.DomEvent.removeListener=o.DomEvent.off,o.PosAnimation=o.Evented.extend({run:function(t,e,i,n){this.stop(),this._el=t,this._inProgress=!0,this._duration=i||.25,this._easeOutPower=1/Math.max(n||.5,.2),this._startPos=o.DomUtil.getPosition(t),this._offset=e.subtract(this._startPos),this._startTime=+new Date,this.fire("start"),this._animate()},stop:function(){this._inProgress&&(this._step(!0),this._complete())},_animate:function(){this._animId=o.Util.requestAnimFrame(this._animate,this),this._step()},_step:function(t){var e=+new Date-this._startTime,i=1e3*this._duration;e<i?this._runFrame(this._easeOut(e/i),t):(this._runFrame(1),this._complete())},_runFrame:function(t,e){var i=this._startPos.add(this._offset.multiplyBy(t));e&&i._round(),o.DomUtil.setPosition(this._el,i),this.fire("step")},_complete:function(){o.Util.cancelAnimFrame(this._animId),this._inProgress=!1,this.fire("end")},_easeOut:function(t){return 1-Math.pow(1-t,this._easeOutPower)}}),o.Projection.Mercator={R:6378137,R_MINOR:6356752.314245179,bounds:o.bounds([-20037508.34279,-15496570.73972],[20037508.34279,18764656.23138]),project:function(t){var e=Math.PI/180,i=this.R,n=t.lat*e,s=this.R_MINOR/i,r=Math.sqrt(1-s*s),a=r*Math.sin(n),h=Math.tan(Math.PI/4-n/2)/Math.pow((1-a)/(1+a),r/2);return n=-i*Math.log(Math.max(h,1e-10)),new o.Point(t.lng*e*i,n)},unproject:function(t){for(var e,i=180/Math.PI,n=this.R,s=this.R_MINOR/n,r=Math.sqrt(1-s*s),a=Math.exp(-t.y/n),h=Math.PI/2-2*Math.atan(a),l=0,u=.1;l<15&&Math.abs(u)>1e-7;l++)e=r*Math.sin(h),e=Math.pow((1-e)/(1+e),r/2),u=Math.PI/2-2*Math.atan(a*e)-h,h+=u;return new o.LatLng(h*i,t.x*i/n)}},o.CRS.EPSG3395=o.extend({},o.CRS.Earth,{code:"EPSG:3395",projection:o.Projection.Mercator,transformation:function(){var t=.5/(Math.PI*o.Projection.Mercator.R);return new o.Transformation(t,.5,-t,.5)}()}),o.GridLayer=o.Layer.extend({options:{tileSize:256,opacity:1,updateWhenIdle:o.Browser.mobile,updateWhenZooming:!0,updateInterval:200,zIndex:1,bounds:null,minZoom:0,maxZoom:i,noWrap:!1,pane:"tilePane",className:"",keepBuffer:2},initialize:function(t){o.setOptions(this,t)},onAdd:function(){this._initContainer(),this._levels={},this._tiles={},this._resetView(),this._update()},beforeAdd:function(t){t._addZoomLimit(this)},onRemove:function(t){this._removeAllTiles(),o.DomUtil.remove(this._container),t._removeZoomLimit(this),this._container=null,this._tileZoom=null},bringToFront:function(){return this._map&&(o.DomUtil.toFront(this._container),this._setAutoZIndex(Math.max)),this},bringToBack:function(){return this._map&&(o.DomUtil.toBack(this._container),this._setAutoZIndex(Math.min)),this},getContainer:function(){return this._container},setOpacity:function(t){return this.options.opacity=t,this._updateOpacity(),this},setZIndex:function(t){return this.options.zIndex=t,this._updateZIndex(),this},isLoading:function(){return this._loading},redraw:function(){return this._map&&(this._removeAllTiles(),this._update()),this},getEvents:function(){var t={viewprereset:this._invalidateAll,viewreset:this._resetView,zoom:this._resetView,moveend:this._onMoveEnd};return this.options.updateWhenIdle||(this._onMove||(this._onMove=o.Util.throttle(this._onMoveEnd,this.options.updateInterval,this)),t.move=this._onMove),this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},createTile:function(){return e.createElement("div")},getTileSize:function(){var t=this.options.tileSize;return t instanceof o.Point?t:new o.Point(t,t)},_updateZIndex:function(){this._container&&this.options.zIndex!==i&&null!==this.options.zIndex&&(this._container.style.zIndex=this.options.zIndex)},_setAutoZIndex:function(t){for(var e,i=this.getPane().children,n=-t(-(1/0),1/0),o=0,s=i.length;o<s;o++)e=i[o].style.zIndex,i[o]!==this._container&&e&&(n=t(n,+e));isFinite(n)&&(this.options.zIndex=n+t(-1,1),this._updateZIndex())},_updateOpacity:function(){if(this._map&&!o.Browser.ielt9){o.DomUtil.setOpacity(this._container,this.options.opacity);var t=+new Date,e=!1,i=!1;for(var n in this._tiles){var s=this._tiles[n];if(s.current&&s.loaded){var r=Math.min(1,(t-s.loaded)/200);o.DomUtil.setOpacity(s.el,r),r<1?e=!0:(s.active&&(i=!0),s.active=!0)}}i&&!this._noPrune&&this._pruneTiles(),e&&(o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this))}},_initContainer:function(){this._container||(this._container=o.DomUtil.create("div","leaflet-layer "+(this.options.className||"")),this._updateZIndex(),this.options.opacity<1&&this._updateOpacity(),this.getPane().appendChild(this._container))},_updateLevels:function(){var t=this._tileZoom,e=this.options.maxZoom;if(t===i)return i;for(var n in this._levels)this._levels[n].el.children.length||n===t?this._levels[n].el.style.zIndex=e-Math.abs(t-n):(o.DomUtil.remove(this._levels[n].el),this._removeTilesAtZoom(n),delete this._levels[n]);var s=this._levels[t],r=this._map;return s||(s=this._levels[t]={},s.el=o.DomUtil.create("div","leaflet-tile-container leaflet-zoom-animated",this._container),s.el.style.zIndex=e,s.origin=r.project(r.unproject(r.getPixelOrigin()),t).round(),s.zoom=t,this._setZoomTransform(s,r.getCenter(),r.getZoom()),o.Util.falseFn(s.el.offsetWidth)),this._level=s,s},_pruneTiles:function(){if(this._map){var t,e,i=this._map.getZoom();if(i>this.options.maxZoom||i<this.options.minZoom)return void this._removeAllTiles();for(t in this._tiles)e=this._tiles[t],e.retain=e.current;for(t in this._tiles)if(e=this._tiles[t],e.current&&!e.active){var n=e.coords;this._retainParent(n.x,n.y,n.z,n.z-5)||this._retainChildren(n.x,n.y,n.z,n.z+2)}for(t in this._tiles)this._tiles[t].retain||this._removeTile(t)}},_removeTilesAtZoom:function(t){for(var e in this._tiles)this._tiles[e].coords.z===t&&this._removeTile(e)},_removeAllTiles:function(){for(var t in this._tiles)this._removeTile(t)},_invalidateAll:function(){for(var t in this._levels)o.DomUtil.remove(this._levels[t].el),delete this._levels[t];this._removeAllTiles(),this._tileZoom=null},_retainParent:function(t,e,i,n){var s=Math.floor(t/2),r=Math.floor(e/2),a=i-1,h=new o.Point(+s,+r);h.z=+a;var l=this._tileCoordsToKey(h),u=this._tiles[l];return u&&u.active?(u.retain=!0,!0):(u&&u.loaded&&(u.retain=!0),a>n&&this._retainParent(s,r,a,n))},_retainChildren:function(t,e,i,n){for(var s=2*t;s<2*t+2;s++)for(var r=2*e;r<2*e+2;r++){var a=new o.Point(s,r);a.z=i+1;var h=this._tileCoordsToKey(a),l=this._tiles[h];l&&l.active?l.retain=!0:(l&&l.loaded&&(l.retain=!0),i+1<n&&this._retainChildren(s,r,i+1,n))}},_resetView:function(t){var e=t&&(t.pinch||t.flyTo);this._setView(this._map.getCenter(),this._map.getZoom(),e,e)},_animateZoom:function(t){this._setView(t.center,t.zoom,!0,t.noUpdate)},_setView:function(t,e,n,o){var s=Math.round(e);(this.options.maxZoom!==i&&s>this.options.maxZoom||this.options.minZoom!==i&&s<this.options.minZoom)&&(s=i);var r=this.options.updateWhenZooming&&s!==this._tileZoom;o&&!r||(this._tileZoom=s,this._abortLoading&&this._abortLoading(),this._updateLevels(),this._resetGrid(),s!==i&&this._update(t),n||this._pruneTiles(),this._noPrune=!!n),this._setZoomTransforms(t,e)},_setZoomTransforms:function(t,e){for(var i in this._levels)this._setZoomTransform(this._levels[i],t,e)},_setZoomTransform:function(t,e,i){var n=this._map.getZoomScale(i,t.zoom),s=t.origin.multiplyBy(n).subtract(this._map._getNewPixelOrigin(e,i)).round();o.Browser.any3d?o.DomUtil.setTransform(t.el,s,n):o.DomUtil.setPosition(t.el,s)},_resetGrid:function(){var t=this._map,e=t.options.crs,i=this._tileSize=this.getTileSize(),n=this._tileZoom,o=this._map.getPixelWorldBounds(this._tileZoom);o&&(this._globalTileRange=this._pxBoundsToTileRange(o)),this._wrapX=e.wrapLng&&!this.options.noWrap&&[Math.floor(t.project([0,e.wrapLng[0]],n).x/i.x),Math.ceil(t.project([0,e.wrapLng[1]],n).x/i.y)],this._wrapY=e.wrapLat&&!this.options.noWrap&&[Math.floor(t.project([e.wrapLat[0],0],n).y/i.x),Math.ceil(t.project([e.wrapLat[1],0],n).y/i.y)]},_onMoveEnd:function(){this._map&&!this._map._animatingZoom&&this._update()},_getTiledPixelBounds:function(t){var e=this._map,i=e._animatingZoom?Math.max(e._animateToZoom,e.getZoom()):e.getZoom(),n=e.getZoomScale(i,this._tileZoom),s=e.project(t,this._tileZoom).floor(),r=e.getSize().divideBy(2*n);return new o.Bounds(s.subtract(r),s.add(r))},_update:function(t){var n=this._map;if(n){var s=n.getZoom();if(t===i&&(t=n.getCenter()),this._tileZoom!==i){var r=this._getTiledPixelBounds(t),a=this._pxBoundsToTileRange(r),h=a.getCenter(),l=[],u=this.options.keepBuffer,c=new o.Bounds(a.getBottomLeft().subtract([u,-u]),a.getTopRight().add([u,-u]));for(var d in this._tiles){var _=this._tiles[d].coords;_.z===this._tileZoom&&c.contains(o.point(_.x,_.y))||(this._tiles[d].current=!1)}if(Math.abs(s-this._tileZoom)>1)return void this._setView(t,s);for(var m=a.min.y;m<=a.max.y;m++)for(var p=a.min.x;p<=a.max.x;p++){var f=new o.Point(p,m);if(f.z=this._tileZoom,this._isValidTile(f)){var g=this._tiles[this._tileCoordsToKey(f)];g?g.current=!0:l.push(f)}}if(l.sort(function(t,e){return t.distanceTo(h)-e.distanceTo(h)}),0!==l.length){this._loading||(this._loading=!0,this.fire("loading"));var v=e.createDocumentFragment();for(p=0;p<l.length;p++)this._addTile(l[p],v);this._level.el.appendChild(v)}}}},_isValidTile:function(t){var e=this._map.options.crs;if(!e.infinite){var i=this._globalTileRange;if(!e.wrapLng&&(t.x<i.min.x||t.x>i.max.x)||!e.wrapLat&&(t.y<i.min.y||t.y>i.max.y))return!1}if(!this.options.bounds)return!0;var n=this._tileCoordsToBounds(t);return o.latLngBounds(this.options.bounds).overlaps(n)},_keyToBounds:function(t){return this._tileCoordsToBounds(this._keyToTileCoords(t))},_tileCoordsToBounds:function(t){var e=this._map,i=this.getTileSize(),n=t.scaleBy(i),s=n.add(i),r=e.unproject(n,t.z),a=e.unproject(s,t.z),h=new o.LatLngBounds(r,a);return this.options.noWrap||e.wrapLatLngBounds(h),h},_tileCoordsToKey:function(t){return t.x+":"+t.y+":"+t.z},_keyToTileCoords:function(t){var e=t.split(":"),i=new o.Point(+e[0],+e[1]);return i.z=+e[2],i},_removeTile:function(t){var e=this._tiles[t];e&&(o.DomUtil.remove(e.el),delete this._tiles[t],this.fire("tileunload",{tile:e.el,coords:this._keyToTileCoords(t)}))},_initTile:function(t){o.DomUtil.addClass(t,"leaflet-tile");var e=this.getTileSize();t.style.width=e.x+"px",t.style.height=e.y+"px",t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,o.Browser.ielt9&&this.options.opacity<1&&o.DomUtil.setOpacity(t,this.options.opacity),o.Browser.android&&!o.Browser.android23&&(t.style.WebkitBackfaceVisibility="hidden")},_addTile:function(t,e){var i=this._getTilePos(t),n=this._tileCoordsToKey(t),s=this.createTile(this._wrapCoords(t),o.bind(this._tileReady,this,t));this._initTile(s),this.createTile.length<2&&o.Util.requestAnimFrame(o.bind(this._tileReady,this,t,null,s)),o.DomUtil.setPosition(s,i),this._tiles[n]={el:s,coords:t,current:!0},e.appendChild(s),this.fire("tileloadstart",{tile:s,coords:t})},_tileReady:function(t,e,i){if(this._map){e&&this.fire("tileerror",{error:e,tile:i,coords:t});var n=this._tileCoordsToKey(t);i=this._tiles[n],i&&(i.loaded=+new Date,this._map._fadeAnimated?(o.DomUtil.setOpacity(i.el,0),o.Util.cancelAnimFrame(this._fadeFrame),this._fadeFrame=o.Util.requestAnimFrame(this._updateOpacity,this)):(i.active=!0,this._pruneTiles()),e||(o.DomUtil.addClass(i.el,"leaflet-tile-loaded"),this.fire("tileload",{tile:i.el,coords:t})),this._noTilesToLoad()&&(this._loading=!1,this.fire("load"),o.Browser.ielt9||!this._map._fadeAnimated?o.Util.requestAnimFrame(this._pruneTiles,this):setTimeout(o.bind(this._pruneTiles,this),250)))}},_getTilePos:function(t){return t.scaleBy(this.getTileSize()).subtract(this._level.origin)},_wrapCoords:function(t){var e=new o.Point(this._wrapX?o.Util.wrapNum(t.x,this._wrapX):t.x,this._wrapY?o.Util.wrapNum(t.y,this._wrapY):t.y);return e.z=t.z,e},_pxBoundsToTileRange:function(t){var e=this.getTileSize();return new o.Bounds(t.min.unscaleBy(e).floor(),t.max.unscaleBy(e).ceil().subtract([1,1]))},_noTilesToLoad:function(){for(var t in this._tiles)if(!this._tiles[t].loaded)return!1;return!0}}),o.gridLayer=function(t){return new o.GridLayer(t)},o.TileLayer=o.GridLayer.extend({options:{minZoom:0,maxZoom:18,maxNativeZoom:null,minNativeZoom:null,subdomains:"abc",errorTileUrl:"",zoomOffset:0,tms:!1,zoomReverse:!1,detectRetina:!1,crossOrigin:!1},initialize:function(t,e){this._url=t,e=o.setOptions(this,e),e.detectRetina&&o.Browser.retina&&e.maxZoom>0&&(e.tileSize=Math.floor(e.tileSize/2),e.zoomReverse?(e.zoomOffset--,e.minZoom++):(e.zoomOffset++,e.maxZoom--),e.minZoom=Math.max(0,e.minZoom)),"string"==typeof e.subdomains&&(e.subdomains=e.subdomains.split("")),o.Browser.android||this.on("tileunload",this._onTileRemove)},setUrl:function(t,e){return this._url=t,e||this.redraw(),this},createTile:function(t,i){var n=e.createElement("img");return o.DomEvent.on(n,"load",o.bind(this._tileOnLoad,this,i,n)),o.DomEvent.on(n,"error",o.bind(this._tileOnError,this,i,n)),this.options.crossOrigin&&(n.crossOrigin=""),n.alt="",n.setAttribute("role","presentation"),n.src=this.getTileUrl(t),n},getTileUrl:function(t){var e={r:o.Browser.retina?"@2x":"",s:this._getSubdomain(t),x:t.x,y:t.y,z:this._getZoomForUrl()};if(this._map&&!this._map.options.crs.infinite){var i=this._globalTileRange.max.y-t.y;this.options.tms&&(e.y=i),e["-y"]=i}return o.Util.template(this._url,o.extend(e,this.options))},_tileOnLoad:function(t,e){o.Browser.ielt9?setTimeout(o.bind(t,this,null,e),0):t(null,e)},_tileOnError:function(t,e,i){var n=this.options.errorTileUrl;n&&e.src!==n&&(e.src=n),t(i,e)},getTileSize:function(){var t=this._map,e=o.GridLayer.prototype.getTileSize.call(this),i=this._tileZoom+this.options.zoomOffset,n=this.options.minNativeZoom,s=this.options.maxNativeZoom;return null!==n&&i<n?e.divideBy(t.getZoomScale(n,i)).round():null!==s&&i>s?e.divideBy(t.getZoomScale(s,i)).round():e},_onTileRemove:function(t){t.tile.onload=null},_getZoomForUrl:function(){var t=this._tileZoom,e=this.options.maxZoom,i=this.options.zoomReverse,n=this.options.zoomOffset,o=this.options.minNativeZoom,s=this.options.maxNativeZoom;return i&&(t=e-t),t+=n,null!==o&&t<o?o:null!==s&&t>s?s:t},_getSubdomain:function(t){var e=Math.abs(t.x+t.y)%this.options.subdomains.length;return this.options.subdomains[e]},_abortLoading:function(){var t,e;for(t in this._tiles)this._tiles[t].coords.z!==this._tileZoom&&(e=this._tiles[t].el,e.onload=o.Util.falseFn,e.onerror=o.Util.falseFn,e.complete||(e.src=o.Util.emptyImageUrl,o.DomUtil.remove(e)))}}),o.tileLayer=function(t,e){return new o.TileLayer(t,e)},o.TileLayer.WMS=o.TileLayer.extend({defaultWmsParams:{service:"WMS",request:"GetMap",layers:"",styles:"",format:"image/jpeg",transparent:!1,version:"1.1.1"},options:{crs:null,uppercase:!1},initialize:function(t,e){this._url=t;var i=o.extend({},this.defaultWmsParams);for(var n in e)n in this.options||(i[n]=e[n]);e=o.setOptions(this,e),i.width=i.height=e.tileSize*(e.detectRetina&&o.Browser.retina?2:1),this.wmsParams=i},onAdd:function(t){this._crs=this.options.crs||t.options.crs,this._wmsVersion=parseFloat(this.wmsParams.version);var e=this._wmsVersion>=1.3?"crs":"srs";this.wmsParams[e]=this._crs.code,o.TileLayer.prototype.onAdd.call(this,t)},getTileUrl:function(t){var e=this._tileCoordsToBounds(t),i=this._crs.project(e.getNorthWest()),n=this._crs.project(e.getSouthEast()),s=(this._wmsVersion>=1.3&&this._crs===o.CRS.EPSG4326?[n.y,i.x,i.y,n.x]:[i.x,n.y,n.x,i.y]).join(","),r=o.TileLayer.prototype.getTileUrl.call(this,t);return r+o.Util.getParamString(this.wmsParams,r,this.options.uppercase)+(this.options.uppercase?"&BBOX=":"&bbox=")+s},setParams:function(t,e){return o.extend(this.wmsParams,t),e||this.redraw(),this}}),o.tileLayer.wms=function(t,e){return new o.TileLayer.WMS(t,e)},o.ImageOverlay=o.Layer.extend({options:{opacity:1,alt:"",interactive:!1,crossOrigin:!1},initialize:function(t,e,i){this._url=t,this._bounds=o.latLngBounds(e),o.setOptions(this,i)},onAdd:function(){this._image||(this._initImage(),this.options.opacity<1&&this._updateOpacity()),this.options.interactive&&(o.DomUtil.addClass(this._image,"leaflet-interactive"),this.addInteractiveTarget(this._image)),this.getPane().appendChild(this._image),this._reset()},onRemove:function(){o.DomUtil.remove(this._image),this.options.interactive&&this.removeInteractiveTarget(this._image)},setOpacity:function(t){return this.options.opacity=t,this._image&&this._updateOpacity(),this},setStyle:function(t){return t.opacity&&this.setOpacity(t.opacity),this},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._image),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._image),this},setUrl:function(t){return this._url=t,this._image&&(this._image.src=t),this},setBounds:function(t){return this._bounds=t,this._map&&this._reset(),this},getEvents:function(){var t={zoom:this._reset,viewreset:this._reset};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},getBounds:function(){return this._bounds},getElement:function(){return this._image},_initImage:function(){var t=this._image=o.DomUtil.create("img","leaflet-image-layer "+(this._zoomAnimated?"leaflet-zoom-animated":""));t.onselectstart=o.Util.falseFn,t.onmousemove=o.Util.falseFn,t.onload=o.bind(this.fire,this,"load"),this.options.crossOrigin&&(t.crossOrigin=""),t.src=this._url,t.alt=this.options.alt},_animateZoom:function(t){var e=this._map.getZoomScale(t.zoom),i=this._map._latLngBoundsToNewLayerBounds(this._bounds,t.zoom,t.center).min;
7
o.DomUtil.setTransform(this._image,i,e)},_reset:function(){var t=this._image,e=new o.Bounds(this._map.latLngToLayerPoint(this._bounds.getNorthWest()),this._map.latLngToLayerPoint(this._bounds.getSouthEast())),i=e.getSize();o.DomUtil.setPosition(t,e.min),t.style.width=i.x+"px",t.style.height=i.y+"px"},_updateOpacity:function(){o.DomUtil.setOpacity(this._image,this.options.opacity)}}),o.imageOverlay=function(t,e,i){return new o.ImageOverlay(t,e,i)},o.Icon=o.Class.extend({initialize:function(t){o.setOptions(this,t)},createIcon:function(t){return this._createIcon("icon",t)},createShadow:function(t){return this._createIcon("shadow",t)},_createIcon:function(t,e){var i=this._getIconUrl(t);if(!i){if("icon"===t)throw new Error("iconUrl not set in Icon options (see the docs).");return null}var n=this._createImg(i,e&&"IMG"===e.tagName?e:null);return this._setIconStyles(n,t),n},_setIconStyles:function(t,e){var i=this.options,n=i[e+"Size"];"number"==typeof n&&(n=[n,n]);var s=o.point(n),r=o.point("shadow"===e&&i.shadowAnchor||i.iconAnchor||s&&s.divideBy(2,!0));t.className="leaflet-marker-"+e+" "+(i.className||""),r&&(t.style.marginLeft=-r.x+"px",t.style.marginTop=-r.y+"px"),s&&(t.style.width=s.x+"px",t.style.height=s.y+"px")},_createImg:function(t,i){return i=i||e.createElement("img"),i.src=t,i},_getIconUrl:function(t){return o.Browser.retina&&this.options[t+"RetinaUrl"]||this.options[t+"Url"]}}),o.icon=function(t){return new o.Icon(t)},o.Icon.Default=o.Icon.extend({options:{iconUrl:"marker-icon.png",iconRetinaUrl:"marker-icon-2x.png",shadowUrl:"marker-shadow.png",iconSize:[25,41],iconAnchor:[12,41],popupAnchor:[1,-34],tooltipAnchor:[16,-28],shadowSize:[41,41]},_getIconUrl:function(t){return o.Icon.Default.imagePath||(o.Icon.Default.imagePath=this._detectIconPath()),(this.options.imagePath||o.Icon.Default.imagePath)+o.Icon.prototype._getIconUrl.call(this,t)},_detectIconPath:function(){var t=o.DomUtil.create("div","leaflet-default-icon-path",e.body),i=o.DomUtil.getStyle(t,"background-image")||o.DomUtil.getStyle(t,"backgroundImage");return e.body.removeChild(t),0===i.indexOf("url")?i.replace(/^url\([\"\']?/,"").replace(/marker-icon\.png[\"\']?\)$/,""):""}}),o.Marker=o.Layer.extend({options:{icon:new o.Icon.Default,interactive:!0,draggable:!1,keyboard:!0,title:"",alt:"",zIndexOffset:0,opacity:1,riseOnHover:!1,riseOffset:250,pane:"markerPane",nonBubblingEvents:["click","dblclick","mouseover","mouseout","contextmenu"]},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t)},onAdd:function(t){this._zoomAnimated=this._zoomAnimated&&t.options.markerZoomAnimation,this._zoomAnimated&&t.on("zoomanim",this._animateZoom,this),this._initIcon(),this.update()},onRemove:function(t){this.dragging&&this.dragging.enabled()&&(this.options.draggable=!0,this.dragging.removeHooks()),this._zoomAnimated&&t.off("zoomanim",this._animateZoom,this),this._removeIcon(),this._removeShadow()},getEvents:function(){return{zoom:this.update,viewreset:this.update}},getLatLng:function(){return this._latlng},setLatLng:function(t){var e=this._latlng;return this._latlng=o.latLng(t),this.update(),this.fire("move",{oldLatLng:e,latlng:this._latlng})},setZIndexOffset:function(t){return this.options.zIndexOffset=t,this.update()},setIcon:function(t){return this.options.icon=t,this._map&&(this._initIcon(),this.update()),this._popup&&this.bindPopup(this._popup,this._popup.options),this},getElement:function(){return this._icon},update:function(){if(this._icon){var t=this._map.latLngToLayerPoint(this._latlng).round();this._setPos(t)}return this},_initIcon:function(){var t=this.options,e="leaflet-zoom-"+(this._zoomAnimated?"animated":"hide"),i=t.icon.createIcon(this._icon),n=!1;i!==this._icon&&(this._icon&&this._removeIcon(),n=!0,t.title&&(i.title=t.title),t.alt&&(i.alt=t.alt)),o.DomUtil.addClass(i,e),t.keyboard&&(i.tabIndex="0"),this._icon=i,t.riseOnHover&&this.on({mouseover:this._bringToFront,mouseout:this._resetZIndex});var s=t.icon.createShadow(this._shadow),r=!1;s!==this._shadow&&(this._removeShadow(),r=!0),s&&(o.DomUtil.addClass(s,e),s.alt=""),this._shadow=s,t.opacity<1&&this._updateOpacity(),n&&this.getPane().appendChild(this._icon),this._initInteraction(),s&&r&&this.getPane("shadowPane").appendChild(this._shadow)},_removeIcon:function(){this.options.riseOnHover&&this.off({mouseover:this._bringToFront,mouseout:this._resetZIndex}),o.DomUtil.remove(this._icon),this.removeInteractiveTarget(this._icon),this._icon=null},_removeShadow:function(){this._shadow&&o.DomUtil.remove(this._shadow),this._shadow=null},_setPos:function(t){o.DomUtil.setPosition(this._icon,t),this._shadow&&o.DomUtil.setPosition(this._shadow,t),this._zIndex=t.y+this.options.zIndexOffset,this._resetZIndex()},_updateZIndex:function(t){this._icon.style.zIndex=this._zIndex+t},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center).round();this._setPos(e)},_initInteraction:function(){if(this.options.interactive&&(o.DomUtil.addClass(this._icon,"leaflet-interactive"),this.addInteractiveTarget(this._icon),o.Handler.MarkerDrag)){var t=this.options.draggable;this.dragging&&(t=this.dragging.enabled(),this.dragging.disable()),this.dragging=new o.Handler.MarkerDrag(this),t&&this.dragging.enable()}},setOpacity:function(t){return this.options.opacity=t,this._map&&this._updateOpacity(),this},_updateOpacity:function(){var t=this.options.opacity;o.DomUtil.setOpacity(this._icon,t),this._shadow&&o.DomUtil.setOpacity(this._shadow,t)},_bringToFront:function(){this._updateZIndex(this.options.riseOffset)},_resetZIndex:function(){this._updateZIndex(0)},_getPopupAnchor:function(){return this.options.icon.options.popupAnchor||[0,0]},_getTooltipAnchor:function(){return this.options.icon.options.tooltipAnchor||[0,0]}}),o.marker=function(t,e){return new o.Marker(t,e)},o.DivIcon=o.Icon.extend({options:{iconSize:[12,12],html:!1,bgPos:null,className:"leaflet-div-icon"},createIcon:function(t){var i=t&&"DIV"===t.tagName?t:e.createElement("div"),n=this.options;if(i.innerHTML=n.html!==!1?n.html:"",n.bgPos){var s=o.point(n.bgPos);i.style.backgroundPosition=-s.x+"px "+-s.y+"px"}return this._setIconStyles(i,"icon"),i},createShadow:function(){return null}}),o.divIcon=function(t){return new o.DivIcon(t)},o.DivOverlay=o.Layer.extend({options:{offset:[0,7],className:"",pane:"popupPane"},initialize:function(t,e){o.setOptions(this,t),this._source=e},onAdd:function(t){this._zoomAnimated=t._zoomAnimated,this._container||this._initLayout(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,0),clearTimeout(this._removeTimeout),this.getPane().appendChild(this._container),this.update(),t._fadeAnimated&&o.DomUtil.setOpacity(this._container,1),this.bringToFront()},onRemove:function(t){t._fadeAnimated?(o.DomUtil.setOpacity(this._container,0),this._removeTimeout=setTimeout(o.bind(o.DomUtil.remove,o.DomUtil,this._container),200)):o.DomUtil.remove(this._container)},getLatLng:function(){return this._latlng},setLatLng:function(t){return this._latlng=o.latLng(t),this._map&&(this._updatePosition(),this._adjustPan()),this},getContent:function(){return this._content},setContent:function(t){return this._content=t,this.update(),this},getElement:function(){return this._container},update:function(){this._map&&(this._container.style.visibility="hidden",this._updateContent(),this._updateLayout(),this._updatePosition(),this._container.style.visibility="",this._adjustPan())},getEvents:function(){var t={zoom:this._updatePosition,viewreset:this._updatePosition};return this._zoomAnimated&&(t.zoomanim=this._animateZoom),t},isOpen:function(){return!!this._map&&this._map.hasLayer(this)},bringToFront:function(){return this._map&&o.DomUtil.toFront(this._container),this},bringToBack:function(){return this._map&&o.DomUtil.toBack(this._container),this},_updateContent:function(){if(this._content){var t=this._contentNode,e="function"==typeof this._content?this._content(this._source||this):this._content;if("string"==typeof e)t.innerHTML=e;else{for(;t.hasChildNodes();)t.removeChild(t.firstChild);t.appendChild(e)}this.fire("contentupdate")}},_updatePosition:function(){if(this._map){var t=this._map.latLngToLayerPoint(this._latlng),e=o.point(this.options.offset),i=this._getAnchor();this._zoomAnimated?o.DomUtil.setPosition(this._container,t.add(i)):e=e.add(t).add(i);var n=this._containerBottom=-e.y,s=this._containerLeft=-Math.round(this._containerWidth/2)+e.x;this._container.style.bottom=n+"px",this._container.style.left=s+"px"}},_getAnchor:function(){return[0,0]}}),o.Popup=o.DivOverlay.extend({options:{maxWidth:300,minWidth:50,maxHeight:null,autoPan:!0,autoPanPaddingTopLeft:null,autoPanPaddingBottomRight:null,autoPanPadding:[5,5],keepInView:!1,closeButton:!0,autoClose:!0,className:""},openOn:function(t){return t.openPopup(this),this},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),t.fire("popupopen",{popup:this}),this._source&&(this._source.fire("popupopen",{popup:this},!0),this._source instanceof o.Path||this._source.on("preclick",o.DomEvent.stopPropagation))},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("popupclose",{popup:this}),this._source&&(this._source.fire("popupclose",{popup:this},!0),this._source instanceof o.Path||this._source.off("preclick",o.DomEvent.stopPropagation))},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return("closeOnClick"in this.options?this.options.closeOnClick:this._map.options.closePopupOnClick)&&(t.preclick=this._close),this.options.keepInView&&(t.moveend=this._adjustPan),t},_close:function(){this._map&&this._map.closePopup(this)},_initLayout:function(){var t="leaflet-popup",e=this._container=o.DomUtil.create("div",t+" "+(this.options.className||"")+" leaflet-zoom-animated");if(this.options.closeButton){var i=this._closeButton=o.DomUtil.create("a",t+"-close-button",e);i.href="#close",i.innerHTML="&#215;",o.DomEvent.on(i,"click",this._onCloseButtonClick,this)}var n=this._wrapper=o.DomUtil.create("div",t+"-content-wrapper",e);this._contentNode=o.DomUtil.create("div",t+"-content",n),o.DomEvent.disableClickPropagation(n).disableScrollPropagation(this._contentNode).on(n,"contextmenu",o.DomEvent.stopPropagation),this._tipContainer=o.DomUtil.create("div",t+"-tip-container",e),this._tip=o.DomUtil.create("div",t+"-tip",this._tipContainer)},_updateLayout:function(){var t=this._contentNode,e=t.style;e.width="",e.whiteSpace="nowrap";var i=t.offsetWidth;i=Math.min(i,this.options.maxWidth),i=Math.max(i,this.options.minWidth),e.width=i+1+"px",e.whiteSpace="",e.height="";var n=t.offsetHeight,s=this.options.maxHeight,r="leaflet-popup-scrolled";s&&n>s?(e.height=s+"px",o.DomUtil.addClass(t,r)):o.DomUtil.removeClass(t,r),this._containerWidth=this._container.offsetWidth},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center),i=this._getAnchor();o.DomUtil.setPosition(this._container,e.add(i))},_adjustPan:function(){if(!(!this.options.autoPan||this._map._panAnim&&this._map._panAnim._inProgress)){var t=this._map,e=parseInt(o.DomUtil.getStyle(this._container,"marginBottom"),10)||0,i=this._container.offsetHeight+e,n=this._containerWidth,s=new o.Point(this._containerLeft,-i-this._containerBottom);s._add(o.DomUtil.getPosition(this._container));var r=t.layerPointToContainerPoint(s),a=o.point(this.options.autoPanPadding),h=o.point(this.options.autoPanPaddingTopLeft||a),l=o.point(this.options.autoPanPaddingBottomRight||a),u=t.getSize(),c=0,d=0;r.x+n+l.x>u.x&&(c=r.x+n-u.x+l.x),r.x-c-h.x<0&&(c=r.x-h.x),r.y+i+l.y>u.y&&(d=r.y+i-u.y+l.y),r.y-d-h.y<0&&(d=r.y-h.y),(c||d)&&t.fire("autopanstart").panBy([c,d])}},_onCloseButtonClick:function(t){this._close(),o.DomEvent.stop(t)},_getAnchor:function(){return o.point(this._source&&this._source._getPopupAnchor?this._source._getPopupAnchor():[0,0])}}),o.popup=function(t,e){return new o.Popup(t,e)},o.Map.mergeOptions({closePopupOnClick:!0}),o.Map.include({openPopup:function(t,e,i){return t instanceof o.Popup||(t=new o.Popup(i).setContent(t)),e&&t.setLatLng(e),this.hasLayer(t)?this:(this._popup&&this._popup.options.autoClose&&this.closePopup(),this._popup=t,this.addLayer(t))},closePopup:function(t){return t&&t!==this._popup||(t=this._popup,this._popup=null),t&&this.removeLayer(t),this}}),o.Layer.include({bindPopup:function(t,e){return t instanceof o.Popup?(o.setOptions(t,e),this._popup=t,t._source=this):(this._popup&&!e||(this._popup=new o.Popup(e,this)),this._popup.setContent(t)),this._popupHandlersAdded||(this.on({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!0),this},unbindPopup:function(){return this._popup&&(this.off({click:this._openPopup,remove:this.closePopup,move:this._movePopup}),this._popupHandlersAdded=!1,this._popup=null),this},openPopup:function(t,e){if(t instanceof o.Layer||(e=t,t=this),t instanceof o.FeatureGroup)for(var i in this._layers){t=this._layers[i];break}return e||(e=t.getCenter?t.getCenter():t.getLatLng()),this._popup&&this._map&&(this._popup._source=t,this._popup.update(),this._map.openPopup(this._popup,e)),this},closePopup:function(){return this._popup&&this._popup._close(),this},togglePopup:function(t){return this._popup&&(this._popup._map?this.closePopup():this.openPopup(t)),this},isPopupOpen:function(){return!!this._popup&&this._popup.isOpen()},setPopupContent:function(t){return this._popup&&this._popup.setContent(t),this},getPopup:function(){return this._popup},_openPopup:function(t){var e=t.layer||t.target;if(this._popup&&this._map)return o.DomEvent.stop(t),e instanceof o.Path?void this.openPopup(t.layer||t.target,t.latlng):void(this._map.hasLayer(this._popup)&&this._popup._source===e?this.closePopup():this.openPopup(e,t.latlng))},_movePopup:function(t){this._popup.setLatLng(t.latlng)}}),o.Tooltip=o.DivOverlay.extend({options:{pane:"tooltipPane",offset:[0,0],direction:"auto",permanent:!1,sticky:!1,interactive:!1,opacity:.9},onAdd:function(t){o.DivOverlay.prototype.onAdd.call(this,t),this.setOpacity(this.options.opacity),t.fire("tooltipopen",{tooltip:this}),this._source&&this._source.fire("tooltipopen",{tooltip:this},!0)},onRemove:function(t){o.DivOverlay.prototype.onRemove.call(this,t),t.fire("tooltipclose",{tooltip:this}),this._source&&this._source.fire("tooltipclose",{tooltip:this},!0)},getEvents:function(){var t=o.DivOverlay.prototype.getEvents.call(this);return o.Browser.touch&&!this.options.permanent&&(t.preclick=this._close),t},_close:function(){this._map&&this._map.closeTooltip(this)},_initLayout:function(){var t="leaflet-tooltip",e=t+" "+(this.options.className||"")+" leaflet-zoom-"+(this._zoomAnimated?"animated":"hide");this._contentNode=this._container=o.DomUtil.create("div",e)},_updateLayout:function(){},_adjustPan:function(){},_setPosition:function(t){var e=this._map,i=this._container,n=e.latLngToContainerPoint(e.getCenter()),s=e.layerPointToContainerPoint(t),r=this.options.direction,a=i.offsetWidth,h=i.offsetHeight,l=o.point(this.options.offset),u=this._getAnchor();"top"===r?t=t.add(o.point(-a/2+l.x,-h+l.y+u.y,!0)):"bottom"===r?t=t.subtract(o.point(a/2-l.x,-l.y,!0)):"center"===r?t=t.subtract(o.point(a/2+l.x,h/2-u.y+l.y,!0)):"right"===r||"auto"===r&&s.x<n.x?(r="right",t=t.add(o.point(l.x+u.x,u.y-h/2+l.y,!0))):(r="left",t=t.subtract(o.point(a+u.x-l.x,h/2-u.y-l.y,!0))),o.DomUtil.removeClass(i,"leaflet-tooltip-right"),o.DomUtil.removeClass(i,"leaflet-tooltip-left"),o.DomUtil.removeClass(i,"leaflet-tooltip-top"),o.DomUtil.removeClass(i,"leaflet-tooltip-bottom"),o.DomUtil.addClass(i,"leaflet-tooltip-"+r),o.DomUtil.setPosition(i,t)},_updatePosition:function(){var t=this._map.latLngToLayerPoint(this._latlng);this._setPosition(t)},setOpacity:function(t){this.options.opacity=t,this._container&&o.DomUtil.setOpacity(this._container,t)},_animateZoom:function(t){var e=this._map._latLngToNewLayerPoint(this._latlng,t.zoom,t.center);this._setPosition(e)},_getAnchor:function(){return o.point(this._source&&this._source._getTooltipAnchor&&!this.options.sticky?this._source._getTooltipAnchor():[0,0])}}),o.tooltip=function(t,e){return new o.Tooltip(t,e)},o.Map.include({openTooltip:function(t,e,i){return t instanceof o.Tooltip||(t=new o.Tooltip(i).setContent(t)),e&&t.setLatLng(e),this.hasLayer(t)?this:this.addLayer(t)},closeTooltip:function(t){return t&&this.removeLayer(t),this}}),o.Layer.include({bindTooltip:function(t,e){return t instanceof o.Tooltip?(o.setOptions(t,e),this._tooltip=t,t._source=this):(this._tooltip&&!e||(this._tooltip=o.tooltip(e,this)),this._tooltip.setContent(t)),this._initTooltipInteractions(),this._tooltip.options.permanent&&this._map&&this._map.hasLayer(this)&&this.openTooltip(),this},unbindTooltip:function(){return this._tooltip&&(this._initTooltipInteractions(!0),this.closeTooltip(),this._tooltip=null),this},_initTooltipInteractions:function(t){if(t||!this._tooltipHandlersAdded){var e=t?"off":"on",i={remove:this.closeTooltip,move:this._moveTooltip};this._tooltip.options.permanent?i.add=this._openTooltip:(i.mouseover=this._openTooltip,i.mouseout=this.closeTooltip,this._tooltip.options.sticky&&(i.mousemove=this._moveTooltip),o.Browser.touch&&(i.click=this._openTooltip)),this[e](i),this._tooltipHandlersAdded=!t}},openTooltip:function(t,e){if(t instanceof o.Layer||(e=t,t=this),t instanceof o.FeatureGroup)for(var i in this._layers){t=this._layers[i];break}return e||(e=t.getCenter?t.getCenter():t.getLatLng()),this._tooltip&&this._map&&(this._tooltip._source=t,this._tooltip.update(),this._map.openTooltip(this._tooltip,e),this._tooltip.options.interactive&&this._tooltip._container&&(o.DomUtil.addClass(this._tooltip._container,"leaflet-clickable"),this.addInteractiveTarget(this._tooltip._container))),this},closeTooltip:function(){return this._tooltip&&(this._tooltip._close(),this._tooltip.options.interactive&&this._tooltip._container&&(o.DomUtil.removeClass(this._tooltip._container,"leaflet-clickable"),this.removeInteractiveTarget(this._tooltip._container))),this},toggleTooltip:function(t){return this._tooltip&&(this._tooltip._map?this.closeTooltip():this.openTooltip(t)),this},isTooltipOpen:function(){return this._tooltip.isOpen()},setTooltipContent:function(t){return this._tooltip&&this._tooltip.setContent(t),this},getTooltip:function(){return this._tooltip},_openTooltip:function(t){var e=t.layer||t.target;this._tooltip&&this._map&&this.openTooltip(e,this._tooltip.options.sticky?t.latlng:i)},_moveTooltip:function(t){var e,i,n=t.latlng;this._tooltip.options.sticky&&t.originalEvent&&(e=this._map.mouseEventToContainerPoint(t.originalEvent),i=this._map.containerPointToLayerPoint(e),n=this._map.layerPointToLatLng(i)),this._tooltip.setLatLng(n)}}),o.LayerGroup=o.Layer.extend({initialize:function(t){this._layers={};var e,i;if(t)for(e=0,i=t.length;e<i;e++)this.addLayer(t[e])},addLayer:function(t){var e=this.getLayerId(t);return this._layers[e]=t,this._map&&this._map.addLayer(t),this},removeLayer:function(t){var e=t in this._layers?t:this.getLayerId(t);return this._map&&this._layers[e]&&this._map.removeLayer(this._layers[e]),delete this._layers[e],this},hasLayer:function(t){return!!t&&(t in this._layers||this.getLayerId(t)in this._layers)},clearLayers:function(){for(var t in this._layers)this.removeLayer(this._layers[t]);return this},invoke:function(t){var e,i,n=Array.prototype.slice.call(arguments,1);for(e in this._layers)i=this._layers[e],i[t]&&i[t].apply(i,n);return this},onAdd:function(t){for(var e in this._layers)t.addLayer(this._layers[e])},onRemove:function(t){for(var e in this._layers)t.removeLayer(this._layers[e])},eachLayer:function(t,e){for(var i in this._layers)t.call(e,this._layers[i]);return this},getLayer:function(t){return this._layers[t]},getLayers:function(){var t=[];for(var e in this._layers)t.push(this._layers[e]);return t},setZIndex:function(t){return this.invoke("setZIndex",t)},getLayerId:function(t){return o.stamp(t)}}),o.layerGroup=function(t){return new o.LayerGroup(t)},o.FeatureGroup=o.LayerGroup.extend({addLayer:function(t){return this.hasLayer(t)?this:(t.addEventParent(this),o.LayerGroup.prototype.addLayer.call(this,t),this.fire("layeradd",{layer:t}))},removeLayer:function(t){return this.hasLayer(t)?(t in this._layers&&(t=this._layers[t]),t.removeEventParent(this),o.LayerGroup.prototype.removeLayer.call(this,t),this.fire("layerremove",{layer:t})):this},setStyle:function(t){return this.invoke("setStyle",t)},bringToFront:function(){return this.invoke("bringToFront")},bringToBack:function(){return this.invoke("bringToBack")},getBounds:function(){var t=new o.LatLngBounds;for(var e in this._layers){var i=this._layers[e];t.extend(i.getBounds?i.getBounds():i.getLatLng())}return t}}),o.featureGroup=function(t){return new o.FeatureGroup(t)},o.Renderer=o.Layer.extend({options:{padding:.1},initialize:function(t){o.setOptions(this,t),o.stamp(this),this._layers=this._layers||{}},onAdd:function(){this._container||(this._initContainer(),this._zoomAnimated&&o.DomUtil.addClass(this._container,"leaflet-zoom-animated")),this.getPane().appendChild(this._container),this._update(),this.on("update",this._updatePaths,this)},onRemove:function(){o.DomUtil.remove(this._container),this.off("update",this._updatePaths,this)},getEvents:function(){var t={viewreset:this._reset,zoom:this._onZoom,moveend:this._update,zoomend:this._onZoomEnd};return this._zoomAnimated&&(t.zoomanim=this._onAnimZoom),t},_onAnimZoom:function(t){this._updateTransform(t.center,t.zoom)},_onZoom:function(){this._updateTransform(this._map.getCenter(),this._map.getZoom())},_updateTransform:function(t,e){var i=this._map.getZoomScale(e,this._zoom),n=o.DomUtil.getPosition(this._container),s=this._map.getSize().multiplyBy(.5+this.options.padding),r=this._map.project(this._center,e),a=this._map.project(t,e),h=a.subtract(r),l=s.multiplyBy(-i).add(n).add(s).subtract(h);o.Browser.any3d?o.DomUtil.setTransform(this._container,l,i):o.DomUtil.setPosition(this._container,l)},_reset:function(){this._update(),this._updateTransform(this._center,this._zoom);for(var t in this._layers)this._layers[t]._reset()},_onZoomEnd:function(){for(var t in this._layers)this._layers[t]._project()},_updatePaths:function(){for(var t in this._layers)this._layers[t]._update()},_update:function(){var t=this.options.padding,e=this._map.getSize(),i=this._map.containerPointToLayerPoint(e.multiplyBy(-t)).round();this._bounds=new o.Bounds(i,i.add(e.multiplyBy(1+2*t)).round()),this._center=this._map.getCenter(),this._zoom=this._map.getZoom()}}),o.Map.include({getRenderer:function(t){var e=t.options.renderer||this._getPaneRenderer(t.options.pane)||this.options.renderer||this._renderer;return e||(e=this._renderer=this.options.preferCanvas&&o.canvas()||o.svg()),this.hasLayer(e)||this.addLayer(e),e},_getPaneRenderer:function(t){if("overlayPane"===t||t===i)return!1;var e=this._paneRenderers[t];return e===i&&(e=o.SVG&&o.svg({pane:t})||o.Canvas&&o.canvas({pane:t}),this._paneRenderers[t]=e),e}}),o.Path=o.Layer.extend({options:{stroke:!0,color:"#3388ff",weight:3,opacity:1,lineCap:"round",lineJoin:"round",dashArray:null,dashOffset:null,fill:!1,fillColor:null,fillOpacity:.2,fillRule:"evenodd",interactive:!0},beforeAdd:function(t){this._renderer=t.getRenderer(this)},onAdd:function(){this._renderer._initPath(this),this._reset(),this._renderer._addPath(this)},onRemove:function(){this._renderer._removePath(this)},redraw:function(){return this._map&&this._renderer._updatePath(this),this},setStyle:function(t){return o.setOptions(this,t),this._renderer&&this._renderer._updateStyle(this),this},bringToFront:function(){return this._renderer&&this._renderer._bringToFront(this),this},bringToBack:function(){return this._renderer&&this._renderer._bringToBack(this),this},getElement:function(){return this._path},_reset:function(){this._project(),this._update()},_clickTolerance:function(){return(this.options.stroke?this.options.weight/2:0)+(o.Browser.touch?10:0)}}),o.LineUtil={simplify:function(t,e){if(!e||!t.length)return t.slice();var i=e*e;return t=this._reducePoints(t,i),t=this._simplifyDP(t,i)},pointToSegmentDistance:function(t,e,i){return Math.sqrt(this._sqClosestPointOnSegment(t,e,i,!0))},closestPointOnSegment:function(t,e,i){return this._sqClosestPointOnSegment(t,e,i)},_simplifyDP:function(t,e){var n=t.length,o=typeof Uint8Array!=i+""?Uint8Array:Array,s=new o(n);s[0]=s[n-1]=1,this._simplifyDPStep(t,s,e,0,n-1);var r,a=[];for(r=0;r<n;r++)s[r]&&a.push(t[r]);return a},_simplifyDPStep:function(t,e,i,n,o){var s,r,a,h=0;for(r=n+1;r<=o-1;r++)a=this._sqClosestPointOnSegment(t[r],t[n],t[o],!0),a>h&&(s=r,h=a);h>i&&(e[s]=1,this._simplifyDPStep(t,e,i,n,s),this._simplifyDPStep(t,e,i,s,o))},_reducePoints:function(t,e){for(var i=[t[0]],n=1,o=0,s=t.length;n<s;n++)this._sqDist(t[n],t[o])>e&&(i.push(t[n]),o=n);return o<s-1&&i.push(t[s-1]),i},clipSegment:function(t,e,i,n,o){var s,r,a,h=n?this._lastCode:this._getBitCode(t,i),l=this._getBitCode(e,i);for(this._lastCode=l;;){if(!(h|l))return[t,e];if(h&l)return!1;s=h||l,r=this._getEdgeIntersection(t,e,s,i,o),a=this._getBitCode(r,i),s===h?(t=r,h=a):(e=r,l=a)}},_getEdgeIntersection:function(t,e,i,n,s){var r,a,h=e.x-t.x,l=e.y-t.y,u=n.min,c=n.max;return 8&i?(r=t.x+h*(c.y-t.y)/l,a=c.y):4&i?(r=t.x+h*(u.y-t.y)/l,a=u.y):2&i?(r=c.x,a=t.y+l*(c.x-t.x)/h):1&i&&(r=u.x,a=t.y+l*(u.x-t.x)/h),new o.Point(r,a,s)},_getBitCode:function(t,e){var i=0;return t.x<e.min.x?i|=1:t.x>e.max.x&&(i|=2),t.y<e.min.y?i|=4:t.y>e.max.y&&(i|=8),i},_sqDist:function(t,e){var i=e.x-t.x,n=e.y-t.y;return i*i+n*n},_sqClosestPointOnSegment:function(t,e,i,n){var s,r=e.x,a=e.y,h=i.x-r,l=i.y-a,u=h*h+l*l;return u>0&&(s=((t.x-r)*h+(t.y-a)*l)/u,s>1?(r=i.x,a=i.y):s>0&&(r+=h*s,a+=l*s)),h=t.x-r,l=t.y-a,n?h*h+l*l:new o.Point(r,a)}},o.Polyline=o.Path.extend({options:{smoothFactor:1,noClip:!1},initialize:function(t,e){o.setOptions(this,e),this._setLatLngs(t)},getLatLngs:function(){return this._latlngs},setLatLngs:function(t){return this._setLatLngs(t),this.redraw()},isEmpty:function(){return!this._latlngs.length},closestLayerPoint:function(t){for(var e,i,n=1/0,s=null,r=o.LineUtil._sqClosestPointOnSegment,a=0,h=this._parts.length;a<h;a++)for(var l=this._parts[a],u=1,c=l.length;u<c;u++){e=l[u-1],i=l[u];var d=r(t,e,i,!0);d<n&&(n=d,s=r(t,e,i))}return s&&(s.distance=Math.sqrt(n)),s},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,e,i,n,o,s,r,a=this._rings[0],h=a.length;if(!h)return null;for(t=0,e=0;t<h-1;t++)e+=a[t].distanceTo(a[t+1])/2;if(0===e)return this._map.layerPointToLatLng(a[0]);for(t=0,n=0;t<h-1;t++)if(o=a[t],s=a[t+1],i=o.distanceTo(s),n+=i,n>e)return r=(n-e)/i,this._map.layerPointToLatLng([s.x-r*(s.x-o.x),s.y-r*(s.y-o.y)])},getBounds:function(){return this._bounds},addLatLng:function(t,e){return e=e||this._defaultShape(),t=o.latLng(t),e.push(t),this._bounds.extend(t),this.redraw()},_setLatLngs:function(t){this._bounds=new o.LatLngBounds,this._latlngs=this._convertLatLngs(t)},_defaultShape:function(){return o.Polyline._flat(this._latlngs)?this._latlngs:this._latlngs[0]},_convertLatLngs:function(t){for(var e=[],i=o.Polyline._flat(t),n=0,s=t.length;n<s;n++)i?(e[n]=o.latLng(t[n]),this._bounds.extend(e[n])):e[n]=this._convertLatLngs(t[n]);return e},_project:function(){var t=new o.Bounds;this._rings=[],this._projectLatlngs(this._latlngs,this._rings,t);var e=this._clickTolerance(),i=new o.Point(e,e);this._bounds.isValid()&&t.isValid()&&(t.min._subtract(i),t.max._add(i),this._pxBounds=t)},_projectLatlngs:function(t,e,i){var n,s,r=t[0]instanceof o.LatLng,a=t.length;if(r){for(s=[],n=0;n<a;n++)s[n]=this._map.latLngToLayerPoint(t[n]),i.extend(s[n]);e.push(s)}else for(n=0;n<a;n++)this._projectLatlngs(t[n],e,i)},_clipPoints:function(){var t=this._renderer._bounds;if(this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);var e,i,n,s,r,a,h,l=this._parts;for(e=0,n=0,s=this._rings.length;e<s;e++)for(h=this._rings[e],i=0,r=h.length;i<r-1;i++)a=o.LineUtil.clipSegment(h[i],h[i+1],t,i,!0),a&&(l[n]=l[n]||[],l[n].push(a[0]),a[1]===h[i+1]&&i!==r-2||(l[n].push(a[1]),n++))}},_simplifyPoints:function(){for(var t=this._parts,e=this.options.smoothFactor,i=0,n=t.length;i<n;i++)t[i]=o.LineUtil.simplify(t[i],e)},_update:function(){this._map&&(this._clipPoints(),this._simplifyPoints(),this._updatePath())},_updatePath:function(){this._renderer._updatePoly(this)}}),o.polyline=function(t,e){return new o.Polyline(t,e)},o.Polyline._flat=function(t){return!o.Util.isArray(t[0])||"object"!=typeof t[0][0]&&"undefined"!=typeof t[0][0]},o.PolyUtil={},o.PolyUtil.clipPolygon=function(t,e,i){var n,s,r,a,h,l,u,c,d,_=[1,4,2,8],m=o.LineUtil;for(s=0,u=t.length;s<u;s++)t[s]._code=m._getBitCode(t[s],e);for(a=0;a<4;a++){for(c=_[a],n=[],s=0,u=t.length,r=u-1;s<u;r=s++)h=t[s],l=t[r],h._code&c?l._code&c||(d=m._getEdgeIntersection(l,h,c,e,i),d._code=m._getBitCode(d,e),n.push(d)):(l._code&c&&(d=m._getEdgeIntersection(l,h,c,e,i),d._code=m._getBitCode(d,e),n.push(d)),n.push(h));t=n}return t},o.Polygon=o.Polyline.extend({options:{fill:!0},isEmpty:function(){return!this._latlngs.length||!this._latlngs[0].length},getCenter:function(){if(!this._map)throw new Error("Must add layer to map before using getCenter()");var t,e,i,n,o,s,r,a,h,l=this._rings[0],u=l.length;if(!u)return null;for(s=r=a=0,t=0,e=u-1;t<u;e=t++)i=l[t],n=l[e],o=i.y*n.x-n.y*i.x,r+=(i.x+n.x)*o,a+=(i.y+n.y)*o,s+=3*o;return h=0===s?l[0]:[r/s,a/s],this._map.layerPointToLatLng(h)},_convertLatLngs:function(t){var e=o.Polyline.prototype._convertLatLngs.call(this,t),i=e.length;return i>=2&&e[0]instanceof o.LatLng&&e[0].equals(e[i-1])&&e.pop(),e},_setLatLngs:function(t){o.Polyline.prototype._setLatLngs.call(this,t),o.Polyline._flat(this._latlngs)&&(this._latlngs=[this._latlngs])},_defaultShape:function(){return o.Polyline._flat(this._latlngs[0])?this._latlngs[0]:this._latlngs[0][0]},_clipPoints:function(){var t=this._renderer._bounds,e=this.options.weight,i=new o.Point(e,e);if(t=new o.Bounds(t.min.subtract(i),t.max.add(i)),this._parts=[],this._pxBounds&&this._pxBounds.intersects(t)){if(this.options.noClip)return void(this._parts=this._rings);for(var n,s=0,r=this._rings.length;s<r;s++)n=o.PolyUtil.clipPolygon(this._rings[s],t,!0),n.length&&this._parts.push(n)}},_updatePath:function(){this._renderer._updatePoly(this,!0)}}),o.polygon=function(t,e){return new o.Polygon(t,e)},o.Rectangle=o.Polygon.extend({initialize:function(t,e){o.Polygon.prototype.initialize.call(this,this._boundsToLatLngs(t),e)},setBounds:function(t){return this.setLatLngs(this._boundsToLatLngs(t))},_boundsToLatLngs:function(t){return t=o.latLngBounds(t),[t.getSouthWest(),t.getNorthWest(),t.getNorthEast(),t.getSouthEast()]}}),o.rectangle=function(t,e){return new o.Rectangle(t,e)},o.CircleMarker=o.Path.extend({options:{fill:!0,radius:10},initialize:function(t,e){o.setOptions(this,e),this._latlng=o.latLng(t),this._radius=this.options.radius},setLatLng:function(t){return this._latlng=o.latLng(t),this.redraw(),this.fire("move",{latlng:this._latlng})},getLatLng:function(){return this._latlng},setRadius:function(t){return this.options.radius=this._radius=t,this.redraw()},getRadius:function(){return this._radius},setStyle:function(t){var e=t&&t.radius||this._radius;return o.Path.prototype.setStyle.call(this,t),this.setRadius(e),this},_project:function(){this._point=this._map.latLngToLayerPoint(this._latlng),this._updateBounds()},_updateBounds:function(){var t=this._radius,e=this._radiusY||t,i=this._clickTolerance(),n=[t+i,e+i];this._pxBounds=new o.Bounds(this._point.subtract(n),this._point.add(n))},_update:function(){this._map&&this._updatePath()},_updatePath:function(){this._renderer._updateCircle(this)},_empty:function(){return this._radius&&!this._renderer._bounds.intersects(this._pxBounds)}}),o.circleMarker=function(t,e){return new o.CircleMarker(t,e)},o.Circle=o.CircleMarker.extend({initialize:function(t,e,i){if("number"==typeof e&&(e=o.extend({},i,{radius:e})),o.setOptions(this,e),this._latlng=o.latLng(t),isNaN(this.options.radius))throw new Error("Circle radius cannot be NaN");this._mRadius=this.options.radius},setRadius:function(t){return this._mRadius=t,
8
this.redraw()},getRadius:function(){return this._mRadius},getBounds:function(){var t=[this._radius,this._radiusY||this._radius];return new o.LatLngBounds(this._map.layerPointToLatLng(this._point.subtract(t)),this._map.layerPointToLatLng(this._point.add(t)))},setStyle:o.Path.prototype.setStyle,_project:function(){var t=this._latlng.lng,e=this._latlng.lat,i=this._map,n=i.options.crs;if(n.distance===o.CRS.Earth.distance){var s=Math.PI/180,r=this._mRadius/o.CRS.Earth.R/s,a=i.project([e+r,t]),h=i.project([e-r,t]),l=a.add(h).divideBy(2),u=i.unproject(l).lat,c=Math.acos((Math.cos(r*s)-Math.sin(e*s)*Math.sin(u*s))/(Math.cos(e*s)*Math.cos(u*s)))/s;(isNaN(c)||0===c)&&(c=r/Math.cos(Math.PI/180*e)),this._point=l.subtract(i.getPixelOrigin()),this._radius=isNaN(c)?0:Math.max(Math.round(l.x-i.project([u,t-c]).x),1),this._radiusY=Math.max(Math.round(l.y-a.y),1)}else{var d=n.unproject(n.project(this._latlng).subtract([this._mRadius,0]));this._point=i.latLngToLayerPoint(this._latlng),this._radius=this._point.x-i.latLngToLayerPoint(d).x}this._updateBounds()}}),o.circle=function(t,e,i){return new o.Circle(t,e,i)},o.SVG=o.Renderer.extend({getEvents:function(){var t=o.Renderer.prototype.getEvents.call(this);return t.zoomstart=this._onZoomStart,t},_initContainer:function(){this._container=o.SVG.create("svg"),this._container.setAttribute("pointer-events","none"),this._rootGroup=o.SVG.create("g"),this._container.appendChild(this._rootGroup)},_onZoomStart:function(){this._update()},_update:function(){if(!this._map._animatingZoom||!this._bounds){o.Renderer.prototype._update.call(this);var t=this._bounds,e=t.getSize(),i=this._container;this._svgSize&&this._svgSize.equals(e)||(this._svgSize=e,i.setAttribute("width",e.x),i.setAttribute("height",e.y)),o.DomUtil.setPosition(i,t.min),i.setAttribute("viewBox",[t.min.x,t.min.y,e.x,e.y].join(" ")),this.fire("update")}},_initPath:function(t){var e=t._path=o.SVG.create("path");t.options.className&&o.DomUtil.addClass(e,t.options.className),t.options.interactive&&o.DomUtil.addClass(e,"leaflet-interactive"),this._updateStyle(t),this._layers[o.stamp(t)]=t},_addPath:function(t){this._rootGroup.appendChild(t._path),t.addInteractiveTarget(t._path)},_removePath:function(t){o.DomUtil.remove(t._path),t.removeInteractiveTarget(t._path),delete this._layers[o.stamp(t)]},_updatePath:function(t){t._project(),t._update()},_updateStyle:function(t){var e=t._path,i=t.options;e&&(i.stroke?(e.setAttribute("stroke",i.color),e.setAttribute("stroke-opacity",i.opacity),e.setAttribute("stroke-width",i.weight),e.setAttribute("stroke-linecap",i.lineCap),e.setAttribute("stroke-linejoin",i.lineJoin),i.dashArray?e.setAttribute("stroke-dasharray",i.dashArray):e.removeAttribute("stroke-dasharray"),i.dashOffset?e.setAttribute("stroke-dashoffset",i.dashOffset):e.removeAttribute("stroke-dashoffset")):e.setAttribute("stroke","none"),i.fill?(e.setAttribute("fill",i.fillColor||i.color),e.setAttribute("fill-opacity",i.fillOpacity),e.setAttribute("fill-rule",i.fillRule||"evenodd")):e.setAttribute("fill","none"))},_updatePoly:function(t,e){this._setPath(t,o.SVG.pointsToPath(t._parts,e))},_updateCircle:function(t){var e=t._point,i=t._radius,n=t._radiusY||i,o="a"+i+","+n+" 0 1,0 ",s=t._empty()?"M0 0":"M"+(e.x-i)+","+e.y+o+2*i+",0 "+o+2*-i+",0 ";this._setPath(t,s)},_setPath:function(t,e){t._path.setAttribute("d",e)},_bringToFront:function(t){o.DomUtil.toFront(t._path)},_bringToBack:function(t){o.DomUtil.toBack(t._path)}}),o.extend(o.SVG,{create:function(t){return e.createElementNS("http://www.w3.org/2000/svg",t)},pointsToPath:function(t,e){var i,n,s,r,a,h,l="";for(i=0,s=t.length;i<s;i++){for(a=t[i],n=0,r=a.length;n<r;n++)h=a[n],l+=(n?"L":"M")+h.x+" "+h.y;l+=e?o.Browser.svg?"z":"x":""}return l||"M0 0"}}),o.Browser.svg=!(!e.createElementNS||!o.SVG.create("svg").createSVGRect),o.svg=function(t){return o.Browser.svg||o.Browser.vml?new o.SVG(t):null},o.Browser.vml=!o.Browser.svg&&function(){try{var t=e.createElement("div");t.innerHTML='<v:shape adj="1"/>';var i=t.firstChild;return i.style.behavior="url(#default#VML)",i&&"object"==typeof i.adj}catch(t){return!1}}(),o.SVG.include(o.Browser.vml?{_initContainer:function(){this._container=o.DomUtil.create("div","leaflet-vml-container")},_update:function(){this._map._animatingZoom||(o.Renderer.prototype._update.call(this),this.fire("update"))},_initPath:function(t){var e=t._container=o.SVG.create("shape");o.DomUtil.addClass(e,"leaflet-vml-shape "+(this.options.className||"")),e.coordsize="1 1",t._path=o.SVG.create("path"),e.appendChild(t._path),this._updateStyle(t),this._layers[o.stamp(t)]=t},_addPath:function(t){var e=t._container;this._container.appendChild(e),t.options.interactive&&t.addInteractiveTarget(e)},_removePath:function(t){var e=t._container;o.DomUtil.remove(e),t.removeInteractiveTarget(e),delete this._layers[o.stamp(t)]},_updateStyle:function(t){var e=t._stroke,i=t._fill,n=t.options,s=t._container;s.stroked=!!n.stroke,s.filled=!!n.fill,n.stroke?(e||(e=t._stroke=o.SVG.create("stroke")),s.appendChild(e),e.weight=n.weight+"px",e.color=n.color,e.opacity=n.opacity,n.dashArray?e.dashStyle=o.Util.isArray(n.dashArray)?n.dashArray.join(" "):n.dashArray.replace(/( *, *)/g," "):e.dashStyle="",e.endcap=n.lineCap.replace("butt","flat"),e.joinstyle=n.lineJoin):e&&(s.removeChild(e),t._stroke=null),n.fill?(i||(i=t._fill=o.SVG.create("fill")),s.appendChild(i),i.color=n.fillColor||n.color,i.opacity=n.fillOpacity):i&&(s.removeChild(i),t._fill=null)},_updateCircle:function(t){var e=t._point.round(),i=Math.round(t._radius),n=Math.round(t._radiusY||i);this._setPath(t,t._empty()?"M0 0":"AL "+e.x+","+e.y+" "+i+","+n+" 0,23592600")},_setPath:function(t,e){t._path.v=e},_bringToFront:function(t){o.DomUtil.toFront(t._container)},_bringToBack:function(t){o.DomUtil.toBack(t._container)}}:{}),o.Browser.vml&&(o.SVG.create=function(){try{return e.namespaces.add("lvml","urn:schemas-microsoft-com:vml"),function(t){return e.createElement("<lvml:"+t+' class="lvml">')}}catch(t){return function(t){return e.createElement("<"+t+' xmlns="urn:schemas-microsoft.com:vml" class="lvml">')}}}()),o.Canvas=o.Renderer.extend({getEvents:function(){var t=o.Renderer.prototype.getEvents.call(this);return t.viewprereset=this._onViewPreReset,t},_onViewPreReset:function(){this._postponeUpdatePaths=!0},onAdd:function(){o.Renderer.prototype.onAdd.call(this),this._draw()},_initContainer:function(){var t=this._container=e.createElement("canvas");o.DomEvent.on(t,"mousemove",o.Util.throttle(this._onMouseMove,32,this),this).on(t,"click dblclick mousedown mouseup contextmenu",this._onClick,this).on(t,"mouseout",this._handleMouseOut,this),this._ctx=t.getContext("2d")},_updatePaths:function(){if(!this._postponeUpdatePaths){var t;this._redrawBounds=null;for(var e in this._layers)t=this._layers[e],t._update();this._redraw()}},_update:function(){if(!this._map._animatingZoom||!this._bounds){this._drawnLayers={},o.Renderer.prototype._update.call(this);var t=this._bounds,e=this._container,i=t.getSize(),n=o.Browser.retina?2:1;o.DomUtil.setPosition(e,t.min),e.width=n*i.x,e.height=n*i.y,e.style.width=i.x+"px",e.style.height=i.y+"px",o.Browser.retina&&this._ctx.scale(2,2),this._ctx.translate(-t.min.x,-t.min.y),this.fire("update")}},_reset:function(){o.Renderer.prototype._reset.call(this),this._postponeUpdatePaths&&(this._postponeUpdatePaths=!1,this._updatePaths())},_initPath:function(t){this._updateDashArray(t),this._layers[o.stamp(t)]=t;var e=t._order={layer:t,prev:this._drawLast,next:null};this._drawLast&&(this._drawLast.next=e),this._drawLast=e,this._drawFirst=this._drawFirst||this._drawLast},_addPath:function(t){this._requestRedraw(t)},_removePath:function(t){var e=t._order,i=e.next,n=e.prev;i?i.prev=n:this._drawLast=n,n?n.next=i:this._drawFirst=i,delete t._order,delete this._layers[o.stamp(t)],this._requestRedraw(t)},_updatePath:function(t){this._extendRedrawBounds(t),t._project(),t._update(),this._requestRedraw(t)},_updateStyle:function(t){this._updateDashArray(t),this._requestRedraw(t)},_updateDashArray:function(t){if(t.options.dashArray){var e,i=t.options.dashArray.split(","),n=[];for(e=0;e<i.length;e++)n.push(Number(i[e]));t.options._dashArray=n}},_requestRedraw:function(t){this._map&&(this._extendRedrawBounds(t),this._redrawRequest=this._redrawRequest||o.Util.requestAnimFrame(this._redraw,this))},_extendRedrawBounds:function(t){var e=(t.options.weight||0)+1;this._redrawBounds=this._redrawBounds||new o.Bounds,this._redrawBounds.extend(t._pxBounds.min.subtract([e,e])),this._redrawBounds.extend(t._pxBounds.max.add([e,e]))},_redraw:function(){this._redrawRequest=null,this._redrawBounds&&(this._redrawBounds.min._floor(),this._redrawBounds.max._ceil()),this._clear(),this._draw(),this._redrawBounds=null},_clear:function(){var t=this._redrawBounds;if(t){var e=t.getSize();this._ctx.clearRect(t.min.x,t.min.y,e.x,e.y)}else this._ctx.clearRect(0,0,this._container.width,this._container.height)},_draw:function(){var t,e=this._redrawBounds;if(this._ctx.save(),e){var i=e.getSize();this._ctx.beginPath(),this._ctx.rect(e.min.x,e.min.y,i.x,i.y),this._ctx.clip()}this._drawing=!0;for(var n=this._drawFirst;n;n=n.next)t=n.layer,(!e||t._pxBounds&&t._pxBounds.intersects(e))&&t._updatePath();this._drawing=!1,this._ctx.restore()},_updatePoly:function(t,e){if(this._drawing){var i,n,o,s,r=t._parts,a=r.length,h=this._ctx;if(a){for(this._drawnLayers[t._leaflet_id]=t,h.beginPath(),h.setLineDash&&h.setLineDash(t.options&&t.options._dashArray||[]),i=0;i<a;i++){for(n=0,o=r[i].length;n<o;n++)s=r[i][n],h[n?"lineTo":"moveTo"](s.x,s.y);e&&h.closePath()}this._fillStroke(h,t)}}},_updateCircle:function(t){if(this._drawing&&!t._empty()){var e=t._point,i=this._ctx,n=t._radius,o=(t._radiusY||n)/n;this._drawnLayers[t._leaflet_id]=t,1!==o&&(i.save(),i.scale(1,o)),i.beginPath(),i.arc(e.x,e.y/o,n,0,2*Math.PI,!1),1!==o&&i.restore(),this._fillStroke(i,t)}},_fillStroke:function(t,e){var i=e.options;i.fill&&(t.globalAlpha=i.fillOpacity,t.fillStyle=i.fillColor||i.color,t.fill(i.fillRule||"evenodd")),i.stroke&&0!==i.weight&&(t.globalAlpha=i.opacity,t.lineWidth=i.weight,t.strokeStyle=i.color,t.lineCap=i.lineCap,t.lineJoin=i.lineJoin,t.stroke())},_onClick:function(t){for(var e,i,n=this._map.mouseEventToLayerPoint(t),s=this._drawFirst;s;s=s.next)e=s.layer,e.options.interactive&&e._containsPoint(n)&&!this._map._draggableMoved(e)&&(i=e);i&&(o.DomEvent._fakeStop(t),this._fireEvent([i],t))},_onMouseMove:function(t){if(this._map&&!this._map.dragging.moving()&&!this._map._animatingZoom){var e=this._map.mouseEventToLayerPoint(t);this._handleMouseHover(t,e)}},_handleMouseOut:function(t){var e=this._hoveredLayer;e&&(o.DomUtil.removeClass(this._container,"leaflet-interactive"),this._fireEvent([e],t,"mouseout"),this._hoveredLayer=null)},_handleMouseHover:function(t,e){for(var i,n,s=this._drawFirst;s;s=s.next)i=s.layer,i.options.interactive&&i._containsPoint(e)&&(n=i);n!==this._hoveredLayer&&(this._handleMouseOut(t),n&&(o.DomUtil.addClass(this._container,"leaflet-interactive"),this._fireEvent([n],t,"mouseover"),this._hoveredLayer=n)),this._hoveredLayer&&this._fireEvent([this._hoveredLayer],t)},_fireEvent:function(t,e,i){this._map._fireDOMEvent(e,i||e.type,t)},_bringToFront:function(t){var e=t._order,i=e.next,n=e.prev;i&&(i.prev=n,n?n.next=i:i&&(this._drawFirst=i),e.prev=this._drawLast,this._drawLast.next=e,e.next=null,this._drawLast=e,this._requestRedraw(t))},_bringToBack:function(t){var e=t._order,i=e.next,n=e.prev;n&&(n.next=i,i?i.prev=n:n&&(this._drawLast=n),e.prev=null,e.next=this._drawFirst,this._drawFirst.prev=e,this._drawFirst=e,this._requestRedraw(t))}}),o.Browser.canvas=function(){return!!e.createElement("canvas").getContext}(),o.canvas=function(t){return o.Browser.canvas?new o.Canvas(t):null},o.Polyline.prototype._containsPoint=function(t,e){var i,n,s,r,a,h,l=this._clickTolerance();if(!this._pxBounds.contains(t))return!1;for(i=0,r=this._parts.length;i<r;i++)for(h=this._parts[i],n=0,a=h.length,s=a-1;n<a;s=n++)if((e||0!==n)&&o.LineUtil.pointToSegmentDistance(t,h[s],h[n])<=l)return!0;return!1},o.Polygon.prototype._containsPoint=function(t){var e,i,n,s,r,a,h,l,u=!1;if(!this._pxBounds.contains(t))return!1;for(s=0,h=this._parts.length;s<h;s++)for(e=this._parts[s],r=0,l=e.length,a=l-1;r<l;a=r++)i=e[r],n=e[a],i.y>t.y!=n.y>t.y&&t.x<(n.x-i.x)*(t.y-i.y)/(n.y-i.y)+i.x&&(u=!u);return u||o.Polyline.prototype._containsPoint.call(this,t,!0)},o.CircleMarker.prototype._containsPoint=function(t){return t.distanceTo(this._point)<=this._radius+this._clickTolerance()},o.GeoJSON=o.FeatureGroup.extend({initialize:function(t,e){o.setOptions(this,e),this._layers={},t&&this.addData(t)},addData:function(t){var e,i,n,s=o.Util.isArray(t)?t:t.features;if(s){for(e=0,i=s.length;e<i;e++)n=s[e],(n.geometries||n.geometry||n.features||n.coordinates)&&this.addData(n);return this}var r=this.options;if(r.filter&&!r.filter(t))return this;var a=o.GeoJSON.geometryToLayer(t,r);return a?(a.feature=o.GeoJSON.asFeature(t),a.defaultOptions=a.options,this.resetStyle(a),r.onEachFeature&&r.onEachFeature(t,a),this.addLayer(a)):this},resetStyle:function(t){return t.options=o.Util.extend({},t.defaultOptions),this._setLayerStyle(t,this.options.style),this},setStyle:function(t){return this.eachLayer(function(e){this._setLayerStyle(e,t)},this)},_setLayerStyle:function(t,e){"function"==typeof e&&(e=e(t.feature)),t.setStyle&&t.setStyle(e)}}),o.extend(o.GeoJSON,{geometryToLayer:function(t,e){var i,n,s,r,a="Feature"===t.type?t.geometry:t,h=a?a.coordinates:null,l=[],u=e&&e.pointToLayer,c=e&&e.coordsToLatLng||this.coordsToLatLng;if(!h&&!a)return null;switch(a.type){case"Point":return i=c(h),u?u(t,i):new o.Marker(i);case"MultiPoint":for(s=0,r=h.length;s<r;s++)i=c(h[s]),l.push(u?u(t,i):new o.Marker(i));return new o.FeatureGroup(l);case"LineString":case"MultiLineString":return n=this.coordsToLatLngs(h,"LineString"===a.type?0:1,c),new o.Polyline(n,e);case"Polygon":case"MultiPolygon":return n=this.coordsToLatLngs(h,"Polygon"===a.type?1:2,c),new o.Polygon(n,e);case"GeometryCollection":for(s=0,r=a.geometries.length;s<r;s++){var d=this.geometryToLayer({geometry:a.geometries[s],type:"Feature",properties:t.properties},e);d&&l.push(d)}return new o.FeatureGroup(l);default:throw new Error("Invalid GeoJSON object.")}},coordsToLatLng:function(t){return new o.LatLng(t[1],t[0],t[2])},coordsToLatLngs:function(t,e,i){for(var n,o=[],s=0,r=t.length;s<r;s++)n=e?this.coordsToLatLngs(t[s],e-1,i):(i||this.coordsToLatLng)(t[s]),o.push(n);return o},latLngToCoords:function(t){return t.alt!==i?[t.lng,t.lat,t.alt]:[t.lng,t.lat]},latLngsToCoords:function(t,e,i){for(var n=[],s=0,r=t.length;s<r;s++)n.push(e?o.GeoJSON.latLngsToCoords(t[s],e-1,i):o.GeoJSON.latLngToCoords(t[s]));return!e&&i&&n.push(n[0]),n},getFeature:function(t,e){return t.feature?o.extend({},t.feature,{geometry:e}):o.GeoJSON.asFeature(e)},asFeature:function(t){return"Feature"===t.type||"FeatureCollection"===t.type?t:{type:"Feature",properties:{},geometry:t}}});var a={toGeoJSON:function(){return o.GeoJSON.getFeature(this,{type:"Point",coordinates:o.GeoJSON.latLngToCoords(this.getLatLng())})}};o.Marker.include(a),o.Circle.include(a),o.CircleMarker.include(a),o.Polyline.prototype.toGeoJSON=function(){var t=!o.Polyline._flat(this._latlngs),e=o.GeoJSON.latLngsToCoords(this._latlngs,t?1:0);return o.GeoJSON.getFeature(this,{type:(t?"Multi":"")+"LineString",coordinates:e})},o.Polygon.prototype.toGeoJSON=function(){var t=!o.Polyline._flat(this._latlngs),e=t&&!o.Polyline._flat(this._latlngs[0]),i=o.GeoJSON.latLngsToCoords(this._latlngs,e?2:t?1:0,!0);return t||(i=[i]),o.GeoJSON.getFeature(this,{type:(e?"Multi":"")+"Polygon",coordinates:i})},o.LayerGroup.include({toMultiPoint:function(){var t=[];return this.eachLayer(function(e){t.push(e.toGeoJSON().geometry.coordinates)}),o.GeoJSON.getFeature(this,{type:"MultiPoint",coordinates:t})},toGeoJSON:function(){var t=this.feature&&this.feature.geometry&&this.feature.geometry.type;if("MultiPoint"===t)return this.toMultiPoint();var e="GeometryCollection"===t,i=[];return this.eachLayer(function(t){if(t.toGeoJSON){var n=t.toGeoJSON();i.push(e?n.geometry:o.GeoJSON.asFeature(n))}}),e?o.GeoJSON.getFeature(this,{geometries:i,type:"GeometryCollection"}):{type:"FeatureCollection",features:i}}}),o.geoJSON=function(t,e){return new o.GeoJSON(t,e)},o.geoJson=o.geoJSON,o.Draggable=o.Evented.extend({options:{clickTolerance:3},statics:{START:o.Browser.touch?["touchstart","mousedown"]:["mousedown"],END:{mousedown:"mouseup",touchstart:"touchend",pointerdown:"touchend",MSPointerDown:"touchend"},MOVE:{mousedown:"mousemove",touchstart:"touchmove",pointerdown:"touchmove",MSPointerDown:"touchmove"}},initialize:function(t,e,i){this._element=t,this._dragStartTarget=e||t,this._preventOutline=i},enable:function(){this._enabled||(o.DomEvent.on(this._dragStartTarget,o.Draggable.START.join(" "),this._onDown,this),this._enabled=!0)},disable:function(){this._enabled&&(o.Draggable._dragging===this&&this.finishDrag(),o.DomEvent.off(this._dragStartTarget,o.Draggable.START.join(" "),this._onDown,this),this._enabled=!1,this._moved=!1)},_onDown:function(t){if(!t._simulated&&this._enabled&&(this._moved=!1,!o.DomUtil.hasClass(this._element,"leaflet-zoom-anim")&&!(o.Draggable._dragging||t.shiftKey||1!==t.which&&1!==t.button&&!t.touches||(o.Draggable._dragging=this,this._preventOutline&&o.DomUtil.preventOutline(this._element),o.DomUtil.disableImageDrag(),o.DomUtil.disableTextSelection(),this._moving)))){this.fire("down");var i=t.touches?t.touches[0]:t;this._startPoint=new o.Point(i.clientX,i.clientY),o.DomEvent.on(e,o.Draggable.MOVE[t.type],this._onMove,this).on(e,o.Draggable.END[t.type],this._onUp,this)}},_onMove:function(i){if(!i._simulated&&this._enabled){if(i.touches&&i.touches.length>1)return void(this._moved=!0);var n=i.touches&&1===i.touches.length?i.touches[0]:i,s=new o.Point(n.clientX,n.clientY),r=s.subtract(this._startPoint);(r.x||r.y)&&(Math.abs(r.x)+Math.abs(r.y)<this.options.clickTolerance||(o.DomEvent.preventDefault(i),this._moved||(this.fire("dragstart"),this._moved=!0,this._startPos=o.DomUtil.getPosition(this._element).subtract(r),o.DomUtil.addClass(e.body,"leaflet-dragging"),this._lastTarget=i.target||i.srcElement,t.SVGElementInstance&&this._lastTarget instanceof SVGElementInstance&&(this._lastTarget=this._lastTarget.correspondingUseElement),o.DomUtil.addClass(this._lastTarget,"leaflet-drag-target")),this._newPos=this._startPos.add(r),this._moving=!0,o.Util.cancelAnimFrame(this._animRequest),this._lastEvent=i,this._animRequest=o.Util.requestAnimFrame(this._updatePosition,this,!0)))}},_updatePosition:function(){var t={originalEvent:this._lastEvent};this.fire("predrag",t),o.DomUtil.setPosition(this._element,this._newPos),this.fire("drag",t)},_onUp:function(t){!t._simulated&&this._enabled&&this.finishDrag()},finishDrag:function(){o.DomUtil.removeClass(e.body,"leaflet-dragging"),this._lastTarget&&(o.DomUtil.removeClass(this._lastTarget,"leaflet-drag-target"),this._lastTarget=null);for(var t in o.Draggable.MOVE)o.DomEvent.off(e,o.Draggable.MOVE[t],this._onMove,this).off(e,o.Draggable.END[t],this._onUp,this);o.DomUtil.enableImageDrag(),o.DomUtil.enableTextSelection(),this._moved&&this._moving&&(o.Util.cancelAnimFrame(this._animRequest),this.fire("dragend",{distance:this._newPos.distanceTo(this._startPos)})),this._moving=!1,o.Draggable._dragging=!1}}),o.Handler=o.Class.extend({initialize:function(t){this._map=t},enable:function(){return this._enabled?this:(this._enabled=!0,this.addHooks(),this)},disable:function(){return this._enabled?(this._enabled=!1,this.removeHooks(),this):this},enabled:function(){return!!this._enabled}}),o.Map.mergeOptions({dragging:!0,inertia:!o.Browser.android23,inertiaDeceleration:3400,inertiaMaxSpeed:1/0,easeLinearity:.2,worldCopyJump:!1,maxBoundsViscosity:0}),o.Map.Drag=o.Handler.extend({addHooks:function(){if(!this._draggable){var t=this._map;this._draggable=new o.Draggable(t._mapPane,t._container),this._draggable.on({down:this._onDown,dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this),this._draggable.on("predrag",this._onPreDragLimit,this),t.options.worldCopyJump&&(this._draggable.on("predrag",this._onPreDragWrap,this),t.on("zoomend",this._onZoomEnd,this),t.whenReady(this._onZoomEnd,this))}o.DomUtil.addClass(this._map._container,"leaflet-grab leaflet-touch-drag"),this._draggable.enable(),this._positions=[],this._times=[]},removeHooks:function(){o.DomUtil.removeClass(this._map._container,"leaflet-grab"),o.DomUtil.removeClass(this._map._container,"leaflet-touch-drag"),this._draggable.disable()},moved:function(){return this._draggable&&this._draggable._moved},moving:function(){return this._draggable&&this._draggable._moving},_onDown:function(){this._map._stop()},_onDragStart:function(){var t=this._map;if(this._map.options.maxBounds&&this._map.options.maxBoundsViscosity){var e=o.latLngBounds(this._map.options.maxBounds);this._offsetLimit=o.bounds(this._map.latLngToContainerPoint(e.getNorthWest()).multiplyBy(-1),this._map.latLngToContainerPoint(e.getSouthEast()).multiplyBy(-1).add(this._map.getSize())),this._viscosity=Math.min(1,Math.max(0,this._map.options.maxBoundsViscosity))}else this._offsetLimit=null;t.fire("movestart").fire("dragstart"),t.options.inertia&&(this._positions=[],this._times=[])},_onDrag:function(t){if(this._map.options.inertia){var e=this._lastTime=+new Date,i=this._lastPos=this._draggable._absPos||this._draggable._newPos;this._positions.push(i),this._times.push(e),e-this._times[0]>50&&(this._positions.shift(),this._times.shift())}this._map.fire("move",t).fire("drag",t)},_onZoomEnd:function(){var t=this._map.getSize().divideBy(2),e=this._map.latLngToLayerPoint([0,0]);this._initialWorldOffset=e.subtract(t).x,this._worldWidth=this._map.getPixelWorldBounds().getSize().x},_viscousLimit:function(t,e){return t-(t-e)*this._viscosity},_onPreDragLimit:function(){if(this._viscosity&&this._offsetLimit){var t=this._draggable._newPos.subtract(this._draggable._startPos),e=this._offsetLimit;t.x<e.min.x&&(t.x=this._viscousLimit(t.x,e.min.x)),t.y<e.min.y&&(t.y=this._viscousLimit(t.y,e.min.y)),t.x>e.max.x&&(t.x=this._viscousLimit(t.x,e.max.x)),t.y>e.max.y&&(t.y=this._viscousLimit(t.y,e.max.y)),this._draggable._newPos=this._draggable._startPos.add(t)}},_onPreDragWrap:function(){var t=this._worldWidth,e=Math.round(t/2),i=this._initialWorldOffset,n=this._draggable._newPos.x,o=(n-e+i)%t+e-i,s=(n+e+i)%t-e-i,r=Math.abs(o+i)<Math.abs(s+i)?o:s;this._draggable._absPos=this._draggable._newPos.clone(),this._draggable._newPos.x=r},_onDragEnd:function(t){var e=this._map,i=e.options,n=!i.inertia||this._times.length<2;if(e.fire("dragend",t),n)e.fire("moveend");else{var s=this._lastPos.subtract(this._positions[0]),r=(this._lastTime-this._times[0])/1e3,a=i.easeLinearity,h=s.multiplyBy(a/r),l=h.distanceTo([0,0]),u=Math.min(i.inertiaMaxSpeed,l),c=h.multiplyBy(u/l),d=u/(i.inertiaDeceleration*a),_=c.multiplyBy(-d/2).round();_.x||_.y?(_=e._limitOffset(_,e.options.maxBounds),o.Util.requestAnimFrame(function(){e.panBy(_,{duration:d,easeLinearity:a,noMoveStart:!0,animate:!0})})):e.fire("moveend")}}}),o.Map.addInitHook("addHandler","dragging",o.Map.Drag),o.Map.mergeOptions({doubleClickZoom:!0}),o.Map.DoubleClickZoom=o.Handler.extend({addHooks:function(){this._map.on("dblclick",this._onDoubleClick,this)},removeHooks:function(){this._map.off("dblclick",this._onDoubleClick,this)},_onDoubleClick:function(t){var e=this._map,i=e.getZoom(),n=e.options.zoomDelta,o=t.originalEvent.shiftKey?i-n:i+n;"center"===e.options.doubleClickZoom?e.setZoom(o):e.setZoomAround(t.containerPoint,o)}}),o.Map.addInitHook("addHandler","doubleClickZoom",o.Map.DoubleClickZoom),o.Map.mergeOptions({scrollWheelZoom:!0,wheelDebounceTime:40,wheelPxPerZoomLevel:60}),o.Map.ScrollWheelZoom=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"mousewheel",this._onWheelScroll,this),this._delta=0},removeHooks:function(){o.DomEvent.off(this._map._container,"mousewheel",this._onWheelScroll,this)},_onWheelScroll:function(t){var e=o.DomEvent.getWheelDelta(t),i=this._map.options.wheelDebounceTime;this._delta+=e,this._lastMousePos=this._map.mouseEventToContainerPoint(t),this._startTime||(this._startTime=+new Date);var n=Math.max(i-(+new Date-this._startTime),0);clearTimeout(this._timer),this._timer=setTimeout(o.bind(this._performZoom,this),n),o.DomEvent.stop(t)},_performZoom:function(){var t=this._map,e=t.getZoom(),i=this._map.options.zoomSnap||0;t._stop();var n=this._delta/(4*this._map.options.wheelPxPerZoomLevel),o=4*Math.log(2/(1+Math.exp(-Math.abs(n))))/Math.LN2,s=i?Math.ceil(o/i)*i:o,r=t._limitZoom(e+(this._delta>0?s:-s))-e;this._delta=0,this._startTime=null,r&&("center"===t.options.scrollWheelZoom?t.setZoom(e+r):t.setZoomAround(this._lastMousePos,e+r))}}),o.Map.addInitHook("addHandler","scrollWheelZoom",o.Map.ScrollWheelZoom),o.extend(o.DomEvent,{_touchstart:o.Browser.msPointer?"MSPointerDown":o.Browser.pointer?"pointerdown":"touchstart",_touchend:o.Browser.msPointer?"MSPointerUp":o.Browser.pointer?"pointerup":"touchend",addDoubleTapListener:function(t,e,i){function n(t){var e;if(o.Browser.pointer){if(!o.Browser.edge||"mouse"===t.pointerType)return;e=o.DomEvent._pointersCount}else e=t.touches.length;if(!(e>1)){var i=Date.now(),n=i-(r||i);a=t.touches?t.touches[0]:t,h=n>0&&n<=l,r=i}}function s(t){if(h&&!a.cancelBubble){if(o.Browser.pointer){if(!o.Browser.edge||"mouse"===t.pointerType)return;var i,n,s={};for(n in a)i=a[n],s[n]=i&&i.bind?i.bind(a):i;a=s}a.type="dblclick",e(a),r=null}}var r,a,h=!1,l=250,u="_leaflet_",c=this._touchstart,d=this._touchend;return t[u+c+i]=n,t[u+d+i]=s,t[u+"dblclick"+i]=e,t.addEventListener(c,n,!1),t.addEventListener(d,s,!1),t.addEventListener("dblclick",e,!1),this},removeDoubleTapListener:function(t,e){var i="_leaflet_",n=t[i+this._touchstart+e],s=t[i+this._touchend+e],r=t[i+"dblclick"+e];return t.removeEventListener(this._touchstart,n,!1),t.removeEventListener(this._touchend,s,!1),o.Browser.edge||t.removeEventListener("dblclick",r,!1),this}}),o.extend(o.DomEvent,{POINTER_DOWN:o.Browser.msPointer?"MSPointerDown":"pointerdown",POINTER_MOVE:o.Browser.msPointer?"MSPointerMove":"pointermove",POINTER_UP:o.Browser.msPointer?"MSPointerUp":"pointerup",POINTER_CANCEL:o.Browser.msPointer?"MSPointerCancel":"pointercancel",TAG_WHITE_LIST:["INPUT","SELECT","OPTION"],_pointers:{},_pointersCount:0,addPointerListener:function(t,e,i,n){return"touchstart"===e?this._addPointerStart(t,i,n):"touchmove"===e?this._addPointerMove(t,i,n):"touchend"===e&&this._addPointerEnd(t,i,n),this},removePointerListener:function(t,e,i){var n=t["_leaflet_"+e+i];return"touchstart"===e?t.removeEventListener(this.POINTER_DOWN,n,!1):"touchmove"===e?t.removeEventListener(this.POINTER_MOVE,n,!1):"touchend"===e&&(t.removeEventListener(this.POINTER_UP,n,!1),t.removeEventListener(this.POINTER_CANCEL,n,!1)),this},_addPointerStart:function(t,i,n){var s=o.bind(function(t){if("mouse"!==t.pointerType&&t.MSPOINTER_TYPE_MOUSE&&t.pointerType!==t.MSPOINTER_TYPE_MOUSE){if(!(this.TAG_WHITE_LIST.indexOf(t.target.tagName)<0))return;o.DomEvent.preventDefault(t)}this._handlePointer(t,i)},this);if(t["_leaflet_touchstart"+n]=s,t.addEventListener(this.POINTER_DOWN,s,!1),!this._pointerDocListener){var r=o.bind(this._globalPointerUp,this);e.documentElement.addEventListener(this.POINTER_DOWN,o.bind(this._globalPointerDown,this),!0),e.documentElement.addEventListener(this.POINTER_MOVE,o.bind(this._globalPointerMove,this),!0),e.documentElement.addEventListener(this.POINTER_UP,r,!0),e.documentElement.addEventListener(this.POINTER_CANCEL,r,!0),this._pointerDocListener=!0}},_globalPointerDown:function(t){this._pointers[t.pointerId]=t,this._pointersCount++},_globalPointerMove:function(t){this._pointers[t.pointerId]&&(this._pointers[t.pointerId]=t)},_globalPointerUp:function(t){delete this._pointers[t.pointerId],this._pointersCount--},_handlePointer:function(t,e){t.touches=[];for(var i in this._pointers)t.touches.push(this._pointers[i]);t.changedTouches=[t],e(t)},_addPointerMove:function(t,e,i){var n=o.bind(function(t){(t.pointerType!==t.MSPOINTER_TYPE_MOUSE&&"mouse"!==t.pointerType||0!==t.buttons)&&this._handlePointer(t,e)},this);t["_leaflet_touchmove"+i]=n,t.addEventListener(this.POINTER_MOVE,n,!1)},_addPointerEnd:function(t,e,i){var n=o.bind(function(t){this._handlePointer(t,e)},this);t["_leaflet_touchend"+i]=n,t.addEventListener(this.POINTER_UP,n,!1),t.addEventListener(this.POINTER_CANCEL,n,!1)}}),o.Map.mergeOptions({touchZoom:o.Browser.touch&&!o.Browser.android23,bounceAtZoomLimits:!0}),o.Map.TouchZoom=o.Handler.extend({addHooks:function(){o.DomUtil.addClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.on(this._map._container,"touchstart",this._onTouchStart,this)},removeHooks:function(){o.DomUtil.removeClass(this._map._container,"leaflet-touch-zoom"),o.DomEvent.off(this._map._container,"touchstart",this._onTouchStart,this)},_onTouchStart:function(t){var i=this._map;if(t.touches&&2===t.touches.length&&!i._animatingZoom&&!this._zooming){var n=i.mouseEventToContainerPoint(t.touches[0]),s=i.mouseEventToContainerPoint(t.touches[1]);this._centerPoint=i.getSize()._divideBy(2),this._startLatLng=i.containerPointToLatLng(this._centerPoint),"center"!==i.options.touchZoom&&(this._pinchStartLatLng=i.containerPointToLatLng(n.add(s)._divideBy(2))),this._startDist=n.distanceTo(s),this._startZoom=i.getZoom(),this._moved=!1,this._zooming=!0,i._stop(),o.DomEvent.on(e,"touchmove",this._onTouchMove,this).on(e,"touchend",this._onTouchEnd,this),o.DomEvent.preventDefault(t)}},_onTouchMove:function(t){if(t.touches&&2===t.touches.length&&this._zooming){var e=this._map,i=e.mouseEventToContainerPoint(t.touches[0]),n=e.mouseEventToContainerPoint(t.touches[1]),s=i.distanceTo(n)/this._startDist;if(this._zoom=e.getScaleZoom(s,this._startZoom),!e.options.bounceAtZoomLimits&&(this._zoom<e.getMinZoom()&&s<1||this._zoom>e.getMaxZoom()&&s>1)&&(this._zoom=e._limitZoom(this._zoom)),"center"===e.options.touchZoom){if(this._center=this._startLatLng,1===s)return}else{var r=i._add(n)._divideBy(2)._subtract(this._centerPoint);if(1===s&&0===r.x&&0===r.y)return;this._center=e.unproject(e.project(this._pinchStartLatLng,this._zoom).subtract(r),this._zoom)}this._moved||(e._moveStart(!0),this._moved=!0),o.Util.cancelAnimFrame(this._animRequest);var a=o.bind(e._move,e,this._center,this._zoom,{pinch:!0,round:!1});this._animRequest=o.Util.requestAnimFrame(a,this,!0),o.DomEvent.preventDefault(t)}},_onTouchEnd:function(){return this._moved&&this._zooming?(this._zooming=!1,o.Util.cancelAnimFrame(this._animRequest),o.DomEvent.off(e,"touchmove",this._onTouchMove).off(e,"touchend",this._onTouchEnd),void(this._map.options.zoomAnimation?this._map._animateZoom(this._center,this._map._limitZoom(this._zoom),!0,this._map.options.zoomSnap):this._map._resetView(this._center,this._map._limitZoom(this._zoom)))):void(this._zooming=!1)}}),o.Map.addInitHook("addHandler","touchZoom",o.Map.TouchZoom),o.Map.mergeOptions({tap:!0,tapTolerance:15}),o.Map.Tap=o.Handler.extend({addHooks:function(){o.DomEvent.on(this._map._container,"touchstart",this._onDown,this)},removeHooks:function(){o.DomEvent.off(this._map._container,"touchstart",this._onDown,this)},_onDown:function(t){if(t.touches){if(o.DomEvent.preventDefault(t),this._fireClick=!0,t.touches.length>1)return this._fireClick=!1,void clearTimeout(this._holdTimeout);var i=t.touches[0],n=i.target;this._startPos=this._newPos=new o.Point(i.clientX,i.clientY),n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.addClass(n,"leaflet-active"),this._holdTimeout=setTimeout(o.bind(function(){this._isTapValid()&&(this._fireClick=!1,this._onUp(),this._simulateEvent("contextmenu",i))},this),1e3),this._simulateEvent("mousedown",i),o.DomEvent.on(e,{touchmove:this._onMove,touchend:this._onUp},this)}},_onUp:function(t){if(clearTimeout(this._holdTimeout),o.DomEvent.off(e,{touchmove:this._onMove,touchend:this._onUp},this),this._fireClick&&t&&t.changedTouches){var i=t.changedTouches[0],n=i.target;n&&n.tagName&&"a"===n.tagName.toLowerCase()&&o.DomUtil.removeClass(n,"leaflet-active"),this._simulateEvent("mouseup",i),
9
this._isTapValid()&&this._simulateEvent("click",i)}},_isTapValid:function(){return this._newPos.distanceTo(this._startPos)<=this._map.options.tapTolerance},_onMove:function(t){var e=t.touches[0];this._newPos=new o.Point(e.clientX,e.clientY),this._simulateEvent("mousemove",e)},_simulateEvent:function(i,n){var o=e.createEvent("MouseEvents");o._simulated=!0,n.target._simulatedClick=!0,o.initMouseEvent(i,!0,!0,t,1,n.screenX,n.screenY,n.clientX,n.clientY,!1,!1,!1,!1,0,null),n.target.dispatchEvent(o)}}),o.Browser.touch&&!o.Browser.pointer&&o.Map.addInitHook("addHandler","tap",o.Map.Tap),o.Map.mergeOptions({boxZoom:!0}),o.Map.BoxZoom=o.Handler.extend({initialize:function(t){this._map=t,this._container=t._container,this._pane=t._panes.overlayPane},addHooks:function(){o.DomEvent.on(this._container,"mousedown",this._onMouseDown,this)},removeHooks:function(){o.DomEvent.off(this._container,"mousedown",this._onMouseDown,this)},moved:function(){return this._moved},_resetState:function(){this._moved=!1},_onMouseDown:function(t){return!(!t.shiftKey||1!==t.which&&1!==t.button)&&(this._resetState(),o.DomUtil.disableTextSelection(),o.DomUtil.disableImageDrag(),this._startPoint=this._map.mouseEventToContainerPoint(t),void o.DomEvent.on(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this))},_onMouseMove:function(t){this._moved||(this._moved=!0,this._box=o.DomUtil.create("div","leaflet-zoom-box",this._container),o.DomUtil.addClass(this._container,"leaflet-crosshair"),this._map.fire("boxzoomstart")),this._point=this._map.mouseEventToContainerPoint(t);var e=new o.Bounds(this._point,this._startPoint),i=e.getSize();o.DomUtil.setPosition(this._box,e.min),this._box.style.width=i.x+"px",this._box.style.height=i.y+"px"},_finish:function(){this._moved&&(o.DomUtil.remove(this._box),o.DomUtil.removeClass(this._container,"leaflet-crosshair")),o.DomUtil.enableTextSelection(),o.DomUtil.enableImageDrag(),o.DomEvent.off(e,{contextmenu:o.DomEvent.stop,mousemove:this._onMouseMove,mouseup:this._onMouseUp,keydown:this._onKeyDown},this)},_onMouseUp:function(t){if((1===t.which||1===t.button)&&(this._finish(),this._moved)){setTimeout(o.bind(this._resetState,this),0);var e=new o.LatLngBounds(this._map.containerPointToLatLng(this._startPoint),this._map.containerPointToLatLng(this._point));this._map.fitBounds(e).fire("boxzoomend",{boxZoomBounds:e})}},_onKeyDown:function(t){27===t.keyCode&&this._finish()}}),o.Map.addInitHook("addHandler","boxZoom",o.Map.BoxZoom),o.Map.mergeOptions({keyboard:!0,keyboardPanDelta:80}),o.Map.Keyboard=o.Handler.extend({keyCodes:{left:[37],right:[39],down:[40],up:[38],zoomIn:[187,107,61,171],zoomOut:[189,109,54,173]},initialize:function(t){this._map=t,this._setPanDelta(t.options.keyboardPanDelta),this._setZoomDelta(t.options.zoomDelta)},addHooks:function(){var t=this._map._container;t.tabIndex<=0&&(t.tabIndex="0"),o.DomEvent.on(t,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.on({focus:this._addHooks,blur:this._removeHooks},this)},removeHooks:function(){this._removeHooks(),o.DomEvent.off(this._map._container,{focus:this._onFocus,blur:this._onBlur,mousedown:this._onMouseDown},this),this._map.off({focus:this._addHooks,blur:this._removeHooks},this)},_onMouseDown:function(){if(!this._focused){var i=e.body,n=e.documentElement,o=i.scrollTop||n.scrollTop,s=i.scrollLeft||n.scrollLeft;this._map._container.focus(),t.scrollTo(s,o)}},_onFocus:function(){this._focused=!0,this._map.fire("focus")},_onBlur:function(){this._focused=!1,this._map.fire("blur")},_setPanDelta:function(t){var e,i,n=this._panKeys={},o=this.keyCodes;for(e=0,i=o.left.length;e<i;e++)n[o.left[e]]=[-1*t,0];for(e=0,i=o.right.length;e<i;e++)n[o.right[e]]=[t,0];for(e=0,i=o.down.length;e<i;e++)n[o.down[e]]=[0,t];for(e=0,i=o.up.length;e<i;e++)n[o.up[e]]=[0,-1*t]},_setZoomDelta:function(t){var e,i,n=this._zoomKeys={},o=this.keyCodes;for(e=0,i=o.zoomIn.length;e<i;e++)n[o.zoomIn[e]]=t;for(e=0,i=o.zoomOut.length;e<i;e++)n[o.zoomOut[e]]=-t},_addHooks:function(){o.DomEvent.on(e,"keydown",this._onKeyDown,this)},_removeHooks:function(){o.DomEvent.off(e,"keydown",this._onKeyDown,this)},_onKeyDown:function(t){if(!(t.altKey||t.ctrlKey||t.metaKey)){var e,i=t.keyCode,n=this._map;if(i in this._panKeys){if(n._panAnim&&n._panAnim._inProgress)return;e=this._panKeys[i],t.shiftKey&&(e=o.point(e).multiplyBy(3)),n.panBy(e),n.options.maxBounds&&n.panInsideBounds(n.options.maxBounds)}else if(i in this._zoomKeys)n.setZoom(n.getZoom()+(t.shiftKey?3:1)*this._zoomKeys[i]);else{if(27!==i)return;n.closePopup()}o.DomEvent.stop(t)}}}),o.Map.addInitHook("addHandler","keyboard",o.Map.Keyboard),o.Handler.MarkerDrag=o.Handler.extend({initialize:function(t){this._marker=t},addHooks:function(){var t=this._marker._icon;this._draggable||(this._draggable=new o.Draggable(t,t,!0)),this._draggable.on({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this).enable(),o.DomUtil.addClass(t,"leaflet-marker-draggable")},removeHooks:function(){this._draggable.off({dragstart:this._onDragStart,drag:this._onDrag,dragend:this._onDragEnd},this).disable(),this._marker._icon&&o.DomUtil.removeClass(this._marker._icon,"leaflet-marker-draggable")},moved:function(){return this._draggable&&this._draggable._moved},_onDragStart:function(){this._oldLatLng=this._marker.getLatLng(),this._marker.closePopup().fire("movestart").fire("dragstart")},_onDrag:function(t){var e=this._marker,i=e._shadow,n=o.DomUtil.getPosition(e._icon),s=e._map.layerPointToLatLng(n);i&&o.DomUtil.setPosition(i,n),e._latlng=s,t.latlng=s,t.oldLatLng=this._oldLatLng,e.fire("move",t).fire("drag",t)},_onDragEnd:function(t){delete this._oldLatLng,this._marker.fire("moveend").fire("dragend",t)}}),o.Control=o.Class.extend({options:{position:"topright"},initialize:function(t){o.setOptions(this,t)},getPosition:function(){return this.options.position},setPosition:function(t){var e=this._map;return e&&e.removeControl(this),this.options.position=t,e&&e.addControl(this),this},getContainer:function(){return this._container},addTo:function(t){this.remove(),this._map=t;var e=this._container=this.onAdd(t),i=this.getPosition(),n=t._controlCorners[i];return o.DomUtil.addClass(e,"leaflet-control"),i.indexOf("bottom")!==-1?n.insertBefore(e,n.firstChild):n.appendChild(e),this},remove:function(){return this._map?(o.DomUtil.remove(this._container),this.onRemove&&this.onRemove(this._map),this._map=null,this):this},_refocusOnMap:function(t){this._map&&t&&t.screenX>0&&t.screenY>0&&this._map.getContainer().focus()}}),o.control=function(t){return new o.Control(t)},o.Map.include({addControl:function(t){return t.addTo(this),this},removeControl:function(t){return t.remove(),this},_initControlPos:function(){function t(t,s){var r=i+t+" "+i+s;e[t+s]=o.DomUtil.create("div",r,n)}var e=this._controlCorners={},i="leaflet-",n=this._controlContainer=o.DomUtil.create("div",i+"control-container",this._container);t("top","left"),t("top","right"),t("bottom","left"),t("bottom","right")},_clearControlPos:function(){o.DomUtil.remove(this._controlContainer)}}),o.Control.Zoom=o.Control.extend({options:{position:"topleft",zoomInText:"+",zoomInTitle:"Zoom in",zoomOutText:"-",zoomOutTitle:"Zoom out"},onAdd:function(t){var e="leaflet-control-zoom",i=o.DomUtil.create("div",e+" leaflet-bar"),n=this.options;return this._zoomInButton=this._createButton(n.zoomInText,n.zoomInTitle,e+"-in",i,this._zoomIn),this._zoomOutButton=this._createButton(n.zoomOutText,n.zoomOutTitle,e+"-out",i,this._zoomOut),this._updateDisabled(),t.on("zoomend zoomlevelschange",this._updateDisabled,this),i},onRemove:function(t){t.off("zoomend zoomlevelschange",this._updateDisabled,this)},disable:function(){return this._disabled=!0,this._updateDisabled(),this},enable:function(){return this._disabled=!1,this._updateDisabled(),this},_zoomIn:function(t){!this._disabled&&this._map._zoom<this._map.getMaxZoom()&&this._map.zoomIn(this._map.options.zoomDelta*(t.shiftKey?3:1))},_zoomOut:function(t){!this._disabled&&this._map._zoom>this._map.getMinZoom()&&this._map.zoomOut(this._map.options.zoomDelta*(t.shiftKey?3:1))},_createButton:function(t,e,i,n,s){var r=o.DomUtil.create("a",i,n);return r.innerHTML=t,r.href="#",r.title=e,r.setAttribute("role","button"),r.setAttribute("aria-label",e),o.DomEvent.on(r,"mousedown dblclick",o.DomEvent.stopPropagation).on(r,"click",o.DomEvent.stop).on(r,"click",s,this).on(r,"click",this._refocusOnMap,this),r},_updateDisabled:function(){var t=this._map,e="leaflet-disabled";o.DomUtil.removeClass(this._zoomInButton,e),o.DomUtil.removeClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMinZoom())&&o.DomUtil.addClass(this._zoomOutButton,e),(this._disabled||t._zoom===t.getMaxZoom())&&o.DomUtil.addClass(this._zoomInButton,e)}}),o.Map.mergeOptions({zoomControl:!0}),o.Map.addInitHook(function(){this.options.zoomControl&&(this.zoomControl=new o.Control.Zoom,this.addControl(this.zoomControl))}),o.control.zoom=function(t){return new o.Control.Zoom(t)},o.Control.Attribution=o.Control.extend({options:{position:"bottomright",prefix:'<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'},initialize:function(t){o.setOptions(this,t),this._attributions={}},onAdd:function(t){t.attributionControl=this,this._container=o.DomUtil.create("div","leaflet-control-attribution"),o.DomEvent&&o.DomEvent.disableClickPropagation(this._container);for(var e in t._layers)t._layers[e].getAttribution&&this.addAttribution(t._layers[e].getAttribution());return this._update(),this._container},setPrefix:function(t){return this.options.prefix=t,this._update(),this},addAttribution:function(t){return t?(this._attributions[t]||(this._attributions[t]=0),this._attributions[t]++,this._update(),this):this},removeAttribution:function(t){return t?(this._attributions[t]&&(this._attributions[t]--,this._update()),this):this},_update:function(){if(this._map){var t=[];for(var e in this._attributions)this._attributions[e]&&t.push(e);var i=[];this.options.prefix&&i.push(this.options.prefix),t.length&&i.push(t.join(", ")),this._container.innerHTML=i.join(" | ")}}}),o.Map.mergeOptions({attributionControl:!0}),o.Map.addInitHook(function(){this.options.attributionControl&&(new o.Control.Attribution).addTo(this)}),o.control.attribution=function(t){return new o.Control.Attribution(t)},o.Control.Scale=o.Control.extend({options:{position:"bottomleft",maxWidth:100,metric:!0,imperial:!0},onAdd:function(t){var e="leaflet-control-scale",i=o.DomUtil.create("div",e),n=this.options;return this._addScales(n,e+"-line",i),t.on(n.updateWhenIdle?"moveend":"move",this._update,this),t.whenReady(this._update,this),i},onRemove:function(t){t.off(this.options.updateWhenIdle?"moveend":"move",this._update,this)},_addScales:function(t,e,i){t.metric&&(this._mScale=o.DomUtil.create("div",e,i)),t.imperial&&(this._iScale=o.DomUtil.create("div",e,i))},_update:function(){var t=this._map,e=t.getSize().y/2,i=t.distance(t.containerPointToLatLng([0,e]),t.containerPointToLatLng([this.options.maxWidth,e]));this._updateScales(i)},_updateScales:function(t){this.options.metric&&t&&this._updateMetric(t),this.options.imperial&&t&&this._updateImperial(t)},_updateMetric:function(t){var e=this._getRoundNum(t),i=e<1e3?e+" m":e/1e3+" km";this._updateScale(this._mScale,i,e/t)},_updateImperial:function(t){var e,i,n,o=3.2808399*t;o>5280?(e=o/5280,i=this._getRoundNum(e),this._updateScale(this._iScale,i+" mi",i/e)):(n=this._getRoundNum(o),this._updateScale(this._iScale,n+" ft",n/o))},_updateScale:function(t,e,i){t.style.width=Math.round(this.options.maxWidth*i)+"px",t.innerHTML=e},_getRoundNum:function(t){var e=Math.pow(10,(Math.floor(t)+"").length-1),i=t/e;return i=i>=10?10:i>=5?5:i>=3?3:i>=2?2:1,e*i}}),o.control.scale=function(t){return new o.Control.Scale(t)},o.Control.Layers=o.Control.extend({options:{collapsed:!0,position:"topright",autoZIndex:!0,hideSingleBase:!1,sortLayers:!1,sortFunction:function(t,e,i,n){return i<n?-1:n<i?1:0}},initialize:function(t,e,i){o.setOptions(this,i),this._layers=[],this._lastZIndex=0,this._handlingClick=!1;for(var n in t)this._addLayer(t[n],n);for(n in e)this._addLayer(e[n],n,!0)},onAdd:function(t){return this._initLayout(),this._update(),this._map=t,t.on("zoomend",this._checkDisabledLayers,this),this._container},onRemove:function(){this._map.off("zoomend",this._checkDisabledLayers,this);for(var t=0;t<this._layers.length;t++)this._layers[t].layer.off("add remove",this._onLayerChange,this)},addBaseLayer:function(t,e){return this._addLayer(t,e),this._map?this._update():this},addOverlay:function(t,e){return this._addLayer(t,e,!0),this._map?this._update():this},removeLayer:function(t){t.off("add remove",this._onLayerChange,this);var e=this._getLayer(o.stamp(t));return e&&this._layers.splice(this._layers.indexOf(e),1),this._map?this._update():this},expand:function(){o.DomUtil.addClass(this._container,"leaflet-control-layers-expanded"),this._form.style.height=null;var t=this._map.getSize().y-(this._container.offsetTop+50);return t<this._form.clientHeight?(o.DomUtil.addClass(this._form,"leaflet-control-layers-scrollbar"),this._form.style.height=t+"px"):o.DomUtil.removeClass(this._form,"leaflet-control-layers-scrollbar"),this._checkDisabledLayers(),this},collapse:function(){return o.DomUtil.removeClass(this._container,"leaflet-control-layers-expanded"),this},_initLayout:function(){var t="leaflet-control-layers",e=this._container=o.DomUtil.create("div",t),i=this.options.collapsed;e.setAttribute("aria-haspopup",!0),o.DomEvent.disableClickPropagation(e),o.Browser.touch||o.DomEvent.disableScrollPropagation(e);var n=this._form=o.DomUtil.create("form",t+"-list");i&&(this._map.on("click",this.collapse,this),o.Browser.android||o.DomEvent.on(e,{mouseenter:this.expand,mouseleave:this.collapse},this));var s=this._layersLink=o.DomUtil.create("a",t+"-toggle",e);s.href="#",s.title="Layers",o.Browser.touch?o.DomEvent.on(s,"click",o.DomEvent.stop).on(s,"click",this.expand,this):o.DomEvent.on(s,"focus",this.expand,this),o.DomEvent.on(n,"click",function(){setTimeout(o.bind(this._onInputClick,this),0)},this),i||this.expand(),this._baseLayersList=o.DomUtil.create("div",t+"-base",n),this._separator=o.DomUtil.create("div",t+"-separator",n),this._overlaysList=o.DomUtil.create("div",t+"-overlays",n),e.appendChild(n)},_getLayer:function(t){for(var e=0;e<this._layers.length;e++)if(this._layers[e]&&o.stamp(this._layers[e].layer)===t)return this._layers[e]},_addLayer:function(t,e,i){t.on("add remove",this._onLayerChange,this),this._layers.push({layer:t,name:e,overlay:i}),this.options.sortLayers&&this._layers.sort(o.bind(function(t,e){return this.options.sortFunction(t.layer,e.layer,t.name,e.name)},this)),this.options.autoZIndex&&t.setZIndex&&(this._lastZIndex++,t.setZIndex(this._lastZIndex))},_update:function(){if(!this._container)return this;o.DomUtil.empty(this._baseLayersList),o.DomUtil.empty(this._overlaysList);var t,e,i,n,s=0;for(i=0;i<this._layers.length;i++)n=this._layers[i],this._addItem(n),e=e||n.overlay,t=t||!n.overlay,s+=n.overlay?0:1;return this.options.hideSingleBase&&(t=t&&s>1,this._baseLayersList.style.display=t?"":"none"),this._separator.style.display=e&&t?"":"none",this},_onLayerChange:function(t){this._handlingClick||this._update();var e=this._getLayer(o.stamp(t.target)),i=e.overlay?"add"===t.type?"overlayadd":"overlayremove":"add"===t.type?"baselayerchange":null;i&&this._map.fire(i,e)},_createRadioElement:function(t,i){var n='<input type="radio" class="leaflet-control-layers-selector" name="'+t+'"'+(i?' checked="checked"':"")+"/>",o=e.createElement("div");return o.innerHTML=n,o.firstChild},_addItem:function(t){var i,n=e.createElement("label"),s=this._map.hasLayer(t.layer);t.overlay?(i=e.createElement("input"),i.type="checkbox",i.className="leaflet-control-layers-selector",i.defaultChecked=s):i=this._createRadioElement("leaflet-base-layers",s),i.layerId=o.stamp(t.layer),o.DomEvent.on(i,"click",this._onInputClick,this);var r=e.createElement("span");r.innerHTML=" "+t.name;var a=e.createElement("div");n.appendChild(a),a.appendChild(i),a.appendChild(r);var h=t.overlay?this._overlaysList:this._baseLayersList;return h.appendChild(n),this._checkDisabledLayers(),n},_onInputClick:function(){var t,e,i,n=this._form.getElementsByTagName("input"),o=[],s=[];this._handlingClick=!0;for(var r=n.length-1;r>=0;r--)t=n[r],e=this._getLayer(t.layerId).layer,i=this._map.hasLayer(e),t.checked&&!i?o.push(e):!t.checked&&i&&s.push(e);for(r=0;r<s.length;r++)this._map.removeLayer(s[r]);for(r=0;r<o.length;r++)this._map.addLayer(o[r]);this._handlingClick=!1,this._refocusOnMap()},_checkDisabledLayers:function(){for(var t,e,n=this._form.getElementsByTagName("input"),o=this._map.getZoom(),s=n.length-1;s>=0;s--)t=n[s],e=this._getLayer(t.layerId).layer,t.disabled=e.options.minZoom!==i&&o<e.options.minZoom||e.options.maxZoom!==i&&o>e.options.maxZoom},_expand:function(){return this.expand()},_collapse:function(){return this.collapse()}}),o.control.layers=function(t,e,i){return new o.Control.Layers(t,e,i)}}(window,document);

Return to bug 18066