aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/index.html124
-rw-r--r--examples/jquery.min.js4
-rw-r--r--examples/leaflet-src.js9169
-rw-r--r--examples/osmtogeojson.js1
4 files changed, 9298 insertions, 0 deletions
diff --git a/examples/index.html b/examples/index.html
new file mode 100644
index 0000000..fcb411e
--- /dev/null
+++ b/examples/index.html
@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Indoor Map Example</title>
+
+ <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.2/leaflet.css" />
+
+ <!--[if lte IE 8]><link rel="stylesheet" href="libs/leaflet.ie.css" /><![endif]-->
+
+ <style type="text/css">
+ body {
+ padding: 0;
+ margin: 0;
+ }
+
+ html, body, #map {
+ height: 100%;
+ }
+
+ .info {
+ width: 150px;
+ padding: 6px 8px;
+ font: 14px/16px Arial, Helvetica, sans-serif;
+ background: white;
+ background: rgba(255,255,255,1);
+ box-shadow: 0 0 15px rgba(0,0,0,0.2);
+ border-radius: 5px;
+ }
+ </style>
+</head>
+<body>
+ <div id="map"></div>
+
+ <script src="jquery.min.js"></script>
+ <script src="leaflet-src.js"></script>
+ <script src="../leaflet-indoor.js"></script>
+ <script src="osmtogeojson.js"></script>
+ <script type="text/JavaScript">
+
+ // Create the map
+ var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
+ osm = new L.TileLayer(osmUrl, {
+ maxZoom: 22,
+ attribution: "Map data &copy; OpenStreetMap contributors"
+ });
+
+ map = new L.Map('map', {
+ layers: [osm],
+ center: new L.LatLng(49.41873, 8.67689),
+ zoom: 19
+ });
+
+ var query = '(relation(1370729);>>->.rels;>;);out;';
+
+ $.get("http://overpass.osm.rambler.ru/cgi/interpreter?data=" + query, function(data) {
+ var geoJSON = osmtogeojson(data, {
+ polygonFeatures: {
+ buildingpart: true
+ }
+ });
+
+ var indoorLayer = new L.Indoor(geoJSON, {
+ getLevel: function(feature) {
+ if (feature.properties.relations.length === 0)
+ return null;
+
+ return feature.properties.relations[0].reltags.level;
+ },
+ onEachFeature: function(feature, layer) {
+ layer.bindPopup(JSON.stringify(feature.properties, null, 4));
+ },
+ style: function(feature) {
+ var fill = 'white';
+
+ if (feature.properties.tags.buildingpart === 'corridor') {
+ fill = '#169EC6';
+ } else if (feature.properties.tags.buildingpart === 'verticalpassage') {
+ fill = '#0A485B';
+ }
+
+ return {
+ fillColor: fill,
+ weight: 1,
+ color: '#666',
+ fillOpacity: 1
+ };
+ }
+ });
+
+ indoorLayer.setLevel("0");
+
+ indoorLayer.addTo(map);
+
+ var levelControl = new L.Control.Level({
+ level: "0",
+ levels: indoorLayer.getLevels()
+ });
+
+ // Connect the level control to the indoor layer
+ levelControl.addEventListener("levelchange", indoorLayer.setLevel, indoorLayer);
+
+ levelControl.addTo(map);
+ });
+
+ var legend = L.control({position: 'topright'});
+
+ legend.onAdd = function(map) {
+ var d = "This Leaflet plugin makes it easier to create indoor " +
+ "maps. This example pulls in the data for a particular " +
+ "building, and then displays it on the map, you can " +
+ "change the level displayed by using the selector at " +
+ "the bottom right of the map."
+
+ var div = L.DomUtil.create('div', 'info legend');
+
+ div.appendChild(document.createTextNode(d));
+
+ return div;
+ };
+
+ legend.addTo(map);
+ </script>
+</body>
+</html>
diff --git a/examples/jquery.min.js b/examples/jquery.min.js
new file mode 100644
index 0000000..4d24ba4
--- /dev/null
+++ b/examples/jquery.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.2 jquery.com | jquery.org/license */
+(function(e,t){function u(e){var t=o[e]={},n,r;e=e.split(/\s+/);for(n=0,r=e.length;n<r;n++)t[e[n]]=!0;return t}function c(e,n,r){if(r===t&&e.nodeType===1){var i="data-"+n.replace(l,"-$1").toLowerCase();r=e.getAttribute(i);if(typeof r=="string"){try{r=r==="true"?!0:r==="false"?!1:r==="null"?null:s.isNumeric(r)?+r:f.test(r)?s.parseJSON(r):r}catch(o){}s.data(e,n,r)}else r=t}return r}function h(e){for(var t in e){if(t==="data"&&s.isEmptyObject(e[t]))continue;if(t!=="toJSON")return!1}return!0}function p(e,t,n){var r=t+"defer",i=t+"queue",o=t+"mark",u=s._data(e,r);u&&(n==="queue"||!s._data(e,i))&&(n==="mark"||!s._data(e,o))&&setTimeout(function(){!s._data(e,i)&&!s._data(e,o)&&(s.removeData(e,r,!0),u.fire())},0)}function H(){return!1}function B(){return!0}function W(e){return!e||!e.parentNode||e.parentNode.nodeType===11}function X(e,t,n){t=t||0;if(s.isFunction(t))return s.grep(e,function(e,r){var i=!!t.call(e,r,e);return i===n});if(t.nodeType)return s.grep(e,function(e,r){return e===t===n});if(typeof t=="string"){var r=s.grep(e,function(e){return e.nodeType===1});if(q.test(t))return s.filter(t,r,!n);t=s.filter(t,r)}return s.grep(e,function(e,r){return s.inArray(e,t)>=0===n})}function V(e){var t=$.split("|"),n=e.createDocumentFragment();if(n.createElement)while(t.length)n.createElement(t.pop());return n}function at(e,t){return s.nodeName(e,"table")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e,t){if(t.nodeType!==1||!s.hasData(e))return;var n,r,i,o=s._data(e),u=s._data(t,o),a=o.events;if(a){delete u.handle,u.events={};for(n in a)for(r=0,i=a[n].length;r<i;r++)s.event.add(t,n,a[n][r])}u.data&&(u.data=s.extend({},u.data))}function lt(e,t){var n;if(t.nodeType!==1)return;t.clearAttributes&&t.clearAttributes(),t.mergeAttributes&&t.mergeAttributes(e),n=t.nodeName.toLowerCase(),n==="object"?t.outerHTML=e.outerHTML:n!=="input"||e.type!=="checkbox"&&e.type!=="radio"?n==="option"?t.selected=e.defaultSelected:n==="input"||n==="textarea"?t.defaultValue=e.defaultValue:n==="script"&&t.text!==e.text&&(t.text=e.text):(e.checked&&(t.defaultChecked=t.checked=e.checked),t.value!==e.value&&(t.value=e.value)),t.removeAttribute(s.expando),t.removeAttribute("_submit_attached"),t.removeAttribute("_change_attached")}function ct(e){return typeof e.getElementsByTagName!="undefined"?e.getElementsByTagName("*"):typeof e.querySelectorAll!="undefined"?e.querySelectorAll("*"):[]}function ht(e){if(e.type==="checkbox"||e.type==="radio")e.defaultChecked=e.checked}function pt(e){var t=(e.nodeName||"").toLowerCase();t==="input"?ht(e):t!=="script"&&typeof e.getElementsByTagName!="undefined"&&s.grep(e.getElementsByTagName("input"),ht)}function dt(e){var t=n.createElement("div");return ut.appendChild(t),t.innerHTML=e.outerHTML,t.firstChild}function kt(e,t,n){var r=t==="width"?e.offsetWidth:e.offsetHeight,i=t==="width"?1:0,o=4;if(r>0){if(n!=="border")for(;i<o;i+=2)n||(r-=parseFloat(s.css(e,"padding"+xt[i]))||0),n==="margin"?r+=parseFloat(s.css(e,n+xt[i]))||0:r-=parseFloat(s.css(e,"border"+xt[i]+"Width"))||0;return r+"px"}r=Tt(e,t);if(r<0||r==null)r=e.style[t];if(bt.test(r))return r;r=parseFloat(r)||0;if(n)for(;i<o;i+=2)r+=parseFloat(s.css(e,"padding"+xt[i]))||0,n!=="padding"&&(r+=parseFloat(s.css(e,"border"+xt[i]+"Width"))||0),n==="margin"&&(r+=parseFloat(s.css(e,n+xt[i]))||0);return r+"px"}function Qt(e){return function(t,n){typeof t!="string"&&(n=t,t="*");if(s.isFunction(n)){var r=t.toLowerCase().split(qt),i=0,o=r.length,u,a,f;for(;i<o;i++)u=r[i],f=/^\+/.test(u),f&&(u=u.substr(1)||"*"),a=e[u]=e[u]||[],a[f?"unshift":"push"](n)}}}function Gt(e,n,r,i,s,o){s=s||n.dataTypes[0],o=o||{},o[s]=!0;var u=e[s],a=0,f=u?u.length:0,l=e===Wt,c;for(;a<f&&(l||!c);a++)c=u[a](n,r,i),typeof c=="string"&&(!l||o[c]?c=t:(n.dataTypes.unshift(c),c=Gt(e,n,r,i,c,o)));return(l||!c)&&!o["*"]&&(c=Gt(e,n,r,i,"*",o)),c}function Yt(e,n){var r,i,o=s.ajaxSettings.flatOptions||{};for(r in n)n[r]!==t&&((o[r]?e:i||(i={}))[r]=n[r]);i&&s.extend(!0,e,i)}function Zt(e,t,n,r){if(s.isArray(t))s.each(t,function(t,i){n||At.test(e)?r(e,i):Zt(e+"["+(typeof i=="object"?t:"")+"]",i,n,r)});else if(!n&&s.type(t)==="object")for(var i in t)Zt(e+"["+i+"]",t[i],n,r);else r(e,t)}function en(e,n,r){var i=e.contents,s=e.dataTypes,o=e.responseFields,u,a,f,l;for(a in o)a in r&&(n[o[a]]=r[a]);while(s[0]==="*")s.shift(),u===t&&(u=e.mimeType||n.getResponseHeader("content-type"));if(u)for(a in i)if(i[a]&&i[a].test(u)){s.unshift(a);break}if(s[0]in r)f=s[0];else{for(a in r){if(!s[0]||e.converters[a+" "+s[0]]){f=a;break}l||(l=a)}f=f||l}if(f)return f!==s[0]&&s.unshift(f),r[f]}function tn(e,n){e.dataFilter&&(n=e.dataFilter(n,e.dataType));var r=e.dataTypes,i={},o,u,a=r.length,f,l=r[0],c,h,p,d,v;for(o=1;o<a;o++){if(o===1)for(u in e.converters)typeof u=="string"&&(i[u.toLowerCase()]=e.converters[u]);c=l,l=r[o];if(l==="*")l=c;else if(c!=="*"&&c!==l){h=c+" "+l,p=i[h]||i["* "+l];if(!p){v=t;for(d in i){f=d.split(" ");if(f[0]===c||f[0]==="*"){v=i[f[1]+" "+l];if(v){d=i[d],d===!0?p=v:v===!0&&(p=d);break}}}}!p&&!v&&s.error("No conversion from "+h.replace(" "," to ")),p!==!0&&(n=p?p(n):v(d(n)))}}return n}function an(){try{return new e.XMLHttpRequest}catch(t){}}function fn(){try{return new e.ActiveXObject("Microsoft.XMLHTTP")}catch(t){}}function yn(){return setTimeout(bn,0),gn=s.now()}function bn(){gn=t}function wn(e,t){var n={};return s.each(mn.concat.apply([],mn.slice(0,t)),function(){n[this]=e}),n}function En(e){if(!ln[e]){var t=n.body,r=s("<"+e+">").appendTo(t),i=r.css("display");r.remove();if(i==="none"||i===""){cn||(cn=n.createElement("iframe"),cn.frameBorder=cn.width=cn.height=0),t.appendChild(cn);if(!hn||!cn.createElement)hn=(cn.contentWindow||cn.contentDocument).document,hn.write((s.support.boxModel?"<!doctype html>":"")+"<html><body>"),hn.close();r=hn.createElement(e),hn.body.appendChild(r),i=s.css(r,"display"),t.removeChild(cn)}ln[e]=i}return ln[e]}function Nn(e){return s.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:!1}var n=e.document,r=e.navigator,i=e.location,s=function(){function H(){if(i.isReady)return;try{n.documentElement.doScroll("left")}catch(e){setTimeout(H,1);return}i.ready()}var i=function(e,t){return new i.fn.init(e,t,u)},s=e.jQuery,o=e.$,u,a=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,f=/\S/,l=/^\s+/,c=/\s+$/,h=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,p=/^[\],:{}\s]*$/,d=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,v=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,m=/(?:^|:|,)(?:\s*\[)+/g,g=/(webkit)[ \/]([\w.]+)/,y=/(opera)(?:.*version)?[ \/]([\w.]+)/,b=/(msie) ([\w.]+)/,w=/(mozilla)(?:.*? rv:([\w.]+))?/,E=/-([a-z]|[0-9])/ig,S=/^-ms-/,x=function(e,t){return(t+"").toUpperCase()},T=r.userAgent,N,C,k,L=Object.prototype.toString,A=Object.prototype.hasOwnProperty,O=Array.prototype.push,M=Array.prototype.slice,_=String.prototype.trim,D=Array.prototype.indexOf,P={};return i.fn=i.prototype={constructor:i,init:function(e,r,s){var o,u,f,l;if(!e)return this;if(e.nodeType)return this.context=this[0]=e,this.length=1,this;if(e==="body"&&!r&&n.body)return this.context=n,this[0]=n.body,this.selector=e,this.length=1,this;if(typeof e=="string"){e.charAt(0)!=="<"||e.charAt(e.length-1)!==">"||e.length<3?o=a.exec(e):o=[null,e,null];if(o&&(o[1]||!r)){if(o[1])return r=r instanceof i?r[0]:r,l=r?r.ownerDocument||r:n,f=h.exec(e),f?i.isPlainObject(r)?(e=[n.createElement(f[1])],i.fn.attr.call(e,r,!0)):e=[l.createElement(f[1])]:(f=i.buildFragment([o[1]],[l]),e=(f.cacheable?i.clone(f.fragment):f.fragment).childNodes),i.merge(this,e);u=n.getElementById(o[2]);if(u&&u.parentNode){if(u.id!==o[2])return s.find(e);this.length=1,this[0]=u}return this.context=n,this.selector=e,this}return!r||r.jquery?(r||s).find(e):this.constructor(r).find(e)}return i.isFunction(e)?s.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),i.makeArray(e,this))},selector:"",jquery:"1.7.2",length:0,size:function(){return this.length},toArray:function(){return M.call(this,0)},get:function(e){return e==null?this.toArray():e<0?this[this.length+e]:this[e]},pushStack:function(e,t,n){var r=this.constructor();return i.isArray(e)?O.apply(r,e):i.merge(r,e),r.prevObject=this,r.context=this.context,t==="find"?r.selector=this.selector+(this.selector?" ":"")+n:t&&(r.selector=this.selector+"."+t+"("+n+")"),r},each:function(e,t){return i.each(this,e,t)},ready:function(e){return i.bindReady(),C.add(e),this},eq:function(e){return e=+e,e===-1?this.slice(e):this.slice(e,e+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(M.apply(this,arguments),"slice",M.call(arguments).join(","))},map:function(e){return this.pushStack(i.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:O,sort:[].sort,splice:[].splice},i.fn.init.prototype=i.fn,i.extend=i.fn.extend=function(){var e,n,r,s,o,u,a=arguments[0]||{},f=1,l=arguments.length,c=!1;typeof a=="boolean"&&(c=a,a=arguments[1]||{},f=2),typeof a!="object"&&!i.isFunction(a)&&(a={}),l===f&&(a=this,--f);for(;f<l;f++)if((e=arguments[f])!=null)for(n in e){r=a[n],s=e[n];if(a===s)continue;c&&s&&(i.isPlainObject(s)||(o=i.isArray(s)))?(o?(o=!1,u=r&&i.isArray(r)?r:[]):u=r&&i.isPlainObject(r)?r:{},a[n]=i.extend(c,u,s)):s!==t&&(a[n]=s)}return a},i.extend({noConflict:function(t){return e.$===i&&(e.$=o),t&&e.jQuery===i&&(e.jQuery=s),i},isReady:!1,readyWait:1,holdReady:function(e){e?i.readyWait++:i.ready(!0)},ready:function(e){if(e===!0&&!--i.readyWait||e!==!0&&!i.isReady){if(!n.body)return setTimeout(i.ready,1);i.isReady=!0;if(e!==!0&&--i.readyWait>0)return;C.fireWith(n,[i]),i.fn.trigger&&i(n).trigger("ready").off("ready")}},bindReady:function(){if(C)return;C=i.Callbacks("once memory");if(n.readyState==="complete")return setTimeout(i.ready,1);if(n.addEventListener)n.addEventListener("DOMContentLoaded",k,!1),e.addEventListener("load",i.ready,!1);else if(n.attachEvent){n.attachEvent("onreadystatechange",k),e.attachEvent("onload",i.ready);var t=!1;try{t=e.frameElement==null}catch(r){}n.documentElement.doScroll&&t&&H()}},isFunction:function(e){return i.type(e)==="function"},isArray:Array.isArray||function(e){return i.type(e)==="array"},isWindow:function(e){return e!=null&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return e==null?e+"":P[L.call(e)]||"object"},isPlainObject:function(e){if(!e||i.type(e)!=="object"||e.nodeType||i.isWindow(e))return!1;try{if(e.constructor&&!A.call(e,"constructor")&&!A.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||A.call(e,r)},isEmptyObject:function(e){for(var t in e)return!1;return!0},error:function(e){throw Error(e)},parseJSON:function(t){if(typeof t!="string"||!t)return null;t=i.trim(t);if(e.JSON&&e.JSON.parse)return e.JSON.parse(t);if(p.test(t.replace(d,"@").replace(v,"]").replace(m,"")))return Function("return "+t)();i.error("Invalid JSON: "+t)},parseXML:function(n){if(typeof n!="string"||!n)return null;var r,s;try{e.DOMParser?(s=new DOMParser,r=s.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return(!r||!r.documentElement||r.getElementsByTagName("parsererror").length)&&i.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&f.test(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(S,"ms-").replace(E,x)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toUpperCase()===t.toUpperCase()},each:function(e,n,r){var s,o=0,u=e.length,a=u===t||i.isFunction(e);if(r){if(a){for(s in e)if(n.apply(e[s],r)===!1)break}else for(;o<u;)if(n.apply(e[o++],r)===!1)break}else if(a){for(s in e)if(n.call(e[s],s,e[s])===!1)break}else for(;o<u;)if(n.call(e[o],o,e[o++])===!1)break;return e},trim:_?function(e){return e==null?"":_.call(e)}:function(e){return e==null?"":(e+"").replace(l,"").replace(c,"")},makeArray:function(e,t){var n=t||[];if(e!=null){var r=i.type(e);e.length==null||r==="string"||r==="function"||r==="regexp"||i.isWindow(e)?O.call(n,e):i.merge(n,e)}return n},inArray:function(e,t,n){var r;if(t){if(D)return D.call(t,e,n);r=t.length,n=n?n<0?Math.max(0,r+n):n:0;for(;n<r;n++)if(n in t&&t[n]===e)return n}return-1},merge:function(e,n){var r=e.length,i=0;if(typeof n.length=="number")for(var s=n.length;i<s;i++)e[r++]=n[i];else while(n[i]!==t)e[r++]=n[i++];return e.length=r,e},grep:function(e,t,n){var r=[],i;n=!!n;for(var s=0,o=e.length;s<o;s++)i=!!t(e[s],s),n!==i&&r.push(e[s]);return r},map:function(e,n,r){var s,o,u=[],a=0,f=e.length,l=e instanceof i||f!==t&&typeof f=="number"&&(f>0&&e[0]&&e[f-1]||f===0||i.isArray(e));if(l)for(;a<f;a++)s=n(e[a],a,r),s!=null&&(u[u.length]=s);else for(o in e)s=n(e[o],o,r),s!=null&&(u[u.length]=s);return u.concat.apply([],u)},guid:1,proxy:function(e,n){if(typeof n=="string"){var r=e[n];n=e,e=r}if(!i.isFunction(e))return t;var s=M.call(arguments,2),o=function(){return e.apply(n,s.concat(M.call(arguments)))};return o.guid=e.guid=e.guid||o.guid||i.guid++,o},access:function(e,n,r,s,o,u,a){var f,l=r==null,c=0,h=e.length;if(r&&typeof r=="object"){for(c in r)i.access(e,n,c,r[c],1,u,s);o=1}else if(s!==t){f=a===t&&i.isFunction(s),l&&(f?(f=n,n=function(e,t,n){return f.call(i(e),n)}):(n.call(e,s),n=null));if(n)for(;c<h;c++)n(e[c],r,f?s.call(e[c],c,n(e[c],r)):s,a);o=1}return o?e:l?n.call(e):h?n(e[0],r):u},now:function(){return(new Date).getTime()},uaMatch:function(e){e=e.toLowerCase();var t=g.exec(e)||y.exec(e)||b.exec(e)||e.indexOf("compatible")<0&&w.exec(e)||[];return{browser:t[1]||"",version:t[2]||"0"}},sub:function(){function e(t,n){return new e.fn.init(t,n)}i.extend(!0,e,this),e.superclass=this,e.fn=e.prototype=this(),e.fn.constructor=e,e.sub=this.sub,e.fn.init=function(r,s){return s&&s instanceof i&&!(s instanceof e)&&(s=e(s)),i.fn.init.call(this,r,s,t)},e.fn.init.prototype=e.fn;var t=e(n);return e},browser:{}}),i.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(e,t){P["[object "+t+"]"]=t.toLowerCase()}),N=i.uaMatch(T),N.browser&&(i.browser[N.browser]=!0,i.browser.version=N.version),i.browser.webkit&&(i.browser.safari=!0),f.test(" ")&&(l=/^[\s\xA0]+/,c=/[\s\xA0]+$/),u=i(n),n.addEventListener?k=function(){n.removeEventListener("DOMContentLoaded",k,!1),i.ready()}:n.attachEvent&&(k=function(){n.readyState==="complete"&&(n.detachEvent("onreadystatechange",k),i.ready())}),i}(),o={};s.Callbacks=function(e){e=e?o[e]||u(e):{};var n=[],r=[],i,a,f,l,c,h,p=function(t){var r,i,o,u,a;for(r=0,i=t.length;r<i;r++)o=t[r],u=s.type(o),u==="array"?p(o):u==="function"&&(!e.unique||!v.has(o))&&n.push(o)},d=function(t,s){s=s||[],i=!e.memory||[t,s],a=!0,f=!0,h=l||0,l=0,c=n.length;for(;n&&h<c;h++)if(n[h].apply(t,s)===!1&&e.stopOnFalse){i=!0;break}f=!1,n&&(e.once?i===!0?v.disable():n=[]:r&&r.length&&(i=r.shift(),v.fireWith(i[0],i[1])))},v={add:function(){if(n){var e=n.length;p(arguments),f?c=n.length:i&&i!==!0&&(l=e,d(i[0],i[1]))}return this},remove:function(){if(n){var t=arguments,r=0,i=t.length;for(;r<i;r++)for(var s=0;s<n.length;s++)if(t[r]===n[s]){f&&s<=c&&(c--,s<=h&&h--),n.splice(s--,1);if(e.unique)break}}return this},has:function(e){if(n){var t=0,r=n.length;for(;t<r;t++)if(e===n[t])return!0}return!1},empty:function(){return n=[],this},disable:function(){return n=r=i=t,this},disabled:function(){return!n},lock:function(){return r=t,(!i||i===!0)&&v.disable(),this},locked:function(){return!r},fireWith:function(t,n){return r&&(f?e.once||r.push([t,n]):(!e.once||!i)&&d(t,n)),this},fire:function(){return v.fireWith(this,arguments),this},fired:function(){return!!a}};return v};var a=[].slice;s.extend({Deferred:function(e){var t=s.Callbacks("once memory"),n=s.Callbacks("once memory"),r=s.Callbacks("memory"),i="pending",o={resolve:t,reject:n,notify:r},u={done:t.add,fail:n.add,progress:r.add,state:function(){return i},isResolved:t.fired,isRejected:n.fired,then:function(e,t,n){return a.done(e).fail(t).progress(n),this},always:function(){return a.done.apply(a,arguments).fail.apply(a,arguments),this},pipe:function(e,t,n){return s.Deferred(function(r){s.each({done:[e,"resolve"],fail:[t,"reject"],progress:[n,"notify"]},function(e,t){var n=t[0],i=t[1],o;s.isFunction(n)?a[e](function(){o=n.apply(this,arguments),o&&s.isFunction(o.promise)?o.promise().then(r.resolve,r.reject,r.notify):r[i+"With"](this===a?r:this,[o])}):a[e](r[i])})}).promise()},promise:function(e){if(e==null)e=u;else for(var t in u)e[t]=u[t];return e}},a=u.promise({}),f;for(f in o)a[f]=o[f].fire,a[f+"With"]=o[f].fireWith;return a.done(function(){i="resolved"},n.disable,r.lock).fail(function(){i="rejected"},t.disable,r.lock),e&&e.call(a,a),a},when:function(e){function c(e){return function(n){t[e]=arguments.length>1?a.call(arguments,0):n,--o||f.resolveWith(f,t)}}function h(e){return function(t){i[e]=arguments.length>1?a.call(arguments,0):t,f.notifyWith(l,i)}}var t=a.call(arguments,0),n=0,r=t.length,i=Array(r),o=r,u=r,f=r<=1&&e&&s.isFunction(e.promise)?e:s.Deferred(),l=f.promise();if(r>1){for(;n<r;n++)t[n]&&t[n].promise&&s.isFunction(t[n].promise)?t[n].promise().then(c(n),f.reject,h(n)):--o;o||f.resolveWith(f,t)}else f!==e&&f.resolveWith(f,r?[e]:[]);return l}}),s.support=function(){var t,r,i,o,u,a,f,l,c,h,p,d,v=n.createElement("div"),m=n.documentElement;v.setAttribute("className","t"),v.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",r=v.getElementsByTagName("*"),i=v.getElementsByTagName("a")[0];if(!r||!r.length||!i)return{};o=n.createElement("select"),u=o.appendChild(n.createElement("option")),a=v.getElementsByTagName("input")[0],t={leadingWhitespace:v.firstChild.nodeType===3,tbody:!v.getElementsByTagName("tbody").length,htmlSerialize:!!v.getElementsByTagName("link").length,style:/top/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:a.value==="on",optSelected:u.selected,getSetAttribute:v.className!=="t",enctype:!!n.createElement("form").enctype,html5Clone:n.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0,pixelMargin:!0},s.boxModel=t.boxModel=n.compatMode==="CSS1Compat",a.checked=!0,t.noCloneChecked=a.cloneNode(!0).checked,o.disabled=!0,t.optDisabled=!u.disabled;try{delete v.test}catch(g){t.deleteExpando=!1}!v.addEventListener&&v.attachEvent&&v.fireEvent&&(v.attachEvent("onclick",function(){t.noCloneEvent=!1}),v.cloneNode(!0).fireEvent("onclick")),a=n.createElement("input"),a.value="t",a.setAttribute("type","radio"),t.radioValue=a.value==="t",a.setAttribute("checked","checked"),a.setAttribute("name","t"),v.appendChild(a),f=n.createDocumentFragment(),f.appendChild(v.lastChild),t.checkClone=f.cloneNode(!0).cloneNode(!0).lastChild.checked,t.appendChecked=a.checked,f.removeChild(a),f.appendChild(v);if(v.attachEvent)for(p in{submit:1,change:1,focusin:1})h="on"+p,d=h in v,d||(v.setAttribute(h,"return;"),d=typeof v[h]=="function"),t[p+"Bubbles"]=d;return f.removeChild(v),f=o=u=v=a=null,s(function(){var r,i,o,u,a,f,c,h,p,m,g,y,b,w=n.getElementsByTagName("body")[0];if(!w)return;h=1,b="padding:0;margin:0;border:",g="position:absolute;top:0;left:0;width:1px;height:1px;",y=b+"0;visibility:hidden;",p="style='"+g+b+"5px solid #000;",m="<div "+p+"display:block;'><div style='"+b+"0;display:block;overflow:hidden;'></div></div>"+"<table "+p+"' cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",r=n.createElement("div"),r.style.cssText=y+"width:0;height:0;position:static;top:0;margin-top:"+h+"px",w.insertBefore(r,w.firstChild),v=n.createElement("div"),r.appendChild(v),v.innerHTML="<table><tr><td style='"+b+"0;display:none'></td><td>t</td></tr></table>",l=v.getElementsByTagName("td"),d=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",t.reliableHiddenOffsets=d&&l[0].offsetHeight===0,e.getComputedStyle&&(v.innerHTML="",c=n.createElement("div"),c.style.width="0",c.style.marginRight="0",v.style.width="2px",v.appendChild(c),t.reliableMarginRight=(parseInt((e.getComputedStyle(c,null)||{marginRight:0}).marginRight,10)||0)===0),typeof v.style.zoom!="undefined"&&(v.innerHTML="",v.style.width=v.style.padding="1px",v.style.border=0,v.style.overflow="hidden",v.style.display="inline",v.style.zoom=1,t.inlineBlockNeedsLayout=v.offsetWidth===3,v.style.display="block",v.style.overflow="visible",v.innerHTML="<div style='width:5px;'></div>",t.shrinkWrapBlocks=v.offsetWidth!==3),v.style.cssText=g+y,v.innerHTML=m,i=v.firstChild,o=i.firstChild,a=i.nextSibling.firstChild.firstChild,f={doesNotAddBorder:o.offsetTop!==5,doesAddBorderForTableAndCells:a.offsetTop===5},o.style.position="fixed",o.style.top="20px",f.fixedPosition=o.offsetTop===20||o.offsetTop===15,o.style.position=o.style.top="",i.style.overflow="hidden",i.style.position="relative",f.subtractsBorderForOverflowNotVisible=o.offsetTop===-5,f.doesNotIncludeMarginInBodyOffset=w.offsetTop!==h,e.getComputedStyle&&(v.style.marginTop="1%",t.pixelMargin=(e.getComputedStyle(v,null)||{marginTop:0}).marginTop!=="1%"),typeof r.style.zoom!="undefined"&&(r.style.zoom=1),w.removeChild(r),c=v=r=null,s.extend(t,f)}),t}();var f=/^(?:\{.*\}|\[.*\])$/,l=/([A-Z])/g;s.extend({cache:{},uuid:0,expando:"jQuery"+(s.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(e){return e=e.nodeType?s.cache[e[s.expando]]:e[s.expando],!!e&&!h(e)},data:function(e,n,r,i){if(!s.acceptData(e))return;var o,u,a,f=s.expando,l=typeof n=="string",c=e.nodeType,h=c?s.cache:e,p=c?e[f]:e[f]&&f,d=n==="events";if((!p||!h[p]||!d&&!i&&!h[p].data)&&l&&r===t)return;p||(c?e[f]=p=++s.uuid:p=f),h[p]||(h[p]={},c||(h[p].toJSON=s.noop));if(typeof n=="object"||typeof n=="function")i?h[p]=s.extend(h[p],n):h[p].data=s.extend(h[p].data,n);return o=u=h[p],i||(u.data||(u.data={}),u=u.data),r!==t&&(u[s.camelCase(n)]=r),d&&!u[n]?o.events:(l?(a=u[n],a==null&&(a=u[s.camelCase(n)])):a=u,a)},removeData:function(e,t,n){if(!s.acceptData(e))return;var r,i,o,u=s.expando,a=e.nodeType,f=a?s.cache:e,l=a?e[u]:u;if(!f[l])return;if(t){r=n?f[l]:f[l].data;if(r){s.isArray(t)||(t in r?t=[t]:(t=s.camelCase(t),t in r?t=[t]:t=t.split(" ")));for(i=0,o=t.length;i<o;i++)delete r[t[i]];if(!(n?h:s.isEmptyObject)(r))return}}if(!n){delete f[l].data;if(!h(f[l]))return}s.support.deleteExpando||!f.setInterval?delete f[l]:f[l]=null,a&&(s.support.deleteExpando?delete e[u]:e.removeAttribute?e.removeAttribute(u):e[u]=null)},_data:function(e,t,n){return s.data(e,t,n,!0)},acceptData:function(e){if(e.nodeName){var t=s.noData[e.nodeName.toLowerCase()];if(t)return t!==!0&&e.getAttribute("classid")===t}return!0}}),s.fn.extend({data:function(e,n){var r,i,o,u,a,f=this[0],l=0,h=null;if(e===t){if(this.length){h=s.data(f);if(f.nodeType===1&&!s._data(f,"parsedAttrs")){o=f.attributes;for(a=o.length;l<a;l++)u=o[l].name,u.indexOf("data-")===0&&(u=s.camelCase(u.substring(5)),c(f,u,h[u]));s._data(f,"parsedAttrs",!0)}}return h}return typeof e=="object"?this.each(function(){s.data(this,e)}):(r=e.split(".",2),r[1]=r[1]?"."+r[1]:"",i=r[1]+"!",s.access(this,function(n){if(n===t)return h=this.triggerHandler("getData"+i,[r[0]]),h===t&&f&&(h=s.data(f,e),h=c(f,e,h)),h===t&&r[1]?this.data(r[0]):h;r[1]=n,this.each(function(){var t=s(this);t.triggerHandler("setData"+i,r),s.data(this,e,n),t.triggerHandler("changeData"+i,r)})},null,n,arguments.length>1,null,!1))},removeData:function(e){return this.each(function(){s.removeData(this,e)})}}),s.extend({_mark:function(e,t){e&&(t=(t||"fx")+"mark",s._data(e,t,(s._data(e,t)||0)+1))},_unmark:function(e,t,n){e!==!0&&(n=t,t=e,e=!1);if(t){n=n||"fx";var r=n+"mark",i=e?0:(s._data(t,r)||1)-1;i?s._data(t,r,i):(s.removeData(t,r,!0),p(t,n,"mark"))}},queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=s._data(e,t),n&&(!r||s.isArray(n)?r=s._data(e,t,s.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=s.queue(e,t),r=n.shift(),i={};r==="inprogress"&&(r=n.shift()),r&&(t==="fx"&&n.unshift("inprogress"),s._data(e,t+".run",i),r.call(e,function(){s.dequeue(e,t)},i)),n.length||(s.removeData(e,t+"queue "+t+".run",!0),p(e,t,"queue"))}}),s.fn.extend({queue:function(e,n){var r=2;return typeof e!="string"&&(n=e,e="fx",r--),arguments.length<r?s.queue(this[0],e):n===t?this:this.each(function(){var t=s.queue(this,e,n);e==="fx"&&t[0]!=="inprogress"&&s.dequeue(this,e)})},dequeue:function(e){return this.each(function(){s.dequeue(this,e)})},delay:function(e,t){return e=s.fx?s.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,n){function h(){--u||r.resolveWith(i,[i])}typeof e!="string"&&(n=e,e=t),e=e||"fx";var r=s.Deferred(),i=this,o=i.length,u=1,a=e+"defer",f=e+"queue",l=e+"mark",c;while(o--)if(c=s.data(i[o],a,t,!0)||(s.data(i[o],f,t,!0)||s.data(i[o],l,t,!0))&&s.data(i[o],a,s.Callbacks("once memory"),!0))u++,c.add(h);return h(),r.promise(n)}});var d=/[\n\t\r]/g,v=/\s+/,m=/\r/g,g=/^(?:button|input)$/i,y=/^(?:button|input|object|select|textarea)$/i,b=/^a(?:rea)?$/i,w=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,E=s.support.getSetAttribute,S,x,T;s.fn.extend({attr:function(e,t){return s.access(this,s.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){s.removeAttr(this,e)})},prop:function(e,t){return s.access(this,s.prop,e,t,arguments.length>1)},removeProp:function(e){return e=s.propFix[e]||e,this.each(function(){try{this[e]=t,delete this[e]}catch(n){}})},addClass:function(e){var t,n,r,i,o,u,a;if(s.isFunction(e))return this.each(function(t){s(this).addClass(e.call(this,t,this.className))});if(e&&typeof e=="string"){t=e.split(v);for(n=0,r=this.length;n<r;n++){i=this[n];if(i.nodeType===1)if(!i.className&&t.length===1)i.className=e;else{o=" "+i.className+" ";for(u=0,a=t.length;u<a;u++)~o.indexOf(" "+t[u]+" ")||(o+=t[u]+" ");i.className=s.trim(o)}}}return this},removeClass:function(e){var n,r,i,o,u,a,f;if(s.isFunction(e))return this.each(function(t){s(this).removeClass(e.call(this,t,this.className))});if(e&&typeof e=="string"||e===t){n=(e||"").split(v);for(r=0,i=this.length;r<i;r++){o=this[r];if(o.nodeType===1&&o.className)if(e){u=(" "+o.className+" ").replace(d," ");for(a=0,f=n.length;a<f;a++)u=u.replace(" "+n[a]+" "," ");o.className=s.trim(u)}else o.className=""}}return this},toggleClass:function(e,t){var n=typeof e,r=typeof t=="boolean";return s.isFunction(e)?this.each(function(n){s(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if(n==="string"){var i,o=0,u=s(this),a=t,f=e.split(v);while(i=f[o++])a=r?a:!u.hasClass(i),u[a?"addClass":"removeClass"](i)}else if(n==="undefined"||n==="boolean")this.className&&s._data(this,"__className__",this.className),this.className=this.className||e===!1?"":s._data(this,"__className__")||""})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;n<r;n++)if(this[n].nodeType===1&&(" "+this[n].className+" ").replace(d," ").indexOf(t)>-1)return!0;return!1},val:function(e){var n,r,i,o=this[0];if(!arguments.length){if(o)return n=s.valHooks[o.type]||s.valHooks[o.nodeName.toLowerCase()],n&&"get"in n&&(r=n.get(o,"value"))!==t?r:(r=o.value,typeof r=="string"?r.replace(m,""):r==null?"":r);return}return i=s.isFunction(e),this.each(function(r){var o=s(this),u;if(this.nodeType!==1)return;i?u=e.call(this,r,o.val()):u=e,u==null?u="":typeof u=="number"?u+="":s.isArray(u)&&(u=s.map(u,function(e){return e==null?"":e+""})),n=s.valHooks[this.type]||s.valHooks[this.nodeName.toLowerCase()];if(!n||!("set"in n)||n.set(this,u,"value")===t)this.value=u})}}),s.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r,i,o=e.selectedIndex,u=[],a=e.options,f=e.type==="select-one";if(o<0)return null;n=f?o:0,r=f?o+1:a.length;for(;n<r;n++){i=a[n];if(i.selected&&(s.support.optDisabled?!i.disabled:i.getAttribute("disabled")===null)&&(!i.parentNode.disabled||!s.nodeName(i.parentNode,"optgroup"))){t=s(i).val();if(f)return t;u.push(t)}}return f&&!u.length&&a.length?s(a[o]).val():u},set:function(e,t){var n=s.makeArray(t);return s(e).find("option").each(function(){this.selected=s.inArray(s(this).val(),n)>=0}),n.length||(e.selectedIndex=-1),n}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(e,n,r,i){var o,u,a,f=e.nodeType;if(!e||f===3||f===8||f===2)return;if(i&&n in s.attrFn)return s(e)[n](r);if(typeof e.getAttribute=="undefined")return s.prop(e,n,r);a=f!==1||!s.isXMLDoc(e),a&&(n=n.toLowerCase(),u=s.attrHooks[n]||(w.test(n)?x:S));if(r!==t){if(r===null){s.removeAttr(e,n);return}return u&&"set"in u&&a&&(o=u.set(e,r,n))!==t?o:(e.setAttribute(n,""+r),r)}return u&&"get"in u&&a&&(o=u.get(e,n))!==null?o:(o=e.getAttribute(n),o===null?t:o)},removeAttr:function(e,t){var n,r,i,o,u,a=0;if(t&&e.nodeType===1){r=t.toLowerCase().split(v),o=r.length;for(;a<o;a++)i=r[a],i&&(n=s.propFix[i]||i,u=w.test(i),u||s.attr(e,i,""),e.removeAttribute(E?i:n),u&&n in e&&(e[n]=!1))}},attrHooks:{type:{set:function(e,t){if(g.test(e.nodeName)&&e.parentNode)s.error("type property can't be changed");else if(!s.support.radioValue&&t==="radio"&&s.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}},value:{get:function(e,t){return S&&s.nodeName(e,"button")?S.get(e,t):t in e?e.value:null},set:function(e,t,n){if(S&&s.nodeName(e,"button"))return S.set(e,t,n);e.value=t}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(e,n,r){var i,o,u,a=e.nodeType;if(!e||a===3||a===8||a===2)return;return u=a!==1||!s.isXMLDoc(e),u&&(n=s.propFix[n]||n,o=s.propHooks[n]),r!==t?o&&"set"in o&&(i=o.set(e,r,n))!==t?i:e[n]=r:o&&"get"in o&&(i=o.get(e,n))!==null?i:e[n]},propHooks:{tabIndex:{get:function(e){var n=e.getAttributeNode("tabindex");return n&&n.specified?parseInt(n.value,10):y.test(e.nodeName)||b.test(e.nodeName)&&e.href?0:t}}}}),s.attrHooks.tabindex=s.propHooks.tabIndex,x={get:function(e,n){var r,i=s.prop(e,n);return i===!0||typeof i!="boolean"&&(r=e.getAttributeNode(n))&&r.nodeValue!==!1?n.toLowerCase():t},set:function(e,t,n){var r;return t===!1?s.removeAttr(e,n):(r=s.propFix[n]||n,r in e&&(e[r]=!0),e.setAttribute(n,n.toLowerCase())),n}},E||(T={name:!0,id:!0,coords:!0},S=s.valHooks.button={get:function(e,n){var r;return r=e.getAttributeNode(n),r&&(T[n]?r.nodeValue!=="":r.specified)?r.nodeValue:t},set:function(e,t,r){var i=e.getAttributeNode(r);return i||(i=n.createAttribute(r),e.setAttributeNode(i)),i.nodeValue=t+""}},s.attrHooks.tabindex.set=S.set,s.each(["width","height"],function(e,t){s.attrHooks[t]=s.extend(s.attrHooks[t],{set:function(e,n){if(n==="")return e.setAttribute(t,"auto"),n}})}),s.attrHooks.contenteditable={get:S.get,set:function(e,t,n){t===""&&(t="false"),S.set(e,t,n)}}),s.support.hrefNormalized||s.each(["href","src","width","height"],function(e,n){s.attrHooks[n]=s.extend(s.attrHooks[n],{get:function(e){var r=e.getAttribute(n,2);return r===null?t:r}})}),s.support.style||(s.attrHooks.style={get:function(e){return e.style.cssText.toLowerCase()||t},set:function(e,t){return e.style.cssText=""+t}}),s.support.optSelected||(s.propHooks.selected=s.extend(s.propHooks.selected,{get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null}})),s.support.enctype||(s.propFix.enctype="encoding"),s.support.checkOn||s.each(["radio","checkbox"],function(){s.valHooks[this]={get:function(e){return e.getAttribute("value")===null?"on":e.value}}}),s.each(["radio","checkbox"],function(){s.valHooks[this]=s.extend(s.valHooks[this],{set:function(e,t){if(s.isArray(t))return e.checked=s.inArray(s(e).val(),t)>=0}})});var N=/^(?:textarea|input|select)$/i,C=/^([^\.]*)?(?:\.(.+))?$/,k=/(?:^|\s)hover(\.\S+)?\b/,L=/^key/,A=/^(?:mouse|contextmenu)|click/,O=/^(?:focusinfocus|focusoutblur)$/,M=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,_=function(e){var t=M.exec(e);return t&&(t[1]=(t[1]||"").toLowerCase(
+),t[3]=t[3]&&RegExp("(?:^|\\s)"+t[3]+"(?:\\s|$)")),t},D=function(e,t){var n=e.attributes||{};return(!t[1]||e.nodeName.toLowerCase()===t[1])&&(!t[2]||(n.id||{}).value===t[2])&&(!t[3]||t[3].test((n["class"]||{}).value))},P=function(e){return s.event.special.hover?e:e.replace(k,"mouseenter$1 mouseleave$1")};s.event={add:function(e,n,r,i,o){var u,a,f,l,c,h,p,d,v,m,g,y;if(e.nodeType===3||e.nodeType===8||!n||!r||!(u=s._data(e)))return;r.handler&&(v=r,r=v.handler,o=v.selector),r.guid||(r.guid=s.guid++),f=u.events,f||(u.events=f={}),a=u.handle,a||(u.handle=a=function(e){return typeof s=="undefined"||!!e&&s.event.triggered===e.type?t:s.event.dispatch.apply(a.elem,arguments)},a.elem=e),n=s.trim(P(n)).split(" ");for(l=0;l<n.length;l++){c=C.exec(n[l])||[],h=c[1],p=(c[2]||"").split(".").sort(),y=s.event.special[h]||{},h=(o?y.delegateType:y.bindType)||h,y=s.event.special[h]||{},d=s.extend({type:h,origType:c[1],data:i,handler:r,guid:r.guid,selector:o,quick:o&&_(o),namespace:p.join(".")},v),g=f[h];if(!g){g=f[h]=[],g.delegateCount=0;if(!y.setup||y.setup.call(e,i,p,a)===!1)e.addEventListener?e.addEventListener(h,a,!1):e.attachEvent&&e.attachEvent("on"+h,a)}y.add&&(y.add.call(e,d),d.handler.guid||(d.handler.guid=r.guid)),o?g.splice(g.delegateCount++,0,d):g.push(d),s.event.global[h]=!0}e=null},global:{},remove:function(e,t,n,r,i){var o=s.hasData(e)&&s._data(e),u,a,f,l,c,h,p,d,v,m,g,y;if(!o||!(d=o.events))return;t=s.trim(P(t||"")).split(" ");for(u=0;u<t.length;u++){a=C.exec(t[u])||[],f=l=a[1],c=a[2];if(!f){for(f in d)s.event.remove(e,f+t[u],n,r,!0);continue}v=s.event.special[f]||{},f=(r?v.delegateType:v.bindType)||f,g=d[f]||[],h=g.length,c=c?RegExp("(^|\\.)"+c.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(p=0;p<g.length;p++)y=g[p],(i||l===y.origType)&&(!n||n.guid===y.guid)&&(!c||c.test(y.namespace))&&(!r||r===y.selector||r==="**"&&y.selector)&&(g.splice(p--,1),y.selector&&g.delegateCount--,v.remove&&v.remove.call(e,y));g.length===0&&h!==g.length&&((!v.teardown||v.teardown.call(e,c)===!1)&&s.removeEvent(e,f,o.handle),delete d[f])}s.isEmptyObject(d)&&(m=o.handle,m&&(m.elem=null),s.removeData(e,["events","handle"],!0))},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(n,r,i,o){if(!i||i.nodeType!==3&&i.nodeType!==8){var u=n.type||n,a=[],f,l,c,h,p,d,v,m,g,y;if(O.test(u+s.event.triggered))return;u.indexOf("!")>=0&&(u=u.slice(0,-1),l=!0),u.indexOf(".")>=0&&(a=u.split("."),u=a.shift(),a.sort());if((!i||s.event.customEvent[u])&&!s.event.global[u])return;n=typeof n=="object"?n[s.expando]?n:new s.Event(u,n):new s.Event(u),n.type=u,n.isTrigger=!0,n.exclusive=l,n.namespace=a.join("."),n.namespace_re=n.namespace?RegExp("(^|\\.)"+a.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,d=u.indexOf(":")<0?"on"+u:"";if(!i){f=s.cache;for(c in f)f[c].events&&f[c].events[u]&&s.event.trigger(n,r,f[c].handle.elem,!0);return}n.result=t,n.target||(n.target=i),r=r!=null?s.makeArray(r):[],r.unshift(n),v=s.event.special[u]||{};if(v.trigger&&v.trigger.apply(i,r)===!1)return;g=[[i,v.bindType||u]];if(!o&&!v.noBubble&&!s.isWindow(i)){y=v.delegateType||u,h=O.test(y+u)?i:i.parentNode,p=null;for(;h;h=h.parentNode)g.push([h,y]),p=h;p&&p===i.ownerDocument&&g.push([p.defaultView||p.parentWindow||e,y])}for(c=0;c<g.length&&!n.isPropagationStopped();c++)h=g[c][0],n.type=g[c][1],m=(s._data(h,"events")||{})[n.type]&&s._data(h,"handle"),m&&m.apply(h,r),m=d&&h[d],m&&s.acceptData(h)&&m.apply(h,r)===!1&&n.preventDefault();return n.type=u,!o&&!n.isDefaultPrevented()&&(!v._default||v._default.apply(i.ownerDocument,r)===!1)&&(u!=="click"||!s.nodeName(i,"a"))&&s.acceptData(i)&&d&&i[u]&&(u!=="focus"&&u!=="blur"||n.target.offsetWidth!==0)&&!s.isWindow(i)&&(p=i[d],p&&(i[d]=null),s.event.triggered=u,i[u](),s.event.triggered=t,p&&(i[d]=p)),n.result}return},dispatch:function(n){n=s.event.fix(n||e.event);var r=(s._data(this,"events")||{})[n.type]||[],i=r.delegateCount,o=[].slice.call(arguments,0),u=!n.exclusive&&!n.namespace,a=s.event.special[n.type]||{},f=[],l,c,h,p,d,v,m,g,y,b,w;o[0]=n,n.delegateTarget=this;if(a.preDispatch&&a.preDispatch.call(this,n)===!1)return;if(i&&(!n.button||n.type!=="click")){p=s(this),p.context=this.ownerDocument||this;for(h=n.target;h!=this;h=h.parentNode||this)if(h.disabled!==!0){v={},g=[],p[0]=h;for(l=0;l<i;l++)y=r[l],b=y.selector,v[b]===t&&(v[b]=y.quick?D(h,y.quick):p.is(b)),v[b]&&g.push(y);g.length&&f.push({elem:h,matches:g})}}r.length>i&&f.push({elem:this,matches:r.slice(i)});for(l=0;l<f.length&&!n.isPropagationStopped();l++){m=f[l],n.currentTarget=m.elem;for(c=0;c<m.matches.length&&!n.isImmediatePropagationStopped();c++){y=m.matches[c];if(u||!n.namespace&&!y.namespace||n.namespace_re&&n.namespace_re.test(y.namespace))n.data=y.data,n.handleObj=y,d=((s.event.special[y.origType]||{}).handle||y.handler).apply(m.elem,o),d!==t&&(n.result=d,d===!1&&(n.preventDefault(),n.stopPropagation()))}}return a.postDispatch&&a.postDispatch.call(this,n),n.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return e.which==null&&(e.which=t.charCode!=null?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,r){var i,s,o,u=r.button,a=r.fromElement;return e.pageX==null&&r.clientX!=null&&(i=e.target.ownerDocument||n,s=i.documentElement,o=i.body,e.pageX=r.clientX+(s&&s.scrollLeft||o&&o.scrollLeft||0)-(s&&s.clientLeft||o&&o.clientLeft||0),e.pageY=r.clientY+(s&&s.scrollTop||o&&o.scrollTop||0)-(s&&s.clientTop||o&&o.clientTop||0)),!e.relatedTarget&&a&&(e.relatedTarget=a===e.target?r.toElement:a),!e.which&&u!==t&&(e.which=u&1?1:u&2?3:u&4?2:0),e}},fix:function(e){if(e[s.expando])return e;var r,i,o=e,u=s.event.fixHooks[e.type]||{},a=u.props?this.props.concat(u.props):this.props;e=s.Event(o);for(r=a.length;r;)i=a[--r],e[i]=o[i];return e.target||(e.target=o.srcElement||n),e.target.nodeType===3&&(e.target=e.target.parentNode),e.metaKey===t&&(e.metaKey=e.ctrlKey),u.filter?u.filter(e,o):e},special:{ready:{setup:s.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(e,t,n){s.isWindow(this)&&(this.onbeforeunload=n)},teardown:function(e,t){this.onbeforeunload===t&&(this.onbeforeunload=null)}}},simulate:function(e,t,n,r){var i=s.extend(new s.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?s.event.trigger(i,null,t):s.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},s.event.handle=s.event.dispatch,s.removeEvent=n.removeEventListener?function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)}:function(e,t,n){e.detachEvent&&e.detachEvent("on"+t,n)},s.Event=function(e,t){if(!(this instanceof s.Event))return new s.Event(e,t);e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.returnValue===!1||e.getPreventDefault&&e.getPreventDefault()?B:H):this.type=e,t&&s.extend(this,t),this.timeStamp=e&&e.timeStamp||s.now(),this[s.expando]=!0},s.Event.prototype={preventDefault:function(){this.isDefaultPrevented=B;var e=this.originalEvent;if(!e)return;e.preventDefault?e.preventDefault():e.returnValue=!1},stopPropagation:function(){this.isPropagationStopped=B;var e=this.originalEvent;if(!e)return;e.stopPropagation&&e.stopPropagation(),e.cancelBubble=!0},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=B,this.stopPropagation()},isDefaultPrevented:H,isPropagationStopped:H,isImmediatePropagationStopped:H},s.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){s.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n=this,r=e.relatedTarget,i=e.handleObj,o=i.selector,u;if(!r||r!==n&&!s.contains(n,r))e.type=i.origType,u=i.handler.apply(this,arguments),e.type=t;return u}}}),s.support.submitBubbles||(s.event.special.submit={setup:function(){if(s.nodeName(this,"form"))return!1;s.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=s.nodeName(n,"input")||s.nodeName(n,"button")?n.form:t;r&&!r._submit_attached&&(s.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),r._submit_attached=!0)})},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&s.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){if(s.nodeName(this,"form"))return!1;s.event.remove(this,"._submit")}}),s.support.changeBubbles||(s.event.special.change={setup:function(){if(N.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")s.event.add(this,"propertychange._change",function(e){e.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),s.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1,s.event.simulate("change",this,e,!0))});return!1}s.event.add(this,"beforeactivate._change",function(e){var t=e.target;N.test(t.nodeName)&&!t._change_attached&&(s.event.add(t,"change._change",function(e){this.parentNode&&!e.isSimulated&&!e.isTrigger&&s.event.simulate("change",this.parentNode,e,!0)}),t._change_attached=!0)})},handle:function(e){var t=e.target;if(this!==t||e.isSimulated||e.isTrigger||t.type!=="radio"&&t.type!=="checkbox")return e.handleObj.handler.apply(this,arguments)},teardown:function(){return s.event.remove(this,"._change"),N.test(this.nodeName)}}),s.support.focusinBubbles||s.each({focus:"focusin",blur:"focusout"},function(e,t){var r=0,i=function(e){s.event.simulate(t,e.target,s.event.fix(e),!0)};s.event.special[t]={setup:function(){r++===0&&n.addEventListener(e,i,!0)},teardown:function(){--r===0&&n.removeEventListener(e,i,!0)}}}),s.fn.extend({on:function(e,n,r,i,o){var u,a;if(typeof e=="object"){typeof n!="string"&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}r==null&&i==null?(i=n,r=n=t):i==null&&(typeof n=="string"?(i=r,r=t):(i=r,r=n,n=t));if(i===!1)i=H;else if(!i)return this;return o===1&&(u=i,i=function(e){return s().off(e),u.apply(this,arguments)},i.guid=u.guid||(u.guid=s.guid++)),this.each(function(){s.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){if(e&&e.preventDefault&&e.handleObj){var i=e.handleObj;return s(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this}if(typeof e=="object"){for(var o in e)this.off(o,n,e[o]);return this}if(n===!1||typeof n=="function")r=n,n=t;return r===!1&&(r=H),this.each(function(){s.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},live:function(e,t,n){return s(this.context).on(e,this.selector,t,n),this},die:function(e,t){return s(this.context).off(e,this.selector||"**",t),this},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return arguments.length==1?this.off(e,"**"):this.off(t,e,n)},trigger:function(e,t){return this.each(function(){s.event.trigger(e,t,this)})},triggerHandler:function(e,t){if(this[0])return s.event.trigger(e,t,this[0],!0)},toggle:function(e){var t=arguments,n=e.guid||s.guid++,r=0,i=function(n){var i=(s._data(this,"lastToggle"+e.guid)||0)%r;return s._data(this,"lastToggle"+e.guid,i+1),n.preventDefault(),t[i].apply(this,arguments)||!1};i.guid=n;while(r<t.length)t[r++].guid=n;return this.click(i)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),s.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){s.fn[t]=function(e,n){return n==null&&(n=e,e=null),arguments.length>0?this.on(t,null,e,n):this.trigger(t)},s.attrFn&&(s.attrFn[t]=!0),L.test(t)&&(s.event.fixHooks[t]=s.event.keyHooks),A.test(t)&&(s.event.fixHooks[t]=s.event.mouseHooks)}),function(){function S(e,t,n,i,s,o){for(var u=0,a=i.length;u<a;u++){var f=i[u];if(f){var l=!1;f=f[e];while(f){if(f[r]===n){l=i[f.sizset];break}f.nodeType===1&&!o&&(f[r]=n,f.sizset=u);if(f.nodeName.toLowerCase()===t){l=f;break}f=f[e]}i[u]=l}}}function x(e,t,n,i,s,o){for(var u=0,a=i.length;u<a;u++){var f=i[u];if(f){var l=!1;f=f[e];while(f){if(f[r]===n){l=i[f.sizset];break}if(f.nodeType===1){o||(f[r]=n,f.sizset=u);if(typeof t!="string"){if(f===t){l=!0;break}}else if(h.filter(t,[f]).length>0){l=f;break}}f=f[e]}i[u]=l}}}var e=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,r="sizcache"+(Math.random()+"").replace(".",""),i=0,o=Object.prototype.toString,u=!1,a=!0,f=/\\/g,l=/\r\n/g,c=/\W/;[0,0].sort(function(){return a=!1,0});var h=function(t,r,i,s){i=i||[],r=r||n;var u=r;if(r.nodeType!==1&&r.nodeType!==9)return[];if(!t||typeof t!="string")return i;var a,f,l,c,p,m,g,b,w=!0,E=h.isXML(r),S=[],x=t;do{e.exec(""),a=e.exec(x);if(a){x=a[3],S.push(a[1]);if(a[2]){c=a[3];break}}}while(a);if(S.length>1&&v.exec(t))if(S.length===2&&d.relative[S[0]])f=T(S[0]+S[1],r,s);else{f=d.relative[S[0]]?[r]:h(S.shift(),r);while(S.length)t=S.shift(),d.relative[t]&&(t+=S.shift()),f=T(t,f,s)}else{!s&&S.length>1&&r.nodeType===9&&!E&&d.match.ID.test(S[0])&&!d.match.ID.test(S[S.length-1])&&(p=h.find(S.shift(),r,E),r=p.expr?h.filter(p.expr,p.set)[0]:p.set[0]);if(r){p=s?{expr:S.pop(),set:y(s)}:h.find(S.pop(),S.length!==1||S[0]!=="~"&&S[0]!=="+"||!r.parentNode?r:r.parentNode,E),f=p.expr?h.filter(p.expr,p.set):p.set,S.length>0?l=y(f):w=!1;while(S.length)m=S.pop(),g=m,d.relative[m]?g=S.pop():m="",g==null&&(g=r),d.relative[m](l,g,E)}else l=S=[]}l||(l=f),l||h.error(m||t);if(o.call(l)==="[object Array]")if(!w)i.push.apply(i,l);else if(r&&r.nodeType===1)for(b=0;l[b]!=null;b++)l[b]&&(l[b]===!0||l[b].nodeType===1&&h.contains(r,l[b]))&&i.push(f[b]);else for(b=0;l[b]!=null;b++)l[b]&&l[b].nodeType===1&&i.push(f[b]);else y(l,i);return c&&(h(c,u,i,s),h.uniqueSort(i)),i};h.uniqueSort=function(e){if(w){u=a,e.sort(w);if(u)for(var t=1;t<e.length;t++)e[t]===e[t-1]&&e.splice(t--,1)}return e},h.matches=function(e,t){return h(e,null,null,t)},h.matchesSelector=function(e,t){return h(t,null,null,[e]).length>0},h.find=function(e,t,n){var r,i,s,o,u,a;if(!e)return[];for(i=0,s=d.order.length;i<s;i++){u=d.order[i];if(o=d.leftMatch[u].exec(e)){a=o[1],o.splice(1,1);if(a.substr(a.length-1)!=="\\"){o[1]=(o[1]||"").replace(f,""),r=d.find[u](o,t,n);if(r!=null){e=e.replace(d.match[u],"");break}}}}return r||(r=typeof t.getElementsByTagName!="undefined"?t.getElementsByTagName("*"):[]),{set:r,expr:e}},h.filter=function(e,n,r,i){var s,o,u,a,f,l,c,p,v,m=e,g=[],y=n,b=n&&n[0]&&h.isXML(n[0]);while(e&&n.length){for(u in d.filter)if((s=d.leftMatch[u].exec(e))!=null&&s[2]){l=d.filter[u],c=s[1],o=!1,s.splice(1,1);if(c.substr(c.length-1)==="\\")continue;y===g&&(g=[]);if(d.preFilter[u]){s=d.preFilter[u](s,y,r,g,i,b);if(!s)o=a=!0;else if(s===!0)continue}if(s)for(p=0;(f=y[p])!=null;p++)f&&(a=l(f,s,p,y),v=i^a,r&&a!=null?v?o=!0:y[p]=!1:v&&(g.push(f),o=!0));if(a!==t){r||(y=g),e=e.replace(d.match[u],"");if(!o)return[];break}}if(e===m){if(o!=null)break;h.error(e)}m=e}return y},h.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)};var p=h.getText=function(e){var t,n,r=e.nodeType,i="";if(r){if(r===1||r===9||r===11){if(typeof e.textContent=="string")return e.textContent;if(typeof e.innerText=="string")return e.innerText.replace(l,"");for(e=e.firstChild;e;e=e.nextSibling)i+=p(e)}else if(r===3||r===4)return e.nodeValue}else for(t=0;n=e[t];t++)n.nodeType!==8&&(i+=p(n));return i},d=h.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(e){return e.getAttribute("href")},type:function(e){return e.getAttribute("type")}},relative:{"+":function(e,t){var n=typeof t=="string",r=n&&!c.test(t),i=n&&!r;r&&(t=t.toLowerCase());for(var s=0,o=e.length,u;s<o;s++)if(u=e[s]){while((u=u.previousSibling)&&u.nodeType!==1);e[s]=i||u&&u.nodeName.toLowerCase()===t?u||!1:u===t}i&&h.filter(t,e,!0)},">":function(e,t){var n,r=typeof t=="string",i=0,s=e.length;if(r&&!c.test(t)){t=t.toLowerCase();for(;i<s;i++){n=e[i];if(n){var o=n.parentNode;e[i]=o.nodeName.toLowerCase()===t?o:!1}}}else{for(;i<s;i++)n=e[i],n&&(e[i]=r?n.parentNode:n.parentNode===t);r&&h.filter(t,e,!0)}},"":function(e,t,n){var r,s=i++,o=x;typeof t=="string"&&!c.test(t)&&(t=t.toLowerCase(),r=t,o=S),o("parentNode",t,s,e,r,n)},"~":function(e,t,n){var r,s=i++,o=x;typeof t=="string"&&!c.test(t)&&(t=t.toLowerCase(),r=t,o=S),o("previousSibling",t,s,e,r,n)}},find:{ID:function(e,t,n){if(typeof t.getElementById!="undefined"&&!n){var r=t.getElementById(e[1]);return r&&r.parentNode?[r]:[]}},NAME:function(e,t){if(typeof t.getElementsByName!="undefined"){var n=[],r=t.getElementsByName(e[1]);for(var i=0,s=r.length;i<s;i++)r[i].getAttribute("name")===e[1]&&n.push(r[i]);return n.length===0?null:n}},TAG:function(e,t){if(typeof t.getElementsByTagName!="undefined")return t.getElementsByTagName(e[1])}},preFilter:{CLASS:function(e,t,n,r,i,s){e=" "+e[1].replace(f,"")+" ";if(s)return e;for(var o=0,u;(u=t[o])!=null;o++)u&&(i^(u.className&&(" "+u.className+" ").replace(/[\t\n\r]/g," ").indexOf(e)>=0)?n||r.push(u):n&&(t[o]=!1));return!1},ID:function(e){return e[1].replace(f,"")},TAG:function(e,t){return e[1].replace(f,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){e[2]||h.error(e[0]),e[2]=e[2].replace(/^\+|\s*/g,"");var t=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=t[1]+(t[2]||1)-0,e[3]=t[3]-0}else e[2]&&h.error(e[0]);return e[0]=i++,e},ATTR:function(e,t,n,r,i,s){var o=e[1]=e[1].replace(f,"");return!s&&d.attrMap[o]&&(e[1]=d.attrMap[o]),e[4]=(e[4]||e[5]||"").replace(f,""),e[2]==="~="&&(e[4]=" "+e[4]+" "),e},PSEUDO:function(t,n,r,i,s){if(t[1]==="not"){if((e.exec(t[3])||"").length<=1&&!/^\w/.test(t[3])){var o=h.filter(t[3],n,r,!0^s);return r||i.push.apply(i,o),!1}t[3]=h(t[3],null,null,n)}else if(d.match.POS.test(t[0])||d.match.CHILD.test(t[0]))return!0;return t},POS:function(e){return e.unshift(!0),e}},filters:{enabled:function(e){return e.disabled===!1&&e.type!=="hidden"},disabled:function(e){return e.disabled===!0},checked:function(e){return e.checked===!0},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},parent:function(e){return!!e.firstChild},empty:function(e){return!e.firstChild},has:function(e,t,n){return!!h(n[3],e).length},header:function(e){return/h\d/i.test(e.nodeName)},text:function(e){var t=e.getAttribute("type"),n=e.type;return e.nodeName.toLowerCase()==="input"&&"text"===n&&(t===n||t===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(e){var t=e.nodeName.toLowerCase();return(t==="input"||t==="button")&&"submit"===e.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(e){var t=e.nodeName.toLowerCase();return(t==="input"||t==="button")&&"reset"===e.type},button:function(e){var t=e.nodeName.toLowerCase();return t==="input"&&"button"===e.type||t==="button"},input:function(e){return/input|select|textarea|button/i.test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(e,t){return t===0},last:function(e,t,n,r){return t===r.length-1},even:function(e,t){return t%2===0},odd:function(e,t){return t%2===1},lt:function(e,t,n){return t<n[3]-0},gt:function(e,t,n){return t>n[3]-0},nth:function(e,t,n){return n[3]-0===t},eq:function(e,t,n){return n[3]-0===t}},filter:{PSEUDO:function(e,t,n,r){var i=t[1],s=d.filters[i];if(s)return s(e,n,t,r);if(i==="contains")return(e.textContent||e.innerText||p([e])||"").indexOf(t[3])>=0;if(i==="not"){var o=t[3];for(var u=0,a=o.length;u<a;u++)if(o[u]===e)return!1;return!0}h.error(i)},CHILD:function(e,t){var n,i,s,o,u,a,f,l=t[1],c=e;switch(l){case"only":case"first":while(c=c.previousSibling)if(c.nodeType===1)return!1;if(l==="first")return!0;c=e;case"last":while(c=c.nextSibling)if(c.nodeType===1)return!1;return!0;case"nth":n=t[2],i=t[3];if(n===1&&i===0)return!0;s=t[0],o=e.parentNode;if(o&&(o[r]!==s||!e.nodeIndex)){a=0;for(c=o.firstChild;c;c=c.nextSibling)c.nodeType===1&&(c.nodeIndex=++a);o[r]=s}return f=e.nodeIndex-i,n===0?f===0:f%n===0&&f/n>=0}},ID:function(e,t){return e.nodeType===1&&e.getAttribute("id")===t},TAG:function(e,t){return t==="*"&&e.nodeType===1||!!e.nodeName&&e.nodeName.toLowerCase()===t},CLASS:function(e,t){return(" "+(e.className||e.getAttribute("class"))+" ").indexOf(t)>-1},ATTR:function(e,t){var n=t[1],r=h.attr?h.attr(e,n):d.attrHandle[n]?d.attrHandle[n](e):e[n]!=null?e[n]:e.getAttribute(n),i=r+"",s=t[2],o=t[4];return r==null?s==="!=":!s&&h.attr?r!=null:s==="="?i===o:s==="*="?i.indexOf(o)>=0:s==="~="?(" "+i+" ").indexOf(o)>=0:o?s==="!="?i!==o:s==="^="?i.indexOf(o)===0:s==="$="?i.substr(i.length-o.length)===o:s==="|="?i===o||i.substr(0,o.length+1)===o+"-":!1:i&&r!==!1},POS:function(e,t,n,r){var i=t[2],s=d.setFilters[i];if(s)return s(e,n,t,r)}}},v=d.match.POS,m=function(e,t){return"\\"+(t-0+1)};for(var g in d.match)d.match[g]=RegExp(d.match[g].source+/(?![^\[]*\])(?![^\(]*\))/.source),d.leftMatch[g]=RegExp(/(^(?:.|\r|\n)*?)/.source+d.match[g].source.replace(/\\(\d+)/g,m));d.match.globalPOS=v;var y=function(e,t){return e=Array.prototype.slice.call(e,0),t?(t.push.apply(t,e),t):e};try{Array.prototype.slice.call(n.documentElement.childNodes,0)[0].nodeType}catch(b){y=function(e,t){var n=0,r=t||[];if(o.call(e)==="[object Array]")Array.prototype.push.apply(r,e);else if(typeof e.length=="number")for(var i=e.length;n<i;n++)r.push(e[n]);else for(;e[n];n++)r.push(e[n]);return r}}var w,E;n.documentElement.compareDocumentPosition?w=function(e,t){return e===t?(u=!0,0):!e.compareDocumentPosition||!t.compareDocumentPosition?e.compareDocumentPosition?-1:1:e.compareDocumentPosition(t)&4?-1:1}:(w=function(e,t){if(e===t)return u=!0,0;if(e.sourceIndex&&t.sourceIndex)return e.sourceIndex-t.sourceIndex;var n,r,i=[],s=[],o=e.parentNode,a=t.parentNode,f=o;if(o===a)return E(e,t);if(!o)return-1;if(!a)return 1;while(f)i.unshift(f),f=f.parentNode;f=a;while(f)s.unshift(f),f=f.parentNode;n=i.length,r=s.length;for(var l=0;l<n&&l<r;l++)if(i[l]!==s[l])return E(i[l],s[l]);return l===n?E(e,s[l],-1):E(i[l],t,1)},E=function(e,t,n){if(e===t)return n;var r=e.nextSibling;while(r){if(r===t)return-1;r=r.nextSibling}return 1}),function(){var e=n.createElement("div"),r="script"+(new Date).getTime(),i=n.documentElement;e.innerHTML="<a name='"+r+"'/>",i.insertBefore(e,i.firstChild),n.getElementById(r)&&(d.find.ID=function(e,n,r){if(typeof n.getElementById!="undefined"&&!r){var i=n.getElementById(e[1]);return i?i.id===e[1]||typeof i.getAttributeNode!="undefined"&&i.getAttributeNode("id").nodeValue===e[1]?[i]:t:[]}},d.filter.ID=function(e,t){var n=typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id");return e.nodeType===1&&n&&n.nodeValue===t}),i.removeChild(e),i=e=null}(),function(){var e=n.createElement("div");e.appendChild(n.createComment("")),e.getElementsByTagName("*").length>0&&(d.find.TAG=function(e,t){var n=t.getElementsByTagName(e[1]);if(e[1]==="*"){var r=[];for(var i=0;n[i];i++)n[i].nodeType===1&&r.push(n[i]);n=r}return n}),e.innerHTML="<a href='#'></a>",e.firstChild&&typeof e.firstChild.getAttribute!="undefined"&&e.firstChild.getAttribute("href")!=="#"&&(d.attrHandle.href=function(e){return e.getAttribute("href",2)}),e=null}(),n.querySelectorAll&&function(){var e=h,t=n.createElement("div"),r="__sizzle__";t.innerHTML="<p class='TEST'></p>";if(t.querySelectorAll&&t.querySelectorAll(".TEST").length===0)return;h=function(t,i,s,o){i=i||n;if(!o&&!h.isXML(i)){var u=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(t);if(u&&(i.nodeType===1||i.nodeType===9)){if(u[1])return y(i.getElementsByTagName(t),s);if(u[2]&&d.find.CLASS&&i.getElementsByClassName)return y(i.getElementsByClassName(u[2]),s)}if(i.nodeType===9){if(t==="body"&&i.body)return y([i.body],s);if(u&&u[3]){var a=i.getElementById(u[3]);if(!a||!a.parentNode)return y([],s);if(a.id===u[3])return y([a],s)}try{return y(i.querySelectorAll(t),s)}catch(f){}}else if(i.nodeType===1&&i.nodeName.toLowerCase()!=="object"){var l=i,c=i.getAttribute("id"),p=c||r,v=i.parentNode,m=/^\s*[+~]/.test(t);c?p=p.replace(/'/g,"\\$&"):i.setAttribute("id",p),m&&v&&(i=i.parentNode);try{if(!m||v)return y(i.querySelectorAll("[id='"+p+"'] "+t),s)}catch(g){}finally{c||l.removeAttribute("id")}}}return e(t,i,s,o)};for(var i in e)h[i]=e[i];t=null}(),function(){var e=n.documentElement,t=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(t){var r=!t.call(n.createElement("div"),"div"),i=!1;try{t.call(n.documentElement,"[test!='']:sizzle")}catch(s){i=!0}h.matchesSelector=function(e,n){n=n.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!h.isXML(e))try{if(i||!d.match.PSEUDO.test(n)&&!/!=/.test(n)){var s=t.call(e,n);if(s||!r||e.document&&e.document.nodeType!==11)return s}}catch(o){}return h(n,null,null,[e]).length>0}}}(),function(){var e=n.createElement("div");e.innerHTML="<div class='test e'></div><div class='test'></div>";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0)return;e.lastChild.className="e";if(e.getElementsByClassName("e").length===1)return;d.order.splice(1,0,"CLASS"),d.find.CLASS=function(e,t,n){if(typeof t.getElementsByClassName!="undefined"&&!n)return t.getElementsByClassName(e[1])},e=null}(),n.documentElement.contains?h.contains=function(e,t){return e!==t&&(e.contains?e.contains(t):!0)}:n.documentElement.compareDocumentPosition?h.contains=function(e,t){return!!(e.compareDocumentPosition(t)&16)}:h.contains=function(){return!1},h.isXML=function(e){var t=(e?e.ownerDocument||e:0).documentElement;return t?t.nodeName!=="HTML":!1};var T=function(e,t,n){var r,i=[],s="",o=t.nodeType?[t]:t;while(r=d.match.PSEUDO.exec(e))s+=r[0],e=e.replace(d.match.PSEUDO,"");e=d.relative[e]?e+"*":e;for(var u=0,a=o.length;u<a;u++)h(e,o[u],i,n);return h.filter(s,i)};h.attr=s.attr,h.selectors.attrMap={},s.find=h,s.expr=h.selectors,s.expr[":"]=s.expr.filters,s.unique=h.uniqueSort,s.text=h.getText,s.isXMLDoc=h.isXML,s.contains=h.contains}();var j=/Until$/,F=/^(?:parents|prevUntil|prevAll)/,I=/,/,q=/^.[^:#\[\.,]*$/,R=Array.prototype.slice,U=s.expr.match.globalPOS,z={children:!0,contents:!0,next:!0,prev:!0};s.fn.extend({find:function(e){var t=this,n,r;if(typeof e!="string")return s(e).filter(function(){for(n=0,r=t.length;n<r;n++)if(s.contains(t[n],this))return!0});var i=this.pushStack("","find",e),o,u,a;for(n=0,r=this.length;n<r;n++){o=i.length,s.find(e,this[n],i);if(n>0)for(u=o;u<i.length;u++)for(a=0;a<o;a++)if(i[a]===i[u]){i.splice(u--,1);break}}return i},has:function(e){var t=s(e);return this.filter(function(){for(var e=0,n=t.length;e<n;e++)if(s.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(X(this,e,!1),"not",e)},filter:function(e){return this.pushStack(X(this,e,!0),"filter",e)},is:function(e){return!!e&&(typeof e=="string"?U.test(e)?s(e,this.context).index(this[0])>=0:s.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n=[],r,i,o=this[0];if(s.isArray(e)){var u=1;while(o&&o.ownerDocument&&o!==t){for(r=0;r<e.length;r++)s(o).is(e[r])&&n.push({selector:e[r],elem:o,level:u});o=o.parentNode,u++}return n}var a=U.test(e)||typeof e!="string"?s(e,t||this.context):0;for(r=0,i=this.length;r<i;r++){o=this[r];while(o){if(a?a.index(o)>-1:s.find.matchesSelector(o,e)){n.push(o);break}o=o.parentNode;if(!o||!o.ownerDocument||o===t||o.nodeType===11)break}}return n=n.length>1?s.unique(n):n,this.pushStack(n,"closest",e)},index:function(e){return e?typeof e=="string"?s.inArray(this[0],s(e)):s.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.prevAll().length:-1},add:function(e,t){var n=typeof e=="string"?s(e,t):s.makeArray(e&&e.nodeType?[e]:e),r=s.merge(this.get(),n);return this.pushStack(W(n[0])||W(r[0])?r:s.unique(r))},andSelf:function(){return this.add(this.prevObject)}}),s.each({parent:function(e){var t=e.parentNode;return t&&t.nodeType!==11?t:null},parents:function(e){return s.dir(e,"parentNode")},parentsUntil:function(e,t,n){return s.dir(e,"parentNode",n)},next:function(e){return s.nth(e,2,"nextSibling")},prev:function(e){return s.nth(e,2,"previousSibling")},nextAll:function(e){return s.dir(e,"nextSibling")},prevAll:function(e){return s.dir(e,"previousSibling")},nextUntil:function(e,t,n){return s.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return s.dir(e,"previousSibling",n)},siblings:function(e){return s.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return s.sibling(e.firstChild)},contents:function(e){return s.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:s.makeArray(e.childNodes)}},function(e,t){s.fn[e]=function(n,r){var i=s.map(this,t,n);return j.test(e)||(r=n),r&&typeof r=="string"&&(i=s.filter(r,i)),i=this.length>1&&!z[e]?s.unique(i):i,(this.length>1||I.test(r))&&F.test(e)&&(i=i.reverse()),this.pushStack(i,e,R.call(arguments).join(","))}}),s.extend({filter:function(e,t,n){return n&&(e=":not("+e+")"),t.length===1?s.find.matchesSelector(t[0],e)?[t[0]]:[]:s.find.matches(e,t)},dir:function(e,n,r){var i=[],o=e[n];while(o&&o.nodeType!==9&&(r===t||o.nodeType!==1||!s(o).is(r)))o.nodeType===1&&i.push(o),o=o[n];return i},nth:function(e,t,n,r){t=t||1;var i=0;for(;e;e=e[n])if(e.nodeType===1&&++i===t)break;return e},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)e.nodeType===1&&e!==t&&n.push(e);return n}});var $="abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",J=/ jQuery\d+="(?:\d+|null)"/g,K=/^\s+/,Q=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,G=/<([\w:]+)/,Y=/<tbody/i,Z=/<|&#?\w+;/,et=/<(?:script|style)/i,tt=/<(?:script|object|embed|option|style)/i,nt=RegExp("<(?:"+$+")[\\s/>]","i"),rt=/checked\s*(?:[^=]|=\s*.checked.)/i,it=/\/(java|ecma)script/i,st=/^\s*<!(?:\[CDATA\[|\-\-)/,ot={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},ut=V(n);ot.optgroup=ot.option,ot.tbody=ot.tfoot=ot.colgroup=ot.caption=ot.thead,ot.th=ot.td,s.support.htmlSerialize||(ot._default=[1,"div<div>","</div>"]),s.fn.extend({text:function(e){return s.access(this,function(e){return e===t?s.text(this):this.empty().append((this[0]&&this[0].ownerDocument||n).createTextNode(e))},null,e,arguments.length)},wrapAll:function(e){if(s.isFunction(e))return this.each(function(t){s(this).wrapAll(e.call(this,t))});if(this[0]){var t=s(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstChild&&e.firstChild.nodeType===1)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return s.isFunction(e)?this.each(function(t){s(this).wrapInner(e.call(this,t))}):this.each(function(){var t=s(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=s.isFunction(e);return this.each(function(n){s(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){s.nodeName(this,"body")||s(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(e){this.nodeType===1&&this.appendChild(e)})},prepend:function(){return this.domManip(arguments,!0,function(e){this.nodeType===1&&this.insertBefore(e,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this)});if(arguments.length){var e=s.clean(arguments);return e.push.apply(e,this.toArray()),this.pushStack(e,"before",arguments)}},after:function(){if(
+this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(e){this.parentNode.insertBefore(e,this.nextSibling)});if(arguments.length){var e=this.pushStack(this,"after",arguments);return e.push.apply(e,s.clean(arguments)),e}},remove:function(e,t){for(var n=0,r;(r=this[n])!=null;n++)if(!e||s.filter(e,[r]).length)!t&&r.nodeType===1&&(s.cleanData(r.getElementsByTagName("*")),s.cleanData([r])),r.parentNode&&r.parentNode.removeChild(r);return this},empty:function(){for(var e=0,t;(t=this[e])!=null;e++){t.nodeType===1&&s.cleanData(t.getElementsByTagName("*"));while(t.firstChild)t.removeChild(t.firstChild)}return this},clone:function(e,t){return e=e==null?!1:e,t=t==null?e:t,this.map(function(){return s.clone(this,e,t)})},html:function(e){return s.access(this,function(e){var n=this[0]||{},r=0,i=this.length;if(e===t)return n.nodeType===1?n.innerHTML.replace(J,""):null;if(typeof e=="string"&&!et.test(e)&&(s.support.leadingWhitespace||!K.test(e))&&!ot[(G.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(Q,"<$1></$2>");try{for(;r<i;r++)n=this[r]||{},n.nodeType===1&&(s.cleanData(n.getElementsByTagName("*")),n.innerHTML=e);n=0}catch(o){}}n&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(e){return this[0]&&this[0].parentNode?s.isFunction(e)?this.each(function(t){var n=s(this),r=n.html();n.replaceWith(e.call(this,t,r))}):(typeof e!="string"&&(e=s(e).detach()),this.each(function(){var t=this.nextSibling,n=this.parentNode;s(this).remove(),t?s(t).before(e):s(n).append(e)})):this.length?this.pushStack(s(s.isFunction(e)?e():e),"replaceWith",e):this},detach:function(e){return this.remove(e,!0)},domManip:function(e,n,r){var i,o,u,a,f=e[0],l=[];if(!s.support.checkClone&&arguments.length===3&&typeof f=="string"&&rt.test(f))return this.each(function(){s(this).domManip(e,n,r,!0)});if(s.isFunction(f))return this.each(function(i){var o=s(this);e[0]=f.call(this,i,n?o.html():t),o.domManip(e,n,r)});if(this[0]){a=f&&f.parentNode,s.support.parentNode&&a&&a.nodeType===11&&a.childNodes.length===this.length?i={fragment:a}:i=s.buildFragment(e,this,l),u=i.fragment,u.childNodes.length===1?o=u=u.firstChild:o=u.firstChild;if(o){n=n&&s.nodeName(o,"tr");for(var c=0,h=this.length,p=h-1;c<h;c++)r.call(n?at(this[c],o):this[c],i.cacheable||h>1&&c<p?s.clone(u,!0,!0):u)}l.length&&s.each(l,function(e,t){t.src?s.ajax({type:"GET",global:!1,url:t.src,async:!1,dataType:"script"}):s.globalEval((t.text||t.textContent||t.innerHTML||"").replace(st,"/*$0*/")),t.parentNode&&t.parentNode.removeChild(t)})}return this}}),s.buildFragment=function(e,t,r){var i,o,u,a,f=e[0];return t&&t[0]&&(a=t[0].ownerDocument||t[0]),a.createDocumentFragment||(a=n),e.length===1&&typeof f=="string"&&f.length<512&&a===n&&f.charAt(0)==="<"&&!tt.test(f)&&(s.support.checkClone||!rt.test(f))&&(s.support.html5Clone||!nt.test(f))&&(o=!0,u=s.fragments[f],u&&u!==1&&(i=u)),i||(i=a.createDocumentFragment(),s.clean(e,a,i,r)),o&&(s.fragments[f]=u?i:1),{fragment:i,cacheable:o}},s.fragments={},s.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){s.fn[e]=function(n){var r=[],i=s(n),o=this.length===1&&this[0].parentNode;if(o&&o.nodeType===11&&o.childNodes.length===1&&i.length===1)return i[t](this[0]),this;for(var u=0,a=i.length;u<a;u++){var f=(u>0?this.clone(!0):this).get();s(i[u])[t](f),r=r.concat(f)}return this.pushStack(r,e,i.selector)}}),s.extend({clone:function(e,t,n){var r,i,o,u=s.support.html5Clone||s.isXMLDoc(e)||!nt.test("<"+e.nodeName+">")?e.cloneNode(!0):dt(e);if((!s.support.noCloneEvent||!s.support.noCloneChecked)&&(e.nodeType===1||e.nodeType===11)&&!s.isXMLDoc(e)){lt(e,u),r=ct(e),i=ct(u);for(o=0;r[o];++o)i[o]&&lt(r[o],i[o])}if(t){ft(e,u);if(n){r=ct(e),i=ct(u);for(o=0;r[o];++o)ft(r[o],i[o])}}return r=i=null,u},clean:function(e,t,r,i){var o,u,a,f=[];t=t||n,typeof t.createElement=="undefined"&&(t=t.ownerDocument||t[0]&&t[0].ownerDocument||n);for(var l=0,c;(c=e[l])!=null;l++){typeof c=="number"&&(c+="");if(!c)continue;if(typeof c=="string")if(!Z.test(c))c=t.createTextNode(c);else{c=c.replace(Q,"<$1></$2>");var h=(G.exec(c)||["",""])[1].toLowerCase(),p=ot[h]||ot._default,d=p[0],v=t.createElement("div"),m=ut.childNodes,g;t===n?ut.appendChild(v):V(t).appendChild(v),v.innerHTML=p[1]+c+p[2];while(d--)v=v.lastChild;if(!s.support.tbody){var y=Y.test(c),b=h==="table"&&!y?v.firstChild&&v.firstChild.childNodes:p[1]==="<table>"&&!y?v.childNodes:[];for(a=b.length-1;a>=0;--a)s.nodeName(b[a],"tbody")&&!b[a].childNodes.length&&b[a].parentNode.removeChild(b[a])}!s.support.leadingWhitespace&&K.test(c)&&v.insertBefore(t.createTextNode(K.exec(c)[0]),v.firstChild),c=v.childNodes,v&&(v.parentNode.removeChild(v),m.length>0&&(g=m[m.length-1],g&&g.parentNode&&g.parentNode.removeChild(g)))}var w;if(!s.support.appendChecked)if(c[0]&&typeof (w=c.length)=="number")for(a=0;a<w;a++)pt(c[a]);else pt(c);c.nodeType?f.push(c):f=s.merge(f,c)}if(r){o=function(e){return!e.type||it.test(e.type)};for(l=0;f[l];l++){u=f[l];if(i&&s.nodeName(u,"script")&&(!u.type||it.test(u.type)))i.push(u.parentNode?u.parentNode.removeChild(u):u);else{if(u.nodeType===1){var E=s.grep(u.getElementsByTagName("script"),o);f.splice.apply(f,[l+1,0].concat(E))}r.appendChild(u)}}}return f},cleanData:function(e){var t,n,r=s.cache,i=s.event.special,o=s.support.deleteExpando;for(var u=0,a;(a=e[u])!=null;u++){if(a.nodeName&&s.noData[a.nodeName.toLowerCase()])continue;n=a[s.expando];if(n){t=r[n];if(t&&t.events){for(var f in t.events)i[f]?s.event.remove(a,f):s.removeEvent(a,f,t.handle);t.handle&&(t.handle.elem=null)}o?delete a[s.expando]:a.removeAttribute&&a.removeAttribute(s.expando),delete r[n]}}}});var vt=/alpha\([^)]*\)/i,mt=/opacity=([^)]*)/,gt=/([A-Z]|^ms)/g,yt=/^[\-+]?(?:\d*\.)?\d+$/i,bt=/^-?(?:\d*\.)?\d+(?!px)[^\d\s]+$/i,wt=/^([\-+])=([\-+.\de]+)/,Et=/^margin/,St={position:"absolute",visibility:"hidden",display:"block"},xt=["Top","Right","Bottom","Left"],Tt,Nt,Ct;s.fn.css=function(e,n){return s.access(this,function(e,n,r){return r!==t?s.style(e,n,r):s.css(e,n)},e,n,arguments.length>1)},s.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Tt(e,"opacity");return n===""?"1":n}return e.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":s.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(!e||e.nodeType===3||e.nodeType===8||!e.style)return;var o,u,a=s.camelCase(n),f=e.style,l=s.cssHooks[a];n=s.cssProps[a]||a;if(r===t)return l&&"get"in l&&(o=l.get(e,!1,i))!==t?o:f[n];u=typeof r,u==="string"&&(o=wt.exec(r))&&(r=+(o[1]+1)*+o[2]+parseFloat(s.css(e,n)),u="number");if(r==null||u==="number"&&isNaN(r))return;u==="number"&&!s.cssNumber[a]&&(r+="px");if(!l||!("set"in l)||(r=l.set(e,r))!==t)try{f[n]=r}catch(c){}},css:function(e,n,r){var i,o;n=s.camelCase(n),o=s.cssHooks[n],n=s.cssProps[n]||n,n==="cssFloat"&&(n="float");if(o&&"get"in o&&(i=o.get(e,!0,r))!==t)return i;if(Tt)return Tt(e,n)},swap:function(e,t,n){var r={},i,s;for(s in t)r[s]=e.style[s],e.style[s]=t[s];i=n.call(e);for(s in t)e.style[s]=r[s];return i}}),s.curCSS=s.css,n.defaultView&&n.defaultView.getComputedStyle&&(Nt=function(e,t){var n,r,i,o,u=e.style;return t=t.replace(gt,"-$1").toLowerCase(),(r=e.ownerDocument.defaultView)&&(i=r.getComputedStyle(e,null))&&(n=i.getPropertyValue(t),n===""&&!s.contains(e.ownerDocument.documentElement,e)&&(n=s.style(e,t))),!s.support.pixelMargin&&i&&Et.test(t)&&bt.test(n)&&(o=u.width,u.width=n,n=i.width,u.width=o),n}),n.documentElement.currentStyle&&(Ct=function(e,t){var n,r,i,s=e.currentStyle&&e.currentStyle[t],o=e.style;return s==null&&o&&(i=o[t])&&(s=i),bt.test(s)&&(n=o.left,r=e.runtimeStyle&&e.runtimeStyle.left,r&&(e.runtimeStyle.left=e.currentStyle.left),o.left=t==="fontSize"?"1em":s,s=o.pixelLeft+"px",o.left=n,r&&(e.runtimeStyle.left=r)),s===""?"auto":s}),Tt=Nt||Ct,s.each(["height","width"],function(e,t){s.cssHooks[t]={get:function(e,n,r){if(n)return e.offsetWidth!==0?kt(e,t,r):s.swap(e,St,function(){return kt(e,t,r)})},set:function(e,t){return yt.test(t)?t+"px":t}}}),s.support.opacity||(s.cssHooks.opacity={get:function(e,t){return mt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?parseFloat(RegExp.$1)/100+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=s.isNumeric(t)?"alpha(opacity="+t*100+")":"",o=r&&r.filter||n.filter||"";n.zoom=1;if(t>=1&&s.trim(o.replace(vt,""))===""){n.removeAttribute("filter");if(r&&!r.filter)return}n.filter=vt.test(o)?o.replace(vt,i):o+" "+i}}),s(function(){s.support.reliableMarginRight||(s.cssHooks.marginRight={get:function(e,t){return s.swap(e,{display:"inline-block"},function(){return t?Tt(e,"margin-right"):e.style.marginRight})}})}),s.expr&&s.expr.filters&&(s.expr.filters.hidden=function(e){var t=e.offsetWidth,n=e.offsetHeight;return t===0&&n===0||!s.support.reliableHiddenOffsets&&(e.style&&e.style.display||s.css(e,"display"))==="none"},s.expr.filters.visible=function(e){return!s.expr.filters.hidden(e)}),s.each({margin:"",padding:"",border:"Width"},function(e,t){s.cssHooks[e+t]={expand:function(n){var r,i=typeof n=="string"?n.split(" "):[n],s={};for(r=0;r<4;r++)s[e+xt[r]+t]=i[r]||i[r-2]||i[0];return s}}});var Lt=/%20/g,At=/\[\]$/,Ot=/\r?\n/g,Mt=/#.*$/,_t=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,Dt=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,Pt=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,Ht=/^(?:GET|HEAD)$/,Bt=/^\/\//,jt=/\?/,Ft=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,It=/^(?:select|textarea)/i,qt=/\s+/,Rt=/([?&])_=[^&]*/,Ut=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,zt=s.fn.load,Wt={},Xt={},Vt,$t,Jt=["*/"]+["*"];try{Vt=i.href}catch(Kt){Vt=n.createElement("a"),Vt.href="",Vt=Vt.href}$t=Ut.exec(Vt.toLowerCase())||[],s.fn.extend({load:function(e,n,r){if(typeof e!="string"&&zt)return zt.apply(this,arguments);if(!this.length)return this;var i=e.indexOf(" ");if(i>=0){var o=e.slice(i,e.length);e=e.slice(0,i)}var u="GET";n&&(s.isFunction(n)?(r=n,n=t):typeof n=="object"&&(n=s.param(n,s.ajaxSettings.traditional),u="POST"));var a=this;return s.ajax({url:e,type:u,dataType:"html",data:n,complete:function(e,t,n){n=e.responseText,e.isResolved()&&(e.done(function(e){n=e}),a.html(o?s("<div>").append(n.replace(Ft,"")).find(o):n)),r&&a.each(r,[n,t,e])}}),this},serialize:function(){return s.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?s.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||It.test(this.nodeName)||Dt.test(this.type))}).map(function(e,t){var n=s(this).val();return n==null?null:s.isArray(n)?s.map(n,function(e,n){return{name:t.name,value:e.replace(Ot,"\r\n")}}):{name:t.name,value:n.replace(Ot,"\r\n")}}).get()}}),s.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(e,t){s.fn[t]=function(e){return this.on(t,e)}}),s.each(["get","post"],function(e,n){s[n]=function(e,r,i,o){return s.isFunction(r)&&(o=o||i,i=r,r=t),s.ajax({type:n,url:e,data:r,success:i,dataType:o})}}),s.extend({getScript:function(e,n){return s.get(e,t,n,"script")},getJSON:function(e,t,n){return s.get(e,t,n,"json")},ajaxSetup:function(e,t){return t?Yt(e,s.ajaxSettings):(t=e,e=s.ajaxSettings),Yt(e,t),e},ajaxSettings:{url:Vt,isLocal:Pt.test($t[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded; charset=UTF-8",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":Jt},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":e.String,"text html":!0,"text json":s.parseJSON,"text xml":s.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:Qt(Wt),ajaxTransport:Qt(Xt),ajax:function(e,n){function S(e,n,c,h){if(y===2)return;y=2,m&&clearTimeout(m),v=t,p=h||"",E.readyState=e>0?4:0;var d,g,w,S=n,x=c?en(r,E,c):t,T,N;if(e>=200&&e<300||e===304){if(r.ifModified){if(T=E.getResponseHeader("Last-Modified"))s.lastModified[l]=T;if(N=E.getResponseHeader("Etag"))s.etag[l]=N}if(e===304)S="notmodified",d=!0;else try{g=tn(r,x),S="success",d=!0}catch(C){S="parsererror",w=C}}else{w=S;if(!S||e)S="error",e<0&&(e=0)}E.status=e,E.statusText=""+(n||S),d?u.resolveWith(i,[g,S,E]):u.rejectWith(i,[E,S,w]),E.statusCode(f),f=t,b&&o.trigger("ajax"+(d?"Success":"Error"),[E,r,d?g:w]),a.fireWith(i,[E,S]),b&&(o.trigger("ajaxComplete",[E,r]),--s.active||s.event.trigger("ajaxStop"))}typeof e=="object"&&(n=e,e=t),n=n||{};var r=s.ajaxSetup({},n),i=r.context||r,o=i!==r&&(i.nodeType||i instanceof s)?s(i):s.event,u=s.Deferred(),a=s.Callbacks("once memory"),f=r.statusCode||{},l,c={},h={},p,d,v,m,g,y=0,b,w,E={readyState:0,setRequestHeader:function(e,t){if(!y){var n=e.toLowerCase();e=h[n]=h[n]||e,c[e]=t}return this},getAllResponseHeaders:function(){return y===2?p:null},getResponseHeader:function(e){var n;if(y===2){if(!d){d={};while(n=_t.exec(p))d[n[1].toLowerCase()]=n[2]}n=d[e.toLowerCase()]}return n===t?null:n},overrideMimeType:function(e){return y||(r.mimeType=e),this},abort:function(e){return e=e||"abort",v&&v.abort(e),S(0,e),this}};u.promise(E),E.success=E.done,E.error=E.fail,E.complete=a.add,E.statusCode=function(e){if(e){var t;if(y<2)for(t in e)f[t]=[f[t],e[t]];else t=e[E.status],E.then(t,t)}return this},r.url=((e||r.url)+"").replace(Mt,"").replace(Bt,$t[1]+"//"),r.dataTypes=s.trim(r.dataType||"*").toLowerCase().split(qt),r.crossDomain==null&&(g=Ut.exec(r.url.toLowerCase()),r.crossDomain=!(!g||g[1]==$t[1]&&g[2]==$t[2]&&(g[3]||(g[1]==="http:"?80:443))==($t[3]||($t[1]==="http:"?80:443)))),r.data&&r.processData&&typeof r.data!="string"&&(r.data=s.param(r.data,r.traditional)),Gt(Wt,r,n,E);if(y===2)return!1;b=r.global,r.type=r.type.toUpperCase(),r.hasContent=!Ht.test(r.type),b&&s.active++===0&&s.event.trigger("ajaxStart");if(!r.hasContent){r.data&&(r.url+=(jt.test(r.url)?"&":"?")+r.data,delete r.data),l=r.url;if(r.cache===!1){var x=s.now(),T=r.url.replace(Rt,"$1_="+x);r.url=T+(T===r.url?(jt.test(r.url)?"&":"?")+"_="+x:"")}}(r.data&&r.hasContent&&r.contentType!==!1||n.contentType)&&E.setRequestHeader("Content-Type",r.contentType),r.ifModified&&(l=l||r.url,s.lastModified[l]&&E.setRequestHeader("If-Modified-Since",s.lastModified[l]),s.etag[l]&&E.setRequestHeader("If-None-Match",s.etag[l])),E.setRequestHeader("Accept",r.dataTypes[0]&&r.accepts[r.dataTypes[0]]?r.accepts[r.dataTypes[0]]+(r.dataTypes[0]!=="*"?", "+Jt+"; q=0.01":""):r.accepts["*"]);for(w in r.headers)E.setRequestHeader(w,r.headers[w]);if(!r.beforeSend||r.beforeSend.call(i,E,r)!==!1&&y!==2){for(w in{success:1,error:1,complete:1})E[w](r[w]);v=Gt(Xt,r,n,E);if(!v)S(-1,"No Transport");else{E.readyState=1,b&&o.trigger("ajaxSend",[E,r]),r.async&&r.timeout>0&&(m=setTimeout(function(){E.abort("timeout")},r.timeout));try{y=1,v.send(c,S)}catch(N){if(y>=2)throw N;S(-1,N)}}return E}return E.abort(),!1},param:function(e,n){var r=[],i=function(e,t){t=s.isFunction(t)?t():t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};n===t&&(n=s.ajaxSettings.traditional);if(s.isArray(e)||e.jquery&&!s.isPlainObject(e))s.each(e,function(){i(this.name,this.value)});else for(var o in e)Zt(o,e[o],n,i);return r.join("&").replace(Lt,"+")}}),s.extend({active:0,lastModified:{},etag:{}});var nn=s.now(),rn=/(\=)\?(&|$)|\?\?/i;s.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return s.expando+"_"+nn++}}),s.ajaxPrefilter("json jsonp",function(t,n,r){var i=typeof t.data=="string"&&/^application\/x\-www\-form\-urlencoded/.test(t.contentType);if(t.dataTypes[0]==="jsonp"||t.jsonp!==!1&&(rn.test(t.url)||i&&rn.test(t.data))){var o,u=t.jsonpCallback=s.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a=e[u],f=t.url,l=t.data,c="$1"+u+"$2";return t.jsonp!==!1&&(f=f.replace(rn,c),t.url===f&&(i&&(l=l.replace(rn,c)),t.data===l&&(f+=(/\?/.test(f)?"&":"?")+t.jsonp+"="+u))),t.url=f,t.data=l,e[u]=function(e){o=[e]},r.always(function(){e[u]=a,o&&s.isFunction(a)&&e[u](o[0])}),t.converters["script json"]=function(){return o||s.error(u+" was not called"),o[0]},t.dataTypes[0]="json","script"}}),s.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(e){return s.globalEval(e),e}}}),s.ajaxPrefilter("script",function(e){e.cache===t&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),s.ajaxTransport("script",function(e){if(e.crossDomain){var r,i=n.head||n.getElementsByTagName("head")[0]||n.documentElement;return{send:function(s,o){r=n.createElement("script"),r.async="async",e.scriptCharset&&(r.charset=e.scriptCharset),r.src=e.url,r.onload=r.onreadystatechange=function(e,n){if(n||!r.readyState||/loaded|complete/.test(r.readyState))r.onload=r.onreadystatechange=null,i&&r.parentNode&&i.removeChild(r),r=t,n||o(200,"success")},i.insertBefore(r,i.firstChild)},abort:function(){r&&r.onload(0,1)}}}});var sn=e.ActiveXObject?function(){for(var e in un)un[e](0,1)}:!1,on=0,un;s.ajaxSettings.xhr=e.ActiveXObject?function(){return!this.isLocal&&an()||fn()}:an,function(e){s.extend(s.support,{ajax:!!e,cors:!!e&&"withCredentials"in e})}(s.ajaxSettings.xhr()),s.support.ajax&&s.ajaxTransport(function(n){if(!n.crossDomain||s.support.cors){var r;return{send:function(i,o){var u=n.xhr(),a,f;n.username?u.open(n.type,n.url,n.async,n.username,n.password):u.open(n.type,n.url,n.async);if(n.xhrFields)for(f in n.xhrFields)u[f]=n.xhrFields[f];n.mimeType&&u.overrideMimeType&&u.overrideMimeType(n.mimeType),!n.crossDomain&&!i["X-Requested-With"]&&(i["X-Requested-With"]="XMLHttpRequest");try{for(f in i)u.setRequestHeader(f,i[f])}catch(l){}u.send(n.hasContent&&n.data||null),r=function(e,i){var f,l,c,h,p;try{if(r&&(i||u.readyState===4)){r=t,a&&(u.onreadystatechange=s.noop,sn&&delete un[a]);if(i)u.readyState!==4&&u.abort();else{f=u.status,c=u.getAllResponseHeaders(),h={},p=u.responseXML,p&&p.documentElement&&(h.xml=p);try{h.text=u.responseText}catch(e){}try{l=u.statusText}catch(d){l=""}!f&&n.isLocal&&!n.crossDomain?f=h.text?200:404:f===1223&&(f=204)}}}catch(v){i||o(-1,v)}h&&o(f,l,h,c)},!n.async||u.readyState===4?r():(a=++on,sn&&(un||(un={},s(e).unload(sn)),un[a]=r),u.onreadystatechange=r)},abort:function(){r&&r(0,1)}}}});var ln={},cn,hn,pn=/^(?:toggle|show|hide)$/,dn=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,vn,mn=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],gn;s.fn.extend({show:function(e,t,n){var r,i;if(e||e===0)return this.animate(wn("show",3),e,t,n);for(var o=0,u=this.length;o<u;o++)r=this[o],r.style&&(i=r.style.display,!s._data(r,"olddisplay")&&i==="none"&&(i=r.style.display=""),(i===""&&s.css(r,"display")==="none"||!s.contains(r.ownerDocument.documentElement,r))&&s._data(r,"olddisplay",En(r.nodeName)));for(o=0;o<u;o++){r=this[o];if(r.style){i=r.style.display;if(i===""||i==="none")r.style.display=s._data(r,"olddisplay")||""}}return this},hide:function(e,t,n){if(e||e===0)return this.animate(wn("hide",3),e,t,n);var r,i,o=0,u=this.length;for(;o<u;o++)r=this[o],r.style&&(i=s.css(r,"display"),i!=="none"&&!s._data(r,"olddisplay")&&s._data(r,"olddisplay",i));for(o=0;o<u;o++)this[o].style&&(this[o].style.display="none");return this},_toggle:s.fn.toggle,toggle:function(e,t,n){var r=typeof e=="boolean";return s.isFunction(e)&&s.isFunction(t)?this._toggle.apply(this,arguments):e==null||r?this.each(function(){var t=r?e:s(this).is(":hidden");s(this)[t?"show":"hide"]()}):this.animate(wn("toggle",3),e,t,n),this},fadeTo:function(e,t,n,r){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){function o(){i.queue===!1&&s._mark(this);var t=s.extend({},i),n=this.nodeType===1,r=n&&s(this).is(":hidden"),o,u,a,f,l,c,h,p,d,v,m;t.animatedProperties={};for(a in e){o=s.camelCase(a),a!==o&&(e[o]=e[a],delete e[a]);if((l=s.cssHooks[o])&&"expand"in l){c=l.expand(e[o]),delete e[o];for(a in c)a in e||(e[a]=c[a])}}for(o in e){u=e[o],s.isArray(u)?(t.animatedProperties[o]=u[1],u=e[o]=u[0]):t.animatedProperties[o]=t.specialEasing&&t.specialEasing[o]||t.easing||"swing";if(u==="hide"&&r||u==="show"&&!r)return t.complete.call(this);n&&(o==="height"||o==="width")&&(t.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],s.css(this,"display")==="inline"&&s.css(this,"float")==="none"&&(!s.support.inlineBlockNeedsLayout||En(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}t.overflow!=null&&(this.style.overflow="hidden");for(a in e)f=new s.fx(this,t,a),u=e[a],pn.test(u)?(m=s._data(this,"toggle"+a)||(u==="toggle"?r?"show":"hide":0),m?(s._data(this,"toggle"+a,m==="show"?"hide":"show"),f[m]()):f[u]()):(h=dn.exec(u),p=f.cur(),h?(d=parseFloat(h[2]),v=h[3]||(s.cssNumber[a]?"":"px"),v!=="px"&&(s.style(this,a,(d||1)+v),p=(d||1)/f.cur()*p,s.style(this,a,p+v)),h[1]&&(d=(h[1]==="-="?-1:1)*d+p),f.custom(p,d,v)):f.custom(p,u,""));return!0}var i=s.speed(t,n,r);return s.isEmptyObject(e)?this.each(i.complete,[!1]):(e=s.extend({},e),i.queue===!1?this.each(o):this.queue(i.queue,o))},stop:function(e,n,r){return typeof e!="string"&&(r=n,n=e,e=t),n&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){function u(e,t,n){var i=t[n];s.removeData(e,n,!0),i.stop(r)}var t,n=!1,i=s.timers,o=s._data(this);r||s._unmark(!0,this);if(e==null)for(t in o)o[t]&&o[t].stop&&t.indexOf(".run")===t.length-4&&u(this,o,t);else o[t=e+".run"]&&o[t].stop&&u(this,o,t);for(t=i.length;t--;)i[t].elem===this&&(e==null||i[t].queue===e)&&(r?i[t](!0):i[t].saveState(),n=!0,i.splice(t,1));(!r||!n)&&s.dequeue(this,e)})}}),s.each({slideDown:wn("show",1),slideUp:wn("hide",1),slideToggle:wn("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){s.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),s.extend({speed:function(e,t,n){var r=e&&typeof e=="object"?s.extend({},e):{complete:n||!n&&t||s.isFunction(e)&&e,duration:e,easing:n&&t||t&&!s.isFunction(t)&&t};r.duration=s.fx.off?0:typeof r.duration=="number"?r.duration:r.duration in s.fx.speeds?s.fx.speeds[r.duration]:s.fx.speeds._default;if(r.queue==null||r.queue===!0)r.queue="fx";return r.old=r.complete,r.complete=function(e){s.isFunction(r.old)&&r.old.call(this),r.queue?s.dequeue(this,r.queue):e!==!1&&s._unmark(this)},r},easing:{linear:function(e){return e},swing:function(e){return-Math.cos(e*Math.PI)/2+.5}},timers:[],fx:function(e,t,n){this.options=t,this.elem=e,this.prop=n,t.orig=t.orig||{}}}),s.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(s.fx.step[this.prop]||s.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]==null||!!this.elem.style&&this.elem.style[this.prop]!=null){var e,t=s.css(this.elem,this.prop);return isNaN(e=parseFloat(t))?!t||t==="auto"?0:t:e}return this.elem[this.prop]},custom:function(e,n,r){function u(e){return i.step(e)}var i=this,o=s.fx;this.startTime=gn||yn(),this.end=n,this.now=this.start=e,this.pos=this.state=0,this.unit=r||this.unit||(s.cssNumber[this.prop]?"":"px"),u.queue=this.options.queue,u.elem=this.elem,u.saveState=function(){s._data(i.elem,"fxshow"+i.prop)===t&&(i.options.hide?s._data(i.elem,"fxshow"+i.prop,i.start):i.options.show&&s._data(i.elem,"fxshow"+i.prop,i.end))},u()&&s.timers.push(u)&&!vn&&(vn=setInterval(o.tick,o.interval))},show:function(){var e=s._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=e||s.style(this.elem,this.prop),this.options.show=!0,e!==t?this.custom(this.cur(),e):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),s(this.elem).show()},hide:function(){this.options.orig[this.prop]=s._data(this.elem,"fxshow"+this.prop)||s.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(e){var t,n,r,i=gn||yn(),o=!0,u=this.elem,a=this.options;if(e||i>=a.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),a.animatedProperties[this.prop]=!0;for(t in a.animatedProperties)a.animatedProperties[t]!==!0&&(o=!1);if(o){a.overflow!=null&&!s.support.shrinkWrapBlocks&&s.each(["","X","Y"],function(e,t){u.style["overflow"+t]=a.overflow[e]}),a.hide&&s(u).hide();if(a.hide||a.show)for(t in a.animatedProperties)s.style(u,t,a.orig[t]),s.removeData(u,"fxshow"+t,!0),s.removeData(u,"toggle"+t,!0);r=a.complete,r&&(a.complete=!1,r.call(u))}return!1}return a.duration==Infinity?this.now=i:(n=i-this.startTime,this.state=n/a.duration,this.pos=s.easing[a.animatedProperties[this.prop]](this.state,n,0,1,a.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update(),!0}},s.extend(s.fx,{tick:function(){var e,t=s.timers,n=0;for(;n<t.length;n++)e=t[n],!e()&&t[n]===e&&t.splice(n--,1);t.length||s.fx.stop()},interval:13,stop:function(){clearInterval(vn),vn=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(e){s.style(e.elem,"opacity",e.now)},_default:function(e){e.elem.style&&e.elem.style[e.prop]!=null?e.elem.style[e.prop]=e.now+e.unit:e.elem[e.prop]=e.now}}}),s.each(mn.concat.apply([],mn),function(e,t){t.indexOf("margin")&&(s.fx.step[t]=function(e){s.style(e.elem,t,Math.max(0,e.now)+e.unit)})}),s.expr&&s.expr.filters&&(s.expr.filters.animated=function(e){return s.grep(s.timers,function(t){return e===t.elem}).length});var Sn,xn=/^t(?:able|d|h)$/i,Tn=/^(?:body|html)$/i;"getBoundingClientRect"in n.documentElement?Sn=function(e,t,n,r){try{r=e.getBoundingClientRect()}catch(i){}if(!r||!s.contains(n,e))return r?{top:r.top,left:r.left}:{top:0,left:0};var o=t.body,u=Nn(t),a=n.clientTop||o.clientTop||0,f=n.clientLeft||o.clientLeft||0,l=u.pageYOffset||s.support.boxModel&&n.scrollTop||o.scrollTop,c=u.pageXOffset||s.support.boxModel&&n.scrollLeft||o.scrollLeft,h=r.top+l-a,p=r.left+c-f;return{top:h,left:p}}:Sn=function(e,t,n){var r,i=e.offsetParent,o=e,u=t.body,a=t.defaultView,f=a?a.getComputedStyle(e,null):e.currentStyle,l=e.offsetTop,c=e.offsetLeft;while((e=e.parentNode)&&e!==u&&e!==n){if(s.support.fixedPosition&&f.position==="fixed")break;r=a?a.getComputedStyle(e,null):e.currentStyle,l-=e.scrollTop,c-=e.scrollLeft,e===i&&(l+=e.offsetTop,c+=e.offsetLeft,s.support.doesNotAddBorder&&(!s.support.doesAddBorderForTableAndCells||!xn.test(e.nodeName))&&(l+=parseFloat(r.borderTopWidth)||0,c+=parseFloat(r.borderLeftWidth)||0),o=i,i=e.offsetParent),s.support.subtractsBorderForOverflowNotVisible&&r.overflow!=="visible"&&(l+=parseFloat(r.borderTopWidth)||0,c+=parseFloat(r.borderLeftWidth)||0),f=r}if(f.position==="relative"||f.position==="static")l+=u.offsetTop,c+=u.offsetLeft;return s.support.fixedPosition&&f.position==="fixed"&&(l+=Math.max(n.scrollTop,u.scrollTop),c+=Math.max(n.scrollLeft,u.scrollLeft)),{top:l,left:c}},s.fn.offset=function(e){if(arguments.length)return e===t?this:this.each(function(t){s.offset.setOffset(this,e,t)});var n=this[0],r=n&&n.ownerDocument;return r?n===r.body?s.offset.bodyOffset(n):Sn(n,r,r.documentElement):null},s.offset={bodyOffset:function(e){var t=e.offsetTop,n=e.offsetLeft;return s.support.doesNotIncludeMarginInBodyOffset&&(t+=parseFloat(s.css(e,"marginTop"))||0,n+=parseFloat(s.css(e,"marginLeft"))||0),{top:t,left:n}},setOffset:function(e,t,n){var r=s.css(e,"position");r==="static"&&(e.style.position="relative");var i=s(e),o=i.offset(),u=s.css(e,"top"),a=s.css(e,"left"),f=(r==="absolute"||r==="fixed")&&s.inArray("auto",[u,a])>-1,l={},c={},h,p;f?(c=i.position(),h=c.top,p=c.left):(h=parseFloat(u)||0,p=parseFloat(a)||0),s.isFunction(t)&&(t=t.call(e,n,o)),t.top!=null&&(l.top=t.top-o.top+h),t.left!=null&&(l.left=t.left-o.left+p),"using"in t?t.using.call(e,l):i.css(l)}},s.fn.extend({position:function(){if(!this[0])return null;var e=this[0],t=this.offsetParent(),n=this.offset(),r=Tn.test(t[0].nodeName)?{top:0,left:0}:t.offset();return n.top-=parseFloat(s.css(e,"marginTop"))||0,n.left-=parseFloat(s.css(e,"marginLeft"))||0,r.top+=parseFloat(s.css(t[0],"borderTopWidth"))||0,r.left+=parseFloat(s.css(t[0],"borderLeftWidth"))||0,{top:n.top-r.top,left:n.left-r.left}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||n.body;while(e&&!Tn.test(e.nodeName)&&s.css(e,"position")==="static")e=e.offsetParent;return e})}}),s.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,n){var r=/Y/.test(n);s.fn[e]=function(i){return s.access(this,function(e,i,o){var u=Nn(e);if(o===t)return u?n in u?u[n]:s.support.boxModel&&u.document.documentElement[i]||u.document.body[i]:e[i];u?u.scrollTo(r?s(u).scrollLeft():o,r?o:s(u).scrollTop()):e[i]=o},e,i,arguments.length,null)}}),s.each({Height:"height",Width:"width"},function(e,n){var r="client"+e,i="scroll"+e,o="offset"+e;s.fn["inner"+e]=function(){var e=this[0];return e?e.style?parseFloat(s.css(e,n,"padding")):this[n]():null},s.fn["outer"+e]=function(e){var t=this[0];return t?t.style?parseFloat(s.css(t,n,e?"margin":"border")):this[n]():null},s.fn[n]=function(e){return s.access(this,function(e,n,u){var a,f,l,c;if(s.isWindow(e))return a=e.document,f=a.documentElement[r],s.support.boxModel&&f||a.body&&a.body[r]||f;if(e.nodeType===9)return a=e.documentElement,a[r]<a[i]?Math.max(e.body[i],a[i],e.body[o],a[o]):a[r];if(u===t)return l=s.css(e,n),c=parseFloat(l),s.isNumeric(c)?c:l;s(e).css(n,u)},n,e,arguments.length,null)}}),e.jQuery=e.$=s,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return s})})(window);; \ No newline at end of file
diff --git a/examples/leaflet-src.js b/examples/leaflet-src.js
new file mode 100644
index 0000000..e40bfbf
--- /dev/null
+++ b/examples/leaflet-src.js
@@ -0,0 +1,9169 @@
+/*
+ Leaflet, a JavaScript library for mobile-friendly interactive maps. http://leafletjs.com
+ (c) 2010-2013, Vladimir Agafonkin
+ (c) 2010-2011, CloudMade
+*/
+(function (window, document, undefined) {
+var oldL = window.L,
+ L = {};
+
+L.version = '0.7.2';
+
+// define Leaflet for Node module pattern loaders, including Browserify
+if (typeof module === 'object' && typeof module.exports === 'object') {
+ module.exports = L;
+
+// define Leaflet as an AMD module
+} else if (typeof define === 'function' && define.amd) {
+ define(L);
+}
+
+// define Leaflet as a global L variable, saving the original L to restore later if needed
+
+L.noConflict = function () {
+ window.L = oldL;
+ return this;
+};
+
+window.L = L;
+
+
+/*
+ * L.Util contains various utility functions used throughout Leaflet code.
+ */
+
+L.Util = {
+ extend: function (dest) { // (Object[, Object, ...]) ->
+ var sources = Array.prototype.slice.call(arguments, 1),
+ i, j, len, src;
+
+ for (j = 0, len = sources.length; j < len; j++) {
+ src = sources[j] || {};
+ for (i in src) {
+ if (src.hasOwnProperty(i)) {
+ dest[i] = src[i];
+ }
+ }
+ }
+ return dest;
+ },
+
+ bind: function (fn, obj) { // (Function, Object) -> Function
+ var args = arguments.length > 2 ? Array.prototype.slice.call(arguments, 2) : null;
+ return function () {
+ return fn.apply(obj, args || arguments);
+ };
+ },
+
+ stamp: (function () {
+ var lastId = 0,
+ key = '_leaflet_id';
+ return function (obj) {
+ obj[key] = obj[key] || ++lastId;
+ return obj[key];
+ };
+ }()),
+
+ invokeEach: function (obj, method, context) {
+ var i, args;
+
+ if (typeof obj === 'object') {
+ args = Array.prototype.slice.call(arguments, 3);
+
+ for (i in obj) {
+ method.apply(context, [i, obj[i]].concat(args));
+ }
+ return true;
+ }
+
+ return false;
+ },
+
+ limitExecByInterval: function (fn, time, context) {
+ var lock, execOnUnlock;
+
+ return function wrapperFn() {
+ var args = arguments;
+
+ if (lock) {
+ execOnUnlock = true;
+ return;
+ }
+
+ lock = true;
+
+ setTimeout(function () {
+ lock = false;
+
+ if (execOnUnlock) {
+ wrapperFn.apply(context, args);
+ execOnUnlock = false;
+ }
+ }, time);
+
+ fn.apply(context, args);
+ };
+ },
+
+ falseFn: function () {
+ return false;
+ },
+
+ formatNum: function (num, digits) {
+ var pow = Math.pow(10, digits || 5);
+ return Math.round(num * pow) / pow;
+ },
+
+ trim: function (str) {
+ return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
+ },
+
+ splitWords: function (str) {
+ return L.Util.trim(str).split(/\s+/);
+ },
+
+ setOptions: function (obj, options) {
+ obj.options = L.extend({}, obj.options, options);
+ return obj.options;
+ },
+
+ getParamString: function (obj, existingUrl, uppercase) {
+ var params = [];
+ for (var i in obj) {
+ params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
+ }
+ return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
+ },
+ template: function (str, data) {
+ return str.replace(/\{ *([\w_]+) *\}/g, function (str, key) {
+ var value = data[key];
+ if (value === undefined) {
+ throw new Error('No value provided for variable ' + str);
+ } else if (typeof value === 'function') {
+ value = value(data);
+ }
+ return value;
+ });
+ },
+
+ isArray: Array.isArray || function (obj) {
+ return (Object.prototype.toString.call(obj) === '[object Array]');
+ },
+
+ emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
+};
+
+(function () {
+
+ // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
+
+ function getPrefixed(name) {
+ var i, fn,
+ prefixes = ['webkit', 'moz', 'o', 'ms'];
+
+ for (i = 0; i < prefixes.length && !fn; i++) {
+ fn = window[prefixes[i] + name];
+ }
+
+ return fn;
+ }
+
+ var lastTime = 0;
+
+ function timeoutDefer(fn) {
+ var time = +new Date(),
+ timeToCall = Math.max(0, 16 - (time - lastTime));
+
+ lastTime = time + timeToCall;
+ return window.setTimeout(fn, timeToCall);
+ }
+
+ var requestFn = window.requestAnimationFrame ||
+ getPrefixed('RequestAnimationFrame') || timeoutDefer;
+
+ var cancelFn = window.cancelAnimationFrame ||
+ getPrefixed('CancelAnimationFrame') ||
+ getPrefixed('CancelRequestAnimationFrame') ||
+ function (id) { window.clearTimeout(id); };
+
+
+ L.Util.requestAnimFrame = function (fn, context, immediate, element) {
+ fn = L.bind(fn, context);
+
+ if (immediate && requestFn === timeoutDefer) {
+ fn();
+ } else {
+ return requestFn.call(window, fn, element);
+ }
+ };
+
+ L.Util.cancelAnimFrame = function (id) {
+ if (id) {
+ cancelFn.call(window, id);
+ }
+ };
+
+}());
+
+// shortcuts for most used utility functions
+L.extend = L.Util.extend;
+L.bind = L.Util.bind;
+L.stamp = L.Util.stamp;
+L.setOptions = L.Util.setOptions;
+
+
+/*
+ * L.Class powers the OOP facilities of the library.
+ * Thanks to John Resig and Dean Edwards for inspiration!
+ */
+
+L.Class = function () {};
+
+L.Class.extend = function (props) {
+
+ // extended class with the new prototype
+ var NewClass = function () {
+
+ // call the constructor
+ if (this.initialize) {
+ this.initialize.apply(this, arguments);
+ }
+
+ // call all constructor hooks
+ if (this._initHooks) {
+ this.callInitHooks();
+ }
+ };
+
+ // instantiate class without calling constructor
+ var F = function () {};
+ F.prototype = this.prototype;
+
+ var proto = new F();
+ proto.constructor = NewClass;
+
+ NewClass.prototype = proto;
+
+ //inherit parent's statics
+ for (var i in this) {
+ if (this.hasOwnProperty(i) && i !== 'prototype') {
+ NewClass[i] = this[i];
+ }
+ }
+
+ // mix static properties into the class
+ if (props.statics) {
+ L.extend(NewClass, props.statics);
+ delete props.statics;
+ }
+
+ // mix includes into the prototype
+ if (props.includes) {
+ L.Util.extend.apply(null, [proto].concat(props.includes));
+ delete props.includes;
+ }
+
+ // merge options
+ if (props.options && proto.options) {
+ props.options = L.extend({}, proto.options, props.options);
+ }
+
+ // mix given properties into the prototype
+ L.extend(proto, props);
+
+ proto._initHooks = [];
+
+ var parent = this;
+ // jshint camelcase: false
+ NewClass.__super__ = parent.prototype;
+
+ // add method for calling all hooks
+ proto.callInitHooks = function () {
+
+ if (this._initHooksCalled) { return; }
+
+ if (parent.prototype.callInitHooks) {
+ parent.prototype.callInitHooks.call(this);
+ }
+
+ this._initHooksCalled = true;
+
+ for (var i = 0, len = proto._initHooks.length; i < len; i++) {
+ proto._initHooks[i].call(this);
+ }
+ };
+
+ return NewClass;
+};
+
+
+// method for adding properties to prototype
+L.Class.include = function (props) {
+ L.extend(this.prototype, props);
+};
+
+// merge new default options to the Class
+L.Class.mergeOptions = function (options) {
+ L.extend(this.prototype.options, options);
+};
+
+// add a constructor hook
+L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
+ var args = Array.prototype.slice.call(arguments, 1);
+
+ var init = typeof fn === 'function' ? fn : function () {
+ this[fn].apply(this, args);
+ };
+
+ this.prototype._initHooks = this.prototype._initHooks || [];
+ this.prototype._initHooks.push(init);
+};
+
+
+/*
+ * L.Mixin.Events is used to add custom events functionality to Leaflet classes.
+ */
+
+var eventsKey = '_leaflet_events';
+
+L.Mixin = {};
+
+L.Mixin.Events = {
+
+ addEventListener: function (types, fn, context) { // (String, Function[, Object]) or (Object[, Object])
+
+ // types can be a map of types/handlers
+ if (L.Util.invokeEach(types, this.addEventListener, this, fn, context)) { return this; }
+
+ var events = this[eventsKey] = this[eventsKey] || {},
+ contextId = context && context !== this && L.stamp(context),
+ i, len, event, type, indexKey, indexLenKey, typeIndex;
+
+ // types can be a string of space-separated words
+ types = L.Util.splitWords(types);
+
+ for (i = 0, len = types.length; i < len; i++) {
+ event = {
+ action: fn,
+ context: context || this
+ };
+ type = types[i];
+
+ if (contextId) {
+ // store listeners of a particular context in a separate hash (if it has an id)
+ // gives a major performance boost when removing thousands of map layers
+
+ indexKey = type + '_idx';
+ indexLenKey = indexKey + '_len';
+
+ typeIndex = events[indexKey] = events[indexKey] || {};
+
+ if (!typeIndex[contextId]) {
+ typeIndex[contextId] = [];
+
+ // keep track of the number of keys in the index to quickly check if it's empty
+ events[indexLenKey] = (events[indexLenKey] || 0) + 1;
+ }
+
+ typeIndex[contextId].push(event);
+
+
+ } else {
+ events[type] = events[type] || [];
+ events[type].push(event);
+ }
+ }
+
+ return this;
+ },
+
+ hasEventListeners: function (type) { // (String) -> Boolean
+ var events = this[eventsKey];
+ return !!events && ((type in events && events[type].length > 0) ||
+ (type + '_idx' in events && events[type + '_idx_len'] > 0));
+ },
+
+ removeEventListener: function (types, fn, context) { // ([String, Function, Object]) or (Object[, Object])
+
+ if (!this[eventsKey]) {
+ return this;
+ }
+
+ if (!types) {
+ return this.clearAllEventListeners();
+ }
+
+ if (L.Util.invokeEach(types, this.removeEventListener, this, fn, context)) { return this; }
+
+ var events = this[eventsKey],
+ contextId = context && context !== this && L.stamp(context),
+ i, len, type, listeners, j, indexKey, indexLenKey, typeIndex, removed;
+
+ types = L.Util.splitWords(types);
+
+ for (i = 0, len = types.length; i < len; i++) {
+ type = types[i];
+ indexKey = type + '_idx';
+ indexLenKey = indexKey + '_len';
+
+ typeIndex = events[indexKey];
+
+ if (!fn) {
+ // clear all listeners for a type if function isn't specified
+ delete events[type];
+ delete events[indexKey];
+ delete events[indexLenKey];
+
+ } else {
+ listeners = contextId && typeIndex ? typeIndex[contextId] : events[type];
+
+ if (listeners) {
+ for (j = listeners.length - 1; j >= 0; j--) {
+ if ((listeners[j].action === fn) && (!context || (listeners[j].context === context))) {
+ removed = listeners.splice(j, 1);
+ // set the old action to a no-op, because it is possible
+ // that the listener is being iterated over as part of a dispatch
+ removed[0].action = L.Util.falseFn;
+ }
+ }
+
+ if (context && typeIndex && (listeners.length === 0)) {
+ delete typeIndex[contextId];
+ events[indexLenKey]--;
+ }
+ }
+ }
+ }
+
+ return this;
+ },
+
+ clearAllEventListeners: function () {
+ delete this[eventsKey];
+ return this;
+ },
+
+ fireEvent: function (type, data) { // (String[, Object])
+ if (!this.hasEventListeners(type)) {
+ return this;
+ }
+
+ var event = L.Util.extend({}, data, { type: type, target: this });
+
+ var events = this[eventsKey],
+ listeners, i, len, typeIndex, contextId;
+
+ if (events[type]) {
+ // make sure adding/removing listeners inside other listeners won't cause infinite loop
+ listeners = events[type].slice();
+
+ for (i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].action.call(listeners[i].context, event);
+ }
+ }
+
+ // fire event for the context-indexed listeners as well
+ typeIndex = events[type + '_idx'];
+
+ for (contextId in typeIndex) {
+ listeners = typeIndex[contextId].slice();
+
+ if (listeners) {
+ for (i = 0, len = listeners.length; i < len; i++) {
+ listeners[i].action.call(listeners[i].context, event);
+ }
+ }
+ }
+
+ return this;
+ },
+
+ addOneTimeEventListener: function (types, fn, context) {
+
+ if (L.Util.invokeEach(types, this.addOneTimeEventListener, this, fn, context)) { return this; }
+
+ var handler = L.bind(function () {
+ this
+ .removeEventListener(types, fn, context)
+ .removeEventListener(types, handler, context);
+ }, this);
+
+ return this
+ .addEventListener(types, fn, context)
+ .addEventListener(types, handler, context);
+ }
+};
+
+L.Mixin.Events.on = L.Mixin.Events.addEventListener;
+L.Mixin.Events.off = L.Mixin.Events.removeEventListener;
+L.Mixin.Events.once = L.Mixin.Events.addOneTimeEventListener;
+L.Mixin.Events.fire = L.Mixin.Events.fireEvent;
+
+
+/*
+ * L.Browser handles different browser and feature detections for internal Leaflet use.
+ */
+
+(function () {
+
+ var ie = 'ActiveXObject' in window,
+ ielt9 = ie && !document.addEventListener,
+
+ // terrible browser detection to work around Safari / iOS / Android browser bugs
+ ua = navigator.userAgent.toLowerCase(),
+ webkit = ua.indexOf('webkit') !== -1,
+ chrome = ua.indexOf('chrome') !== -1,
+ phantomjs = ua.indexOf('phantom') !== -1,
+ android = ua.indexOf('android') !== -1,
+ android23 = ua.search('android [23]') !== -1,
+ gecko = ua.indexOf('gecko') !== -1,
+
+ mobile = typeof orientation !== undefined + '',
+ msPointer = window.navigator && window.navigator.msPointerEnabled &&
+ window.navigator.msMaxTouchPoints && !window.PointerEvent,
+ pointer = (window.PointerEvent && window.navigator.pointerEnabled && window.navigator.maxTouchPoints) ||
+ msPointer,
+ retina = ('devicePixelRatio' in window && window.devicePixelRatio > 1) ||
+ ('matchMedia' in window && window.matchMedia('(min-resolution:144dpi)') &&
+ window.matchMedia('(min-resolution:144dpi)').matches),
+
+ doc = document.documentElement,
+ ie3d = ie && ('transition' in doc.style),
+ webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,
+ gecko3d = 'MozPerspective' in doc.style,
+ opera3d = 'OTransition' in doc.style,
+ any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d || opera3d) && !phantomjs;
+
+
+ // PhantomJS has 'ontouchstart' in document.documentElement, but doesn't actually support touch.
+ // https://github.com/Leaflet/Leaflet/pull/1434#issuecomment-13843151
+
+ var touch = !window.L_NO_TOUCH && !phantomjs && (function () {
+
+ var startName = 'ontouchstart';
+
+ // IE10+ (We simulate these into touch* events in L.DomEvent and L.DomEvent.Pointer) or WebKit, etc.
+ if (pointer || (startName in doc)) {
+ return true;
+ }
+
+ // Firefox/Gecko
+ var div = document.createElement('div'),
+ supported = false;
+
+ if (!div.setAttribute) {
+ return false;
+ }
+ div.setAttribute(startName, 'return;');
+
+ if (typeof div[startName] === 'function') {
+ supported = true;
+ }
+
+ div.removeAttribute(startName);
+ div = null;
+
+ return supported;
+ }());
+
+
+ L.Browser = {
+ ie: ie,
+ ielt9: ielt9,
+ webkit: webkit,
+ gecko: gecko && !webkit && !window.opera && !ie,
+
+ android: android,
+ android23: android23,
+
+ chrome: chrome,
+
+ ie3d: ie3d,
+ webkit3d: webkit3d,
+ gecko3d: gecko3d,
+ opera3d: opera3d,
+ any3d: any3d,
+
+ mobile: mobile,
+ mobileWebkit: mobile && webkit,
+ mobileWebkit3d: mobile && webkit3d,
+ mobileOpera: mobile && window.opera,
+
+ touch: touch,
+ msPointer: msPointer,
+ pointer: pointer,
+
+ retina: retina
+ };
+
+}());
+
+
+/*
+ * L.Point represents a point with x and y coordinates.
+ */
+
+L.Point = function (/*Number*/ x, /*Number*/ y, /*Boolean*/ round) {
+ this.x = (round ? Math.round(x) : x);
+ this.y = (round ? Math.round(y) : y);
+};
+
+L.Point.prototype = {
+
+ clone: function () {
+ return new L.Point(this.x, this.y);
+ },
+
+ // non-destructive, returns a new point
+ add: function (point) {
+ return this.clone()._add(L.point(point));
+ },
+
+ // destructive, used directly for performance in situations where it's safe to modify existing point
+ _add: function (point) {
+ this.x += point.x;
+ this.y += point.y;
+ return this;
+ },
+
+ subtract: function (point) {
+ return this.clone()._subtract(L.point(point));
+ },
+
+ _subtract: function (point) {
+ this.x -= point.x;
+ this.y -= point.y;
+ return this;
+ },
+
+ divideBy: function (num) {
+ return this.clone()._divideBy(num);
+ },
+
+ _divideBy: function (num) {
+ this.x /= num;
+ this.y /= num;
+ return this;
+ },
+
+ multiplyBy: function (num) {
+ return this.clone()._multiplyBy(num);
+ },
+
+ _multiplyBy: function (num) {
+ this.x *= num;
+ this.y *= num;
+ return this;
+ },
+
+ round: function () {
+ return this.clone()._round();
+ },
+
+ _round: function () {
+ this.x = Math.round(this.x);
+ this.y = Math.round(this.y);
+ return this;
+ },
+
+ floor: function () {
+ return this.clone()._floor();
+ },
+
+ _floor: function () {
+ this.x = Math.floor(this.x);
+ this.y = Math.floor(this.y);
+ return this;
+ },
+
+ distanceTo: function (point) {
+ point = L.point(point);
+
+ var x = point.x - this.x,
+ y = point.y - this.y;
+
+ return Math.sqrt(x * x + y * y);
+ },
+
+ equals: function (point) {
+ point = L.point(point);
+
+ return point.x === this.x &&
+ point.y === this.y;
+ },
+
+ contains: function (point) {
+ point = L.point(point);
+
+ return Math.abs(point.x) <= Math.abs(this.x) &&
+ Math.abs(point.y) <= Math.abs(this.y);
+ },
+
+ toString: function () {
+ return 'Point(' +
+ L.Util.formatNum(this.x) + ', ' +
+ L.Util.formatNum(this.y) + ')';
+ }
+};
+
+L.point = function (x, y, round) {
+ if (x instanceof L.Point) {
+ return x;
+ }
+ if (L.Util.isArray(x)) {
+ return new L.Point(x[0], x[1]);
+ }
+ if (x === undefined || x === null) {
+ return x;
+ }
+ return new L.Point(x, y, round);
+};
+
+
+/*
+ * L.Bounds represents a rectangular area on the screen in pixel coordinates.
+ */
+
+L.Bounds = function (a, b) { //(Point, Point) or Point[]
+ if (!a) { return; }
+
+ var points = b ? [a, b] : a;
+
+ for (var i = 0, len = points.length; i < len; i++) {
+ this.extend(points[i]);
+ }
+};
+
+L.Bounds.prototype = {
+ // extend the bounds to contain the given point
+ extend: function (point) { // (Point)
+ point = L.point(point);
+
+ if (!this.min && !this.max) {
+ this.min = point.clone();
+ this.max = point.clone();
+ } else {
+ this.min.x = Math.min(point.x, this.min.x);
+ this.max.x = Math.max(point.x, this.max.x);
+ this.min.y = Math.min(point.y, this.min.y);
+ this.max.y = Math.max(point.y, this.max.y);
+ }
+ return this;
+ },
+
+ getCenter: function (round) { // (Boolean) -> Point
+ return new L.Point(
+ (this.min.x + this.max.x) / 2,
+ (this.min.y + this.max.y) / 2, round);
+ },
+
+ getBottomLeft: function () { // -> Point
+ return new L.Point(this.min.x, this.max.y);
+ },
+
+ getTopRight: function () { // -> Point
+ return new L.Point(this.max.x, this.min.y);
+ },
+
+ getSize: function () {
+ return this.max.subtract(this.min);
+ },
+
+ contains: function (obj) { // (Bounds) or (Point) -> Boolean
+ var min, max;
+
+ if (typeof obj[0] === 'number' || obj instanceof L.Point) {
+ obj = L.point(obj);
+ } else {
+ obj = L.bounds(obj);
+ }
+
+ if (obj instanceof L.Bounds) {
+ min = obj.min;
+ max = obj.max;
+ } else {
+ min = max = obj;
+ }
+
+ return (min.x >= this.min.x) &&
+ (max.x <= this.max.x) &&
+ (min.y >= this.min.y) &&
+ (max.y <= this.max.y);
+ },
+
+ intersects: function (bounds) { // (Bounds) -> Boolean
+ bounds = L.bounds(bounds);
+
+ var min = this.min,
+ max = this.max,
+ min2 = bounds.min,
+ max2 = bounds.max,
+ xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
+ yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
+
+ return xIntersects && yIntersects;
+ },
+
+ isValid: function () {
+ return !!(this.min && this.max);
+ }
+};
+
+L.bounds = function (a, b) { // (Bounds) or (Point, Point) or (Point[])
+ if (!a || a instanceof L.Bounds) {
+ return a;
+ }
+ return new L.Bounds(a, b);
+};
+
+
+/*
+ * L.Transformation is an utility class to perform simple point transformations through a 2d-matrix.
+ */
+
+L.Transformation = function (a, b, c, d) {
+ this._a = a;
+ this._b = b;
+ this._c = c;
+ this._d = d;
+};
+
+L.Transformation.prototype = {
+ transform: function (point, scale) { // (Point, Number) -> Point
+ return this._transform(point.clone(), scale);
+ },
+
+ // destructive transform (faster)
+ _transform: function (point, scale) {
+ scale = scale || 1;
+ point.x = scale * (this._a * point.x + this._b);
+ point.y = scale * (this._c * point.y + this._d);
+ return point;
+ },
+
+ untransform: function (point, scale) {
+ scale = scale || 1;
+ return new L.Point(
+ (point.x / scale - this._b) / this._a,
+ (point.y / scale - this._d) / this._c);
+ }
+};
+
+
+/*
+ * L.DomUtil contains various utility functions for working with DOM.
+ */
+
+L.DomUtil = {
+ get: function (id) {
+ return (typeof id === 'string' ? document.getElementById(id) : id);
+ },
+
+ getStyle: function (el, style) {
+
+ var value = el.style[style];
+
+ if (!value && el.currentStyle) {
+ value = el.currentStyle[style];
+ }
+
+ if ((!value || value === 'auto') && document.defaultView) {
+ var css = document.defaultView.getComputedStyle(el, null);
+ value = css ? css[style] : null;
+ }
+
+ return value === 'auto' ? null : value;
+ },
+
+ getViewportOffset: function (element) {
+
+ var top = 0,
+ left = 0,
+ el = element,
+ docBody = document.body,
+ docEl = document.documentElement,
+ pos;
+
+ do {
+ top += el.offsetTop || 0;
+ left += el.offsetLeft || 0;
+
+ //add borders
+ top += parseInt(L.DomUtil.getStyle(el, 'borderTopWidth'), 10) || 0;
+ left += parseInt(L.DomUtil.getStyle(el, 'borderLeftWidth'), 10) || 0;
+
+ pos = L.DomUtil.getStyle(el, 'position');
+
+ if (el.offsetParent === docBody && pos === 'absolute') { break; }
+
+ if (pos === 'fixed') {
+ top += docBody.scrollTop || docEl.scrollTop || 0;
+ left += docBody.scrollLeft || docEl.scrollLeft || 0;
+ break;
+ }
+
+ if (pos === 'relative' && !el.offsetLeft) {
+ var width = L.DomUtil.getStyle(el, 'width'),
+ maxWidth = L.DomUtil.getStyle(el, 'max-width'),
+ r = el.getBoundingClientRect();
+
+ if (width !== 'none' || maxWidth !== 'none') {
+ left += r.left + el.clientLeft;
+ }
+
+ //calculate full y offset since we're breaking out of the loop
+ top += r.top + (docBody.scrollTop || docEl.scrollTop || 0);
+
+ break;
+ }
+
+ el = el.offsetParent;
+
+ } while (el);
+
+ el = element;
+
+ do {
+ if (el === docBody) { break; }
+
+ top -= el.scrollTop || 0;
+ left -= el.scrollLeft || 0;
+
+ el = el.parentNode;
+ } while (el);
+
+ return new L.Point(left, top);
+ },
+
+ documentIsLtr: function () {
+ if (!L.DomUtil._docIsLtrCached) {
+ L.DomUtil._docIsLtrCached = true;
+ L.DomUtil._docIsLtr = L.DomUtil.getStyle(document.body, 'direction') === 'ltr';
+ }
+ return L.DomUtil._docIsLtr;
+ },
+
+ create: function (tagName, className, container) {
+
+ var el = document.createElement(tagName);
+ el.className = className;
+
+ if (container) {
+ container.appendChild(el);
+ }
+
+ return el;
+ },
+
+ hasClass: function (el, name) {
+ if (el.classList !== undefined) {
+ return el.classList.contains(name);
+ }
+ var className = L.DomUtil._getClass(el);
+ return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
+ },
+
+ addClass: function (el, name) {
+ if (el.classList !== undefined) {
+ var classes = L.Util.splitWords(name);
+ for (var i = 0, len = classes.length; i < len; i++) {
+ el.classList.add(classes[i]);
+ }
+ } else if (!L.DomUtil.hasClass(el, name)) {
+ var className = L.DomUtil._getClass(el);
+ L.DomUtil._setClass(el, (className ? className + ' ' : '') + name);
+ }
+ },
+
+ removeClass: function (el, name) {
+ if (el.classList !== undefined) {
+ el.classList.remove(name);
+ } else {
+ L.DomUtil._setClass(el, L.Util.trim((' ' + L.DomUtil._getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
+ }
+ },
+
+ _setClass: function (el, name) {
+ if (el.className.baseVal === undefined) {
+ el.className = name;
+ } else {
+ // in case of SVG element
+ el.className.baseVal = name;
+ }
+ },
+
+ _getClass: function (el) {
+ return el.className.baseVal === undefined ? el.className : el.className.baseVal;
+ },
+
+ setOpacity: function (el, value) {
+
+ if ('opacity' in el.style) {
+ el.style.opacity = value;
+
+ } else if ('filter' in el.style) {
+
+ var filter = false,
+ filterName = 'DXImageTransform.Microsoft.Alpha';
+
+ // filters collection throws an error if we try to retrieve a filter that doesn't exist
+ try {
+ filter = el.filters.item(filterName);
+ } catch (e) {
+ // don't set opacity to 1 if we haven't already set an opacity,
+ // it isn't needed and breaks transparent pngs.
+ if (value === 1) { return; }
+ }
+
+ value = Math.round(value * 100);
+
+ if (filter) {
+ filter.Enabled = (value !== 100);
+ filter.Opacity = value;
+ } else {
+ el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
+ }
+ }
+ },
+
+ testProp: function (props) {
+
+ var style = document.documentElement.style;
+
+ for (var i = 0; i < props.length; i++) {
+ if (props[i] in style) {
+ return props[i];
+ }
+ }
+ return false;
+ },
+
+ getTranslateString: function (point) {
+ // on WebKit browsers (Chrome/Safari/iOS Safari/Android) using translate3d instead of translate
+ // makes animation smoother as it ensures HW accel is used. Firefox 13 doesn't care
+ // (same speed either way), Opera 12 doesn't support translate3d
+
+ var is3d = L.Browser.webkit3d,
+ open = 'translate' + (is3d ? '3d' : '') + '(',
+ close = (is3d ? ',0' : '') + ')';
+
+ return open + point.x + 'px,' + point.y + 'px' + close;
+ },
+
+ getScaleString: function (scale, origin) {
+
+ var preTranslateStr = L.DomUtil.getTranslateString(origin.add(origin.multiplyBy(-1 * scale))),
+ scaleStr = ' scale(' + scale + ') ';
+
+ return preTranslateStr + scaleStr;
+ },
+
+ setPosition: function (el, point, disable3D) { // (HTMLElement, Point[, Boolean])
+
+ // jshint camelcase: false
+ el._leaflet_pos = point;
+
+ if (!disable3D && L.Browser.any3d) {
+ el.style[L.DomUtil.TRANSFORM] = L.DomUtil.getTranslateString(point);
+ } else {
+ el.style.left = point.x + 'px';
+ el.style.top = point.y + 'px';
+ }
+ },
+
+ getPosition: function (el) {
+ // this method is only used for elements previously positioned using setPosition,
+ // so it's safe to cache the position for performance
+
+ // jshint camelcase: false
+ return el._leaflet_pos;
+ }
+};
+
+
+// prefix style property names
+
+L.DomUtil.TRANSFORM = L.DomUtil.testProp(
+ ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
+
+// webkitTransition comes first because some browser versions that drop vendor prefix don't do
+// the same for the transitionend event, in particular the Android 4.1 stock browser
+
+L.DomUtil.TRANSITION = L.DomUtil.testProp(
+ ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
+
+L.DomUtil.TRANSITION_END =
+ L.DomUtil.TRANSITION === 'webkitTransition' || L.DomUtil.TRANSITION === 'OTransition' ?
+ L.DomUtil.TRANSITION + 'End' : 'transitionend';
+
+(function () {
+ if ('onselectstart' in document) {
+ L.extend(L.DomUtil, {
+ disableTextSelection: function () {
+ L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
+ },
+
+ enableTextSelection: function () {
+ L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
+ }
+ });
+ } else {
+ var userSelectProperty = L.DomUtil.testProp(
+ ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
+
+ L.extend(L.DomUtil, {
+ disableTextSelection: function () {
+ if (userSelectProperty) {
+ var style = document.documentElement.style;
+ this._userSelect = style[userSelectProperty];
+ style[userSelectProperty] = 'none';
+ }
+ },
+
+ enableTextSelection: function () {
+ if (userSelectProperty) {
+ document.documentElement.style[userSelectProperty] = this._userSelect;
+ delete this._userSelect;
+ }
+ }
+ });
+ }
+
+ L.extend(L.DomUtil, {
+ disableImageDrag: function () {
+ L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
+ },
+
+ enableImageDrag: function () {
+ L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
+ }
+ });
+})();
+
+
+/*
+ * L.LatLng represents a geographical point with latitude and longitude coordinates.
+ */
+
+L.LatLng = function (lat, lng, alt) { // (Number, Number, Number)
+ lat = parseFloat(lat);
+ lng = parseFloat(lng);
+
+ if (isNaN(lat) || isNaN(lng)) {
+ throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
+ }
+
+ this.lat = lat;
+ this.lng = lng;
+
+ if (alt !== undefined) {
+ this.alt = parseFloat(alt);
+ }
+};
+
+L.extend(L.LatLng, {
+ DEG_TO_RAD: Math.PI / 180,
+ RAD_TO_DEG: 180 / Math.PI,
+ MAX_MARGIN: 1.0E-9 // max margin of error for the "equals" check
+});
+
+L.LatLng.prototype = {
+ equals: function (obj) { // (LatLng) -> Boolean
+ if (!obj) { return false; }
+
+ obj = L.latLng(obj);
+
+ var margin = Math.max(
+ Math.abs(this.lat - obj.lat),
+ Math.abs(this.lng - obj.lng));
+
+ return margin <= L.LatLng.MAX_MARGIN;
+ },
+
+ toString: function (precision) { // (Number) -> String
+ return 'LatLng(' +
+ L.Util.formatNum(this.lat, precision) + ', ' +
+ L.Util.formatNum(this.lng, precision) + ')';
+ },
+
+ // Haversine distance formula, see http://en.wikipedia.org/wiki/Haversine_formula
+ // TODO move to projection code, LatLng shouldn't know about Earth
+ distanceTo: function (other) { // (LatLng) -> Number
+ other = L.latLng(other);
+
+ var R = 6378137, // earth radius in meters
+ d2r = L.LatLng.DEG_TO_RAD,
+ dLat = (other.lat - this.lat) * d2r,
+ dLon = (other.lng - this.lng) * d2r,
+ lat1 = this.lat * d2r,
+ lat2 = other.lat * d2r,
+ sin1 = Math.sin(dLat / 2),
+ sin2 = Math.sin(dLon / 2);
+
+ var a = sin1 * sin1 + sin2 * sin2 * Math.cos(lat1) * Math.cos(lat2);
+
+ return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
+ },
+
+ wrap: function (a, b) { // (Number, Number) -> LatLng
+ var lng = this.lng;
+
+ a = a || -180;
+ b = b || 180;
+
+ lng = (lng + b) % (b - a) + (lng < a || lng === b ? b : a);
+
+ return new L.LatLng(this.lat, lng);
+ }
+};
+
+L.latLng = function (a, b) { // (LatLng) or ([Number, Number]) or (Number, Number)
+ if (a instanceof L.LatLng) {
+ return a;
+ }
+ if (L.Util.isArray(a)) {
+ if (typeof a[0] === 'number' || typeof a[0] === 'string') {
+ return new L.LatLng(a[0], a[1], a[2]);
+ } else {
+ return null;
+ }
+ }
+ if (a === undefined || a === null) {
+ return a;
+ }
+ if (typeof a === 'object' && 'lat' in a) {
+ return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon);
+ }
+ if (b === undefined) {
+ return null;
+ }
+ return new L.LatLng(a, b);
+};
+
+
+
+/*
+ * L.LatLngBounds represents a rectangular area on the map in geographical coordinates.
+ */
+
+L.LatLngBounds = function (southWest, northEast) { // (LatLng, LatLng) or (LatLng[])
+ if (!southWest) { return; }
+
+ var latlngs = northEast ? [southWest, northEast] : southWest;
+
+ for (var i = 0, len = latlngs.length; i < len; i++) {
+ this.extend(latlngs[i]);
+ }
+};
+
+L.LatLngBounds.prototype = {
+ // extend the bounds to contain the given point or bounds
+ extend: function (obj) { // (LatLng) or (LatLngBounds)
+ if (!obj) { return this; }
+
+ var latLng = L.latLng(obj);
+ if (latLng !== null) {
+ obj = latLng;
+ } else {
+ obj = L.latLngBounds(obj);
+ }
+
+ if (obj instanceof L.LatLng) {
+ if (!this._southWest && !this._northEast) {
+ this._southWest = new L.LatLng(obj.lat, obj.lng);
+ this._northEast = new L.LatLng(obj.lat, obj.lng);
+ } else {
+ this._southWest.lat = Math.min(obj.lat, this._southWest.lat);
+ this._southWest.lng = Math.min(obj.lng, this._southWest.lng);
+
+ this._northEast.lat = Math.max(obj.lat, this._northEast.lat);
+ this._northEast.lng = Math.max(obj.lng, this._northEast.lng);
+ }
+ } else if (obj instanceof L.LatLngBounds) {
+ this.extend(obj._southWest);
+ this.extend(obj._northEast);
+ }
+ return this;
+ },
+
+ // extend the bounds by a percentage
+ pad: function (bufferRatio) { // (Number) -> LatLngBounds
+ var sw = this._southWest,
+ ne = this._northEast,
+ heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
+ widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
+
+ return new L.LatLngBounds(
+ new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
+ new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
+ },
+
+ getCenter: function () { // -> LatLng
+ return new L.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 L.LatLng(this.getNorth(), this.getWest());
+ },
+
+ getSouthEast: function () {
+ return new L.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 (obj) { // (LatLngBounds) or (LatLng) -> Boolean
+ if (typeof obj[0] === 'number' || obj instanceof L.LatLng) {
+ obj = L.latLng(obj);
+ } else {
+ obj = L.latLngBounds(obj);
+ }
+
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2, ne2;
+
+ if (obj instanceof L.LatLngBounds) {
+ sw2 = obj.getSouthWest();
+ ne2 = obj.getNorthEast();
+ } else {
+ sw2 = ne2 = obj;
+ }
+
+ return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
+ (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
+ },
+
+ intersects: function (bounds) { // (LatLngBounds)
+ bounds = L.latLngBounds(bounds);
+
+ var sw = this._southWest,
+ ne = this._northEast,
+ sw2 = bounds.getSouthWest(),
+ ne2 = bounds.getNorthEast(),
+
+ latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
+ lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
+
+ return latIntersects && lngIntersects;
+ },
+
+ toBBoxString: function () {
+ return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
+ },
+
+ equals: function (bounds) { // (LatLngBounds)
+ if (!bounds) { return false; }
+
+ bounds = L.latLngBounds(bounds);
+
+ return this._southWest.equals(bounds.getSouthWest()) &&
+ this._northEast.equals(bounds.getNorthEast());
+ },
+
+ isValid: function () {
+ return !!(this._southWest && this._northEast);
+ }
+};
+
+//TODO International date line?
+
+L.latLngBounds = function (a, b) { // (LatLngBounds) or (LatLng, LatLng)
+ if (!a || a instanceof L.LatLngBounds) {
+ return a;
+ }
+ return new L.LatLngBounds(a, b);
+};
+
+
+/*
+ * L.Projection contains various geographical projections used by CRS classes.
+ */
+
+L.Projection = {};
+
+
+/*
+ * Spherical Mercator is the most popular map projection, used by EPSG:3857 CRS used by default.
+ */
+
+L.Projection.SphericalMercator = {
+ MAX_LATITUDE: 85.0511287798,
+
+ project: function (latlng) { // (LatLng) -> Point
+ var d = L.LatLng.DEG_TO_RAD,
+ max = this.MAX_LATITUDE,
+ lat = Math.max(Math.min(max, latlng.lat), -max),
+ x = latlng.lng * d,
+ y = lat * d;
+
+ y = Math.log(Math.tan((Math.PI / 4) + (y / 2)));
+
+ return new L.Point(x, y);
+ },
+
+ unproject: function (point) { // (Point, Boolean) -> LatLng
+ var d = L.LatLng.RAD_TO_DEG,
+ lng = point.x * d,
+ lat = (2 * Math.atan(Math.exp(point.y)) - (Math.PI / 2)) * d;
+
+ return new L.LatLng(lat, lng);
+ }
+};
+
+
+/*
+ * Simple equirectangular (Plate Carree) projection, used by CRS like EPSG:4326 and Simple.
+ */
+
+L.Projection.LonLat = {
+ project: function (latlng) {
+ return new L.Point(latlng.lng, latlng.lat);
+ },
+
+ unproject: function (point) {
+ return new L.LatLng(point.y, point.x);
+ }
+};
+
+
+/*
+ * L.CRS is a base object for all defined CRS (Coordinate Reference Systems) in Leaflet.
+ */
+
+L.CRS = {
+ latLngToPoint: function (latlng, zoom) { // (LatLng, Number) -> Point
+ var projectedPoint = this.projection.project(latlng),
+ scale = this.scale(zoom);
+
+ return this.transformation._transform(projectedPoint, scale);
+ },
+
+ pointToLatLng: function (point, zoom) { // (Point, Number[, Boolean]) -> LatLng
+ var scale = this.scale(zoom),
+ untransformedPoint = this.transformation.untransform(point, scale);
+
+ return this.projection.unproject(untransformedPoint);
+ },
+
+ project: function (latlng) {
+ return this.projection.project(latlng);
+ },
+
+ scale: function (zoom) {
+ return 256 * Math.pow(2, zoom);
+ },
+
+ getSize: function (zoom) {
+ var s = this.scale(zoom);
+ return L.point(s, s);
+ }
+};
+
+
+/*
+ * A simple CRS that can be used for flat non-Earth maps like panoramas or game maps.
+ */
+
+L.CRS.Simple = L.extend({}, L.CRS, {
+ projection: L.Projection.LonLat,
+ transformation: new L.Transformation(1, 0, -1, 0),
+
+ scale: function (zoom) {
+ return Math.pow(2, zoom);
+ }
+});
+
+
+/*
+ * L.CRS.EPSG3857 (Spherical Mercator) is the most common CRS for web mapping
+ * and is used by Leaflet by default.
+ */
+
+L.CRS.EPSG3857 = L.extend({}, L.CRS, {
+ code: 'EPSG:3857',
+
+ projection: L.Projection.SphericalMercator,
+ transformation: new L.Transformation(0.5 / Math.PI, 0.5, -0.5 / Math.PI, 0.5),
+
+ project: function (latlng) { // (LatLng) -> Point
+ var projectedPoint = this.projection.project(latlng),
+ earthRadius = 6378137;
+ return projectedPoint.multiplyBy(earthRadius);
+ }
+});
+
+L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
+ code: 'EPSG:900913'
+});
+
+
+/*
+ * L.CRS.EPSG4326 is a CRS popular among advanced GIS specialists.
+ */
+
+L.CRS.EPSG4326 = L.extend({}, L.CRS, {
+ code: 'EPSG:4326',
+
+ projection: L.Projection.LonLat,
+ transformation: new L.Transformation(1 / 360, 0.5, -1 / 360, 0.5)
+});
+
+
+/*
+ * L.Map is the central class of the API - it is used to create a map.
+ */
+
+L.Map = L.Class.extend({
+
+ includes: L.Mixin.Events,
+
+ options: {
+ crs: L.CRS.EPSG3857,
+
+ /*
+ center: LatLng,
+ zoom: Number,
+ layers: Array,
+ */
+
+ fadeAnimation: L.DomUtil.TRANSITION && !L.Browser.android23,
+ trackResize: true,
+ markerZoomAnimation: L.DomUtil.TRANSITION && L.Browser.any3d
+ },
+
+ initialize: function (id, options) { // (HTMLElement or String, Object)
+ options = L.setOptions(this, options);
+
+
+ this._initContainer(id);
+ this._initLayout();
+
+ // hack for https://github.com/Leaflet/Leaflet/issues/1980
+ this._onResize = L.bind(this._onResize, this);
+
+ this._initEvents();
+
+ if (options.maxBounds) {
+ this.setMaxBounds(options.maxBounds);
+ }
+
+ if (options.center && options.zoom !== undefined) {
+ this.setView(L.latLng(options.center), options.zoom, {reset: true});
+ }
+
+ this._handlers = [];
+
+ this._layers = {};
+ this._zoomBoundLayers = {};
+ this._tileLayersNum = 0;
+
+ this.callInitHooks();
+
+ this._addLayers(options.layers);
+ },
+
+
+ // public methods that modify map state
+
+ // replaced by animation-powered implementation in Map.PanAnimation.js
+ setView: function (center, zoom) {
+ zoom = zoom === undefined ? this.getZoom() : zoom;
+ this._resetView(L.latLng(center), this._limitZoom(zoom));
+ return this;
+ },
+
+ setZoom: function (zoom, options) {
+ if (!this._loaded) {
+ this._zoom = this._limitZoom(zoom);
+ return this;
+ }
+ return this.setView(this.getCenter(), zoom, {zoom: options});
+ },
+
+ zoomIn: function (delta, options) {
+ return this.setZoom(this._zoom + (delta || 1), options);
+ },
+
+ zoomOut: function (delta, options) {
+ return this.setZoom(this._zoom - (delta || 1), options);
+ },
+
+ setZoomAround: function (latlng, zoom, options) {
+ var scale = this.getZoomScale(zoom),
+ viewHalf = this.getSize().divideBy(2),
+ containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
+
+ centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
+ newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
+
+ return this.setView(newCenter, zoom, {zoom: options});
+ },
+
+ fitBounds: function (bounds, options) {
+
+ options = options || {};
+ bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
+
+ var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
+ paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
+
+ zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)),
+ paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
+
+ swPoint = this.project(bounds.getSouthWest(), zoom),
+ nePoint = this.project(bounds.getNorthEast(), zoom),
+ center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
+
+ zoom = options && options.maxZoom ? Math.min(options.maxZoom, zoom) : zoom;
+
+ return this.setView(center, zoom, options);
+ },
+
+ fitWorld: function (options) {
+ return this.fitBounds([[-90, -180], [90, 180]], options);
+ },
+
+ panTo: function (center, options) { // (LatLng)
+ return this.setView(center, this._zoom, {pan: options});
+ },
+
+ panBy: function (offset) { // (Point)
+ // replaced with animated panBy in Map.PanAnimation.js
+ this.fire('movestart');
+
+ this._rawPanBy(L.point(offset));
+
+ this.fire('move');
+ return this.fire('moveend');
+ },
+
+ setMaxBounds: function (bounds) {
+ bounds = L.latLngBounds(bounds);
+
+ this.options.maxBounds = bounds;
+
+ if (!bounds) {
+ return this.off('moveend', this._panInsideMaxBounds, this);
+ }
+
+ if (this._loaded) {
+ this._panInsideMaxBounds();
+ }
+
+ return this.on('moveend', this._panInsideMaxBounds, this);
+ },
+
+ panInsideBounds: function (bounds, options) {
+ var center = this.getCenter(),
+ newCenter = this._limitCenter(center, this._zoom, bounds);
+
+ if (center.equals(newCenter)) { return this; }
+
+ return this.panTo(newCenter, options);
+ },
+
+ addLayer: function (layer) {
+ // TODO method is too big, refactor
+
+ var id = L.stamp(layer);
+
+ if (this._layers[id]) { return this; }
+
+ this._layers[id] = layer;
+
+ // TODO getMaxZoom, getMinZoom in ILayer (instead of options)
+ if (layer.options && (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom))) {
+ this._zoomBoundLayers[id] = layer;
+ this._updateZoomLevels();
+ }
+
+ // TODO looks ugly, refactor!!!
+ if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
+ this._tileLayersNum++;
+ this._tileLayersToLoad++;
+ layer.on('load', this._onTileLayerLoad, this);
+ }
+
+ if (this._loaded) {
+ this._layerAdd(layer);
+ }
+
+ return this;
+ },
+
+ removeLayer: function (layer) {
+ var id = L.stamp(layer);
+
+ if (!this._layers[id]) { return this; }
+
+ if (this._loaded) {
+ layer.onRemove(this);
+ }
+
+ delete this._layers[id];
+
+ if (this._loaded) {
+ this.fire('layerremove', {layer: layer});
+ }
+
+ if (this._zoomBoundLayers[id]) {
+ delete this._zoomBoundLayers[id];
+ this._updateZoomLevels();
+ }
+
+ // TODO looks ugly, refactor
+ if (this.options.zoomAnimation && L.TileLayer && (layer instanceof L.TileLayer)) {
+ this._tileLayersNum--;
+ this._tileLayersToLoad--;
+ layer.off('load', this._onTileLayerLoad, this);
+ }
+
+ return this;
+ },
+
+ hasLayer: function (layer) {
+ if (!layer) { return false; }
+
+ return (L.stamp(layer) in this._layers);
+ },
+
+ eachLayer: function (method, context) {
+ for (var i in this._layers) {
+ method.call(context, this._layers[i]);
+ }
+ return this;
+ },
+
+ invalidateSize: function (options) {
+ if (!this._loaded) { return this; }
+
+ options = L.extend({
+ animate: false,
+ pan: true
+ }, options === true ? {animate: true} : options);
+
+ var oldSize = this.getSize();
+ this._sizeChanged = true;
+ this._initialCenter = null;
+
+ var newSize = this.getSize(),
+ oldCenter = oldSize.divideBy(2).round(),
+ newCenter = newSize.divideBy(2).round(),
+ offset = oldCenter.subtract(newCenter);
+
+ if (!offset.x && !offset.y) { return this; }
+
+ if (options.animate && options.pan) {
+ this.panBy(offset);
+
+ } else {
+ if (options.pan) {
+ this._rawPanBy(offset);
+ }
+
+ this.fire('move');
+
+ if (options.debounceMoveend) {
+ clearTimeout(this._sizeTimer);
+ this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
+ } else {
+ this.fire('moveend');
+ }
+ }
+
+ return this.fire('resize', {
+ oldSize: oldSize,
+ newSize: newSize
+ });
+ },
+
+ // TODO handler.addTo
+ addHandler: function (name, HandlerClass) {
+ if (!HandlerClass) { return this; }
+
+ var handler = this[name] = new HandlerClass(this);
+
+ this._handlers.push(handler);
+
+ if (this.options[name]) {
+ handler.enable();
+ }
+
+ return this;
+ },
+
+ remove: function () {
+ if (this._loaded) {
+ this.fire('unload');
+ }
+
+ this._initEvents('off');
+
+ try {
+ // throws error in IE6-8
+ delete this._container._leaflet;
+ } catch (e) {
+ this._container._leaflet = undefined;
+ }
+
+ this._clearPanes();
+ if (this._clearControlPos) {
+ this._clearControlPos();
+ }
+
+ this._clearHandlers();
+
+ return this;
+ },
+
+
+ // public methods for getting map state
+
+ getCenter: function () { // (Boolean) -> LatLng
+ this._checkIfLoaded();
+
+ if (this._initialCenter && !this._moved()) {
+ return this._initialCenter;
+ }
+ return this.layerPointToLatLng(this._getCenterLayerPoint());
+ },
+
+ getZoom: function () {
+ return this._zoom;
+ },
+
+ getBounds: function () {
+ var bounds = this.getPixelBounds(),
+ sw = this.unproject(bounds.getBottomLeft()),
+ ne = this.unproject(bounds.getTopRight());
+
+ return new L.LatLngBounds(sw, ne);
+ },
+
+ getMinZoom: function () {
+ return this.options.minZoom === undefined ?
+ (this._layersMinZoom === undefined ? 0 : this._layersMinZoom) :
+ this.options.minZoom;
+ },
+
+ getMaxZoom: function () {
+ return this.options.maxZoom === undefined ?
+ (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
+ this.options.maxZoom;
+ },
+
+ getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
+ bounds = L.latLngBounds(bounds);
+
+ var zoom = this.getMinZoom() - (inside ? 1 : 0),
+ maxZoom = this.getMaxZoom(),
+ size = this.getSize(),
+
+ nw = bounds.getNorthWest(),
+ se = bounds.getSouthEast(),
+
+ zoomNotFound = true,
+ boundsSize;
+
+ padding = L.point(padding || [0, 0]);
+
+ do {
+ zoom++;
+ boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)).add(padding);
+ zoomNotFound = !inside ? size.contains(boundsSize) : boundsSize.x < size.x || boundsSize.y < size.y;
+
+ } while (zoomNotFound && zoom <= maxZoom);
+
+ if (zoomNotFound && inside) {
+ return null;
+ }
+
+ return inside ? zoom : zoom - 1;
+ },
+
+ getSize: function () {
+ if (!this._size || this._sizeChanged) {
+ this._size = new L.Point(
+ this._container.clientWidth,
+ this._container.clientHeight);
+
+ this._sizeChanged = false;
+ }
+ return this._size.clone();
+ },
+
+ getPixelBounds: function () {
+ var topLeftPoint = this._getTopLeftPoint();
+ return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
+ },
+
+ getPixelOrigin: function () {
+ this._checkIfLoaded();
+ return this._initialTopLeftPoint;
+ },
+
+ getPanes: function () {
+ return this._panes;
+ },
+
+ getContainer: function () {
+ return this._container;
+ },
+
+
+ // TODO replace with universal implementation after refactoring projections
+
+ getZoomScale: function (toZoom) {
+ var crs = this.options.crs;
+ return crs.scale(toZoom) / crs.scale(this._zoom);
+ },
+
+ getScaleZoom: function (scale) {
+ return this._zoom + (Math.log(scale) / Math.LN2);
+ },
+
+
+ // conversion methods
+
+ project: function (latlng, zoom) { // (LatLng[, Number]) -> Point
+ zoom = zoom === undefined ? this._zoom : zoom;
+ return this.options.crs.latLngToPoint(L.latLng(latlng), zoom);
+ },
+
+ unproject: function (point, zoom) { // (Point[, Number]) -> LatLng
+ zoom = zoom === undefined ? this._zoom : zoom;
+ return this.options.crs.pointToLatLng(L.point(point), zoom);
+ },
+
+ layerPointToLatLng: function (point) { // (Point)
+ var projectedPoint = L.point(point).add(this.getPixelOrigin());
+ return this.unproject(projectedPoint);
+ },
+
+ latLngToLayerPoint: function (latlng) { // (LatLng)
+ var projectedPoint = this.project(L.latLng(latlng))._round();
+ return projectedPoint._subtract(this.getPixelOrigin());
+ },
+
+ containerPointToLayerPoint: function (point) { // (Point)
+ return L.point(point).subtract(this._getMapPanePos());
+ },
+
+ layerPointToContainerPoint: function (point) { // (Point)
+ return L.point(point).add(this._getMapPanePos());
+ },
+
+ containerPointToLatLng: function (point) {
+ var layerPoint = this.containerPointToLayerPoint(L.point(point));
+ return this.layerPointToLatLng(layerPoint);
+ },
+
+ latLngToContainerPoint: function (latlng) {
+ return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));
+ },
+
+ mouseEventToContainerPoint: function (e) { // (MouseEvent)
+ return L.DomEvent.getMousePosition(e, this._container);
+ },
+
+ mouseEventToLayerPoint: function (e) { // (MouseEvent)
+ return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
+ },
+
+ mouseEventToLatLng: function (e) { // (MouseEvent)
+ return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
+ },
+
+
+ // map initialization methods
+
+ _initContainer: function (id) {
+ var container = this._container = L.DomUtil.get(id);
+
+ if (!container) {
+ throw new Error('Map container not found.');
+ } else if (container._leaflet) {
+ throw new Error('Map container is already initialized.');
+ }
+
+ container._leaflet = true;
+ },
+
+ _initLayout: function () {
+ var container = this._container;
+
+ L.DomUtil.addClass(container, 'leaflet-container' +
+ (L.Browser.touch ? ' leaflet-touch' : '') +
+ (L.Browser.retina ? ' leaflet-retina' : '') +
+ (L.Browser.ielt9 ? ' leaflet-oldie' : '') +
+ (this.options.fadeAnimation ? ' leaflet-fade-anim' : ''));
+
+ var position = L.DomUtil.getStyle(container, 'position');
+
+ if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
+ container.style.position = 'relative';
+ }
+
+ this._initPanes();
+
+ if (this._initControlPos) {
+ this._initControlPos();
+ }
+ },
+
+ _initPanes: function () {
+ var panes = this._panes = {};
+
+ this._mapPane = panes.mapPane = this._createPane('leaflet-map-pane', this._container);
+
+ this._tilePane = panes.tilePane = this._createPane('leaflet-tile-pane', this._mapPane);
+ panes.objectsPane = this._createPane('leaflet-objects-pane', this._mapPane);
+ panes.shadowPane = this._createPane('leaflet-shadow-pane');
+ panes.overlayPane = this._createPane('leaflet-overlay-pane');
+ panes.markerPane = this._createPane('leaflet-marker-pane');
+ panes.popupPane = this._createPane('leaflet-popup-pane');
+
+ var zoomHide = ' leaflet-zoom-hide';
+
+ if (!this.options.markerZoomAnimation) {
+ L.DomUtil.addClass(panes.markerPane, zoomHide);
+ L.DomUtil.addClass(panes.shadowPane, zoomHide);
+ L.DomUtil.addClass(panes.popupPane, zoomHide);
+ }
+ },
+
+ _createPane: function (className, container) {
+ return L.DomUtil.create('div', className, container || this._panes.objectsPane);
+ },
+
+ _clearPanes: function () {
+ this._container.removeChild(this._mapPane);
+ },
+
+ _addLayers: function (layers) {
+ layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];
+
+ for (var i = 0, len = layers.length; i < len; i++) {
+ this.addLayer(layers[i]);
+ }
+ },
+
+
+ // private methods that modify map state
+
+ _resetView: function (center, zoom, preserveMapOffset, afterZoomAnim) {
+
+ var zoomChanged = (this._zoom !== zoom);
+
+ if (!afterZoomAnim) {
+ this.fire('movestart');
+
+ if (zoomChanged) {
+ this.fire('zoomstart');
+ }
+ }
+
+ this._zoom = zoom;
+ this._initialCenter = center;
+
+ this._initialTopLeftPoint = this._getNewTopLeftPoint(center);
+
+ if (!preserveMapOffset) {
+ L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
+ } else {
+ this._initialTopLeftPoint._add(this._getMapPanePos());
+ }
+
+ this._tileLayersToLoad = this._tileLayersNum;
+
+ var loading = !this._loaded;
+ this._loaded = true;
+
+ if (loading) {
+ this.fire('load');
+ this.eachLayer(this._layerAdd, this);
+ }
+
+ this.fire('viewreset', {hard: !preserveMapOffset});
+
+ this.fire('move');
+
+ if (zoomChanged || afterZoomAnim) {
+ this.fire('zoomend');
+ }
+
+ this.fire('moveend', {hard: !preserveMapOffset});
+ },
+
+ _rawPanBy: function (offset) {
+ L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
+ },
+
+ _getZoomSpan: function () {
+ return this.getMaxZoom() - this.getMinZoom();
+ },
+
+ _updateZoomLevels: function () {
+ var i,
+ minZoom = Infinity,
+ maxZoom = -Infinity,
+ oldZoomSpan = this._getZoomSpan();
+
+ for (i in this._zoomBoundLayers) {
+ var layer = this._zoomBoundLayers[i];
+ if (!isNaN(layer.options.minZoom)) {
+ minZoom = Math.min(minZoom, layer.options.minZoom);
+ }
+ if (!isNaN(layer.options.maxZoom)) {
+ maxZoom = Math.max(maxZoom, layer.options.maxZoom);
+ }
+ }
+
+ if (i === undefined) { // we have no tilelayers
+ this._layersMaxZoom = this._layersMinZoom = undefined;
+ } else {
+ this._layersMaxZoom = maxZoom;
+ this._layersMinZoom = minZoom;
+ }
+
+ if (oldZoomSpan !== this._getZoomSpan()) {
+ this.fire('zoomlevelschange');
+ }
+ },
+
+ _panInsideMaxBounds: function () {
+ this.panInsideBounds(this.options.maxBounds);
+ },
+
+ _checkIfLoaded: function () {
+ if (!this._loaded) {
+ throw new Error('Set map center and zoom first.');
+ }
+ },
+
+ // map events
+
+ _initEvents: function (onOff) {
+ if (!L.DomEvent) { return; }
+
+ onOff = onOff || 'on';
+
+ L.DomEvent[onOff](this._container, 'click', this._onMouseClick, this);
+
+ var events = ['dblclick', 'mousedown', 'mouseup', 'mouseenter',
+ 'mouseleave', 'mousemove', 'contextmenu'],
+ i, len;
+
+ for (i = 0, len = events.length; i < len; i++) {
+ L.DomEvent[onOff](this._container, events[i], this._fireMouseEvent, this);
+ }
+
+ if (this.options.trackResize) {
+ L.DomEvent[onOff](window, 'resize', this._onResize, this);
+ }
+ },
+
+ _onResize: function () {
+ L.Util.cancelAnimFrame(this._resizeRequest);
+ this._resizeRequest = L.Util.requestAnimFrame(
+ function () { this.invalidateSize({debounceMoveend: true}); }, this, false, this._container);
+ },
+
+ _onMouseClick: function (e) {
+ if (!this._loaded || (!e._simulated &&
+ ((this.dragging && this.dragging.moved()) ||
+ (this.boxZoom && this.boxZoom.moved()))) ||
+ L.DomEvent._skipped(e)) { return; }
+
+ this.fire('preclick');
+ this._fireMouseEvent(e);
+ },
+
+ _fireMouseEvent: function (e) {
+ if (!this._loaded || L.DomEvent._skipped(e)) { return; }
+
+ var type = e.type;
+
+ type = (type === 'mouseenter' ? 'mouseover' : (type === 'mouseleave' ? 'mouseout' : type));
+
+ if (!this.hasEventListeners(type)) { return; }
+
+ if (type === 'contextmenu') {
+ L.DomEvent.preventDefault(e);
+ }
+
+ var containerPoint = this.mouseEventToContainerPoint(e),
+ layerPoint = this.containerPointToLayerPoint(containerPoint),
+ latlng = this.layerPointToLatLng(layerPoint);
+
+ this.fire(type, {
+ latlng: latlng,
+ layerPoint: layerPoint,
+ containerPoint: containerPoint,
+ originalEvent: e
+ });
+ },
+
+ _onTileLayerLoad: function () {
+ this._tileLayersToLoad--;
+ if (this._tileLayersNum && !this._tileLayersToLoad) {
+ this.fire('tilelayersload');
+ }
+ },
+
+ _clearHandlers: function () {
+ for (var i = 0, len = this._handlers.length; i < len; i++) {
+ this._handlers[i].disable();
+ }
+ },
+
+ whenReady: function (callback, context) {
+ if (this._loaded) {
+ callback.call(context || this, this);
+ } else {
+ this.on('load', callback, context);
+ }
+ return this;
+ },
+
+ _layerAdd: function (layer) {
+ layer.onAdd(this);
+ this.fire('layeradd', {layer: layer});
+ },
+
+
+ // private methods for getting map state
+
+ _getMapPanePos: function () {
+ return L.DomUtil.getPosition(this._mapPane);
+ },
+
+ _moved: function () {
+ var pos = this._getMapPanePos();
+ return pos && !pos.equals([0, 0]);
+ },
+
+ _getTopLeftPoint: function () {
+ return this.getPixelOrigin().subtract(this._getMapPanePos());
+ },
+
+ _getNewTopLeftPoint: function (center, zoom) {
+ var viewHalf = this.getSize()._divideBy(2);
+ // TODO round on display, not calculation to increase precision?
+ return this.project(center, zoom)._subtract(viewHalf)._round();
+ },
+
+ _latLngToNewLayerPoint: function (latlng, newZoom, newCenter) {
+ var topLeft = this._getNewTopLeftPoint(newCenter, newZoom).add(this._getMapPanePos());
+ return this.project(latlng, newZoom)._subtract(topLeft);
+ },
+
+ // layer point of the current center
+ _getCenterLayerPoint: function () {
+ return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
+ },
+
+ // offset of the specified place to the current center in pixels
+ _getCenterOffset: function (latlng) {
+ return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
+ },
+
+ // adjust center for view to get inside bounds
+ _limitCenter: function (center, zoom, bounds) {
+
+ if (!bounds) { return center; }
+
+ var centerPoint = this.project(center, zoom),
+ viewHalf = this.getSize().divideBy(2),
+ viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
+ offset = this._getBoundsOffset(viewBounds, bounds, zoom);
+
+ return this.unproject(centerPoint.add(offset), zoom);
+ },
+
+ // adjust offset for view to get inside bounds
+ _limitOffset: function (offset, bounds) {
+ if (!bounds) { return offset; }
+
+ var viewBounds = this.getPixelBounds(),
+ newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
+
+ return offset.add(this._getBoundsOffset(newBounds, bounds));
+ },
+
+ // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
+ _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
+ var nwOffset = this.project(maxBounds.getNorthWest(), zoom).subtract(pxBounds.min),
+ seOffset = this.project(maxBounds.getSouthEast(), zoom).subtract(pxBounds.max),
+
+ dx = this._rebound(nwOffset.x, -seOffset.x),
+ dy = this._rebound(nwOffset.y, -seOffset.y);
+
+ return new L.Point(dx, dy);
+ },
+
+ _rebound: function (left, right) {
+ return left + right > 0 ?
+ Math.round(left - right) / 2 :
+ Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
+ },
+
+ _limitZoom: function (zoom) {
+ var min = this.getMinZoom(),
+ max = this.getMaxZoom();
+
+ return Math.max(min, Math.min(max, zoom));
+ }
+});
+
+L.map = function (id, options) {
+ return new L.Map(id, options);
+};
+
+
+/*
+ * Mercator projection that takes into account that the Earth is not a perfect sphere.
+ * Less popular than spherical mercator; used by projections like EPSG:3395.
+ */
+
+L.Projection.Mercator = {
+ MAX_LATITUDE: 85.0840591556,
+
+ R_MINOR: 6356752.314245179,
+ R_MAJOR: 6378137,
+
+ project: function (latlng) { // (LatLng) -> Point
+ var d = L.LatLng.DEG_TO_RAD,
+ max = this.MAX_LATITUDE,
+ lat = Math.max(Math.min(max, latlng.lat), -max),
+ r = this.R_MAJOR,
+ r2 = this.R_MINOR,
+ x = latlng.lng * d * r,
+ y = lat * d,
+ tmp = r2 / r,
+ eccent = Math.sqrt(1.0 - tmp * tmp),
+ con = eccent * Math.sin(y);
+
+ con = Math.pow((1 - con) / (1 + con), eccent * 0.5);
+
+ var ts = Math.tan(0.5 * ((Math.PI * 0.5) - y)) / con;
+ y = -r * Math.log(ts);
+
+ return new L.Point(x, y);
+ },
+
+ unproject: function (point) { // (Point, Boolean) -> LatLng
+ var d = L.LatLng.RAD_TO_DEG,
+ r = this.R_MAJOR,
+ r2 = this.R_MINOR,
+ lng = point.x * d / r,
+ tmp = r2 / r,
+ eccent = Math.sqrt(1 - (tmp * tmp)),
+ ts = Math.exp(- point.y / r),
+ phi = (Math.PI / 2) - 2 * Math.atan(ts),
+ numIter = 15,
+ tol = 1e-7,
+ i = numIter,
+ dphi = 0.1,
+ con;
+
+ while ((Math.abs(dphi) > tol) && (--i > 0)) {
+ con = eccent * Math.sin(phi);
+ dphi = (Math.PI / 2) - 2 * Math.atan(ts *
+ Math.pow((1.0 - con) / (1.0 + con), 0.5 * eccent)) - phi;
+ phi += dphi;
+ }
+
+ return new L.LatLng(phi * d, lng);
+ }
+};
+
+
+
+L.CRS.EPSG3395 = L.extend({}, L.CRS, {
+ code: 'EPSG:3395',
+
+ projection: L.Projection.Mercator,
+
+ transformation: (function () {
+ var m = L.Projection.Mercator,
+ r = m.R_MAJOR,
+ scale = 0.5 / (Math.PI * r);
+
+ return new L.Transformation(scale, 0.5, -scale, 0.5);
+ }())
+});
+
+
+/*
+ * L.TileLayer is used for standard xyz-numbered tile layers.
+ */
+
+L.TileLayer = L.Class.extend({
+ includes: L.Mixin.Events,
+
+ options: {
+ minZoom: 0,
+ maxZoom: 18,
+ tileSize: 256,
+ subdomains: 'abc',
+ errorTileUrl: '',
+ attribution: '',
+ zoomOffset: 0,
+ opacity: 1,
+ /*
+ maxNativeZoom: null,
+ zIndex: null,
+ tms: false,
+ continuousWorld: false,
+ noWrap: false,
+ zoomReverse: false,
+ detectRetina: false,
+ reuseTiles: false,
+ bounds: false,
+ */
+ unloadInvisibleTiles: L.Browser.mobile,
+ updateWhenIdle: L.Browser.mobile
+ },
+
+ initialize: function (url, options) {
+ options = L.setOptions(this, options);
+
+ // detecting retina displays, adjusting tileSize and zoom levels
+ if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
+
+ options.tileSize = Math.floor(options.tileSize / 2);
+ options.zoomOffset++;
+
+ if (options.minZoom > 0) {
+ options.minZoom--;
+ }
+ this.options.maxZoom--;
+ }
+
+ if (options.bounds) {
+ options.bounds = L.latLngBounds(options.bounds);
+ }
+
+ this._url = url;
+
+ var subdomains = this.options.subdomains;
+
+ if (typeof subdomains === 'string') {
+ this.options.subdomains = subdomains.split('');
+ }
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+ this._animated = map._zoomAnimated;
+
+ // create a container div for tiles
+ this._initContainer();
+
+ // set up events
+ map.on({
+ 'viewreset': this._reset,
+ 'moveend': this._update
+ }, this);
+
+ if (this._animated) {
+ map.on({
+ 'zoomanim': this._animateZoom,
+ 'zoomend': this._endZoomAnim
+ }, this);
+ }
+
+ if (!this.options.updateWhenIdle) {
+ this._limitedUpdate = L.Util.limitExecByInterval(this._update, 150, this);
+ map.on('move', this._limitedUpdate, this);
+ }
+
+ this._reset();
+ this._update();
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ onRemove: function (map) {
+ this._container.parentNode.removeChild(this._container);
+
+ map.off({
+ 'viewreset': this._reset,
+ 'moveend': this._update
+ }, this);
+
+ if (this._animated) {
+ map.off({
+ 'zoomanim': this._animateZoom,
+ 'zoomend': this._endZoomAnim
+ }, this);
+ }
+
+ if (!this.options.updateWhenIdle) {
+ map.off('move', this._limitedUpdate, this);
+ }
+
+ this._container = null;
+ this._map = null;
+ },
+
+ bringToFront: function () {
+ var pane = this._map._panes.tilePane;
+
+ if (this._container) {
+ pane.appendChild(this._container);
+ this._setAutoZIndex(pane, Math.max);
+ }
+
+ return this;
+ },
+
+ bringToBack: function () {
+ var pane = this._map._panes.tilePane;
+
+ if (this._container) {
+ pane.insertBefore(this._container, pane.firstChild);
+ this._setAutoZIndex(pane, Math.min);
+ }
+
+ return this;
+ },
+
+ getAttribution: function () {
+ return this.options.attribution;
+ },
+
+ getContainer: function () {
+ return this._container;
+ },
+
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+
+ if (this._map) {
+ this._updateOpacity();
+ }
+
+ return this;
+ },
+
+ setZIndex: function (zIndex) {
+ this.options.zIndex = zIndex;
+ this._updateZIndex();
+
+ return this;
+ },
+
+ setUrl: function (url, noRedraw) {
+ this._url = url;
+
+ if (!noRedraw) {
+ this.redraw();
+ }
+
+ return this;
+ },
+
+ redraw: function () {
+ if (this._map) {
+ this._reset({hard: true});
+ this._update();
+ }
+ return this;
+ },
+
+ _updateZIndex: function () {
+ if (this._container && this.options.zIndex !== undefined) {
+ this._container.style.zIndex = this.options.zIndex;
+ }
+ },
+
+ _setAutoZIndex: function (pane, compare) {
+
+ var layers = pane.children,
+ edgeZIndex = -compare(Infinity, -Infinity), // -Infinity for max, Infinity for min
+ zIndex, i, len;
+
+ for (i = 0, len = layers.length; i < len; i++) {
+
+ if (layers[i] !== this._container) {
+ zIndex = parseInt(layers[i].style.zIndex, 10);
+
+ if (!isNaN(zIndex)) {
+ edgeZIndex = compare(edgeZIndex, zIndex);
+ }
+ }
+ }
+
+ this.options.zIndex = this._container.style.zIndex =
+ (isFinite(edgeZIndex) ? edgeZIndex : 0) + compare(1, -1);
+ },
+
+ _updateOpacity: function () {
+ var i,
+ tiles = this._tiles;
+
+ if (L.Browser.ielt9) {
+ for (i in tiles) {
+ L.DomUtil.setOpacity(tiles[i], this.options.opacity);
+ }
+ } else {
+ L.DomUtil.setOpacity(this._container, this.options.opacity);
+ }
+ },
+
+ _initContainer: function () {
+ var tilePane = this._map._panes.tilePane;
+
+ if (!this._container) {
+ this._container = L.DomUtil.create('div', 'leaflet-layer');
+
+ this._updateZIndex();
+
+ if (this._animated) {
+ var className = 'leaflet-tile-container';
+
+ this._bgBuffer = L.DomUtil.create('div', className, this._container);
+ this._tileContainer = L.DomUtil.create('div', className, this._container);
+
+ } else {
+ this._tileContainer = this._container;
+ }
+
+ tilePane.appendChild(this._container);
+
+ if (this.options.opacity < 1) {
+ this._updateOpacity();
+ }
+ }
+ },
+
+ _reset: function (e) {
+ for (var key in this._tiles) {
+ this.fire('tileunload', {tile: this._tiles[key]});
+ }
+
+ this._tiles = {};
+ this._tilesToLoad = 0;
+
+ if (this.options.reuseTiles) {
+ this._unusedTiles = [];
+ }
+
+ this._tileContainer.innerHTML = '';
+
+ if (this._animated && e && e.hard) {
+ this._clearBgBuffer();
+ }
+
+ this._initContainer();
+ },
+
+ _getTileSize: function () {
+ var map = this._map,
+ zoom = map.getZoom() + this.options.zoomOffset,
+ zoomN = this.options.maxNativeZoom,
+ tileSize = this.options.tileSize;
+
+ if (zoomN && zoom > zoomN) {
+ tileSize = Math.round(map.getZoomScale(zoom) / map.getZoomScale(zoomN) * tileSize);
+ }
+
+ return tileSize;
+ },
+
+ _update: function () {
+
+ if (!this._map) { return; }
+
+ var map = this._map,
+ bounds = map.getPixelBounds(),
+ zoom = map.getZoom(),
+ tileSize = this._getTileSize();
+
+ if (zoom > this.options.maxZoom || zoom < this.options.minZoom) {
+ return;
+ }
+
+ var tileBounds = L.bounds(
+ bounds.min.divideBy(tileSize)._floor(),
+ bounds.max.divideBy(tileSize)._floor());
+
+ this._addTilesFromCenterOut(tileBounds);
+
+ if (this.options.unloadInvisibleTiles || this.options.reuseTiles) {
+ this._removeOtherTiles(tileBounds);
+ }
+ },
+
+ _addTilesFromCenterOut: function (bounds) {
+ var queue = [],
+ center = bounds.getCenter();
+
+ var j, i, point;
+
+ for (j = bounds.min.y; j <= bounds.max.y; j++) {
+ for (i = bounds.min.x; i <= bounds.max.x; i++) {
+ point = new L.Point(i, j);
+
+ if (this._tileShouldBeLoaded(point)) {
+ queue.push(point);
+ }
+ }
+ }
+
+ var tilesToLoad = queue.length;
+
+ if (tilesToLoad === 0) { return; }
+
+ // load tiles in order of their distance to center
+ queue.sort(function (a, b) {
+ return a.distanceTo(center) - b.distanceTo(center);
+ });
+
+ var fragment = document.createDocumentFragment();
+
+ // if its the first batch of tiles to load
+ if (!this._tilesToLoad) {
+ this.fire('loading');
+ }
+
+ this._tilesToLoad += tilesToLoad;
+
+ for (i = 0; i < tilesToLoad; i++) {
+ this._addTile(queue[i], fragment);
+ }
+
+ this._tileContainer.appendChild(fragment);
+ },
+
+ _tileShouldBeLoaded: function (tilePoint) {
+ if ((tilePoint.x + ':' + tilePoint.y) in this._tiles) {
+ return false; // already loaded
+ }
+
+ var options = this.options;
+
+ if (!options.continuousWorld) {
+ var limit = this._getWrapTileNum();
+
+ // don't load if exceeds world bounds
+ if ((options.noWrap && (tilePoint.x < 0 || tilePoint.x >= limit.x)) ||
+ tilePoint.y < 0 || tilePoint.y >= limit.y) { return false; }
+ }
+
+ if (options.bounds) {
+ var tileSize = options.tileSize,
+ nwPoint = tilePoint.multiplyBy(tileSize),
+ sePoint = nwPoint.add([tileSize, tileSize]),
+ nw = this._map.unproject(nwPoint),
+ se = this._map.unproject(sePoint);
+
+ // TODO temporary hack, will be removed after refactoring projections
+ // https://github.com/Leaflet/Leaflet/issues/1618
+ if (!options.continuousWorld && !options.noWrap) {
+ nw = nw.wrap();
+ se = se.wrap();
+ }
+
+ if (!options.bounds.intersects([nw, se])) { return false; }
+ }
+
+ return true;
+ },
+
+ _removeOtherTiles: function (bounds) {
+ var kArr, x, y, key;
+
+ for (key in this._tiles) {
+ kArr = key.split(':');
+ x = parseInt(kArr[0], 10);
+ y = parseInt(kArr[1], 10);
+
+ // remove tile if it's out of bounds
+ if (x < bounds.min.x || x > bounds.max.x || y < bounds.min.y || y > bounds.max.y) {
+ this._removeTile(key);
+ }
+ }
+ },
+
+ _removeTile: function (key) {
+ var tile = this._tiles[key];
+
+ this.fire('tileunload', {tile: tile, url: tile.src});
+
+ if (this.options.reuseTiles) {
+ L.DomUtil.removeClass(tile, 'leaflet-tile-loaded');
+ this._unusedTiles.push(tile);
+
+ } else if (tile.parentNode === this._tileContainer) {
+ this._tileContainer.removeChild(tile);
+ }
+
+ // for https://github.com/CloudMade/Leaflet/issues/137
+ if (!L.Browser.android) {
+ tile.onload = null;
+ tile.src = L.Util.emptyImageUrl;
+ }
+
+ delete this._tiles[key];
+ },
+
+ _addTile: function (tilePoint, container) {
+ var tilePos = this._getTilePos(tilePoint);
+
+ // get unused tile - or create a new tile
+ var tile = this._getTile();
+
+ /*
+ Chrome 20 layouts much faster with top/left (verify with timeline, frames)
+ Android 4 browser has display issues with top/left and requires transform instead
+ (other browsers don't currently care) - see debug/hacks/jitter.html for an example
+ */
+ L.DomUtil.setPosition(tile, tilePos, L.Browser.chrome);
+
+ this._tiles[tilePoint.x + ':' + tilePoint.y] = tile;
+
+ this._loadTile(tile, tilePoint);
+
+ if (tile.parentNode !== this._tileContainer) {
+ container.appendChild(tile);
+ }
+ },
+
+ _getZoomForUrl: function () {
+
+ var options = this.options,
+ zoom = this._map.getZoom();
+
+ if (options.zoomReverse) {
+ zoom = options.maxZoom - zoom;
+ }
+
+ zoom += options.zoomOffset;
+
+ return options.maxNativeZoom ? Math.min(zoom, options.maxNativeZoom) : zoom;
+ },
+
+ _getTilePos: function (tilePoint) {
+ var origin = this._map.getPixelOrigin(),
+ tileSize = this._getTileSize();
+
+ return tilePoint.multiplyBy(tileSize).subtract(origin);
+ },
+
+ // image-specific code (override to implement e.g. Canvas or SVG tile layer)
+
+ getTileUrl: function (tilePoint) {
+ return L.Util.template(this._url, L.extend({
+ s: this._getSubdomain(tilePoint),
+ z: tilePoint.z,
+ x: tilePoint.x,
+ y: tilePoint.y
+ }, this.options));
+ },
+
+ _getWrapTileNum: function () {
+ var crs = this._map.options.crs,
+ size = crs.getSize(this._map.getZoom());
+ return size.divideBy(this._getTileSize())._floor();
+ },
+
+ _adjustTilePoint: function (tilePoint) {
+
+ var limit = this._getWrapTileNum();
+
+ // wrap tile coordinates
+ if (!this.options.continuousWorld && !this.options.noWrap) {
+ tilePoint.x = ((tilePoint.x % limit.x) + limit.x) % limit.x;
+ }
+
+ if (this.options.tms) {
+ tilePoint.y = limit.y - tilePoint.y - 1;
+ }
+
+ tilePoint.z = this._getZoomForUrl();
+ },
+
+ _getSubdomain: function (tilePoint) {
+ var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
+ return this.options.subdomains[index];
+ },
+
+ _getTile: function () {
+ if (this.options.reuseTiles && this._unusedTiles.length > 0) {
+ var tile = this._unusedTiles.pop();
+ this._resetTile(tile);
+ return tile;
+ }
+ return this._createTile();
+ },
+
+ // Override if data stored on a tile needs to be cleaned up before reuse
+ _resetTile: function (/*tile*/) {},
+
+ _createTile: function () {
+ var tile = L.DomUtil.create('img', 'leaflet-tile');
+ tile.style.width = tile.style.height = this._getTileSize() + 'px';
+ tile.galleryimg = 'no';
+
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
+
+ if (L.Browser.ielt9 && this.options.opacity !== undefined) {
+ L.DomUtil.setOpacity(tile, this.options.opacity);
+ }
+ // without this hack, tiles disappear after zoom on Chrome for Android
+ // https://github.com/Leaflet/Leaflet/issues/2078
+ if (L.Browser.mobileWebkit3d) {
+ tile.style.WebkitBackfaceVisibility = 'hidden';
+ }
+ return tile;
+ },
+
+ _loadTile: function (tile, tilePoint) {
+ tile._layer = this;
+ tile.onload = this._tileOnLoad;
+ tile.onerror = this._tileOnError;
+
+ this._adjustTilePoint(tilePoint);
+ tile.src = this.getTileUrl(tilePoint);
+
+ this.fire('tileloadstart', {
+ tile: tile,
+ url: tile.src
+ });
+ },
+
+ _tileLoaded: function () {
+ this._tilesToLoad--;
+
+ if (this._animated) {
+ L.DomUtil.addClass(this._tileContainer, 'leaflet-zoom-animated');
+ }
+
+ if (!this._tilesToLoad) {
+ this.fire('load');
+
+ if (this._animated) {
+ // clear scaled tiles after all new tiles are loaded (for performance)
+ clearTimeout(this._clearBgBufferTimer);
+ this._clearBgBufferTimer = setTimeout(L.bind(this._clearBgBuffer, this), 500);
+ }
+ }
+ },
+
+ _tileOnLoad: function () {
+ var layer = this._layer;
+
+ //Only if we are loading an actual image
+ if (this.src !== L.Util.emptyImageUrl) {
+ L.DomUtil.addClass(this, 'leaflet-tile-loaded');
+
+ layer.fire('tileload', {
+ tile: this,
+ url: this.src
+ });
+ }
+
+ layer._tileLoaded();
+ },
+
+ _tileOnError: function () {
+ var layer = this._layer;
+
+ layer.fire('tileerror', {
+ tile: this,
+ url: this.src
+ });
+
+ var newUrl = layer.options.errorTileUrl;
+ if (newUrl) {
+ this.src = newUrl;
+ }
+
+ layer._tileLoaded();
+ }
+});
+
+L.tileLayer = function (url, options) {
+ return new L.TileLayer(url, options);
+};
+
+
+/*
+ * L.TileLayer.WMS is used for putting WMS tile layers on the map.
+ */
+
+L.TileLayer.WMS = L.TileLayer.extend({
+
+ defaultWmsParams: {
+ service: 'WMS',
+ request: 'GetMap',
+ version: '1.1.1',
+ layers: '',
+ styles: '',
+ format: 'image/jpeg',
+ transparent: false
+ },
+
+ initialize: function (url, options) { // (String, Object)
+
+ this._url = url;
+
+ var wmsParams = L.extend({}, this.defaultWmsParams),
+ tileSize = options.tileSize || this.options.tileSize;
+
+ if (options.detectRetina && L.Browser.retina) {
+ wmsParams.width = wmsParams.height = tileSize * 2;
+ } else {
+ wmsParams.width = wmsParams.height = tileSize;
+ }
+
+ for (var i in options) {
+ // all keys that are not TileLayer options go to WMS params
+ if (!this.options.hasOwnProperty(i) && i !== 'crs') {
+ wmsParams[i] = options[i];
+ }
+ }
+
+ this.wmsParams = wmsParams;
+
+ L.setOptions(this, options);
+ },
+
+ onAdd: function (map) {
+
+ this._crs = this.options.crs || map.options.crs;
+
+ this._wmsVersion = parseFloat(this.wmsParams.version);
+
+ var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
+ this.wmsParams[projectionKey] = this._crs.code;
+
+ L.TileLayer.prototype.onAdd.call(this, map);
+ },
+
+ getTileUrl: function (tilePoint) { // (Point, Number) -> String
+
+ var map = this._map,
+ tileSize = this.options.tileSize,
+
+ nwPoint = tilePoint.multiplyBy(tileSize),
+ sePoint = nwPoint.add([tileSize, tileSize]),
+
+ nw = this._crs.project(map.unproject(nwPoint, tilePoint.z)),
+ se = this._crs.project(map.unproject(sePoint, tilePoint.z)),
+ bbox = this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
+ [se.y, nw.x, nw.y, se.x].join(',') :
+ [nw.x, se.y, se.x, nw.y].join(','),
+
+ url = L.Util.template(this._url, {s: this._getSubdomain(tilePoint)});
+
+ return url + L.Util.getParamString(this.wmsParams, url, true) + '&BBOX=' + bbox;
+ },
+
+ setParams: function (params, noRedraw) {
+
+ L.extend(this.wmsParams, params);
+
+ if (!noRedraw) {
+ this.redraw();
+ }
+
+ return this;
+ }
+});
+
+L.tileLayer.wms = function (url, options) {
+ return new L.TileLayer.WMS(url, options);
+};
+
+
+/*
+ * L.TileLayer.Canvas is a class that you can use as a base for creating
+ * dynamically drawn Canvas-based tile layers.
+ */
+
+L.TileLayer.Canvas = L.TileLayer.extend({
+ options: {
+ async: false
+ },
+
+ initialize: function (options) {
+ L.setOptions(this, options);
+ },
+
+ redraw: function () {
+ if (this._map) {
+ this._reset({hard: true});
+ this._update();
+ }
+
+ for (var i in this._tiles) {
+ this._redrawTile(this._tiles[i]);
+ }
+ return this;
+ },
+
+ _redrawTile: function (tile) {
+ this.drawTile(tile, tile._tilePoint, this._map._zoom);
+ },
+
+ _createTile: function () {
+ var tile = L.DomUtil.create('canvas', 'leaflet-tile');
+ tile.width = tile.height = this.options.tileSize;
+ tile.onselectstart = tile.onmousemove = L.Util.falseFn;
+ return tile;
+ },
+
+ _loadTile: function (tile, tilePoint) {
+ tile._layer = this;
+ tile._tilePoint = tilePoint;
+
+ this._redrawTile(tile);
+
+ if (!this.options.async) {
+ this.tileDrawn(tile);
+ }
+ },
+
+ drawTile: function (/*tile, tilePoint*/) {
+ // override with rendering code
+ },
+
+ tileDrawn: function (tile) {
+ this._tileOnLoad.call(tile);
+ }
+});
+
+
+L.tileLayer.canvas = function (options) {
+ return new L.TileLayer.Canvas(options);
+};
+
+
+/*
+ * L.ImageOverlay is used to overlay images over the map (to specific geographical bounds).
+ */
+
+L.ImageOverlay = L.Class.extend({
+ includes: L.Mixin.Events,
+
+ options: {
+ opacity: 1
+ },
+
+ initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
+ this._url = url;
+ this._bounds = L.latLngBounds(bounds);
+
+ L.setOptions(this, options);
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+
+ if (!this._image) {
+ this._initImage();
+ }
+
+ map._panes.overlayPane.appendChild(this._image);
+
+ map.on('viewreset', this._reset, this);
+
+ if (map.options.zoomAnimation && L.Browser.any3d) {
+ map.on('zoomanim', this._animateZoom, this);
+ }
+
+ this._reset();
+ },
+
+ onRemove: function (map) {
+ map.getPanes().overlayPane.removeChild(this._image);
+
+ map.off('viewreset', this._reset, this);
+
+ if (map.options.zoomAnimation) {
+ map.off('zoomanim', this._animateZoom, this);
+ }
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+ this._updateOpacity();
+ return this;
+ },
+
+ // TODO remove bringToFront/bringToBack duplication from TileLayer/Path
+ bringToFront: function () {
+ if (this._image) {
+ this._map._panes.overlayPane.appendChild(this._image);
+ }
+ return this;
+ },
+
+ bringToBack: function () {
+ var pane = this._map._panes.overlayPane;
+ if (this._image) {
+ pane.insertBefore(this._image, pane.firstChild);
+ }
+ return this;
+ },
+
+ setUrl: function (url) {
+ this._url = url;
+ this._image.src = this._url;
+ },
+
+ getAttribution: function () {
+ return this.options.attribution;
+ },
+
+ _initImage: function () {
+ this._image = L.DomUtil.create('img', 'leaflet-image-layer');
+
+ if (this._map.options.zoomAnimation && L.Browser.any3d) {
+ L.DomUtil.addClass(this._image, 'leaflet-zoom-animated');
+ } else {
+ L.DomUtil.addClass(this._image, 'leaflet-zoom-hide');
+ }
+
+ this._updateOpacity();
+
+ //TODO createImage util method to remove duplication
+ L.extend(this._image, {
+ galleryimg: 'no',
+ onselectstart: L.Util.falseFn,
+ onmousemove: L.Util.falseFn,
+ onload: L.bind(this._onImageLoad, this),
+ src: this._url
+ });
+ },
+
+ _animateZoom: function (e) {
+ var map = this._map,
+ image = this._image,
+ scale = map.getZoomScale(e.zoom),
+ nw = this._bounds.getNorthWest(),
+ se = this._bounds.getSouthEast(),
+
+ topLeft = map._latLngToNewLayerPoint(nw, e.zoom, e.center),
+ size = map._latLngToNewLayerPoint(se, e.zoom, e.center)._subtract(topLeft),
+ origin = topLeft._add(size._multiplyBy((1 / 2) * (1 - 1 / scale)));
+
+ image.style[L.DomUtil.TRANSFORM] =
+ L.DomUtil.getTranslateString(origin) + ' scale(' + scale + ') ';
+ },
+
+ _reset: function () {
+ var image = this._image,
+ topLeft = this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
+ size = this._map.latLngToLayerPoint(this._bounds.getSouthEast())._subtract(topLeft);
+
+ L.DomUtil.setPosition(image, topLeft);
+
+ image.style.width = size.x + 'px';
+ image.style.height = size.y + 'px';
+ },
+
+ _onImageLoad: function () {
+ this.fire('load');
+ },
+
+ _updateOpacity: function () {
+ L.DomUtil.setOpacity(this._image, this.options.opacity);
+ }
+});
+
+L.imageOverlay = function (url, bounds, options) {
+ return new L.ImageOverlay(url, bounds, options);
+};
+
+
+/*
+ * L.Icon is an image-based icon class that you can use with L.Marker for custom markers.
+ */
+
+L.Icon = L.Class.extend({
+ options: {
+ /*
+ iconUrl: (String) (required)
+ iconRetinaUrl: (String) (optional, used for retina devices if detected)
+ iconSize: (Point) (can be set through CSS)
+ iconAnchor: (Point) (centered by default, can be set in CSS with negative margins)
+ popupAnchor: (Point) (if not specified, popup opens in the anchor point)
+ shadowUrl: (String) (no shadow by default)
+ shadowRetinaUrl: (String) (optional, used for retina devices if detected)
+ shadowSize: (Point)
+ shadowAnchor: (Point)
+ */
+ className: ''
+ },
+
+ initialize: function (options) {
+ L.setOptions(this, options);
+ },
+
+ createIcon: function (oldIcon) {
+ return this._createIcon('icon', oldIcon);
+ },
+
+ createShadow: function (oldIcon) {
+ return this._createIcon('shadow', oldIcon);
+ },
+
+ _createIcon: function (name, oldIcon) {
+ var src = this._getIconUrl(name);
+
+ if (!src) {
+ if (name === 'icon') {
+ throw new Error('iconUrl not set in Icon options (see the docs).');
+ }
+ return null;
+ }
+
+ var img;
+ if (!oldIcon || oldIcon.tagName !== 'IMG') {
+ img = this._createImg(src);
+ } else {
+ img = this._createImg(src, oldIcon);
+ }
+ this._setIconStyles(img, name);
+
+ return img;
+ },
+
+ _setIconStyles: function (img, name) {
+ var options = this.options,
+ size = L.point(options[name + 'Size']),
+ anchor;
+
+ if (name === 'shadow') {
+ anchor = L.point(options.shadowAnchor || options.iconAnchor);
+ } else {
+ anchor = L.point(options.iconAnchor);
+ }
+
+ if (!anchor && size) {
+ anchor = size.divideBy(2, true);
+ }
+
+ img.className = 'leaflet-marker-' + name + ' ' + options.className;
+
+ if (anchor) {
+ img.style.marginLeft = (-anchor.x) + 'px';
+ img.style.marginTop = (-anchor.y) + 'px';
+ }
+
+ if (size) {
+ img.style.width = size.x + 'px';
+ img.style.height = size.y + 'px';
+ }
+ },
+
+ _createImg: function (src, el) {
+ el = el || document.createElement('img');
+ el.src = src;
+ return el;
+ },
+
+ _getIconUrl: function (name) {
+ if (L.Browser.retina && this.options[name + 'RetinaUrl']) {
+ return this.options[name + 'RetinaUrl'];
+ }
+ return this.options[name + 'Url'];
+ }
+});
+
+L.icon = function (options) {
+ return new L.Icon(options);
+};
+
+
+/*
+ * L.Icon.Default is the blue marker icon used by default in Leaflet.
+ */
+
+L.Icon.Default = L.Icon.extend({
+
+ options: {
+ iconSize: [25, 41],
+ iconAnchor: [12, 41],
+ popupAnchor: [1, -34],
+
+ shadowSize: [41, 41]
+ },
+
+ _getIconUrl: function (name) {
+ var key = name + 'Url';
+
+ if (this.options[key]) {
+ return this.options[key];
+ }
+
+ if (L.Browser.retina && name === 'icon') {
+ name += '-2x';
+ }
+
+ var path = L.Icon.Default.imagePath;
+
+ if (!path) {
+ throw new Error('Couldn\'t autodetect L.Icon.Default.imagePath, set it manually.');
+ }
+
+ return path + '/marker-' + name + '.png';
+ }
+});
+
+L.Icon.Default.imagePath = (function () {
+ var scripts = document.getElementsByTagName('script'),
+ leafletRe = /[\/^]leaflet[\-\._]?([\w\-\._]*)\.js\??/;
+
+ var i, len, src, matches, path;
+
+ for (i = 0, len = scripts.length; i < len; i++) {
+ src = scripts[i].src;
+ matches = src.match(leafletRe);
+
+ if (matches) {
+ path = src.split(leafletRe)[0];
+ return (path ? path + '/' : '') + 'images';
+ }
+ }
+}());
+
+
+/*
+ * L.Marker is used to display clickable/draggable icons on the map.
+ */
+
+L.Marker = L.Class.extend({
+
+ includes: L.Mixin.Events,
+
+ options: {
+ icon: new L.Icon.Default(),
+ title: '',
+ alt: '',
+ clickable: true,
+ draggable: false,
+ keyboard: true,
+ zIndexOffset: 0,
+ opacity: 1,
+ riseOnHover: false,
+ riseOffset: 250
+ },
+
+ initialize: function (latlng, options) {
+ L.setOptions(this, options);
+ this._latlng = L.latLng(latlng);
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+
+ map.on('viewreset', this.update, this);
+
+ this._initIcon();
+ this.update();
+ this.fire('add');
+
+ if (map.options.zoomAnimation && map.options.markerZoomAnimation) {
+ map.on('zoomanim', this._animateZoom, this);
+ }
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ onRemove: function (map) {
+ if (this.dragging) {
+ this.dragging.disable();
+ }
+
+ this._removeIcon();
+ this._removeShadow();
+
+ this.fire('remove');
+
+ map.off({
+ 'viewreset': this.update,
+ 'zoomanim': this._animateZoom
+ }, this);
+
+ this._map = null;
+ },
+
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ setLatLng: function (latlng) {
+ this._latlng = L.latLng(latlng);
+
+ this.update();
+
+ return this.fire('move', { latlng: this._latlng });
+ },
+
+ setZIndexOffset: function (offset) {
+ this.options.zIndexOffset = offset;
+ this.update();
+
+ return this;
+ },
+
+ setIcon: function (icon) {
+
+ this.options.icon = icon;
+
+ if (this._map) {
+ this._initIcon();
+ this.update();
+ }
+
+ if (this._popup) {
+ this.bindPopup(this._popup);
+ }
+
+ return this;
+ },
+
+ update: function () {
+ if (this._icon) {
+ var pos = this._map.latLngToLayerPoint(this._latlng).round();
+ this._setPos(pos);
+ }
+
+ return this;
+ },
+
+ _initIcon: function () {
+ var options = this.options,
+ map = this._map,
+ animation = (map.options.zoomAnimation && map.options.markerZoomAnimation),
+ classToAdd = animation ? 'leaflet-zoom-animated' : 'leaflet-zoom-hide';
+
+ var icon = options.icon.createIcon(this._icon),
+ addIcon = false;
+
+ // if we're not reusing the icon, remove the old one and init new one
+ if (icon !== this._icon) {
+ if (this._icon) {
+ this._removeIcon();
+ }
+ addIcon = true;
+
+ if (options.title) {
+ icon.title = options.title;
+ }
+
+ if (options.alt) {
+ icon.alt = options.alt;
+ }
+ }
+
+ L.DomUtil.addClass(icon, classToAdd);
+
+ if (options.keyboard) {
+ icon.tabIndex = '0';
+ }
+
+ this._icon = icon;
+
+ this._initInteraction();
+
+ if (options.riseOnHover) {
+ L.DomEvent
+ .on(icon, 'mouseover', this._bringToFront, this)
+ .on(icon, 'mouseout', this._resetZIndex, this);
+ }
+
+ var newShadow = options.icon.createShadow(this._shadow),
+ addShadow = false;
+
+ if (newShadow !== this._shadow) {
+ this._removeShadow();
+ addShadow = true;
+ }
+
+ if (newShadow) {
+ L.DomUtil.addClass(newShadow, classToAdd);
+ }
+ this._shadow = newShadow;
+
+
+ if (options.opacity < 1) {
+ this._updateOpacity();
+ }
+
+
+ var panes = this._map._panes;
+
+ if (addIcon) {
+ panes.markerPane.appendChild(this._icon);
+ }
+
+ if (newShadow && addShadow) {
+ panes.shadowPane.appendChild(this._shadow);
+ }
+ },
+
+ _removeIcon: function () {
+ if (this.options.riseOnHover) {
+ L.DomEvent
+ .off(this._icon, 'mouseover', this._bringToFront)
+ .off(this._icon, 'mouseout', this._resetZIndex);
+ }
+
+ this._map._panes.markerPane.removeChild(this._icon);
+
+ this._icon = null;
+ },
+
+ _removeShadow: function () {
+ if (this._shadow) {
+ this._map._panes.shadowPane.removeChild(this._shadow);
+ }
+ this._shadow = null;
+ },
+
+ _setPos: function (pos) {
+ L.DomUtil.setPosition(this._icon, pos);
+
+ if (this._shadow) {
+ L.DomUtil.setPosition(this._shadow, pos);
+ }
+
+ this._zIndex = pos.y + this.options.zIndexOffset;
+
+ this._resetZIndex();
+ },
+
+ _updateZIndex: function (offset) {
+ this._icon.style.zIndex = this._zIndex + offset;
+ },
+
+ _animateZoom: function (opt) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
+
+ this._setPos(pos);
+ },
+
+ _initInteraction: function () {
+
+ if (!this.options.clickable) { return; }
+
+ // TODO refactor into something shared with Map/Path/etc. to DRY it up
+
+ var icon = this._icon,
+ events = ['dblclick', 'mousedown', 'mouseover', 'mouseout', 'contextmenu'];
+
+ L.DomUtil.addClass(icon, 'leaflet-clickable');
+ L.DomEvent.on(icon, 'click', this._onMouseClick, this);
+ L.DomEvent.on(icon, 'keypress', this._onKeyPress, this);
+
+ for (var i = 0; i < events.length; i++) {
+ L.DomEvent.on(icon, events[i], this._fireMouseEvent, this);
+ }
+
+ if (L.Handler.MarkerDrag) {
+ this.dragging = new L.Handler.MarkerDrag(this);
+
+ if (this.options.draggable) {
+ this.dragging.enable();
+ }
+ }
+ },
+
+ _onMouseClick: function (e) {
+ var wasDragged = this.dragging && this.dragging.moved();
+
+ if (this.hasEventListeners(e.type) || wasDragged) {
+ L.DomEvent.stopPropagation(e);
+ }
+
+ if (wasDragged) { return; }
+
+ if ((!this.dragging || !this.dragging._enabled) && this._map.dragging && this._map.dragging.moved()) { return; }
+
+ this.fire(e.type, {
+ originalEvent: e,
+ latlng: this._latlng
+ });
+ },
+
+ _onKeyPress: function (e) {
+ if (e.keyCode === 13) {
+ this.fire('click', {
+ originalEvent: e,
+ latlng: this._latlng
+ });
+ }
+ },
+
+ _fireMouseEvent: function (e) {
+
+ this.fire(e.type, {
+ originalEvent: e,
+ latlng: this._latlng
+ });
+
+ // TODO proper custom event propagation
+ // this line will always be called if marker is in a FeatureGroup
+ if (e.type === 'contextmenu' && this.hasEventListeners(e.type)) {
+ L.DomEvent.preventDefault(e);
+ }
+ if (e.type !== 'mousedown') {
+ L.DomEvent.stopPropagation(e);
+ } else {
+ L.DomEvent.preventDefault(e);
+ }
+ },
+
+ setOpacity: function (opacity) {
+ this.options.opacity = opacity;
+ if (this._map) {
+ this._updateOpacity();
+ }
+
+ return this;
+ },
+
+ _updateOpacity: function () {
+ L.DomUtil.setOpacity(this._icon, this.options.opacity);
+ if (this._shadow) {
+ L.DomUtil.setOpacity(this._shadow, this.options.opacity);
+ }
+ },
+
+ _bringToFront: function () {
+ this._updateZIndex(this.options.riseOffset);
+ },
+
+ _resetZIndex: function () {
+ this._updateZIndex(0);
+ }
+});
+
+L.marker = function (latlng, options) {
+ return new L.Marker(latlng, options);
+};
+
+
+/*
+ * L.DivIcon is a lightweight HTML-based icon class (as opposed to the image-based L.Icon)
+ * to use with L.Marker.
+ */
+
+L.DivIcon = L.Icon.extend({
+ options: {
+ iconSize: [12, 12], // also can be set through CSS
+ /*
+ iconAnchor: (Point)
+ popupAnchor: (Point)
+ html: (String)
+ bgPos: (Point)
+ */
+ className: 'leaflet-div-icon',
+ html: false
+ },
+
+ createIcon: function (oldIcon) {
+ var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
+ options = this.options;
+
+ if (options.html !== false) {
+ div.innerHTML = options.html;
+ } else {
+ div.innerHTML = '';
+ }
+
+ if (options.bgPos) {
+ div.style.backgroundPosition =
+ (-options.bgPos.x) + 'px ' + (-options.bgPos.y) + 'px';
+ }
+
+ this._setIconStyles(div, 'icon');
+ return div;
+ },
+
+ createShadow: function () {
+ return null;
+ }
+});
+
+L.divIcon = function (options) {
+ return new L.DivIcon(options);
+};
+
+
+/*
+ * L.Popup is used for displaying popups on the map.
+ */
+
+L.Map.mergeOptions({
+ closePopupOnClick: true
+});
+
+L.Popup = L.Class.extend({
+ includes: L.Mixin.Events,
+
+ options: {
+ minWidth: 50,
+ maxWidth: 300,
+ // maxHeight: null,
+ autoPan: true,
+ closeButton: true,
+ offset: [0, 7],
+ autoPanPadding: [5, 5],
+ // autoPanPaddingTopLeft: null,
+ // autoPanPaddingBottomRight: null,
+ keepInView: false,
+ className: '',
+ zoomAnimation: true
+ },
+
+ initialize: function (options, source) {
+ L.setOptions(this, options);
+
+ this._source = source;
+ this._animated = L.Browser.any3d && this.options.zoomAnimation;
+ this._isOpen = false;
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+
+ if (!this._container) {
+ this._initLayout();
+ }
+
+ var animFade = map.options.fadeAnimation;
+
+ if (animFade) {
+ L.DomUtil.setOpacity(this._container, 0);
+ }
+ map._panes.popupPane.appendChild(this._container);
+
+ map.on(this._getEvents(), this);
+
+ this.update();
+
+ if (animFade) {
+ L.DomUtil.setOpacity(this._container, 1);
+ }
+
+ this.fire('open');
+
+ map.fire('popupopen', {popup: this});
+
+ if (this._source) {
+ this._source.fire('popupopen', {popup: this});
+ }
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ openOn: function (map) {
+ map.openPopup(this);
+ return this;
+ },
+
+ onRemove: function (map) {
+ map._panes.popupPane.removeChild(this._container);
+
+ L.Util.falseFn(this._container.offsetWidth); // force reflow
+
+ map.off(this._getEvents(), this);
+
+ if (map.options.fadeAnimation) {
+ L.DomUtil.setOpacity(this._container, 0);
+ }
+
+ this._map = null;
+
+ this.fire('close');
+
+ map.fire('popupclose', {popup: this});
+
+ if (this._source) {
+ this._source.fire('popupclose', {popup: this});
+ }
+ },
+
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ setLatLng: function (latlng) {
+ this._latlng = L.latLng(latlng);
+ if (this._map) {
+ this._updatePosition();
+ this._adjustPan();
+ }
+ return this;
+ },
+
+ getContent: function () {
+ return this._content;
+ },
+
+ setContent: function (content) {
+ this._content = content;
+ this.update();
+ return this;
+ },
+
+ update: function () {
+ if (!this._map) { return; }
+
+ this._container.style.visibility = 'hidden';
+
+ this._updateContent();
+ this._updateLayout();
+ this._updatePosition();
+
+ this._container.style.visibility = '';
+
+ this._adjustPan();
+ },
+
+ _getEvents: function () {
+ var events = {
+ viewreset: this._updatePosition
+ };
+
+ if (this._animated) {
+ events.zoomanim = this._zoomAnimation;
+ }
+ if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
+ events.preclick = this._close;
+ }
+ if (this.options.keepInView) {
+ events.moveend = this._adjustPan;
+ }
+
+ return events;
+ },
+
+ _close: function () {
+ if (this._map) {
+ this._map.closePopup(this);
+ }
+ },
+
+ _initLayout: function () {
+ var prefix = 'leaflet-popup',
+ containerClass = prefix + ' ' + this.options.className + ' leaflet-zoom-' +
+ (this._animated ? 'animated' : 'hide'),
+ container = this._container = L.DomUtil.create('div', containerClass),
+ closeButton;
+
+ if (this.options.closeButton) {
+ closeButton = this._closeButton =
+ L.DomUtil.create('a', prefix + '-close-button', container);
+ closeButton.href = '#close';
+ closeButton.innerHTML = '&#215;';
+ L.DomEvent.disableClickPropagation(closeButton);
+
+ L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this);
+ }
+
+ var wrapper = this._wrapper =
+ L.DomUtil.create('div', prefix + '-content-wrapper', container);
+ L.DomEvent.disableClickPropagation(wrapper);
+
+ this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
+
+ L.DomEvent.disableScrollPropagation(this._contentNode);
+ L.DomEvent.on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
+
+ this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
+ this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
+ },
+
+ _updateContent: function () {
+ if (!this._content) { return; }
+
+ if (typeof this._content === 'string') {
+ this._contentNode.innerHTML = this._content;
+ } else {
+ while (this._contentNode.hasChildNodes()) {
+ this._contentNode.removeChild(this._contentNode.firstChild);
+ }
+ this._contentNode.appendChild(this._content);
+ }
+ this.fire('contentupdate');
+ },
+
+ _updateLayout: function () {
+ var container = this._contentNode,
+ style = container.style;
+
+ style.width = '';
+ style.whiteSpace = 'nowrap';
+
+ var width = container.offsetWidth;
+ width = Math.min(width, this.options.maxWidth);
+ width = Math.max(width, this.options.minWidth);
+
+ style.width = (width + 1) + 'px';
+ style.whiteSpace = '';
+
+ style.height = '';
+
+ var height = container.offsetHeight,
+ maxHeight = this.options.maxHeight,
+ scrolledClass = 'leaflet-popup-scrolled';
+
+ if (maxHeight && height > maxHeight) {
+ style.height = maxHeight + 'px';
+ L.DomUtil.addClass(container, scrolledClass);
+ } else {
+ L.DomUtil.removeClass(container, scrolledClass);
+ }
+
+ this._containerWidth = this._container.offsetWidth;
+ },
+
+ _updatePosition: function () {
+ if (!this._map) { return; }
+
+ var pos = this._map.latLngToLayerPoint(this._latlng),
+ animated = this._animated,
+ offset = L.point(this.options.offset);
+
+ if (animated) {
+ L.DomUtil.setPosition(this._container, pos);
+ }
+
+ this._containerBottom = -offset.y - (animated ? 0 : pos.y);
+ this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x + (animated ? 0 : pos.x);
+
+ // bottom position the popup in case the height of the popup changes (images loading etc)
+ this._container.style.bottom = this._containerBottom + 'px';
+ this._container.style.left = this._containerLeft + 'px';
+ },
+
+ _zoomAnimation: function (opt) {
+ var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center);
+
+ L.DomUtil.setPosition(this._container, pos);
+ },
+
+ _adjustPan: function () {
+ if (!this.options.autoPan) { return; }
+
+ var map = this._map,
+ containerHeight = this._container.offsetHeight,
+ containerWidth = this._containerWidth,
+
+ layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
+
+ if (this._animated) {
+ layerPos._add(L.DomUtil.getPosition(this._container));
+ }
+
+ var containerPos = map.layerPointToContainerPoint(layerPos),
+ padding = L.point(this.options.autoPanPadding),
+ paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
+ paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
+ size = map.getSize(),
+ dx = 0,
+ dy = 0;
+
+ if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
+ dx = containerPos.x + containerWidth - size.x + paddingBR.x;
+ }
+ if (containerPos.x - dx - paddingTL.x < 0) { // left
+ dx = containerPos.x - paddingTL.x;
+ }
+ if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
+ dy = containerPos.y + containerHeight - size.y + paddingBR.y;
+ }
+ if (containerPos.y - dy - paddingTL.y < 0) { // top
+ dy = containerPos.y - paddingTL.y;
+ }
+
+ if (dx || dy) {
+ map
+ .fire('autopanstart')
+ .panBy([dx, dy]);
+ }
+ },
+
+ _onCloseButtonClick: function (e) {
+ this._close();
+ L.DomEvent.stop(e);
+ }
+});
+
+L.popup = function (options, source) {
+ return new L.Popup(options, source);
+};
+
+
+L.Map.include({
+ openPopup: function (popup, latlng, options) { // (Popup) or (String || HTMLElement, LatLng[, Object])
+ this.closePopup();
+
+ if (!(popup instanceof L.Popup)) {
+ var content = popup;
+
+ popup = new L.Popup(options)
+ .setLatLng(latlng)
+ .setContent(content);
+ }
+ popup._isOpen = true;
+
+ this._popup = popup;
+ return this.addLayer(popup);
+ },
+
+ closePopup: function (popup) {
+ if (!popup || popup === this._popup) {
+ popup = this._popup;
+ this._popup = null;
+ }
+ if (popup) {
+ this.removeLayer(popup);
+ popup._isOpen = false;
+ }
+ return this;
+ }
+});
+
+
+/*
+ * Popup extension to L.Marker, adding popup-related methods.
+ */
+
+L.Marker.include({
+ openPopup: function () {
+ if (this._popup && this._map && !this._map.hasLayer(this._popup)) {
+ this._popup.setLatLng(this._latlng);
+ this._map.openPopup(this._popup);
+ }
+
+ return this;
+ },
+
+ closePopup: function () {
+ if (this._popup) {
+ this._popup._close();
+ }
+ return this;
+ },
+
+ togglePopup: function () {
+ if (this._popup) {
+ if (this._popup._isOpen) {
+ this.closePopup();
+ } else {
+ this.openPopup();
+ }
+ }
+ return this;
+ },
+
+ bindPopup: function (content, options) {
+ var anchor = L.point(this.options.icon.options.popupAnchor || [0, 0]);
+
+ anchor = anchor.add(L.Popup.prototype.options.offset);
+
+ if (options && options.offset) {
+ anchor = anchor.add(options.offset);
+ }
+
+ options = L.extend({offset: anchor}, options);
+
+ if (!this._popupHandlersAdded) {
+ this
+ .on('click', this.togglePopup, this)
+ .on('remove', this.closePopup, this)
+ .on('move', this._movePopup, this);
+ this._popupHandlersAdded = true;
+ }
+
+ if (content instanceof L.Popup) {
+ L.setOptions(content, options);
+ this._popup = content;
+ } else {
+ this._popup = new L.Popup(options, this)
+ .setContent(content);
+ }
+
+ return this;
+ },
+
+ setPopupContent: function (content) {
+ if (this._popup) {
+ this._popup.setContent(content);
+ }
+ return this;
+ },
+
+ unbindPopup: function () {
+ if (this._popup) {
+ this._popup = null;
+ this
+ .off('click', this.togglePopup, this)
+ .off('remove', this.closePopup, this)
+ .off('move', this._movePopup, this);
+ this._popupHandlersAdded = false;
+ }
+ return this;
+ },
+
+ getPopup: function () {
+ return this._popup;
+ },
+
+ _movePopup: function (e) {
+ this._popup.setLatLng(e.latlng);
+ }
+});
+
+
+/*
+ * L.LayerGroup is a class to combine several layers into one so that
+ * you can manipulate the group (e.g. add/remove it) as one layer.
+ */
+
+L.LayerGroup = L.Class.extend({
+ initialize: function (layers) {
+ this._layers = {};
+
+ var i, len;
+
+ if (layers) {
+ for (i = 0, len = layers.length; i < len; i++) {
+ this.addLayer(layers[i]);
+ }
+ }
+ },
+
+ addLayer: function (layer) {
+ var id = this.getLayerId(layer);
+
+ this._layers[id] = layer;
+
+ if (this._map) {
+ this._map.addLayer(layer);
+ }
+
+ return this;
+ },
+
+ removeLayer: function (layer) {
+ var id = layer in this._layers ? layer : this.getLayerId(layer);
+
+ if (this._map && this._layers[id]) {
+ this._map.removeLayer(this._layers[id]);
+ }
+
+ delete this._layers[id];
+
+ return this;
+ },
+
+ hasLayer: function (layer) {
+ if (!layer) { return false; }
+
+ return (layer in this._layers || this.getLayerId(layer) in this._layers);
+ },
+
+ clearLayers: function () {
+ this.eachLayer(this.removeLayer, this);
+ return this;
+ },
+
+ invoke: function (methodName) {
+ var args = Array.prototype.slice.call(arguments, 1),
+ i, layer;
+
+ for (i in this._layers) {
+ layer = this._layers[i];
+
+ if (layer[methodName]) {
+ layer[methodName].apply(layer, args);
+ }
+ }
+
+ return this;
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+ this.eachLayer(map.addLayer, map);
+ },
+
+ onRemove: function (map) {
+ this.eachLayer(map.removeLayer, map);
+ this._map = null;
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ eachLayer: function (method, context) {
+ for (var i in this._layers) {
+ method.call(context, this._layers[i]);
+ }
+ return this;
+ },
+
+ getLayer: function (id) {
+ return this._layers[id];
+ },
+
+ getLayers: function () {
+ var layers = [];
+
+ for (var i in this._layers) {
+ layers.push(this._layers[i]);
+ }
+ return layers;
+ },
+
+ setZIndex: function (zIndex) {
+ return this.invoke('setZIndex', zIndex);
+ },
+
+ getLayerId: function (layer) {
+ return L.stamp(layer);
+ }
+});
+
+L.layerGroup = function (layers) {
+ return new L.LayerGroup(layers);
+};
+
+
+/*
+ * L.FeatureGroup extends L.LayerGroup by introducing mouse events and additional methods
+ * shared between a group of interactive layers (like vectors or markers).
+ */
+
+L.FeatureGroup = L.LayerGroup.extend({
+ includes: L.Mixin.Events,
+
+ statics: {
+ EVENTS: 'click dblclick mouseover mouseout mousemove contextmenu popupopen popupclose'
+ },
+
+ addLayer: function (layer) {
+ if (this.hasLayer(layer)) {
+ return this;
+ }
+
+ if ('on' in layer) {
+ layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+ }
+
+ L.LayerGroup.prototype.addLayer.call(this, layer);
+
+ if (this._popupContent && layer.bindPopup) {
+ layer.bindPopup(this._popupContent, this._popupOptions);
+ }
+
+ return this.fire('layeradd', {layer: layer});
+ },
+
+ removeLayer: function (layer) {
+ if (!this.hasLayer(layer)) {
+ return this;
+ }
+ if (layer in this._layers) {
+ layer = this._layers[layer];
+ }
+
+ layer.off(L.FeatureGroup.EVENTS, this._propagateEvent, this);
+
+ L.LayerGroup.prototype.removeLayer.call(this, layer);
+
+ if (this._popupContent) {
+ this.invoke('unbindPopup');
+ }
+
+ return this.fire('layerremove', {layer: layer});
+ },
+
+ bindPopup: function (content, options) {
+ this._popupContent = content;
+ this._popupOptions = options;
+ return this.invoke('bindPopup', content, options);
+ },
+
+ openPopup: function (latlng) {
+ // open popup on the first layer
+ for (var id in this._layers) {
+ this._layers[id].openPopup(latlng);
+ break;
+ }
+ return this;
+ },
+
+ setStyle: function (style) {
+ return this.invoke('setStyle', style);
+ },
+
+ bringToFront: function () {
+ return this.invoke('bringToFront');
+ },
+
+ bringToBack: function () {
+ return this.invoke('bringToBack');
+ },
+
+ getBounds: function () {
+ var bounds = new L.LatLngBounds();
+
+ this.eachLayer(function (layer) {
+ bounds.extend(layer instanceof L.Marker ? layer.getLatLng() : layer.getBounds());
+ });
+
+ return bounds;
+ },
+
+ _propagateEvent: function (e) {
+ e = L.extend({
+ layer: e.target,
+ target: this
+ }, e);
+ this.fire(e.type, e);
+ }
+});
+
+L.featureGroup = function (layers) {
+ return new L.FeatureGroup(layers);
+};
+
+
+/*
+ * L.Path is a base class for rendering vector paths on a map. Inherited by Polyline, Circle, etc.
+ */
+
+L.Path = L.Class.extend({
+ includes: [L.Mixin.Events],
+
+ statics: {
+ // how much to extend the clip area around the map view
+ // (relative to its size, e.g. 0.5 is half the screen in each direction)
+ // set it so that SVG element doesn't exceed 1280px (vectors flicker on dragend if it is)
+ CLIP_PADDING: (function () {
+ var max = L.Browser.mobile ? 1280 : 2000,
+ target = (max / Math.max(window.outerWidth, window.outerHeight) - 1) / 2;
+ return Math.max(0, Math.min(0.5, target));
+ })()
+ },
+
+ options: {
+ stroke: true,
+ color: '#0033ff',
+ dashArray: null,
+ lineCap: null,
+ lineJoin: null,
+ weight: 5,
+ opacity: 0.5,
+
+ fill: false,
+ fillColor: null, //same as color by default
+ fillOpacity: 0.2,
+
+ clickable: true
+ },
+
+ initialize: function (options) {
+ L.setOptions(this, options);
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+
+ if (!this._container) {
+ this._initElements();
+ this._initEvents();
+ }
+
+ this.projectLatlngs();
+ this._updatePath();
+
+ if (this._container) {
+ this._map._pathRoot.appendChild(this._container);
+ }
+
+ this.fire('add');
+
+ map.on({
+ 'viewreset': this.projectLatlngs,
+ 'moveend': this._updatePath
+ }, this);
+ },
+
+ addTo: function (map) {
+ map.addLayer(this);
+ return this;
+ },
+
+ onRemove: function (map) {
+ map._pathRoot.removeChild(this._container);
+
+ // Need to fire remove event before we set _map to null as the event hooks might need the object
+ this.fire('remove');
+ this._map = null;
+
+ if (L.Browser.vml) {
+ this._container = null;
+ this._stroke = null;
+ this._fill = null;
+ }
+
+ map.off({
+ 'viewreset': this.projectLatlngs,
+ 'moveend': this._updatePath
+ }, this);
+ },
+
+ projectLatlngs: function () {
+ // do all projection stuff here
+ },
+
+ setStyle: function (style) {
+ L.setOptions(this, style);
+
+ if (this._container) {
+ this._updateStyle();
+ }
+
+ return this;
+ },
+
+ redraw: function () {
+ if (this._map) {
+ this.projectLatlngs();
+ this._updatePath();
+ }
+ return this;
+ }
+});
+
+L.Map.include({
+ _updatePathViewport: function () {
+ var p = L.Path.CLIP_PADDING,
+ size = this.getSize(),
+ panePos = L.DomUtil.getPosition(this._mapPane),
+ min = panePos.multiplyBy(-1)._subtract(size.multiplyBy(p)._round()),
+ max = min.add(size.multiplyBy(1 + p * 2)._round());
+
+ this._pathViewport = new L.Bounds(min, max);
+ }
+});
+
+
+/*
+ * Extends L.Path with SVG-specific rendering code.
+ */
+
+L.Path.SVG_NS = 'http://www.w3.org/2000/svg';
+
+L.Browser.svg = !!(document.createElementNS && document.createElementNS(L.Path.SVG_NS, 'svg').createSVGRect);
+
+L.Path = L.Path.extend({
+ statics: {
+ SVG: L.Browser.svg
+ },
+
+ bringToFront: function () {
+ var root = this._map._pathRoot,
+ path = this._container;
+
+ if (path && root.lastChild !== path) {
+ root.appendChild(path);
+ }
+ return this;
+ },
+
+ bringToBack: function () {
+ var root = this._map._pathRoot,
+ path = this._container,
+ first = root.firstChild;
+
+ if (path && first !== path) {
+ root.insertBefore(path, first);
+ }
+ return this;
+ },
+
+ getPathString: function () {
+ // form path string here
+ },
+
+ _createElement: function (name) {
+ return document.createElementNS(L.Path.SVG_NS, name);
+ },
+
+ _initElements: function () {
+ this._map._initPathRoot();
+ this._initPath();
+ this._initStyle();
+ },
+
+ _initPath: function () {
+ this._container = this._createElement('g');
+
+ this._path = this._createElement('path');
+
+ if (this.options.className) {
+ L.DomUtil.addClass(this._path, this.options.className);
+ }
+
+ this._container.appendChild(this._path);
+ },
+
+ _initStyle: function () {
+ if (this.options.stroke) {
+ this._path.setAttribute('stroke-linejoin', 'round');
+ this._path.setAttribute('stroke-linecap', 'round');
+ }
+ if (this.options.fill) {
+ this._path.setAttribute('fill-rule', 'evenodd');
+ }
+ if (this.options.pointerEvents) {
+ this._path.setAttribute('pointer-events', this.options.pointerEvents);
+ }
+ if (!this.options.clickable && !this.options.pointerEvents) {
+ this._path.setAttribute('pointer-events', 'none');
+ }
+ this._updateStyle();
+ },
+
+ _updateStyle: function () {
+ if (this.options.stroke) {
+ this._path.setAttribute('stroke', this.options.color);
+ this._path.setAttribute('stroke-opacity', this.options.opacity);
+ this._path.setAttribute('stroke-width', this.options.weight);
+ if (this.options.dashArray) {
+ this._path.setAttribute('stroke-dasharray', this.options.dashArray);
+ } else {
+ this._path.removeAttribute('stroke-dasharray');
+ }
+ if (this.options.lineCap) {
+ this._path.setAttribute('stroke-linecap', this.options.lineCap);
+ }
+ if (this.options.lineJoin) {
+ this._path.setAttribute('stroke-linejoin', this.options.lineJoin);
+ }
+ } else {
+ this._path.setAttribute('stroke', 'none');
+ }
+ if (this.options.fill) {
+ this._path.setAttribute('fill', this.options.fillColor || this.options.color);
+ this._path.setAttribute('fill-opacity', this.options.fillOpacity);
+ } else {
+ this._path.setAttribute('fill', 'none');
+ }
+ },
+
+ _updatePath: function () {
+ var str = this.getPathString();
+ if (!str) {
+ // fix webkit empty string parsing bug
+ str = 'M0 0';
+ }
+ this._path.setAttribute('d', str);
+ },
+
+ // TODO remove duplication with L.Map
+ _initEvents: function () {
+ if (this.options.clickable) {
+ if (L.Browser.svg || !L.Browser.vml) {
+ L.DomUtil.addClass(this._path, 'leaflet-clickable');
+ }
+
+ L.DomEvent.on(this._container, 'click', this._onMouseClick, this);
+
+ var events = ['dblclick', 'mousedown', 'mouseover',
+ 'mouseout', 'mousemove', 'contextmenu'];
+ for (var i = 0; i < events.length; i++) {
+ L.DomEvent.on(this._container, events[i], this._fireMouseEvent, this);
+ }
+ }
+ },
+
+ _onMouseClick: function (e) {
+ if (this._map.dragging && this._map.dragging.moved()) { return; }
+
+ this._fireMouseEvent(e);
+ },
+
+ _fireMouseEvent: function (e) {
+ if (!this.hasEventListeners(e.type)) { return; }
+
+ var map = this._map,
+ containerPoint = map.mouseEventToContainerPoint(e),
+ layerPoint = map.containerPointToLayerPoint(containerPoint),
+ latlng = map.layerPointToLatLng(layerPoint);
+
+ this.fire(e.type, {
+ latlng: latlng,
+ layerPoint: layerPoint,
+ containerPoint: containerPoint,
+ originalEvent: e
+ });
+
+ if (e.type === 'contextmenu') {
+ L.DomEvent.preventDefault(e);
+ }
+ if (e.type !== 'mousemove') {
+ L.DomEvent.stopPropagation(e);
+ }
+ }
+});
+
+L.Map.include({
+ _initPathRoot: function () {
+ if (!this._pathRoot) {
+ this._pathRoot = L.Path.prototype._createElement('svg');
+ this._panes.overlayPane.appendChild(this._pathRoot);
+
+ if (this.options.zoomAnimation && L.Browser.any3d) {
+ L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-animated');
+
+ this.on({
+ 'zoomanim': this._animatePathZoom,
+ 'zoomend': this._endPathZoom
+ });
+ } else {
+ L.DomUtil.addClass(this._pathRoot, 'leaflet-zoom-hide');
+ }
+
+ this.on('moveend', this._updateSvgViewport);
+ this._updateSvgViewport();
+ }
+ },
+
+ _animatePathZoom: function (e) {
+ var scale = this.getZoomScale(e.zoom),
+ offset = this._getCenterOffset(e.center)._multiplyBy(-scale)._add(this._pathViewport.min);
+
+ this._pathRoot.style[L.DomUtil.TRANSFORM] =
+ L.DomUtil.getTranslateString(offset) + ' scale(' + scale + ') ';
+
+ this._pathZooming = true;
+ },
+
+ _endPathZoom: function () {
+ this._pathZooming = false;
+ },
+
+ _updateSvgViewport: function () {
+
+ if (this._pathZooming) {
+ // Do not update SVGs while a zoom animation is going on otherwise the animation will break.
+ // When the zoom animation ends we will be updated again anyway
+ // This fixes the case where you do a momentum move and zoom while the move is still ongoing.
+ return;
+ }
+
+ this._updatePathViewport();
+
+ var vp = this._pathViewport,
+ min = vp.min,
+ max = vp.max,
+ width = max.x - min.x,
+ height = max.y - min.y,
+ root = this._pathRoot,
+ pane = this._panes.overlayPane;
+
+ // Hack to make flicker on drag end on mobile webkit less irritating
+ if (L.Browser.mobileWebkit) {
+ pane.removeChild(root);
+ }
+
+ L.DomUtil.setPosition(root, min);
+ root.setAttribute('width', width);
+ root.setAttribute('height', height);
+ root.setAttribute('viewBox', [min.x, min.y, width, height].join(' '));
+
+ if (L.Browser.mobileWebkit) {
+ pane.appendChild(root);
+ }
+ }
+});
+
+
+/*
+ * Popup extension to L.Path (polylines, polygons, circles), adding popup-related methods.
+ */
+
+L.Path.include({
+
+ bindPopup: function (content, options) {
+
+ if (content instanceof L.Popup) {
+ this._popup = content;
+ } else {
+ if (!this._popup || options) {
+ this._popup = new L.Popup(options, this);
+ }
+ this._popup.setContent(content);
+ }
+
+ if (!this._popupHandlersAdded) {
+ this
+ .on('click', this._openPopup, this)
+ .on('remove', this.closePopup, this);
+
+ this._popupHandlersAdded = true;
+ }
+
+ return this;
+ },
+
+ unbindPopup: function () {
+ if (this._popup) {
+ this._popup = null;
+ this
+ .off('click', this._openPopup)
+ .off('remove', this.closePopup);
+
+ this._popupHandlersAdded = false;
+ }
+ return this;
+ },
+
+ openPopup: function (latlng) {
+
+ if (this._popup) {
+ // open the popup from one of the path's points if not specified
+ latlng = latlng || this._latlng ||
+ this._latlngs[Math.floor(this._latlngs.length / 2)];
+
+ this._openPopup({latlng: latlng});
+ }
+
+ return this;
+ },
+
+ closePopup: function () {
+ if (this._popup) {
+ this._popup._close();
+ }
+ return this;
+ },
+
+ _openPopup: function (e) {
+ this._popup.setLatLng(e.latlng);
+ this._map.openPopup(this._popup);
+ }
+});
+
+
+/*
+ * Vector rendering for IE6-8 through VML.
+ * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
+ */
+
+L.Browser.vml = !L.Browser.svg && (function () {
+ try {
+ var div = document.createElement('div');
+ div.innerHTML = '<v:shape adj="1"/>';
+
+ var shape = div.firstChild;
+ shape.style.behavior = 'url(#default#VML)';
+
+ return shape && (typeof shape.adj === 'object');
+
+ } catch (e) {
+ return false;
+ }
+}());
+
+L.Path = L.Browser.svg || !L.Browser.vml ? L.Path : L.Path.extend({
+ statics: {
+ VML: true,
+ CLIP_PADDING: 0.02
+ },
+
+ _createElement: (function () {
+ try {
+ document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
+ return function (name) {
+ return document.createElement('<lvml:' + name + ' class="lvml">');
+ };
+ } catch (e) {
+ return function (name) {
+ return document.createElement(
+ '<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
+ };
+ }
+ }()),
+
+ _initPath: function () {
+ var container = this._container = this._createElement('shape');
+
+ L.DomUtil.addClass(container, 'leaflet-vml-shape' +
+ (this.options.className ? ' ' + this.options.className : ''));
+
+ if (this.options.clickable) {
+ L.DomUtil.addClass(container, 'leaflet-clickable');
+ }
+
+ container.coordsize = '1 1';
+
+ this._path = this._createElement('path');
+ container.appendChild(this._path);
+
+ this._map._pathRoot.appendChild(container);
+ },
+
+ _initStyle: function () {
+ this._updateStyle();
+ },
+
+ _updateStyle: function () {
+ var stroke = this._stroke,
+ fill = this._fill,
+ options = this.options,
+ container = this._container;
+
+ container.stroked = options.stroke;
+ container.filled = options.fill;
+
+ if (options.stroke) {
+ if (!stroke) {
+ stroke = this._stroke = this._createElement('stroke');
+ stroke.endcap = 'round';
+ container.appendChild(stroke);
+ }
+ stroke.weight = options.weight + 'px';
+ stroke.color = options.color;
+ stroke.opacity = options.opacity;
+
+ if (options.dashArray) {
+ stroke.dashStyle = L.Util.isArray(options.dashArray) ?
+ options.dashArray.join(' ') :
+ options.dashArray.replace(/( *, *)/g, ' ');
+ } else {
+ stroke.dashStyle = '';
+ }
+ if (options.lineCap) {
+ stroke.endcap = options.lineCap.replace('butt', 'flat');
+ }
+ if (options.lineJoin) {
+ stroke.joinstyle = options.lineJoin;
+ }
+
+ } else if (stroke) {
+ container.removeChild(stroke);
+ this._stroke = null;
+ }
+
+ if (options.fill) {
+ if (!fill) {
+ fill = this._fill = this._createElement('fill');
+ container.appendChild(fill);
+ }
+ fill.color = options.fillColor || options.color;
+ fill.opacity = options.fillOpacity;
+
+ } else if (fill) {
+ container.removeChild(fill);
+ this._fill = null;
+ }
+ },
+
+ _updatePath: function () {
+ var style = this._container.style;
+
+ style.display = 'none';
+ this._path.v = this.getPathString() + ' '; // the space fixes IE empty path string bug
+ style.display = '';
+ }
+});
+
+L.Map.include(L.Browser.svg || !L.Browser.vml ? {} : {
+ _initPathRoot: function () {
+ if (this._pathRoot) { return; }
+
+ var root = this._pathRoot = document.createElement('div');
+ root.className = 'leaflet-vml-container';
+ this._panes.overlayPane.appendChild(root);
+
+ this.on('moveend', this._updatePathViewport);
+ this._updatePathViewport();
+ }
+});
+
+
+/*
+ * Vector rendering for all browsers that support canvas.
+ */
+
+L.Browser.canvas = (function () {
+ return !!document.createElement('canvas').getContext;
+}());
+
+L.Path = (L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? L.Path : L.Path.extend({
+ statics: {
+ //CLIP_PADDING: 0.02, // not sure if there's a need to set it to a small value
+ CANVAS: true,
+ SVG: false
+ },
+
+ redraw: function () {
+ if (this._map) {
+ this.projectLatlngs();
+ this._requestUpdate();
+ }
+ return this;
+ },
+
+ setStyle: function (style) {
+ L.setOptions(this, style);
+
+ if (this._map) {
+ this._updateStyle();
+ this._requestUpdate();
+ }
+ return this;
+ },
+
+ onRemove: function (map) {
+ map
+ .off('viewreset', this.projectLatlngs, this)
+ .off('moveend', this._updatePath, this);
+
+ if (this.options.clickable) {
+ this._map.off('click', this._onClick, this);
+ this._map.off('mousemove', this._onMouseMove, this);
+ }
+
+ this._requestUpdate();
+
+ this._map = null;
+ },
+
+ _requestUpdate: function () {
+ if (this._map && !L.Path._updateRequest) {
+ L.Path._updateRequest = L.Util.requestAnimFrame(this._fireMapMoveEnd, this._map);
+ }
+ },
+
+ _fireMapMoveEnd: function () {
+ L.Path._updateRequest = null;
+ this.fire('moveend');
+ },
+
+ _initElements: function () {
+ this._map._initPathRoot();
+ this._ctx = this._map._canvasCtx;
+ },
+
+ _updateStyle: function () {
+ var options = this.options;
+
+ if (options.stroke) {
+ this._ctx.lineWidth = options.weight;
+ this._ctx.strokeStyle = options.color;
+ }
+ if (options.fill) {
+ this._ctx.fillStyle = options.fillColor || options.color;
+ }
+ },
+
+ _drawPath: function () {
+ var i, j, len, len2, point, drawMethod;
+
+ this._ctx.beginPath();
+
+ for (i = 0, len = this._parts.length; i < len; i++) {
+ for (j = 0, len2 = this._parts[i].length; j < len2; j++) {
+ point = this._parts[i][j];
+ drawMethod = (j === 0 ? 'move' : 'line') + 'To';
+
+ this._ctx[drawMethod](point.x, point.y);
+ }
+ // TODO refactor ugly hack
+ if (this instanceof L.Polygon) {
+ this._ctx.closePath();
+ }
+ }
+ },
+
+ _checkIfEmpty: function () {
+ return !this._parts.length;
+ },
+
+ _updatePath: function () {
+ if (this._checkIfEmpty()) { return; }
+
+ var ctx = this._ctx,
+ options = this.options;
+
+ this._drawPath();
+ ctx.save();
+ this._updateStyle();
+
+ if (options.fill) {
+ ctx.globalAlpha = options.fillOpacity;
+ ctx.fill();
+ }
+
+ if (options.stroke) {
+ ctx.globalAlpha = options.opacity;
+ ctx.stroke();
+ }
+
+ ctx.restore();
+
+ // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
+ },
+
+ _initEvents: function () {
+ if (this.options.clickable) {
+ // TODO dblclick
+ this._map.on('mousemove', this._onMouseMove, this);
+ this._map.on('click', this._onClick, this);
+ }
+ },
+
+ _onClick: function (e) {
+ if (this._containsPoint(e.layerPoint)) {
+ this.fire('click', e);
+ }
+ },
+
+ _onMouseMove: function (e) {
+ if (!this._map || this._map._animatingZoom) { return; }
+
+ // TODO don't do on each move
+ if (this._containsPoint(e.layerPoint)) {
+ this._ctx.canvas.style.cursor = 'pointer';
+ this._mouseInside = true;
+ this.fire('mouseover', e);
+
+ } else if (this._mouseInside) {
+ this._ctx.canvas.style.cursor = '';
+ this._mouseInside = false;
+ this.fire('mouseout', e);
+ }
+ }
+});
+
+L.Map.include((L.Path.SVG && !window.L_PREFER_CANVAS) || !L.Browser.canvas ? {} : {
+ _initPathRoot: function () {
+ var root = this._pathRoot,
+ ctx;
+
+ if (!root) {
+ root = this._pathRoot = document.createElement('canvas');
+ root.style.position = 'absolute';
+ ctx = this._canvasCtx = root.getContext('2d');
+
+ ctx.lineCap = 'round';
+ ctx.lineJoin = 'round';
+
+ this._panes.overlayPane.appendChild(root);
+
+ if (this.options.zoomAnimation) {
+ this._pathRoot.className = 'leaflet-zoom-animated';
+ this.on('zoomanim', this._animatePathZoom);
+ this.on('zoomend', this._endPathZoom);
+ }
+ this.on('moveend', this._updateCanvasViewport);
+ this._updateCanvasViewport();
+ }
+ },
+
+ _updateCanvasViewport: function () {
+ // don't redraw while zooming. See _updateSvgViewport for more details
+ if (this._pathZooming) { return; }
+ this._updatePathViewport();
+
+ var vp = this._pathViewport,
+ min = vp.min,
+ size = vp.max.subtract(min),
+ root = this._pathRoot;
+
+ //TODO check if this works properly on mobile webkit
+ L.DomUtil.setPosition(root, min);
+ root.width = size.x;
+ root.height = size.y;
+ root.getContext('2d').translate(-min.x, -min.y);
+ }
+});
+
+
+/*
+ * L.LineUtil contains different utility functions for line segments
+ * and polylines (clipping, simplification, distances, etc.)
+ */
+
+/*jshint bitwise:false */ // allow bitwise operations for this file
+
+L.LineUtil = {
+
+ // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
+ // Improves rendering performance dramatically by lessening the number of points to draw.
+
+ simplify: function (/*Point[]*/ points, /*Number*/ tolerance) {
+ if (!tolerance || !points.length) {
+ return points.slice();
+ }
+
+ var sqTolerance = tolerance * tolerance;
+
+ // stage 1: vertex reduction
+ points = this._reducePoints(points, sqTolerance);
+
+ // stage 2: Douglas-Peucker simplification
+ points = this._simplifyDP(points, sqTolerance);
+
+ return points;
+ },
+
+ // distance from a point to a segment between two points
+ pointToSegmentDistance: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
+ return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true));
+ },
+
+ closestPointOnSegment: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) {
+ return this._sqClosestPointOnSegment(p, p1, p2);
+ },
+
+ // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
+ _simplifyDP: function (points, sqTolerance) {
+
+ var len = points.length,
+ ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
+ markers = new ArrayConstructor(len);
+
+ markers[0] = markers[len - 1] = 1;
+
+ this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
+
+ var i,
+ newPoints = [];
+
+ for (i = 0; i < len; i++) {
+ if (markers[i]) {
+ newPoints.push(points[i]);
+ }
+ }
+
+ return newPoints;
+ },
+
+ _simplifyDPStep: function (points, markers, sqTolerance, first, last) {
+
+ var maxSqDist = 0,
+ index, i, sqDist;
+
+ for (i = first + 1; i <= last - 1; i++) {
+ sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true);
+
+ if (sqDist > maxSqDist) {
+ index = i;
+ maxSqDist = sqDist;
+ }
+ }
+
+ if (maxSqDist > sqTolerance) {
+ markers[index] = 1;
+
+ this._simplifyDPStep(points, markers, sqTolerance, first, index);
+ this._simplifyDPStep(points, markers, sqTolerance, index, last);
+ }
+ },
+
+ // reduce points that are too close to each other to a single point
+ _reducePoints: function (points, sqTolerance) {
+ var reducedPoints = [points[0]];
+
+ for (var i = 1, prev = 0, len = points.length; i < len; i++) {
+ if (this._sqDist(points[i], points[prev]) > sqTolerance) {
+ reducedPoints.push(points[i]);
+ prev = i;
+ }
+ }
+ if (prev < len - 1) {
+ reducedPoints.push(points[len - 1]);
+ }
+ return reducedPoints;
+ },
+
+ // Cohen-Sutherland line clipping algorithm.
+ // Used to avoid rendering parts of a polyline that are not currently visible.
+
+ clipSegment: function (a, b, bounds, useLastCode) {
+ var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds),
+ codeB = this._getBitCode(b, bounds),
+
+ codeOut, p, newCode;
+
+ // save 2nd code to avoid calculating it on the next segment
+ this._lastCode = codeB;
+
+ while (true) {
+ // if a,b is inside the clip window (trivial accept)
+ if (!(codeA | codeB)) {
+ return [a, b];
+ // if a,b is outside the clip window (trivial reject)
+ } else if (codeA & codeB) {
+ return false;
+ // other cases
+ } else {
+ codeOut = codeA || codeB;
+ p = this._getEdgeIntersection(a, b, codeOut, bounds);
+ newCode = this._getBitCode(p, bounds);
+
+ if (codeOut === codeA) {
+ a = p;
+ codeA = newCode;
+ } else {
+ b = p;
+ codeB = newCode;
+ }
+ }
+ }
+ },
+
+ _getEdgeIntersection: function (a, b, code, bounds) {
+ var dx = b.x - a.x,
+ dy = b.y - a.y,
+ min = bounds.min,
+ max = bounds.max;
+
+ if (code & 8) { // top
+ return new L.Point(a.x + dx * (max.y - a.y) / dy, max.y);
+ } else if (code & 4) { // bottom
+ return new L.Point(a.x + dx * (min.y - a.y) / dy, min.y);
+ } else if (code & 2) { // right
+ return new L.Point(max.x, a.y + dy * (max.x - a.x) / dx);
+ } else if (code & 1) { // left
+ return new L.Point(min.x, a.y + dy * (min.x - a.x) / dx);
+ }
+ },
+
+ _getBitCode: function (/*Point*/ p, bounds) {
+ var code = 0;
+
+ if (p.x < bounds.min.x) { // left
+ code |= 1;
+ } else if (p.x > bounds.max.x) { // right
+ code |= 2;
+ }
+ if (p.y < bounds.min.y) { // bottom
+ code |= 4;
+ } else if (p.y > bounds.max.y) { // top
+ code |= 8;
+ }
+
+ return code;
+ },
+
+ // square distance (to avoid unnecessary Math.sqrt calls)
+ _sqDist: function (p1, p2) {
+ var dx = p2.x - p1.x,
+ dy = p2.y - p1.y;
+ return dx * dx + dy * dy;
+ },
+
+ // return closest point on segment or distance to that point
+ _sqClosestPointOnSegment: function (p, p1, p2, sqDist) {
+ var x = p1.x,
+ y = p1.y,
+ dx = p2.x - x,
+ dy = p2.y - y,
+ dot = dx * dx + dy * dy,
+ t;
+
+ if (dot > 0) {
+ t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
+
+ if (t > 1) {
+ x = p2.x;
+ y = p2.y;
+ } else if (t > 0) {
+ x += dx * t;
+ y += dy * t;
+ }
+ }
+
+ dx = p.x - x;
+ dy = p.y - y;
+
+ return sqDist ? dx * dx + dy * dy : new L.Point(x, y);
+ }
+};
+
+
+/*
+ * L.Polyline is used to display polylines on a map.
+ */
+
+L.Polyline = L.Path.extend({
+ initialize: function (latlngs, options) {
+ L.Path.prototype.initialize.call(this, options);
+
+ this._latlngs = this._convertLatLngs(latlngs);
+ },
+
+ options: {
+ // how much to simplify the polyline on each zoom level
+ // more = better performance and smoother look, less = more accurate
+ smoothFactor: 1.0,
+ noClip: false
+ },
+
+ projectLatlngs: function () {
+ this._originalPoints = [];
+
+ for (var i = 0, len = this._latlngs.length; i < len; i++) {
+ this._originalPoints[i] = this._map.latLngToLayerPoint(this._latlngs[i]);
+ }
+ },
+
+ getPathString: function () {
+ for (var i = 0, len = this._parts.length, str = ''; i < len; i++) {
+ str += this._getPathPartStr(this._parts[i]);
+ }
+ return str;
+ },
+
+ getLatLngs: function () {
+ return this._latlngs;
+ },
+
+ setLatLngs: function (latlngs) {
+ this._latlngs = this._convertLatLngs(latlngs);
+ return this.redraw();
+ },
+
+ addLatLng: function (latlng) {
+ this._latlngs.push(L.latLng(latlng));
+ return this.redraw();
+ },
+
+ spliceLatLngs: function () { // (Number index, Number howMany)
+ var removed = [].splice.apply(this._latlngs, arguments);
+ this._convertLatLngs(this._latlngs, true);
+ this.redraw();
+ return removed;
+ },
+
+ closestLayerPoint: function (p) {
+ var minDistance = Infinity, parts = this._parts, p1, p2, minPoint = null;
+
+ for (var j = 0, jLen = parts.length; j < jLen; j++) {
+ var points = parts[j];
+ for (var i = 1, len = points.length; i < len; i++) {
+ p1 = points[i - 1];
+ p2 = points[i];
+ var sqDist = L.LineUtil._sqClosestPointOnSegment(p, p1, p2, true);
+ if (sqDist < minDistance) {
+ minDistance = sqDist;
+ minPoint = L.LineUtil._sqClosestPointOnSegment(p, p1, p2);
+ }
+ }
+ }
+ if (minPoint) {
+ minPoint.distance = Math.sqrt(minDistance);
+ }
+ return minPoint;
+ },
+
+ getBounds: function () {
+ return new L.LatLngBounds(this.getLatLngs());
+ },
+
+ _convertLatLngs: function (latlngs, overwrite) {
+ var i, len, target = overwrite ? latlngs : [];
+
+ for (i = 0, len = latlngs.length; i < len; i++) {
+ if (L.Util.isArray(latlngs[i]) && typeof latlngs[i][0] !== 'number') {
+ return;
+ }
+ target[i] = L.latLng(latlngs[i]);
+ }
+ return target;
+ },
+
+ _initEvents: function () {
+ L.Path.prototype._initEvents.call(this);
+ },
+
+ _getPathPartStr: function (points) {
+ var round = L.Path.VML;
+
+ for (var j = 0, len2 = points.length, str = '', p; j < len2; j++) {
+ p = points[j];
+ if (round) {
+ p._round();
+ }
+ str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
+ }
+ return str;
+ },
+
+ _clipPoints: function () {
+ var points = this._originalPoints,
+ len = points.length,
+ i, k, segment;
+
+ if (this.options.noClip) {
+ this._parts = [points];
+ return;
+ }
+
+ this._parts = [];
+
+ var parts = this._parts,
+ vp = this._map._pathViewport,
+ lu = L.LineUtil;
+
+ for (i = 0, k = 0; i < len - 1; i++) {
+ segment = lu.clipSegment(points[i], points[i + 1], vp, i);
+ if (!segment) {
+ continue;
+ }
+
+ parts[k] = parts[k] || [];
+ parts[k].push(segment[0]);
+
+ // if segment goes out of screen, or it's the last one, it's the end of the line part
+ if ((segment[1] !== points[i + 1]) || (i === len - 2)) {
+ parts[k].push(segment[1]);
+ k++;
+ }
+ }
+ },
+
+ // simplify each clipped part of the polyline
+ _simplifyPoints: function () {
+ var parts = this._parts,
+ lu = L.LineUtil;
+
+ for (var i = 0, len = parts.length; i < len; i++) {
+ parts[i] = lu.simplify(parts[i], this.options.smoothFactor);
+ }
+ },
+
+ _updatePath: function () {
+ if (!this._map) { return; }
+
+ this._clipPoints();
+ this._simplifyPoints();
+
+ L.Path.prototype._updatePath.call(this);
+ }
+});
+
+L.polyline = function (latlngs, options) {
+ return new L.Polyline(latlngs, options);
+};
+
+
+/*
+ * L.PolyUtil contains utility functions for polygons (clipping, etc.).
+ */
+
+/*jshint bitwise:false */ // allow bitwise operations here
+
+L.PolyUtil = {};
+
+/*
+ * Sutherland-Hodgeman polygon clipping algorithm.
+ * Used to avoid rendering parts of a polygon that are not currently visible.
+ */
+L.PolyUtil.clipPolygon = function (points, bounds) {
+ var clippedPoints,
+ edges = [1, 4, 2, 8],
+ i, j, k,
+ a, b,
+ len, edge, p,
+ lu = L.LineUtil;
+
+ for (i = 0, len = points.length; i < len; i++) {
+ points[i]._code = lu._getBitCode(points[i], bounds);
+ }
+
+ // for each edge (left, bottom, right, top)
+ for (k = 0; k < 4; k++) {
+ edge = edges[k];
+ clippedPoints = [];
+
+ for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
+ a = points[i];
+ b = points[j];
+
+ // if a is inside the clip window
+ if (!(a._code & edge)) {
+ // if b is outside the clip window (a->b goes out of screen)
+ if (b._code & edge) {
+ p = lu._getEdgeIntersection(b, a, edge, bounds);
+ p._code = lu._getBitCode(p, bounds);
+ clippedPoints.push(p);
+ }
+ clippedPoints.push(a);
+
+ // else if b is inside the clip window (a->b enters the screen)
+ } else if (!(b._code & edge)) {
+ p = lu._getEdgeIntersection(b, a, edge, bounds);
+ p._code = lu._getBitCode(p, bounds);
+ clippedPoints.push(p);
+ }
+ }
+ points = clippedPoints;
+ }
+
+ return points;
+};
+
+
+/*
+ * L.Polygon is used to display polygons on a map.
+ */
+
+L.Polygon = L.Polyline.extend({
+ options: {
+ fill: true
+ },
+
+ initialize: function (latlngs, options) {
+ L.Polyline.prototype.initialize.call(this, latlngs, options);
+ this._initWithHoles(latlngs);
+ },
+
+ _initWithHoles: function (latlngs) {
+ var i, len, hole;
+ if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
+ this._latlngs = this._convertLatLngs(latlngs[0]);
+ this._holes = latlngs.slice(1);
+
+ for (i = 0, len = this._holes.length; i < len; i++) {
+ hole = this._holes[i] = this._convertLatLngs(this._holes[i]);
+ if (hole[0].equals(hole[hole.length - 1])) {
+ hole.pop();
+ }
+ }
+ }
+
+ // filter out last point if its equal to the first one
+ latlngs = this._latlngs;
+
+ if (latlngs.length >= 2 && latlngs[0].equals(latlngs[latlngs.length - 1])) {
+ latlngs.pop();
+ }
+ },
+
+ projectLatlngs: function () {
+ L.Polyline.prototype.projectLatlngs.call(this);
+
+ // project polygon holes points
+ // TODO move this logic to Polyline to get rid of duplication
+ this._holePoints = [];
+
+ if (!this._holes) { return; }
+
+ var i, j, len, len2;
+
+ for (i = 0, len = this._holes.length; i < len; i++) {
+ this._holePoints[i] = [];
+
+ for (j = 0, len2 = this._holes[i].length; j < len2; j++) {
+ this._holePoints[i][j] = this._map.latLngToLayerPoint(this._holes[i][j]);
+ }
+ }
+ },
+
+ setLatLngs: function (latlngs) {
+ if (latlngs && L.Util.isArray(latlngs[0]) && (typeof latlngs[0][0] !== 'number')) {
+ this._initWithHoles(latlngs);
+ return this.redraw();
+ } else {
+ return L.Polyline.prototype.setLatLngs.call(this, latlngs);
+ }
+ },
+
+ _clipPoints: function () {
+ var points = this._originalPoints,
+ newParts = [];
+
+ this._parts = [points].concat(this._holePoints);
+
+ if (this.options.noClip) { return; }
+
+ for (var i = 0, len = this._parts.length; i < len; i++) {
+ var clipped = L.PolyUtil.clipPolygon(this._parts[i], this._map._pathViewport);
+ if (clipped.length) {
+ newParts.push(clipped);
+ }
+ }
+
+ this._parts = newParts;
+ },
+
+ _getPathPartStr: function (points) {
+ var str = L.Polyline.prototype._getPathPartStr.call(this, points);
+ return str + (L.Browser.svg ? 'z' : 'x');
+ }
+});
+
+L.polygon = function (latlngs, options) {
+ return new L.Polygon(latlngs, options);
+};
+
+
+/*
+ * Contains L.MultiPolyline and L.MultiPolygon layers.
+ */
+
+(function () {
+ function createMulti(Klass) {
+
+ return L.FeatureGroup.extend({
+
+ initialize: function (latlngs, options) {
+ this._layers = {};
+ this._options = options;
+ this.setLatLngs(latlngs);
+ },
+
+ setLatLngs: function (latlngs) {
+ var i = 0,
+ len = latlngs.length;
+
+ this.eachLayer(function (layer) {
+ if (i < len) {
+ layer.setLatLngs(latlngs[i++]);
+ } else {
+ this.removeLayer(layer);
+ }
+ }, this);
+
+ while (i < len) {
+ this.addLayer(new Klass(latlngs[i++], this._options));
+ }
+
+ return this;
+ },
+
+ getLatLngs: function () {
+ var latlngs = [];
+
+ this.eachLayer(function (layer) {
+ latlngs.push(layer.getLatLngs());
+ });
+
+ return latlngs;
+ }
+ });
+ }
+
+ L.MultiPolyline = createMulti(L.Polyline);
+ L.MultiPolygon = createMulti(L.Polygon);
+
+ L.multiPolyline = function (latlngs, options) {
+ return new L.MultiPolyline(latlngs, options);
+ };
+
+ L.multiPolygon = function (latlngs, options) {
+ return new L.MultiPolygon(latlngs, options);
+ };
+}());
+
+
+/*
+ * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
+ */
+
+L.Rectangle = L.Polygon.extend({
+ initialize: function (latLngBounds, options) {
+ L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
+ },
+
+ setBounds: function (latLngBounds) {
+ this.setLatLngs(this._boundsToLatLngs(latLngBounds));
+ },
+
+ _boundsToLatLngs: function (latLngBounds) {
+ latLngBounds = L.latLngBounds(latLngBounds);
+ return [
+ latLngBounds.getSouthWest(),
+ latLngBounds.getNorthWest(),
+ latLngBounds.getNorthEast(),
+ latLngBounds.getSouthEast()
+ ];
+ }
+});
+
+L.rectangle = function (latLngBounds, options) {
+ return new L.Rectangle(latLngBounds, options);
+};
+
+
+/*
+ * L.Circle is a circle overlay (with a certain radius in meters).
+ */
+
+L.Circle = L.Path.extend({
+ initialize: function (latlng, radius, options) {
+ L.Path.prototype.initialize.call(this, options);
+
+ this._latlng = L.latLng(latlng);
+ this._mRadius = radius;
+ },
+
+ options: {
+ fill: true
+ },
+
+ setLatLng: function (latlng) {
+ this._latlng = L.latLng(latlng);
+ return this.redraw();
+ },
+
+ setRadius: function (radius) {
+ this._mRadius = radius;
+ return this.redraw();
+ },
+
+ projectLatlngs: function () {
+ var lngRadius = this._getLngRadius(),
+ latlng = this._latlng,
+ pointLeft = this._map.latLngToLayerPoint([latlng.lat, latlng.lng - lngRadius]);
+
+ this._point = this._map.latLngToLayerPoint(latlng);
+ this._radius = Math.max(this._point.x - pointLeft.x, 1);
+ },
+
+ getBounds: function () {
+ var lngRadius = this._getLngRadius(),
+ latRadius = (this._mRadius / 40075017) * 360,
+ latlng = this._latlng;
+
+ return new L.LatLngBounds(
+ [latlng.lat - latRadius, latlng.lng - lngRadius],
+ [latlng.lat + latRadius, latlng.lng + lngRadius]);
+ },
+
+ getLatLng: function () {
+ return this._latlng;
+ },
+
+ getPathString: function () {
+ var p = this._point,
+ r = this._radius;
+
+ if (this._checkIfEmpty()) {
+ return '';
+ }
+
+ if (L.Browser.svg) {
+ return 'M' + p.x + ',' + (p.y - r) +
+ 'A' + r + ',' + r + ',0,1,1,' +
+ (p.x - 0.1) + ',' + (p.y - r) + ' z';
+ } else {
+ p._round();
+ r = Math.round(r);
+ return 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r + ' 0,' + (65535 * 360);
+ }
+ },
+
+ getRadius: function () {
+ return this._mRadius;
+ },
+
+ // TODO Earth hardcoded, move into projection code!
+
+ _getLatRadius: function () {
+ return (this._mRadius / 40075017) * 360;
+ },
+
+ _getLngRadius: function () {
+ return this._getLatRadius() / Math.cos(L.LatLng.DEG_TO_RAD * this._latlng.lat);
+ },
+
+ _checkIfEmpty: function () {
+ if (!this._map) {
+ return false;
+ }
+ var vp = this._map._pathViewport,
+ r = this._radius,
+ p = this._point;
+
+ return p.x - r > vp.max.x || p.y - r > vp.max.y ||
+ p.x + r < vp.min.x || p.y + r < vp.min.y;
+ }
+});
+
+L.circle = function (latlng, radius, options) {
+ return new L.Circle(latlng, radius, options);
+};
+
+
+/*
+ * L.CircleMarker is a circle overlay with a permanent pixel radius.
+ */
+
+L.CircleMarker = L.Circle.extend({
+ options: {
+ radius: 10,
+ weight: 2
+ },
+
+ initialize: function (latlng, options) {
+ L.Circle.prototype.initialize.call(this, latlng, null, options);
+ this._radius = this.options.radius;
+ },
+
+ projectLatlngs: function () {
+ this._point = this._map.latLngToLayerPoint(this._latlng);
+ },
+
+ _updateStyle : function () {
+ L.Circle.prototype._updateStyle.call(this);
+ this.setRadius(this.options.radius);
+ },
+
+ setLatLng: function (latlng) {
+ L.Circle.prototype.setLatLng.call(this, latlng);
+ if (this._popup && this._popup._isOpen) {
+ this._popup.setLatLng(latlng);
+ }
+ return this;
+ },
+
+ setRadius: function (radius) {
+ this.options.radius = this._radius = radius;
+ return this.redraw();
+ },
+
+ getRadius: function () {
+ return this._radius;
+ }
+});
+
+L.circleMarker = function (latlng, options) {
+ return new L.CircleMarker(latlng, options);
+};
+
+
+/*
+ * Extends L.Polyline to be able to manually detect clicks on Canvas-rendered polylines.
+ */
+
+L.Polyline.include(!L.Path.CANVAS ? {} : {
+ _containsPoint: function (p, closed) {
+ var i, j, k, len, len2, dist, part,
+ w = this.options.weight / 2;
+
+ if (L.Browser.touch) {
+ w += 10; // polyline click tolerance on touch devices
+ }
+
+ for (i = 0, len = this._parts.length; i < len; i++) {
+ part = this._parts[i];
+ for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
+ if (!closed && (j === 0)) {
+ continue;
+ }
+
+ dist = L.LineUtil.pointToSegmentDistance(p, part[k], part[j]);
+
+ if (dist <= w) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+});
+
+
+/*
+ * Extends L.Polygon to be able to manually detect clicks on Canvas-rendered polygons.
+ */
+
+L.Polygon.include(!L.Path.CANVAS ? {} : {
+ _containsPoint: function (p) {
+ var inside = false,
+ part, p1, p2,
+ i, j, k,
+ len, len2;
+
+ // TODO optimization: check if within bounds first
+
+ if (L.Polyline.prototype._containsPoint.call(this, p, true)) {
+ // click on polygon border
+ return true;
+ }
+
+ // ray casting algorithm for detecting if point is in polygon
+
+ for (i = 0, len = this._parts.length; i < len; i++) {
+ part = this._parts[i];
+
+ for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
+ p1 = part[j];
+ p2 = part[k];
+
+ 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)) {
+ inside = !inside;
+ }
+ }
+ }
+
+ return inside;
+ }
+});
+
+
+/*
+ * Extends L.Circle with Canvas-specific code.
+ */
+
+L.Circle.include(!L.Path.CANVAS ? {} : {
+ _drawPath: function () {
+ var p = this._point;
+ this._ctx.beginPath();
+ this._ctx.arc(p.x, p.y, this._radius, 0, Math.PI * 2, false);
+ },
+
+ _containsPoint: function (p) {
+ var center = this._point,
+ w2 = this.options.stroke ? this.options.weight / 2 : 0;
+
+ return (p.distanceTo(center) <= this._radius + w2);
+ }
+});
+
+
+/*
+ * CircleMarker canvas specific drawing parts.
+ */
+
+L.CircleMarker.include(!L.Path.CANVAS ? {} : {
+ _updateStyle: function () {
+ L.Path.prototype._updateStyle.call(this);
+ }
+});
+
+
+/*
+ * L.GeoJSON turns any GeoJSON data into a Leaflet layer.
+ */
+
+L.GeoJSON = L.FeatureGroup.extend({
+
+ initialize: function (geojson, options) {
+ L.setOptions(this, options);
+
+ this._layers = {};
+
+ if (geojson) {
+ this.addData(geojson);
+ }
+ },
+
+ addData: function (geojson) {
+ var features = L.Util.isArray(geojson) ? geojson : geojson.features,
+ i, len, feature;
+
+ if (features) {
+ for (i = 0, len = features.length; i < len; i++) {
+ // Only add this if geometry or geometries are set and not null
+ feature = features[i];
+ if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
+ this.addData(features[i]);
+ }
+ }
+ return this;
+ }
+
+ var options = this.options;
+
+ if (options.filter && !options.filter(geojson)) { return; }
+
+ var layer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng, options);
+ layer.feature = L.GeoJSON.asFeature(geojson);
+
+ layer.defaultOptions = layer.options;
+ this.resetStyle(layer);
+
+ if (options.onEachFeature) {
+ options.onEachFeature(geojson, layer);
+ }
+
+ return this.addLayer(layer);
+ },
+
+ resetStyle: function (layer) {
+ var style = this.options.style;
+ if (style) {
+ // reset any custom styles
+ L.Util.extend(layer.options, layer.defaultOptions);
+
+ this._setLayerStyle(layer, style);
+ }
+ },
+
+ setStyle: function (style) {
+ this.eachLayer(function (layer) {
+ this._setLayerStyle(layer, style);
+ }, this);
+ },
+
+ _setLayerStyle: function (layer, style) {
+ if (typeof style === 'function') {
+ style = style(layer.feature);
+ }
+ if (layer.setStyle) {
+ layer.setStyle(style);
+ }
+ }
+});
+
+L.extend(L.GeoJSON, {
+ geometryToLayer: function (geojson, pointToLayer, coordsToLatLng, vectorOptions) {
+ var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
+ coords = geometry.coordinates,
+ layers = [],
+ latlng, latlngs, i, len;
+
+ coordsToLatLng = coordsToLatLng || this.coordsToLatLng;
+
+ switch (geometry.type) {
+ case 'Point':
+ latlng = coordsToLatLng(coords);
+ return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);
+
+ case 'MultiPoint':
+ for (i = 0, len = coords.length; i < len; i++) {
+ latlng = coordsToLatLng(coords[i]);
+ layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));
+ }
+ return new L.FeatureGroup(layers);
+
+ case 'LineString':
+ latlngs = this.coordsToLatLngs(coords, 0, coordsToLatLng);
+ return new L.Polyline(latlngs, vectorOptions);
+
+ case 'Polygon':
+ if (coords.length === 2 && !coords[1].length) {
+ throw new Error('Invalid GeoJSON object.');
+ }
+ latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
+ return new L.Polygon(latlngs, vectorOptions);
+
+ case 'MultiLineString':
+ latlngs = this.coordsToLatLngs(coords, 1, coordsToLatLng);
+ return new L.MultiPolyline(latlngs, vectorOptions);
+
+ case 'MultiPolygon':
+ latlngs = this.coordsToLatLngs(coords, 2, coordsToLatLng);
+ return new L.MultiPolygon(latlngs, vectorOptions);
+
+ case 'GeometryCollection':
+ for (i = 0, len = geometry.geometries.length; i < len; i++) {
+
+ layers.push(this.geometryToLayer({
+ geometry: geometry.geometries[i],
+ type: 'Feature',
+ properties: geojson.properties
+ }, pointToLayer, coordsToLatLng, vectorOptions));
+ }
+ return new L.FeatureGroup(layers);
+
+ default:
+ throw new Error('Invalid GeoJSON object.');
+ }
+ },
+
+ coordsToLatLng: function (coords) { // (Array[, Boolean]) -> LatLng
+ return new L.LatLng(coords[1], coords[0], coords[2]);
+ },
+
+ coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) { // (Array[, Number, Function]) -> Array
+ var latlng, i, len,
+ latlngs = [];
+
+ for (i = 0, len = coords.length; i < len; i++) {
+ latlng = levelsDeep ?
+ this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) :
+ (coordsToLatLng || this.coordsToLatLng)(coords[i]);
+
+ latlngs.push(latlng);
+ }
+
+ return latlngs;
+ },
+
+ latLngToCoords: function (latlng) {
+ var coords = [latlng.lng, latlng.lat];
+
+ if (latlng.alt !== undefined) {
+ coords.push(latlng.alt);
+ }
+ return coords;
+ },
+
+ latLngsToCoords: function (latLngs) {
+ var coords = [];
+
+ for (var i = 0, len = latLngs.length; i < len; i++) {
+ coords.push(L.GeoJSON.latLngToCoords(latLngs[i]));
+ }
+
+ return coords;
+ },
+
+ getFeature: function (layer, newGeometry) {
+ return layer.feature ? L.extend({}, layer.feature, {geometry: newGeometry}) : L.GeoJSON.asFeature(newGeometry);
+ },
+
+ asFeature: function (geoJSON) {
+ if (geoJSON.type === 'Feature') {
+ return geoJSON;
+ }
+
+ return {
+ type: 'Feature',
+ properties: {},
+ geometry: geoJSON
+ };
+ }
+});
+
+var PointToGeoJSON = {
+ toGeoJSON: function () {
+ return L.GeoJSON.getFeature(this, {
+ type: 'Point',
+ coordinates: L.GeoJSON.latLngToCoords(this.getLatLng())
+ });
+ }
+};
+
+L.Marker.include(PointToGeoJSON);
+L.Circle.include(PointToGeoJSON);
+L.CircleMarker.include(PointToGeoJSON);
+
+L.Polyline.include({
+ toGeoJSON: function () {
+ return L.GeoJSON.getFeature(this, {
+ type: 'LineString',
+ coordinates: L.GeoJSON.latLngsToCoords(this.getLatLngs())
+ });
+ }
+});
+
+L.Polygon.include({
+ toGeoJSON: function () {
+ var coords = [L.GeoJSON.latLngsToCoords(this.getLatLngs())],
+ i, len, hole;
+
+ coords[0].push(coords[0][0]);
+
+ if (this._holes) {
+ for (i = 0, len = this._holes.length; i < len; i++) {
+ hole = L.GeoJSON.latLngsToCoords(this._holes[i]);
+ hole.push(hole[0]);
+ coords.push(hole);
+ }
+ }
+
+ return L.GeoJSON.getFeature(this, {
+ type: 'Polygon',
+ coordinates: coords
+ });
+ }
+});
+
+(function () {
+ function multiToGeoJSON(type) {
+ return function () {
+ var coords = [];
+
+ this.eachLayer(function (layer) {
+ coords.push(layer.toGeoJSON().geometry.coordinates);
+ });
+
+ return L.GeoJSON.getFeature(this, {
+ type: type,
+ coordinates: coords
+ });
+ };
+ }
+
+ L.MultiPolyline.include({toGeoJSON: multiToGeoJSON('MultiLineString')});
+ L.MultiPolygon.include({toGeoJSON: multiToGeoJSON('MultiPolygon')});
+
+ L.LayerGroup.include({
+ toGeoJSON: function () {
+
+ var geometry = this.feature && this.feature.geometry,
+ jsons = [],
+ json;
+
+ if (geometry && geometry.type === 'MultiPoint') {
+ return multiToGeoJSON('MultiPoint').call(this);
+ }
+
+ var isGeometryCollection = geometry && geometry.type === 'GeometryCollection';
+
+ this.eachLayer(function (layer) {
+ if (layer.toGeoJSON) {
+ json = layer.toGeoJSON();
+ jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
+ }
+ });
+
+ if (isGeometryCollection) {
+ return L.GeoJSON.getFeature(this, {
+ geometries: jsons,
+ type: 'GeometryCollection'
+ });
+ }
+
+ return {
+ type: 'FeatureCollection',
+ features: jsons
+ };
+ }
+ });
+}());
+
+L.geoJson = function (geojson, options) {
+ return new L.GeoJSON(geojson, options);
+};
+
+
+/*
+ * L.DomEvent contains functions for working with DOM events.
+ */
+
+L.DomEvent = {
+ /* inspired by John Resig, Dean Edwards and YUI addEvent implementations */
+ addListener: function (obj, type, fn, context) { // (HTMLElement, String, Function[, Object])
+
+ var id = L.stamp(fn),
+ key = '_leaflet_' + type + id,
+ handler, originalHandler, newType;
+
+ if (obj[key]) { return this; }
+
+ handler = function (e) {
+ return fn.call(context || obj, e || L.DomEvent._getEvent());
+ };
+
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
+ return this.addPointerListener(obj, type, handler, id);
+ }
+ if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) {
+ this.addDoubleTapListener(obj, handler, id);
+ }
+
+ if ('addEventListener' in obj) {
+
+ if (type === 'mousewheel') {
+ obj.addEventListener('DOMMouseScroll', handler, false);
+ obj.addEventListener(type, handler, false);
+
+ } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
+
+ originalHandler = handler;
+ newType = (type === 'mouseenter' ? 'mouseover' : 'mouseout');
+
+ handler = function (e) {
+ if (!L.DomEvent._checkMouse(obj, e)) { return; }
+ return originalHandler(e);
+ };
+
+ obj.addEventListener(newType, handler, false);
+
+ } else if (type === 'click' && L.Browser.android) {
+ originalHandler = handler;
+ handler = function (e) {
+ return L.DomEvent._filterClick(e, originalHandler);
+ };
+
+ obj.addEventListener(type, handler, false);
+ } else {
+ obj.addEventListener(type, handler, false);
+ }
+
+ } else if ('attachEvent' in obj) {
+ obj.attachEvent('on' + type, handler);
+ }
+
+ obj[key] = handler;
+
+ return this;
+ },
+
+ removeListener: function (obj, type, fn) { // (HTMLElement, String, Function)
+
+ var id = L.stamp(fn),
+ key = '_leaflet_' + type + id,
+ handler = obj[key];
+
+ if (!handler) { return this; }
+
+ if (L.Browser.pointer && type.indexOf('touch') === 0) {
+ this.removePointerListener(obj, type, id);
+ } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
+ this.removeDoubleTapListener(obj, id);
+
+ } else if ('removeEventListener' in obj) {
+
+ if (type === 'mousewheel') {
+ obj.removeEventListener('DOMMouseScroll', handler, false);
+ obj.removeEventListener(type, handler, false);
+
+ } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
+ obj.removeEventListener((type === 'mouseenter' ? 'mouseover' : 'mouseout'), handler, false);
+ } else {
+ obj.removeEventListener(type, handler, false);
+ }
+ } else if ('detachEvent' in obj) {
+ obj.detachEvent('on' + type, handler);
+ }
+
+ obj[key] = null;
+
+ return this;
+ },
+
+ stopPropagation: function (e) {
+
+ if (e.stopPropagation) {
+ e.stopPropagation();
+ } else {
+ e.cancelBubble = true;
+ }
+ L.DomEvent._skipped(e);
+
+ return this;
+ },
+
+ disableScrollPropagation: function (el) {
+ var stop = L.DomEvent.stopPropagation;
+
+ return L.DomEvent
+ .on(el, 'mousewheel', stop)
+ .on(el, 'MozMousePixelScroll', stop);
+ },
+
+ disableClickPropagation: function (el) {
+ var stop = L.DomEvent.stopPropagation;
+
+ for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
+ L.DomEvent.on(el, L.Draggable.START[i], stop);
+ }
+
+ return L.DomEvent
+ .on(el, 'click', L.DomEvent._fakeStop)
+ .on(el, 'dblclick', stop);
+ },
+
+ preventDefault: function (e) {
+
+ if (e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ return this;
+ },
+
+ stop: function (e) {
+ return L.DomEvent
+ .preventDefault(e)
+ .stopPropagation(e);
+ },
+
+ getMousePosition: function (e, container) {
+ if (!container) {
+ return new L.Point(e.clientX, e.clientY);
+ }
+
+ var rect = container.getBoundingClientRect();
+
+ return new L.Point(
+ e.clientX - rect.left - container.clientLeft,
+ e.clientY - rect.top - container.clientTop);
+ },
+
+ getWheelDelta: function (e) {
+
+ var delta = 0;
+
+ if (e.wheelDelta) {
+ delta = e.wheelDelta / 120;
+ }
+ if (e.detail) {
+ delta = -e.detail / 3;
+ }
+ return delta;
+ },
+
+ _skipEvents: {},
+
+ _fakeStop: function (e) {
+ // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
+ L.DomEvent._skipEvents[e.type] = true;
+ },
+
+ _skipped: function (e) {
+ var skipped = this._skipEvents[e.type];
+ // reset when checking, as it's only used in map container and propagates outside of the map
+ this._skipEvents[e.type] = false;
+ return skipped;
+ },
+
+ // check if element really left/entered the event target (for mouseenter/mouseleave)
+ _checkMouse: function (el, e) {
+
+ var related = e.relatedTarget;
+
+ if (!related) { return true; }
+
+ try {
+ while (related && (related !== el)) {
+ related = related.parentNode;
+ }
+ } catch (err) {
+ return false;
+ }
+ return (related !== el);
+ },
+
+ _getEvent: function () { // evil magic for IE
+ /*jshint noarg:false */
+ var e = window.event;
+ if (!e) {
+ var caller = arguments.callee.caller;
+ while (caller) {
+ e = caller['arguments'][0];
+ if (e && window.Event === e.constructor) {
+ break;
+ }
+ caller = caller.caller;
+ }
+ }
+ return e;
+ },
+
+ // this is a horrible workaround for a bug in Android where a single touch triggers two click events
+ _filterClick: function (e, handler) {
+ var timeStamp = (e.timeStamp || e.originalEvent.timeStamp),
+ elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
+
+ // are they closer together than 1000ms yet more than 100ms?
+ // Android typically triggers them ~300ms apart while multiple listeners
+ // on the same event should be triggered far faster;
+ // or check if click is simulated on the element, and if it is, reject any non-simulated events
+
+ if ((elapsed && elapsed > 100 && elapsed < 1000) || (e.target._simulatedClick && !e._simulated)) {
+ L.DomEvent.stop(e);
+ return;
+ }
+ L.DomEvent._lastClick = timeStamp;
+
+ return handler(e);
+ }
+};
+
+L.DomEvent.on = L.DomEvent.addListener;
+L.DomEvent.off = L.DomEvent.removeListener;
+
+
+/*
+ * L.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
+ */
+
+L.Draggable = L.Class.extend({
+ includes: L.Mixin.Events,
+
+ statics: {
+ START: L.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 (element, dragStartTarget) {
+ this._element = element;
+ this._dragStartTarget = dragStartTarget || element;
+ },
+
+ enable: function () {
+ if (this._enabled) { return; }
+
+ for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
+ L.DomEvent.on(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
+ }
+
+ this._enabled = true;
+ },
+
+ disable: function () {
+ if (!this._enabled) { return; }
+
+ for (var i = L.Draggable.START.length - 1; i >= 0; i--) {
+ L.DomEvent.off(this._dragStartTarget, L.Draggable.START[i], this._onDown, this);
+ }
+
+ this._enabled = false;
+ this._moved = false;
+ },
+
+ _onDown: function (e) {
+ this._moved = false;
+
+ if (e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
+
+ L.DomEvent.stopPropagation(e);
+
+ if (L.Draggable._disabled) { return; }
+
+ L.DomUtil.disableImageDrag();
+ L.DomUtil.disableTextSelection();
+
+ if (this._moving) { return; }
+
+ var first = e.touches ? e.touches[0] : e;
+
+ this._startPoint = new L.Point(first.clientX, first.clientY);
+ this._startPos = this._newPos = L.DomUtil.getPosition(this._element);
+
+ L.DomEvent
+ .on(document, L.Draggable.MOVE[e.type], this._onMove, this)
+ .on(document, L.Draggable.END[e.type], this._onUp, this);
+ },
+
+ _onMove: function (e) {
+ if (e.touches && e.touches.length > 1) {
+ this._moved = true;
+ return;
+ }
+
+ var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
+ newPoint = new L.Point(first.clientX, first.clientY),
+ offset = newPoint.subtract(this._startPoint);
+
+ if (!offset.x && !offset.y) { return; }
+
+ L.DomEvent.preventDefault(e);
+
+ if (!this._moved) {
+ this.fire('dragstart');
+
+ this._moved = true;
+ this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
+
+ L.DomUtil.addClass(document.body, 'leaflet-dragging');
+ L.DomUtil.addClass((e.target || e.srcElement), 'leaflet-drag-target');
+ }
+
+ this._newPos = this._startPos.add(offset);
+ this._moving = true;
+
+ L.Util.cancelAnimFrame(this._animRequest);
+ this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true, this._dragStartTarget);
+ },
+
+ _updatePosition: function () {
+ this.fire('predrag');
+ L.DomUtil.setPosition(this._element, this._newPos);
+ this.fire('drag');
+ },
+
+ _onUp: function (e) {
+ L.DomUtil.removeClass(document.body, 'leaflet-dragging');
+ L.DomUtil.removeClass((e.target || e.srcElement), 'leaflet-drag-target');
+
+ for (var i in L.Draggable.MOVE) {
+ L.DomEvent
+ .off(document, L.Draggable.MOVE[i], this._onMove)
+ .off(document, L.Draggable.END[i], this._onUp);
+ }
+
+ L.DomUtil.enableImageDrag();
+ L.DomUtil.enableTextSelection();
+
+ if (this._moved && this._moving) {
+ // ensure drag is not fired after dragend
+ L.Util.cancelAnimFrame(this._animRequest);
+
+ this.fire('dragend', {
+ distance: this._newPos.distanceTo(this._startPos)
+ });
+ }
+
+ this._moving = false;
+ }
+});
+
+
+/*
+ L.Handler is a base class for handler classes that are used internally to inject
+ interaction features like dragging to classes like Map and Marker.
+*/
+
+L.Handler = L.Class.extend({
+ initialize: function (map) {
+ this._map = map;
+ },
+
+ enable: function () {
+ if (this._enabled) { return; }
+
+ this._enabled = true;
+ this.addHooks();
+ },
+
+ disable: function () {
+ if (!this._enabled) { return; }
+
+ this._enabled = false;
+ this.removeHooks();
+ },
+
+ enabled: function () {
+ return !!this._enabled;
+ }
+});
+
+
+/*
+ * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
+ */
+
+L.Map.mergeOptions({
+ dragging: true,
+
+ inertia: !L.Browser.android23,
+ inertiaDeceleration: 3400, // px/s^2
+ inertiaMaxSpeed: Infinity, // px/s
+ inertiaThreshold: L.Browser.touch ? 32 : 18, // ms
+ easeLinearity: 0.25,
+
+ // TODO refactor, move to CRS
+ worldCopyJump: false
+});
+
+L.Map.Drag = L.Handler.extend({
+ addHooks: function () {
+ if (!this._draggable) {
+ var map = this._map;
+
+ this._draggable = new L.Draggable(map._mapPane, map._container);
+
+ this._draggable.on({
+ 'dragstart': this._onDragStart,
+ 'drag': this._onDrag,
+ 'dragend': this._onDragEnd
+ }, this);
+
+ if (map.options.worldCopyJump) {
+ this._draggable.on('predrag', this._onPreDrag, this);
+ map.on('viewreset', this._onViewReset, this);
+
+ map.whenReady(this._onViewReset, this);
+ }
+ }
+ this._draggable.enable();
+ },
+
+ removeHooks: function () {
+ this._draggable.disable();
+ },
+
+ moved: function () {
+ return this._draggable && this._draggable._moved;
+ },
+
+ _onDragStart: function () {
+ var map = this._map;
+
+ if (map._panAnim) {
+ map._panAnim.stop();
+ }
+
+ map
+ .fire('movestart')
+ .fire('dragstart');
+
+ if (map.options.inertia) {
+ this._positions = [];
+ this._times = [];
+ }
+ },
+
+ _onDrag: function () {
+ if (this._map.options.inertia) {
+ var time = this._lastTime = +new Date(),
+ pos = this._lastPos = this._draggable._newPos;
+
+ this._positions.push(pos);
+ this._times.push(time);
+
+ if (time - this._times[0] > 200) {
+ this._positions.shift();
+ this._times.shift();
+ }
+ }
+
+ this._map
+ .fire('move')
+ .fire('drag');
+ },
+
+ _onViewReset: function () {
+ // TODO fix hardcoded Earth values
+ var pxCenter = this._map.getSize()._divideBy(2),
+ pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
+
+ this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
+ this._worldWidth = this._map.project([0, 180]).x;
+ },
+
+ _onPreDrag: function () {
+ // TODO refactor to be able to adjust map pane position after zoom
+ var worldWidth = this._worldWidth,
+ halfWidth = Math.round(worldWidth / 2),
+ dx = this._initialWorldOffset,
+ x = this._draggable._newPos.x,
+ newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
+ newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
+ newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
+
+ this._draggable._newPos.x = newX;
+ },
+
+ _onDragEnd: function (e) {
+ var map = this._map,
+ options = map.options,
+ delay = +new Date() - this._lastTime,
+
+ noInertia = !options.inertia || delay > options.inertiaThreshold || !this._positions[0];
+
+ map.fire('dragend', e);
+
+ if (noInertia) {
+ map.fire('moveend');
+
+ } else {
+
+ var direction = this._lastPos.subtract(this._positions[0]),
+ duration = (this._lastTime + delay - this._times[0]) / 1000,
+ ease = options.easeLinearity,
+
+ speedVector = direction.multiplyBy(ease / duration),
+ speed = speedVector.distanceTo([0, 0]),
+
+ limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
+ limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
+
+ decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
+ offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
+
+ if (!offset.x || !offset.y) {
+ map.fire('moveend');
+
+ } else {
+ offset = map._limitOffset(offset, map.options.maxBounds);
+
+ L.Util.requestAnimFrame(function () {
+ map.panBy(offset, {
+ duration: decelerationDuration,
+ easeLinearity: ease,
+ noMoveStart: true
+ });
+ });
+ }
+ }
+ }
+});
+
+L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);
+
+
+/*
+ * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
+ */
+
+L.Map.mergeOptions({
+ doubleClickZoom: true
+});
+
+L.Map.DoubleClickZoom = L.Handler.extend({
+ addHooks: function () {
+ this._map.on('dblclick', this._onDoubleClick, this);
+ },
+
+ removeHooks: function () {
+ this._map.off('dblclick', this._onDoubleClick, this);
+ },
+
+ _onDoubleClick: function (e) {
+ var map = this._map,
+ zoom = map.getZoom() + (e.originalEvent.shiftKey ? -1 : 1);
+
+ if (map.options.doubleClickZoom === 'center') {
+ map.setZoom(zoom);
+ } else {
+ map.setZoomAround(e.containerPoint, zoom);
+ }
+ }
+});
+
+L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
+
+
+/*
+ * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
+ */
+
+L.Map.mergeOptions({
+ scrollWheelZoom: true
+});
+
+L.Map.ScrollWheelZoom = L.Handler.extend({
+ addHooks: function () {
+ L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
+ L.DomEvent.on(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
+ this._delta = 0;
+ },
+
+ removeHooks: function () {
+ L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll);
+ L.DomEvent.off(this._map._container, 'MozMousePixelScroll', L.DomEvent.preventDefault);
+ },
+
+ _onWheelScroll: function (e) {
+ var delta = L.DomEvent.getWheelDelta(e);
+
+ this._delta += delta;
+ this._lastMousePos = this._map.mouseEventToContainerPoint(e);
+
+ if (!this._startTime) {
+ this._startTime = +new Date();
+ }
+
+ var left = Math.max(40 - (+new Date() - this._startTime), 0);
+
+ clearTimeout(this._timer);
+ this._timer = setTimeout(L.bind(this._performZoom, this), left);
+
+ L.DomEvent.preventDefault(e);
+ L.DomEvent.stopPropagation(e);
+ },
+
+ _performZoom: function () {
+ var map = this._map,
+ delta = this._delta,
+ zoom = map.getZoom();
+
+ delta = delta > 0 ? Math.ceil(delta) : Math.floor(delta);
+ delta = Math.max(Math.min(delta, 4), -4);
+ delta = map._limitZoom(zoom + delta) - zoom;
+
+ this._delta = 0;
+ this._startTime = null;
+
+ if (!delta) { return; }
+
+ if (map.options.scrollWheelZoom === 'center') {
+ map.setZoom(zoom + delta);
+ } else {
+ map.setZoomAround(this._lastMousePos, zoom + delta);
+ }
+ }
+});
+
+L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
+
+
+/*
+ * Extends the event handling code with double tap support for mobile browsers.
+ */
+
+L.extend(L.DomEvent, {
+
+ _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
+ _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
+
+ // inspired by Zepto touch code by Thomas Fuchs
+ addDoubleTapListener: function (obj, handler, id) {
+ var last,
+ doubleTap = false,
+ delay = 250,
+ touch,
+ pre = '_leaflet_',
+ touchstart = this._touchstart,
+ touchend = this._touchend,
+ trackedTouches = [];
+
+ function onTouchStart(e) {
+ var count;
+
+ if (L.Browser.pointer) {
+ trackedTouches.push(e.pointerId);
+ count = trackedTouches.length;
+ } else {
+ count = e.touches.length;
+ }
+ if (count > 1) {
+ return;
+ }
+
+ var now = Date.now(),
+ delta = now - (last || now);
+
+ touch = e.touches ? e.touches[0] : e;
+ doubleTap = (delta > 0 && delta <= delay);
+ last = now;
+ }
+
+ function onTouchEnd(e) {
+ if (L.Browser.pointer) {
+ var idx = trackedTouches.indexOf(e.pointerId);
+ if (idx === -1) {
+ return;
+ }
+ trackedTouches.splice(idx, 1);
+ }
+
+ if (doubleTap) {
+ if (L.Browser.pointer) {
+ // work around .type being readonly with MSPointer* events
+ var newTouch = { },
+ prop;
+
+ // jshint forin:false
+ for (var i in touch) {
+ prop = touch[i];
+ if (typeof prop === 'function') {
+ newTouch[i] = prop.bind(touch);
+ } else {
+ newTouch[i] = prop;
+ }
+ }
+ touch = newTouch;
+ }
+ touch.type = 'dblclick';
+ handler(touch);
+ last = null;
+ }
+ }
+ obj[pre + touchstart + id] = onTouchStart;
+ obj[pre + touchend + id] = onTouchEnd;
+
+ // on pointer we need to listen on the document, otherwise a drag starting on the map and moving off screen
+ // will not come through to us, so we will lose track of how many touches are ongoing
+ var endElement = L.Browser.pointer ? document.documentElement : obj;
+
+ obj.addEventListener(touchstart, onTouchStart, false);
+ endElement.addEventListener(touchend, onTouchEnd, false);
+
+ if (L.Browser.pointer) {
+ endElement.addEventListener(L.DomEvent.POINTER_CANCEL, onTouchEnd, false);
+ }
+
+ return this;
+ },
+
+ removeDoubleTapListener: function (obj, id) {
+ var pre = '_leaflet_';
+
+ obj.removeEventListener(this._touchstart, obj[pre + this._touchstart + id], false);
+ (L.Browser.pointer ? document.documentElement : obj).removeEventListener(
+ this._touchend, obj[pre + this._touchend + id], false);
+
+ if (L.Browser.pointer) {
+ document.documentElement.removeEventListener(L.DomEvent.POINTER_CANCEL, obj[pre + this._touchend + id],
+ false);
+ }
+
+ return this;
+ }
+});
+
+
+/*
+ * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
+ */
+
+L.extend(L.DomEvent, {
+
+ //static
+ POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown',
+ POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove',
+ POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup',
+ POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
+
+ _pointers: [],
+ _pointerDocumentListener: false,
+
+ // Provides a touch events wrapper for (ms)pointer events.
+ // Based on changes by veproza https://github.com/CloudMade/Leaflet/pull/1019
+ //ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
+
+ addPointerListener: function (obj, type, handler, id) {
+
+ switch (type) {
+ case 'touchstart':
+ return this.addPointerListenerStart(obj, type, handler, id);
+ case 'touchend':
+ return this.addPointerListenerEnd(obj, type, handler, id);
+ case 'touchmove':
+ return this.addPointerListenerMove(obj, type, handler, id);
+ default:
+ throw 'Unknown touch event type';
+ }
+ },
+
+ addPointerListenerStart: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ pointers = this._pointers;
+
+ var cb = function (e) {
+
+ L.DomEvent.preventDefault(e);
+
+ var alreadyInArray = false;
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
+ alreadyInArray = true;
+ break;
+ }
+ }
+ if (!alreadyInArray) {
+ pointers.push(e);
+ }
+
+ e.touches = pointers.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ };
+
+ obj[pre + 'touchstart' + id] = cb;
+ obj.addEventListener(this.POINTER_DOWN, cb, false);
+
+ // need to also listen for end events to keep the _pointers list accurate
+ // this needs to be on the body and never go away
+ if (!this._pointerDocumentListener) {
+ var internalCb = function (e) {
+ for (var i = 0; i < pointers.length; i++) {
+ if (pointers[i].pointerId === e.pointerId) {
+ pointers.splice(i, 1);
+ break;
+ }
+ }
+ };
+ //We listen on the documentElement as any drags that end by moving the touch off the screen get fired there
+ document.documentElement.addEventListener(this.POINTER_UP, internalCb, false);
+ document.documentElement.addEventListener(this.POINTER_CANCEL, internalCb, false);
+
+ this._pointerDocumentListener = true;
+ }
+
+ return this;
+ },
+
+ addPointerListenerMove: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ touches = this._pointers;
+
+ function cb(e) {
+
+ // don't fire touch moves when mouse isn't down
+ if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
+
+ for (var i = 0; i < touches.length; i++) {
+ if (touches[i].pointerId === e.pointerId) {
+ touches[i] = e;
+ break;
+ }
+ }
+
+ e.touches = touches.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ }
+
+ obj[pre + 'touchmove' + id] = cb;
+ obj.addEventListener(this.POINTER_MOVE, cb, false);
+
+ return this;
+ },
+
+ addPointerListenerEnd: function (obj, type, handler, id) {
+ var pre = '_leaflet_',
+ touches = this._pointers;
+
+ var cb = function (e) {
+ for (var i = 0; i < touches.length; i++) {
+ if (touches[i].pointerId === e.pointerId) {
+ touches.splice(i, 1);
+ break;
+ }
+ }
+
+ e.touches = touches.slice();
+ e.changedTouches = [e];
+
+ handler(e);
+ };
+
+ obj[pre + 'touchend' + id] = cb;
+ obj.addEventListener(this.POINTER_UP, cb, false);
+ obj.addEventListener(this.POINTER_CANCEL, cb, false);
+
+ return this;
+ },
+
+ removePointerListener: function (obj, type, id) {
+ var pre = '_leaflet_',
+ cb = obj[pre + type + id];
+
+ switch (type) {
+ case 'touchstart':
+ obj.removeEventListener(this.POINTER_DOWN, cb, false);
+ break;
+ case 'touchmove':
+ obj.removeEventListener(this.POINTER_MOVE, cb, false);
+ break;
+ case 'touchend':
+ obj.removeEventListener(this.POINTER_UP, cb, false);
+ obj.removeEventListener(this.POINTER_CANCEL, cb, false);
+ break;
+ }
+
+ return this;
+ }
+});
+
+
+/*
+ * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
+ */
+
+L.Map.mergeOptions({
+ touchZoom: L.Browser.touch && !L.Browser.android23,
+ bounceAtZoomLimits: true
+});
+
+L.Map.TouchZoom = L.Handler.extend({
+ addHooks: function () {
+ L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
+ },
+
+ removeHooks: function () {
+ L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
+ },
+
+ _onTouchStart: function (e) {
+ var map = this._map;
+
+ if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
+
+ var p1 = map.mouseEventToLayerPoint(e.touches[0]),
+ p2 = map.mouseEventToLayerPoint(e.touches[1]),
+ viewCenter = map._getCenterLayerPoint();
+
+ this._startCenter = p1.add(p2)._divideBy(2);
+ this._startDist = p1.distanceTo(p2);
+
+ this._moved = false;
+ this._zooming = true;
+
+ this._centerOffset = viewCenter.subtract(this._startCenter);
+
+ if (map._panAnim) {
+ map._panAnim.stop();
+ }
+
+ L.DomEvent
+ .on(document, 'touchmove', this._onTouchMove, this)
+ .on(document, 'touchend', this._onTouchEnd, this);
+
+ L.DomEvent.preventDefault(e);
+ },
+
+ _onTouchMove: function (e) {
+ var map = this._map;
+
+ if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
+
+ var p1 = map.mouseEventToLayerPoint(e.touches[0]),
+ p2 = map.mouseEventToLayerPoint(e.touches[1]);
+
+ this._scale = p1.distanceTo(p2) / this._startDist;
+ this._delta = p1._add(p2)._divideBy(2)._subtract(this._startCenter);
+
+ if (this._scale === 1) { return; }
+
+ if (!map.options.bounceAtZoomLimits) {
+ if ((map.getZoom() === map.getMinZoom() && this._scale < 1) ||
+ (map.getZoom() === map.getMaxZoom() && this._scale > 1)) { return; }
+ }
+
+ if (!this._moved) {
+ L.DomUtil.addClass(map._mapPane, 'leaflet-touching');
+
+ map
+ .fire('movestart')
+ .fire('zoomstart');
+
+ this._moved = true;
+ }
+
+ L.Util.cancelAnimFrame(this._animRequest);
+ this._animRequest = L.Util.requestAnimFrame(
+ this._updateOnMove, this, true, this._map._container);
+
+ L.DomEvent.preventDefault(e);
+ },
+
+ _updateOnMove: function () {
+ var map = this._map,
+ origin = this._getScaleOrigin(),
+ center = map.layerPointToLatLng(origin),
+ zoom = map.getScaleZoom(this._scale);
+
+ map._animateZoom(center, zoom, this._startCenter, this._scale, this._delta);
+ },
+
+ _onTouchEnd: function () {
+ if (!this._moved || !this._zooming) {
+ this._zooming = false;
+ return;
+ }
+
+ var map = this._map;
+
+ this._zooming = false;
+ L.DomUtil.removeClass(map._mapPane, 'leaflet-touching');
+ L.Util.cancelAnimFrame(this._animRequest);
+
+ L.DomEvent
+ .off(document, 'touchmove', this._onTouchMove)
+ .off(document, 'touchend', this._onTouchEnd);
+
+ var origin = this._getScaleOrigin(),
+ center = map.layerPointToLatLng(origin),
+
+ oldZoom = map.getZoom(),
+ floatZoomDelta = map.getScaleZoom(this._scale) - oldZoom,
+ roundZoomDelta = (floatZoomDelta > 0 ?
+ Math.ceil(floatZoomDelta) : Math.floor(floatZoomDelta)),
+
+ zoom = map._limitZoom(oldZoom + roundZoomDelta),
+ scale = map.getZoomScale(zoom) / this._scale;
+
+ map._animateZoom(center, zoom, origin, scale);
+ },
+
+ _getScaleOrigin: function () {
+ var centerOffset = this._centerOffset.subtract(this._delta).divideBy(this._scale);
+ return this._startCenter.add(centerOffset);
+ }
+});
+
+L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
+
+
+/*
+ * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
+ */
+
+L.Map.mergeOptions({
+ tap: true,
+ tapTolerance: 15
+});
+
+L.Map.Tap = L.Handler.extend({
+ addHooks: function () {
+ L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);
+ },
+
+ removeHooks: function () {
+ L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);
+ },
+
+ _onDown: function (e) {
+ if (!e.touches) { return; }
+
+ L.DomEvent.preventDefault(e);
+
+ this._fireClick = true;
+
+ // don't simulate click or track longpress if more than 1 touch
+ if (e.touches.length > 1) {
+ this._fireClick = false;
+ clearTimeout(this._holdTimeout);
+ return;
+ }
+
+ var first = e.touches[0],
+ el = first.target;
+
+ this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
+
+ // if touching a link, highlight it
+ if (el.tagName && el.tagName.toLowerCase() === 'a') {
+ L.DomUtil.addClass(el, 'leaflet-active');
+ }
+
+ // simulate long hold but setting a timeout
+ this._holdTimeout = setTimeout(L.bind(function () {
+ if (this._isTapValid()) {
+ this._fireClick = false;
+ this._onUp();
+ this._simulateEvent('contextmenu', first);
+ }
+ }, this), 1000);
+
+ L.DomEvent
+ .on(document, 'touchmove', this._onMove, this)
+ .on(document, 'touchend', this._onUp, this);
+ },
+
+ _onUp: function (e) {
+ clearTimeout(this._holdTimeout);
+
+ L.DomEvent
+ .off(document, 'touchmove', this._onMove, this)
+ .off(document, 'touchend', this._onUp, this);
+
+ if (this._fireClick && e && e.changedTouches) {
+
+ var first = e.changedTouches[0],
+ el = first.target;
+
+ if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
+ L.DomUtil.removeClass(el, 'leaflet-active');
+ }
+
+ // simulate click if the touch didn't move too much
+ if (this._isTapValid()) {
+ this._simulateEvent('click', first);
+ }
+ }
+ },
+
+ _isTapValid: function () {
+ return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
+ },
+
+ _onMove: function (e) {
+ var first = e.touches[0];
+ this._newPos = new L.Point(first.clientX, first.clientY);
+ },
+
+ _simulateEvent: function (type, e) {
+ var simulatedEvent = document.createEvent('MouseEvents');
+
+ simulatedEvent._simulated = true;
+ e.target._simulatedClick = true;
+
+ simulatedEvent.initMouseEvent(
+ type, true, true, window, 1,
+ e.screenX, e.screenY,
+ e.clientX, e.clientY,
+ false, false, false, false, 0, null);
+
+ e.target.dispatchEvent(simulatedEvent);
+ }
+});
+
+if (L.Browser.touch && !L.Browser.pointer) {
+ L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);
+}
+
+
+/*
+ * L.Handler.ShiftDragZoom is used to add shift-drag zoom interaction to the map
+ * (zoom to a selected bounding box), enabled by default.
+ */
+
+L.Map.mergeOptions({
+ boxZoom: true
+});
+
+L.Map.BoxZoom = L.Handler.extend({
+ initialize: function (map) {
+ this._map = map;
+ this._container = map._container;
+ this._pane = map._panes.overlayPane;
+ this._moved = false;
+ },
+
+ addHooks: function () {
+ L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
+ },
+
+ removeHooks: function () {
+ L.DomEvent.off(this._container, 'mousedown', this._onMouseDown);
+ this._moved = false;
+ },
+
+ moved: function () {
+ return this._moved;
+ },
+
+ _onMouseDown: function (e) {
+ this._moved = false;
+
+ if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
+
+ L.DomUtil.disableTextSelection();
+ L.DomUtil.disableImageDrag();
+
+ this._startLayerPoint = this._map.mouseEventToLayerPoint(e);
+
+ L.DomEvent
+ .on(document, 'mousemove', this._onMouseMove, this)
+ .on(document, 'mouseup', this._onMouseUp, this)
+ .on(document, 'keydown', this._onKeyDown, this);
+ },
+
+ _onMouseMove: function (e) {
+ if (!this._moved) {
+ this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._pane);
+ L.DomUtil.setPosition(this._box, this._startLayerPoint);
+
+ //TODO refactor: move cursor to styles
+ this._container.style.cursor = 'crosshair';
+ this._map.fire('boxzoomstart');
+ }
+
+ var startPoint = this._startLayerPoint,
+ box = this._box,
+
+ layerPoint = this._map.mouseEventToLayerPoint(e),
+ offset = layerPoint.subtract(startPoint),
+
+ newPos = new L.Point(
+ Math.min(layerPoint.x, startPoint.x),
+ Math.min(layerPoint.y, startPoint.y));
+
+ L.DomUtil.setPosition(box, newPos);
+
+ this._moved = true;
+
+ // TODO refactor: remove hardcoded 4 pixels
+ box.style.width = (Math.max(0, Math.abs(offset.x) - 4)) + 'px';
+ box.style.height = (Math.max(0, Math.abs(offset.y) - 4)) + 'px';
+ },
+
+ _finish: function () {
+ if (this._moved) {
+ this._pane.removeChild(this._box);
+ this._container.style.cursor = '';
+ }
+
+ L.DomUtil.enableTextSelection();
+ L.DomUtil.enableImageDrag();
+
+ L.DomEvent
+ .off(document, 'mousemove', this._onMouseMove)
+ .off(document, 'mouseup', this._onMouseUp)
+ .off(document, 'keydown', this._onKeyDown);
+ },
+
+ _onMouseUp: function (e) {
+
+ this._finish();
+
+ var map = this._map,
+ layerPoint = map.mouseEventToLayerPoint(e);
+
+ if (this._startLayerPoint.equals(layerPoint)) { return; }
+
+ var bounds = new L.LatLngBounds(
+ map.layerPointToLatLng(this._startLayerPoint),
+ map.layerPointToLatLng(layerPoint));
+
+ map.fitBounds(bounds);
+
+ map.fire('boxzoomend', {
+ boxZoomBounds: bounds
+ });
+ },
+
+ _onKeyDown: function (e) {
+ if (e.keyCode === 27) {
+ this._finish();
+ }
+ }
+});
+
+L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
+
+
+/*
+ * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
+ */
+
+L.Map.mergeOptions({
+ keyboard: true,
+ keyboardPanOffset: 80,
+ keyboardZoomOffset: 1
+});
+
+L.Map.Keyboard = L.Handler.extend({
+
+ keyCodes: {
+ left: [37],
+ right: [39],
+ down: [40],
+ up: [38],
+ zoomIn: [187, 107, 61, 171],
+ zoomOut: [189, 109, 173]
+ },
+
+ initialize: function (map) {
+ this._map = map;
+
+ this._setPanOffset(map.options.keyboardPanOffset);
+ this._setZoomOffset(map.options.keyboardZoomOffset);
+ },
+
+ addHooks: function () {
+ var container = this._map._container;
+
+ // make the container focusable by tabbing
+ if (container.tabIndex === -1) {
+ container.tabIndex = '0';
+ }
+
+ L.DomEvent
+ .on(container, 'focus', this._onFocus, this)
+ .on(container, 'blur', this._onBlur, this)
+ .on(container, 'mousedown', this._onMouseDown, this);
+
+ this._map
+ .on('focus', this._addHooks, this)
+ .on('blur', this._removeHooks, this);
+ },
+
+ removeHooks: function () {
+ this._removeHooks();
+
+ var container = this._map._container;
+
+ L.DomEvent
+ .off(container, 'focus', this._onFocus, this)
+ .off(container, 'blur', this._onBlur, this)
+ .off(container, 'mousedown', this._onMouseDown, this);
+
+ this._map
+ .off('focus', this._addHooks, this)
+ .off('blur', this._removeHooks, this);
+ },
+
+ _onMouseDown: function () {
+ if (this._focused) { return; }
+
+ var body = document.body,
+ docEl = document.documentElement,
+ top = body.scrollTop || docEl.scrollTop,
+ left = body.scrollLeft || docEl.scrollLeft;
+
+ this._map._container.focus();
+
+ window.scrollTo(left, top);
+ },
+
+ _onFocus: function () {
+ this._focused = true;
+ this._map.fire('focus');
+ },
+
+ _onBlur: function () {
+ this._focused = false;
+ this._map.fire('blur');
+ },
+
+ _setPanOffset: function (pan) {
+ var keys = this._panKeys = {},
+ codes = this.keyCodes,
+ i, len;
+
+ for (i = 0, len = codes.left.length; i < len; i++) {
+ keys[codes.left[i]] = [-1 * pan, 0];
+ }
+ for (i = 0, len = codes.right.length; i < len; i++) {
+ keys[codes.right[i]] = [pan, 0];
+ }
+ for (i = 0, len = codes.down.length; i < len; i++) {
+ keys[codes.down[i]] = [0, pan];
+ }
+ for (i = 0, len = codes.up.length; i < len; i++) {
+ keys[codes.up[i]] = [0, -1 * pan];
+ }
+ },
+
+ _setZoomOffset: function (zoom) {
+ var keys = this._zoomKeys = {},
+ codes = this.keyCodes,
+ i, len;
+
+ for (i = 0, len = codes.zoomIn.length; i < len; i++) {
+ keys[codes.zoomIn[i]] = zoom;
+ }
+ for (i = 0, len = codes.zoomOut.length; i < len; i++) {
+ keys[codes.zoomOut[i]] = -zoom;
+ }
+ },
+
+ _addHooks: function () {
+ L.DomEvent.on(document, 'keydown', this._onKeyDown, this);
+ },
+
+ _removeHooks: function () {
+ L.DomEvent.off(document, 'keydown', this._onKeyDown, this);
+ },
+
+ _onKeyDown: function (e) {
+ var key = e.keyCode,
+ map = this._map;
+
+ if (key in this._panKeys) {
+
+ if (map._panAnim && map._panAnim._inProgress) { return; }
+
+ map.panBy(this._panKeys[key]);
+
+ if (map.options.maxBounds) {
+ map.panInsideBounds(map.options.maxBounds);
+ }
+
+ } else if (key in this._zoomKeys) {
+ map.setZoom(map.getZoom() + this._zoomKeys[key]);
+
+ } else {
+ return;
+ }
+
+ L.DomEvent.stop(e);
+ }
+});
+
+L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard);
+
+
+/*
+ * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
+ */
+
+L.Handler.MarkerDrag = L.Handler.extend({
+ initialize: function (marker) {
+ this._marker = marker;
+ },
+
+ addHooks: function () {
+ var icon = this._marker._icon;
+ if (!this._draggable) {
+ this._draggable = new L.Draggable(icon, icon);
+ }
+
+ this._draggable
+ .on('dragstart', this._onDragStart, this)
+ .on('drag', this._onDrag, this)
+ .on('dragend', this._onDragEnd, this);
+ this._draggable.enable();
+ L.DomUtil.addClass(this._marker._icon, 'leaflet-marker-draggable');
+ },
+
+ removeHooks: function () {
+ this._draggable
+ .off('dragstart', this._onDragStart, this)
+ .off('drag', this._onDrag, this)
+ .off('dragend', this._onDragEnd, this);
+
+ this._draggable.disable();
+ L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
+ },
+
+ moved: function () {
+ return this._draggable && this._draggable._moved;
+ },
+
+ _onDragStart: function () {
+ this._marker
+ .closePopup()
+ .fire('movestart')
+ .fire('dragstart');
+ },
+
+ _onDrag: function () {
+ var marker = this._marker,
+ shadow = marker._shadow,
+ iconPos = L.DomUtil.getPosition(marker._icon),
+ latlng = marker._map.layerPointToLatLng(iconPos);
+
+ // update shadow position
+ if (shadow) {
+ L.DomUtil.setPosition(shadow, iconPos);
+ }
+
+ marker._latlng = latlng;
+
+ marker
+ .fire('move', {latlng: latlng})
+ .fire('drag');
+ },
+
+ _onDragEnd: function (e) {
+ this._marker
+ .fire('moveend')
+ .fire('dragend', e);
+ }
+});
+
+
+/*
+ * L.Control is a base class for implementing map controls. Handles positioning.
+ * All other controls extend from this class.
+ */
+
+L.Control = L.Class.extend({
+ options: {
+ position: 'topright'
+ },
+
+ initialize: function (options) {
+ L.setOptions(this, options);
+ },
+
+ getPosition: function () {
+ return this.options.position;
+ },
+
+ setPosition: function (position) {
+ var map = this._map;
+
+ if (map) {
+ map.removeControl(this);
+ }
+
+ this.options.position = position;
+
+ if (map) {
+ map.addControl(this);
+ }
+
+ return this;
+ },
+
+ getContainer: function () {
+ return this._container;
+ },
+
+ addTo: function (map) {
+ this._map = map;
+
+ var container = this._container = this.onAdd(map),
+ pos = this.getPosition(),
+ corner = map._controlCorners[pos];
+
+ L.DomUtil.addClass(container, 'leaflet-control');
+
+ if (pos.indexOf('bottom') !== -1) {
+ corner.insertBefore(container, corner.firstChild);
+ } else {
+ corner.appendChild(container);
+ }
+
+ return this;
+ },
+
+ removeFrom: function (map) {
+ var pos = this.getPosition(),
+ corner = map._controlCorners[pos];
+
+ corner.removeChild(this._container);
+ this._map = null;
+
+ if (this.onRemove) {
+ this.onRemove(map);
+ }
+
+ return this;
+ },
+
+ _refocusOnMap: function () {
+ if (this._map) {
+ this._map.getContainer().focus();
+ }
+ }
+});
+
+L.control = function (options) {
+ return new L.Control(options);
+};
+
+
+// adds control-related methods to L.Map
+
+L.Map.include({
+ addControl: function (control) {
+ control.addTo(this);
+ return this;
+ },
+
+ removeControl: function (control) {
+ control.removeFrom(this);
+ return this;
+ },
+
+ _initControlPos: function () {
+ var corners = this._controlCorners = {},
+ l = 'leaflet-',
+ container = this._controlContainer =
+ L.DomUtil.create('div', l + 'control-container', this._container);
+
+ function createCorner(vSide, hSide) {
+ var className = l + vSide + ' ' + l + hSide;
+
+ corners[vSide + hSide] = L.DomUtil.create('div', className, container);
+ }
+
+ createCorner('top', 'left');
+ createCorner('top', 'right');
+ createCorner('bottom', 'left');
+ createCorner('bottom', 'right');
+ },
+
+ _clearControlPos: function () {
+ this._container.removeChild(this._controlContainer);
+ }
+});
+
+
+/*
+ * L.Control.Zoom is used for the default zoom buttons on the map.
+ */
+
+L.Control.Zoom = L.Control.extend({
+ options: {
+ position: 'topleft',
+ zoomInText: '+',
+ zoomInTitle: 'Zoom in',
+ zoomOutText: '-',
+ zoomOutTitle: 'Zoom out'
+ },
+
+ onAdd: function (map) {
+ var zoomName = 'leaflet-control-zoom',
+ container = L.DomUtil.create('div', zoomName + ' leaflet-bar');
+
+ this._map = map;
+
+ this._zoomInButton = this._createButton(
+ this.options.zoomInText, this.options.zoomInTitle,
+ zoomName + '-in', container, this._zoomIn, this);
+ this._zoomOutButton = this._createButton(
+ this.options.zoomOutText, this.options.zoomOutTitle,
+ zoomName + '-out', container, this._zoomOut, this);
+
+ this._updateDisabled();
+ map.on('zoomend zoomlevelschange', this._updateDisabled, this);
+
+ return container;
+ },
+
+ onRemove: function (map) {
+ map.off('zoomend zoomlevelschange', this._updateDisabled, this);
+ },
+
+ _zoomIn: function (e) {
+ this._map.zoomIn(e.shiftKey ? 3 : 1);
+ },
+
+ _zoomOut: function (e) {
+ this._map.zoomOut(e.shiftKey ? 3 : 1);
+ },
+
+ _createButton: function (html, title, className, container, fn, context) {
+ var link = L.DomUtil.create('a', className, container);
+ link.innerHTML = html;
+ link.href = '#';
+ link.title = title;
+
+ var stop = L.DomEvent.stopPropagation;
+
+ L.DomEvent
+ .on(link, 'click', stop)
+ .on(link, 'mousedown', stop)
+ .on(link, 'dblclick', stop)
+ .on(link, 'click', L.DomEvent.preventDefault)
+ .on(link, 'click', fn, context)
+ .on(link, 'click', this._refocusOnMap, context);
+
+ return link;
+ },
+
+ _updateDisabled: function () {
+ var map = this._map,
+ className = 'leaflet-disabled';
+
+ L.DomUtil.removeClass(this._zoomInButton, className);
+ L.DomUtil.removeClass(this._zoomOutButton, className);
+
+ if (map._zoom === map.getMinZoom()) {
+ L.DomUtil.addClass(this._zoomOutButton, className);
+ }
+ if (map._zoom === map.getMaxZoom()) {
+ L.DomUtil.addClass(this._zoomInButton, className);
+ }
+ }
+});
+
+L.Map.mergeOptions({
+ zoomControl: true
+});
+
+L.Map.addInitHook(function () {
+ if (this.options.zoomControl) {
+ this.zoomControl = new L.Control.Zoom();
+ this.addControl(this.zoomControl);
+ }
+});
+
+L.control.zoom = function (options) {
+ return new L.Control.Zoom(options);
+};
+
+
+
+/*
+ * L.Control.Attribution is used for displaying attribution on the map (added by default).
+ */
+
+L.Control.Attribution = L.Control.extend({
+ options: {
+ position: 'bottomright',
+ prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
+ },
+
+ initialize: function (options) {
+ L.setOptions(this, options);
+
+ this._attributions = {};
+ },
+
+ onAdd: function (map) {
+ this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
+ L.DomEvent.disableClickPropagation(this._container);
+
+ for (var i in map._layers) {
+ if (map._layers[i].getAttribution) {
+ this.addAttribution(map._layers[i].getAttribution());
+ }
+ }
+
+ map
+ .on('layeradd', this._onLayerAdd, this)
+ .on('layerremove', this._onLayerRemove, this);
+
+ this._update();
+
+ return this._container;
+ },
+
+ onRemove: function (map) {
+ map
+ .off('layeradd', this._onLayerAdd)
+ .off('layerremove', this._onLayerRemove);
+
+ },
+
+ setPrefix: function (prefix) {
+ this.options.prefix = prefix;
+ this._update();
+ return this;
+ },
+
+ addAttribution: function (text) {
+ if (!text) { return; }
+
+ if (!this._attributions[text]) {
+ this._attributions[text] = 0;
+ }
+ this._attributions[text]++;
+
+ this._update();
+
+ return this;
+ },
+
+ removeAttribution: function (text) {
+ if (!text) { return; }
+
+ if (this._attributions[text]) {
+ this._attributions[text]--;
+ this._update();
+ }
+
+ return this;
+ },
+
+ _update: function () {
+ if (!this._map) { return; }
+
+ var attribs = [];
+
+ for (var i in this._attributions) {
+ if (this._attributions[i]) {
+ attribs.push(i);
+ }
+ }
+
+ var prefixAndAttribs = [];
+
+ if (this.options.prefix) {
+ prefixAndAttribs.push(this.options.prefix);
+ }
+ if (attribs.length) {
+ prefixAndAttribs.push(attribs.join(', '));
+ }
+
+ this._container.innerHTML = prefixAndAttribs.join(' | ');
+ },
+
+ _onLayerAdd: function (e) {
+ if (e.layer.getAttribution) {
+ this.addAttribution(e.layer.getAttribution());
+ }
+ },
+
+ _onLayerRemove: function (e) {
+ if (e.layer.getAttribution) {
+ this.removeAttribution(e.layer.getAttribution());
+ }
+ }
+});
+
+L.Map.mergeOptions({
+ attributionControl: true
+});
+
+L.Map.addInitHook(function () {
+ if (this.options.attributionControl) {
+ this.attributionControl = (new L.Control.Attribution()).addTo(this);
+ }
+});
+
+L.control.attribution = function (options) {
+ return new L.Control.Attribution(options);
+};
+
+
+/*
+ * L.Control.Scale is used for displaying metric/imperial scale on the map.
+ */
+
+L.Control.Scale = L.Control.extend({
+ options: {
+ position: 'bottomleft',
+ maxWidth: 100,
+ metric: true,
+ imperial: true,
+ updateWhenIdle: false
+ },
+
+ onAdd: function (map) {
+ this._map = map;
+
+ var className = 'leaflet-control-scale',
+ container = L.DomUtil.create('div', className),
+ options = this.options;
+
+ this._addScales(options, className, container);
+
+ map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
+ map.whenReady(this._update, this);
+
+ return container;
+ },
+
+ onRemove: function (map) {
+ map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
+ },
+
+ _addScales: function (options, className, container) {
+ if (options.metric) {
+ this._mScale = L.DomUtil.create('div', className + '-line', container);
+ }
+ if (options.imperial) {
+ this._iScale = L.DomUtil.create('div', className + '-line', container);
+ }
+ },
+
+ _update: function () {
+ var bounds = this._map.getBounds(),
+ centerLat = bounds.getCenter().lat,
+ halfWorldMeters = 6378137 * Math.PI * Math.cos(centerLat * Math.PI / 180),
+ dist = halfWorldMeters * (bounds.getNorthEast().lng - bounds.getSouthWest().lng) / 180,
+
+ size = this._map.getSize(),
+ options = this.options,
+ maxMeters = 0;
+
+ if (size.x > 0) {
+ maxMeters = dist * (options.maxWidth / size.x);
+ }
+
+ this._updateScales(options, maxMeters);
+ },
+
+ _updateScales: function (options, maxMeters) {
+ if (options.metric && maxMeters) {
+ this._updateMetric(maxMeters);
+ }
+
+ if (options.imperial && maxMeters) {
+ this._updateImperial(maxMeters);
+ }
+ },
+
+ _updateMetric: function (maxMeters) {
+ var meters = this._getRoundNum(maxMeters);
+
+ this._mScale.style.width = this._getScaleWidth(meters / maxMeters) + 'px';
+ this._mScale.innerHTML = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
+ },
+
+ _updateImperial: function (maxMeters) {
+ var maxFeet = maxMeters * 3.2808399,
+ scale = this._iScale,
+ maxMiles, miles, feet;
+
+ if (maxFeet > 5280) {
+ maxMiles = maxFeet / 5280;
+ miles = this._getRoundNum(maxMiles);
+
+ scale.style.width = this._getScaleWidth(miles / maxMiles) + 'px';
+ scale.innerHTML = miles + ' mi';
+
+ } else {
+ feet = this._getRoundNum(maxFeet);
+
+ scale.style.width = this._getScaleWidth(feet / maxFeet) + 'px';
+ scale.innerHTML = feet + ' ft';
+ }
+ },
+
+ _getScaleWidth: function (ratio) {
+ return Math.round(this.options.maxWidth * ratio) - 10;
+ },
+
+ _getRoundNum: function (num) {
+ var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
+ d = num / pow10;
+
+ d = d >= 10 ? 10 : d >= 5 ? 5 : d >= 3 ? 3 : d >= 2 ? 2 : 1;
+
+ return pow10 * d;
+ }
+});
+
+L.control.scale = function (options) {
+ return new L.Control.Scale(options);
+};
+
+
+/*
+ * L.Control.Layers is a control to allow users to switch between different layers on the map.
+ */
+
+L.Control.Layers = L.Control.extend({
+ options: {
+ collapsed: true,
+ position: 'topright',
+ autoZIndex: true
+ },
+
+ initialize: function (baseLayers, overlays, options) {
+ L.setOptions(this, options);
+
+ this._layers = {};
+ this._lastZIndex = 0;
+ this._handlingClick = false;
+
+ for (var i in baseLayers) {
+ this._addLayer(baseLayers[i], i);
+ }
+
+ for (i in overlays) {
+ this._addLayer(overlays[i], i, true);
+ }
+ },
+
+ onAdd: function (map) {
+ this._initLayout();
+ this._update();
+
+ map
+ .on('layeradd', this._onLayerChange, this)
+ .on('layerremove', this._onLayerChange, this);
+
+ return this._container;
+ },
+
+ onRemove: function (map) {
+ map
+ .off('layeradd', this._onLayerChange)
+ .off('layerremove', this._onLayerChange);
+ },
+
+ addBaseLayer: function (layer, name) {
+ this._addLayer(layer, name);
+ this._update();
+ return this;
+ },
+
+ addOverlay: function (layer, name) {
+ this._addLayer(layer, name, true);
+ this._update();
+ return this;
+ },
+
+ removeLayer: function (layer) {
+ var id = L.stamp(layer);
+ delete this._layers[id];
+ this._update();
+ return this;
+ },
+
+ _initLayout: function () {
+ var className = 'leaflet-control-layers',
+ container = this._container = L.DomUtil.create('div', className);
+
+ //Makes this work on IE10 Touch devices by stopping it from firing a mouseout event when the touch is released
+ container.setAttribute('aria-haspopup', true);
+
+ if (!L.Browser.touch) {
+ L.DomEvent
+ .disableClickPropagation(container)
+ .disableScrollPropagation(container);
+ } else {
+ L.DomEvent.on(container, 'click', L.DomEvent.stopPropagation);
+ }
+
+ var form = this._form = L.DomUtil.create('form', className + '-list');
+
+ if (this.options.collapsed) {
+ if (!L.Browser.android) {
+ L.DomEvent
+ .on(container, 'mouseover', this._expand, this)
+ .on(container, 'mouseout', this._collapse, this);
+ }
+ var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
+ link.href = '#';
+ link.title = 'Layers';
+
+ if (L.Browser.touch) {
+ L.DomEvent
+ .on(link, 'click', L.DomEvent.stop)
+ .on(link, 'click', this._expand, this);
+ }
+ else {
+ L.DomEvent.on(link, 'focus', this._expand, this);
+ }
+ //Work around for Firefox android issue https://github.com/Leaflet/Leaflet/issues/2033
+ L.DomEvent.on(form, 'click', function () {
+ setTimeout(L.bind(this._onInputClick, this), 0);
+ }, this);
+
+ this._map.on('click', this._collapse, this);
+ // TODO keyboard accessibility
+ } else {
+ this._expand();
+ }
+
+ this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
+ this._separator = L.DomUtil.create('div', className + '-separator', form);
+ this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
+
+ container.appendChild(form);
+ },
+
+ _addLayer: function (layer, name, overlay) {
+ var id = L.stamp(layer);
+
+ this._layers[id] = {
+ layer: layer,
+ name: name,
+ overlay: overlay
+ };
+
+ if (this.options.autoZIndex && layer.setZIndex) {
+ this._lastZIndex++;
+ layer.setZIndex(this._lastZIndex);
+ }
+ },
+
+ _update: function () {
+ if (!this._container) {
+ return;
+ }
+
+ this._baseLayersList.innerHTML = '';
+ this._overlaysList.innerHTML = '';
+
+ var baseLayersPresent = false,
+ overlaysPresent = false,
+ i, obj;
+
+ for (i in this._layers) {
+ obj = this._layers[i];
+ this._addItem(obj);
+ overlaysPresent = overlaysPresent || obj.overlay;
+ baseLayersPresent = baseLayersPresent || !obj.overlay;
+ }
+
+ this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
+ },
+
+ _onLayerChange: function (e) {
+ var obj = this._layers[L.stamp(e.layer)];
+
+ if (!obj) { return; }
+
+ if (!this._handlingClick) {
+ this._update();
+ }
+
+ var type = obj.overlay ?
+ (e.type === 'layeradd' ? 'overlayadd' : 'overlayremove') :
+ (e.type === 'layeradd' ? 'baselayerchange' : null);
+
+ if (type) {
+ this._map.fire(type, obj);
+ }
+ },
+
+ // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
+ _createRadioElement: function (name, checked) {
+
+ var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + name + '"';
+ if (checked) {
+ radioHtml += ' checked="checked"';
+ }
+ radioHtml += '/>';
+
+ var radioFragment = document.createElement('div');
+ radioFragment.innerHTML = radioHtml;
+
+ return radioFragment.firstChild;
+ },
+
+ _addItem: function (obj) {
+ var label = document.createElement('label'),
+ input,
+ checked = this._map.hasLayer(obj.layer);
+
+ if (obj.overlay) {
+ input = document.createElement('input');
+ input.type = 'checkbox';
+ input.className = 'leaflet-control-layers-selector';
+ input.defaultChecked = checked;
+ } else {
+ input = this._createRadioElement('leaflet-base-layers', checked);
+ }
+
+ input.layerId = L.stamp(obj.layer);
+
+ L.DomEvent.on(input, 'click', this._onInputClick, this);
+
+ var name = document.createElement('span');
+ name.innerHTML = ' ' + obj.name;
+
+ label.appendChild(input);
+ label.appendChild(name);
+
+ var container = obj.overlay ? this._overlaysList : this._baseLayersList;
+ container.appendChild(label);
+
+ return label;
+ },
+
+ _onInputClick: function () {
+ var i, input, obj,
+ inputs = this._form.getElementsByTagName('input'),
+ inputsLen = inputs.length;
+
+ this._handlingClick = true;
+
+ for (i = 0; i < inputsLen; i++) {
+ input = inputs[i];
+ obj = this._layers[input.layerId];
+
+ if (input.checked && !this._map.hasLayer(obj.layer)) {
+ this._map.addLayer(obj.layer);
+
+ } else if (!input.checked && this._map.hasLayer(obj.layer)) {
+ this._map.removeLayer(obj.layer);
+ }
+ }
+
+ this._handlingClick = false;
+
+ this._refocusOnMap();
+ },
+
+ _expand: function () {
+ L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
+ },
+
+ _collapse: function () {
+ this._container.className = this._container.className.replace(' leaflet-control-layers-expanded', '');
+ }
+});
+
+L.control.layers = function (baseLayers, overlays, options) {
+ return new L.Control.Layers(baseLayers, overlays, options);
+};
+
+
+/*
+ * L.PosAnimation is used by Leaflet internally for pan animations.
+ */
+
+L.PosAnimation = L.Class.extend({
+ includes: L.Mixin.Events,
+
+ run: function (el, newPos, duration, easeLinearity) { // (HTMLElement, Point[, Number, Number])
+ this.stop();
+
+ this._el = el;
+ this._inProgress = true;
+ this._newPos = newPos;
+
+ this.fire('start');
+
+ el.style[L.DomUtil.TRANSITION] = 'all ' + (duration || 0.25) +
+ 's cubic-bezier(0,0,' + (easeLinearity || 0.5) + ',1)';
+
+ L.DomEvent.on(el, L.DomUtil.TRANSITION_END, this._onTransitionEnd, this);
+ L.DomUtil.setPosition(el, newPos);
+
+ // toggle reflow, Chrome flickers for some reason if you don't do this
+ L.Util.falseFn(el.offsetWidth);
+
+ // there's no native way to track value updates of transitioned properties, so we imitate this
+ this._stepTimer = setInterval(L.bind(this._onStep, this), 50);
+ },
+
+ stop: function () {
+ if (!this._inProgress) { return; }
+
+ // if we just removed the transition property, the element would jump to its final position,
+ // so we need to make it stay at the current position
+
+ L.DomUtil.setPosition(this._el, this._getPos());
+ this._onTransitionEnd();
+ L.Util.falseFn(this._el.offsetWidth); // force reflow in case we are about to start a new animation
+ },
+
+ _onStep: function () {
+ var stepPos = this._getPos();
+ if (!stepPos) {
+ this._onTransitionEnd();
+ return;
+ }
+ // jshint camelcase: false
+ // make L.DomUtil.getPosition return intermediate position value during animation
+ this._el._leaflet_pos = stepPos;
+
+ this.fire('step');
+ },
+
+ // you can't easily get intermediate values of properties animated with CSS3 Transitions,
+ // we need to parse computed style (in case of transform it returns matrix string)
+
+ _transformRe: /([-+]?(?:\d*\.)?\d+)\D*, ([-+]?(?:\d*\.)?\d+)\D*\)/,
+
+ _getPos: function () {
+ var left, top, matches,
+ el = this._el,
+ style = window.getComputedStyle(el);
+
+ if (L.Browser.any3d) {
+ matches = style[L.DomUtil.TRANSFORM].match(this._transformRe);
+ if (!matches) { return; }
+ left = parseFloat(matches[1]);
+ top = parseFloat(matches[2]);
+ } else {
+ left = parseFloat(style.left);
+ top = parseFloat(style.top);
+ }
+
+ return new L.Point(left, top, true);
+ },
+
+ _onTransitionEnd: function () {
+ L.DomEvent.off(this._el, L.DomUtil.TRANSITION_END, this._onTransitionEnd, this);
+
+ if (!this._inProgress) { return; }
+ this._inProgress = false;
+
+ this._el.style[L.DomUtil.TRANSITION] = '';
+
+ // jshint camelcase: false
+ // make sure L.DomUtil.getPosition returns the final position value after animation
+ this._el._leaflet_pos = this._newPos;
+
+ clearInterval(this._stepTimer);
+
+ this.fire('step').fire('end');
+ }
+
+});
+
+
+/*
+ * Extends L.Map to handle panning animations.
+ */
+
+L.Map.include({
+
+ setView: function (center, zoom, options) {
+
+ zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
+ center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
+ options = options || {};
+
+ if (this._panAnim) {
+ this._panAnim.stop();
+ }
+
+ if (this._loaded && !options.reset && options !== true) {
+
+ if (options.animate !== undefined) {
+ options.zoom = L.extend({animate: options.animate}, options.zoom);
+ options.pan = L.extend({animate: options.animate}, options.pan);
+ }
+
+ // try animating pan or zoom
+ var animated = (this._zoom !== zoom) ?
+ this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
+ this._tryAnimatedPan(center, options.pan);
+
+ if (animated) {
+ // prevent resize handler call, the view will refresh after animation anyway
+ clearTimeout(this._sizeTimer);
+ return this;
+ }
+ }
+
+ // animation didn't start, just reset the map view
+ this._resetView(center, zoom);
+
+ return this;
+ },
+
+ panBy: function (offset, options) {
+ offset = L.point(offset).round();
+ options = options || {};
+
+ if (!offset.x && !offset.y) {
+ return this;
+ }
+
+ if (!this._panAnim) {
+ this._panAnim = new L.PosAnimation();
+
+ this._panAnim.on({
+ 'step': this._onPanTransitionStep,
+ 'end': this._onPanTransitionEnd
+ }, this);
+ }
+
+ // don't fire movestart if animating inertia
+ if (!options.noMoveStart) {
+ this.fire('movestart');
+ }
+
+ // animate pan unless animate: false specified
+ if (options.animate !== false) {
+ L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
+
+ var newPos = this._getMapPanePos().subtract(offset);
+ this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
+ } else {
+ this._rawPanBy(offset);
+ this.fire('move').fire('moveend');
+ }
+
+ return this;
+ },
+
+ _onPanTransitionStep: function () {
+ this.fire('move');
+ },
+
+ _onPanTransitionEnd: function () {
+ L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
+ this.fire('moveend');
+ },
+
+ _tryAnimatedPan: function (center, options) {
+ // difference between the new and current centers in pixels
+ var offset = this._getCenterOffset(center)._floor();
+
+ // don't animate too far unless animate: true specified in options
+ if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
+
+ this.panBy(offset, options);
+
+ return true;
+ }
+});
+
+
+/*
+ * L.PosAnimation fallback implementation that powers Leaflet pan animations
+ * in browsers that don't support CSS3 Transitions.
+ */
+
+L.PosAnimation = L.DomUtil.TRANSITION ? L.PosAnimation : L.PosAnimation.extend({
+
+ run: function (el, newPos, duration, easeLinearity) { // (HTMLElement, Point[, Number, Number])
+ this.stop();
+
+ this._el = el;
+ this._inProgress = true;
+ this._duration = duration || 0.25;
+ this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
+
+ this._startPos = L.DomUtil.getPosition(el);
+ this._offset = newPos.subtract(this._startPos);
+ this._startTime = +new Date();
+
+ this.fire('start');
+
+ this._animate();
+ },
+
+ stop: function () {
+ if (!this._inProgress) { return; }
+
+ this._step();
+ this._complete();
+ },
+
+ _animate: function () {
+ // animation loop
+ this._animId = L.Util.requestAnimFrame(this._animate, this);
+ this._step();
+ },
+
+ _step: function () {
+ var elapsed = (+new Date()) - this._startTime,
+ duration = this._duration * 1000;
+
+ if (elapsed < duration) {
+ this._runFrame(this._easeOut(elapsed / duration));
+ } else {
+ this._runFrame(1);
+ this._complete();
+ }
+ },
+
+ _runFrame: function (progress) {
+ var pos = this._startPos.add(this._offset.multiplyBy(progress));
+ L.DomUtil.setPosition(this._el, pos);
+
+ this.fire('step');
+ },
+
+ _complete: function () {
+ L.Util.cancelAnimFrame(this._animId);
+
+ this._inProgress = false;
+ this.fire('end');
+ },
+
+ _easeOut: function (t) {
+ return 1 - Math.pow(1 - t, this._easeOutPower);
+ }
+});
+
+
+/*
+ * Extends L.Map to handle zoom animations.
+ */
+
+L.Map.mergeOptions({
+ zoomAnimation: true,
+ zoomAnimationThreshold: 4
+});
+
+if (L.DomUtil.TRANSITION) {
+
+ L.Map.addInitHook(function () {
+ // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
+ this._zoomAnimated = this.options.zoomAnimation && L.DomUtil.TRANSITION &&
+ L.Browser.any3d && !L.Browser.android23 && !L.Browser.mobileOpera;
+
+ // zoom transitions run with the same duration for all layers, so if one of transitionend events
+ // happens after starting zoom animation (propagating to the map pane), we know that it ended globally
+ if (this._zoomAnimated) {
+ L.DomEvent.on(this._mapPane, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
+ }
+ });
+}
+
+L.Map.include(!L.DomUtil.TRANSITION ? {} : {
+
+ _catchTransitionEnd: function (e) {
+ if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
+ this._onZoomTransitionEnd();
+ }
+ },
+
+ _nothingToAnimate: function () {
+ return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
+ },
+
+ _tryAnimatedZoom: function (center, zoom, options) {
+
+ if (this._animatingZoom) { return true; }
+
+ options = options || {};
+
+ // don't animate if disabled, not supported or zoom difference is too large
+ if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
+ Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
+
+ // offset is the pixel coords of the zoom origin relative to the current center
+ var scale = this.getZoomScale(zoom),
+ offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale),
+ origin = this._getCenterLayerPoint()._add(offset);
+
+ // don't animate if the zoom origin isn't within one screen from the current center, unless forced
+ if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
+
+ this
+ .fire('movestart')
+ .fire('zoomstart');
+
+ this._animateZoom(center, zoom, origin, scale, null, true);
+
+ return true;
+ },
+
+ _animateZoom: function (center, zoom, origin, scale, delta, backwards) {
+
+ this._animatingZoom = true;
+
+ // put transform transition on all layers with leaflet-zoom-animated class
+ L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
+
+ // remember what center/zoom to set after animation
+ this._animateToCenter = center;
+ this._animateToZoom = zoom;
+
+ // disable any dragging during animation
+ if (L.Draggable) {
+ L.Draggable._disabled = true;
+ }
+
+ this.fire('zoomanim', {
+ center: center,
+ zoom: zoom,
+ origin: origin,
+ scale: scale,
+ delta: delta,
+ backwards: backwards
+ });
+ },
+
+ _onZoomTransitionEnd: function () {
+
+ this._animatingZoom = false;
+
+ L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
+
+ this._resetView(this._animateToCenter, this._animateToZoom, true, true);
+
+ if (L.Draggable) {
+ L.Draggable._disabled = false;
+ }
+ }
+});
+
+
+/*
+ Zoom animation logic for L.TileLayer.
+*/
+
+L.TileLayer.include({
+ _animateZoom: function (e) {
+ if (!this._animating) {
+ this._animating = true;
+ this._prepareBgBuffer();
+ }
+
+ var bg = this._bgBuffer,
+ transform = L.DomUtil.TRANSFORM,
+ initialTransform = e.delta ? L.DomUtil.getTranslateString(e.delta) : bg.style[transform],
+ scaleStr = L.DomUtil.getScaleString(e.scale, e.origin);
+
+ bg.style[transform] = e.backwards ?
+ scaleStr + ' ' + initialTransform :
+ initialTransform + ' ' + scaleStr;
+ },
+
+ _endZoomAnim: function () {
+ var front = this._tileContainer,
+ bg = this._bgBuffer;
+
+ front.style.visibility = '';
+ front.parentNode.appendChild(front); // Bring to fore
+
+ // force reflow
+ L.Util.falseFn(bg.offsetWidth);
+
+ this._animating = false;
+ },
+
+ _clearBgBuffer: function () {
+ var map = this._map;
+
+ if (map && !map._animatingZoom && !map.touchZoom._zooming) {
+ this._bgBuffer.innerHTML = '';
+ this._bgBuffer.style[L.DomUtil.TRANSFORM] = '';
+ }
+ },
+
+ _prepareBgBuffer: function () {
+
+ var front = this._tileContainer,
+ bg = this._bgBuffer;
+
+ // if foreground layer doesn't have many tiles but bg layer does,
+ // keep the existing bg layer and just zoom it some more
+
+ var bgLoaded = this._getLoadedTilesPercentage(bg),
+ frontLoaded = this._getLoadedTilesPercentage(front);
+
+ if (bg && bgLoaded > 0.5 && frontLoaded < 0.5) {
+
+ front.style.visibility = 'hidden';
+ this._stopLoadingImages(front);
+ return;
+ }
+
+ // prepare the buffer to become the front tile pane
+ bg.style.visibility = 'hidden';
+ bg.style[L.DomUtil.TRANSFORM] = '';
+
+ // switch out the current layer to be the new bg layer (and vice-versa)
+ this._tileContainer = bg;
+ bg = this._bgBuffer = front;
+
+ this._stopLoadingImages(bg);
+
+ //prevent bg buffer from clearing right after zoom
+ clearTimeout(this._clearBgBufferTimer);
+ },
+
+ _getLoadedTilesPercentage: function (container) {
+ var tiles = container.getElementsByTagName('img'),
+ i, len, count = 0;
+
+ for (i = 0, len = tiles.length; i < len; i++) {
+ if (tiles[i].complete) {
+ count++;
+ }
+ }
+ return count / len;
+ },
+
+ // stops loading all tiles in the background layer
+ _stopLoadingImages: function (container) {
+ var tiles = Array.prototype.slice.call(container.getElementsByTagName('img')),
+ i, len, tile;
+
+ for (i = 0, len = tiles.length; i < len; i++) {
+ tile = tiles[i];
+
+ if (!tile.complete) {
+ tile.onload = L.Util.falseFn;
+ tile.onerror = L.Util.falseFn;
+ tile.src = L.Util.emptyImageUrl;
+
+ tile.parentNode.removeChild(tile);
+ }
+ }
+ }
+});
+
+
+/*
+ * Provides L.Map with convenient shortcuts for using browser geolocation features.
+ */
+
+L.Map.include({
+ _defaultLocateOptions: {
+ watch: false,
+ setView: false,
+ maxZoom: Infinity,
+ timeout: 10000,
+ maximumAge: 0,
+ enableHighAccuracy: false
+ },
+
+ locate: function (/*Object*/ options) {
+
+ options = this._locateOptions = L.extend(this._defaultLocateOptions, options);
+
+ if (!navigator.geolocation) {
+ this._handleGeolocationError({
+ code: 0,
+ message: 'Geolocation not supported.'
+ });
+ return this;
+ }
+
+ var onResponse = L.bind(this._handleGeolocationResponse, this),
+ onError = L.bind(this._handleGeolocationError, this);
+
+ if (options.watch) {
+ this._locationWatchId =
+ navigator.geolocation.watchPosition(onResponse, onError, options);
+ } else {
+ navigator.geolocation.getCurrentPosition(onResponse, onError, options);
+ }
+ return this;
+ },
+
+ stopLocate: function () {
+ if (navigator.geolocation) {
+ navigator.geolocation.clearWatch(this._locationWatchId);
+ }
+ if (this._locateOptions) {
+ this._locateOptions.setView = false;
+ }
+ return this;
+ },
+
+ _handleGeolocationError: function (error) {
+ var c = error.code,
+ message = error.message ||
+ (c === 1 ? 'permission denied' :
+ (c === 2 ? 'position unavailable' : 'timeout'));
+
+ if (this._locateOptions.setView && !this._loaded) {
+ this.fitWorld();
+ }
+
+ this.fire('locationerror', {
+ code: c,
+ message: 'Geolocation error: ' + message + '.'
+ });
+ },
+
+ _handleGeolocationResponse: function (pos) {
+ var lat = pos.coords.latitude,
+ lng = pos.coords.longitude,
+ latlng = new L.LatLng(lat, lng),
+
+ latAccuracy = 180 * pos.coords.accuracy / 40075017,
+ lngAccuracy = latAccuracy / Math.cos(L.LatLng.DEG_TO_RAD * lat),
+
+ bounds = L.latLngBounds(
+ [lat - latAccuracy, lng - lngAccuracy],
+ [lat + latAccuracy, lng + lngAccuracy]),
+
+ options = this._locateOptions;
+
+ if (options.setView) {
+ var zoom = Math.min(this.getBoundsZoom(bounds), options.maxZoom);
+ this.setView(latlng, zoom);
+ }
+
+ var data = {
+ latlng: latlng,
+ bounds: bounds,
+ timestamp: pos.timestamp
+ };
+
+ for (var i in pos.coords) {
+ if (typeof pos.coords[i] === 'number') {
+ data[i] = pos.coords[i];
+ }
+ }
+
+ this.fire('locationfound', data);
+ }
+});
+
+
+}(window, document)); \ No newline at end of file
diff --git a/examples/osmtogeojson.js b/examples/osmtogeojson.js
new file mode 100644
index 0000000..e5f3535
--- /dev/null
+++ b/examples/osmtogeojson.js
@@ -0,0 +1 @@
+!function(e){"object"==typeof exports?module.exports=e():"function"==typeof define&&define.amd?define(e):"undefined"!=typeof window?window.osmtogeojson=e():"undefined"!=typeof global?global.osmtogeojson=e():"undefined"!=typeof self&&(self.osmtogeojson=e())}(function(){return function e(n,t,r){function o(i,u){if(!t[i]){if(!n[i]){var s="function"==typeof require&&require;if(!u&&s)return s(i,!0);if(a)return a(i,!0);throw new Error("Cannot find module '"+i+"'")}var l=t[i]={exports:{}};n[i][0].call(l.exports,function(e){var t=n[i][1][e];return o(t?t:e)},l,l.exports,e,n,t,r)}return t[i].exports}for(var a="function"==typeof require&&require,i=0;i<r.length;i++)o(r[i]);return o}({1:[function(e,n){var t=e("./lodash.custom.js"),r=e("geojson-rewind"),o=e("./polygon_features.json"),a={};a=function(e,n){function a(e){for(var n=new Array,r=new Array,o=new Array,a=0;a<e.elements.length;a++)switch(e.elements[a].type){case"node":var i=e.elements[a];n.push(i);break;case"way":var s=t.clone(e.elements[a]);s.nodes=t.clone(s.nodes),r.push(s);break;case"relation":var l=t.clone(e.elements[a]);l.members=t.clone(l.members),o.push(l)}return u(n,r,o)}function i(e){function n(e,n,t){e.hasAttribute(t)&&(n[t]=e.getAttribute(t))}var r=new Array,o=new Array,a=new Array;return t.each(e.getElementsByTagName("node"),function(e,o){var a={};t.each(e.getElementsByTagName("tag"),function(e){a[e.getAttribute("k")]=e.getAttribute("v")}),r[o]={type:"node"},n(e,r[o],"id"),n(e,r[o],"lat"),n(e,r[o],"lon"),n(e,r[o],"version"),n(e,r[o],"timestamp"),n(e,r[o],"changeset"),n(e,r[o],"uid"),n(e,r[o],"user"),t.isEmpty(a)||(r[o].tags=a)}),t.each(e.getElementsByTagName("way"),function(e,r){var a={},i=[];t.each(e.getElementsByTagName("tag"),function(e){a[e.getAttribute("k")]=e.getAttribute("v")}),t.each(e.getElementsByTagName("nd"),function(e,n){i[n]=e.getAttribute("ref")}),o[r]={type:"way"},n(e,o[r],"id"),n(e,o[r],"version"),n(e,o[r],"timestamp"),n(e,o[r],"changeset"),n(e,o[r],"uid"),n(e,o[r],"user"),i.length>0&&(o[r].nodes=i),t.isEmpty(a)||(o[r].tags=a)}),t.each(e.getElementsByTagName("relation"),function(e,r){var o={},i=[];t.each(e.getElementsByTagName("tag"),function(e){o[e.getAttribute("k")]=e.getAttribute("v")}),t.each(e.getElementsByTagName("member"),function(e,t){i[t]={},n(e,i[t],"ref"),n(e,i[t],"role"),n(e,i[t],"type")}),a[r]={type:"relation"},n(e,a[r],"id"),n(e,a[r],"version"),n(e,a[r],"timestamp"),n(e,a[r],"changeset"),n(e,a[r],"uid"),n(e,a[r],"user"),i.length>0&&(a[r].members=i),t.isEmpty(o)||(a[r].tags=o)}),u(r,o,a)}function u(e,o,a){function i(e,t){if("object"!=typeof t&&(t={}),"function"==typeof n.uninterestingTags)return!n.uninterestingTags(e,t);for(var r in e)if(n.uninterestingTags[r]!==!0&&t[r]!==!0&&t[r]!==e[r])return!0;return!1}function u(e){var n={timestamp:e.timestamp,version:e.version,changeset:e.changeset,user:e.user,uid:e.uid};for(k in n)void 0===n[k]&&delete n[k];return n}function l(e,n){function r(e){for(var n,t,r,o,a,i,u=function(e){return e[0]},s=function(e){return e[e.length-1]},l=[];e.length;)for(n=e.pop().nodes.slice(),l.push(n);e.length&&u(n)!==s(n);){for(t=u(n),r=s(n),o=0;o<e.length;o++){if(i=e[o].nodes,r===u(i)){a=n.push,i=i.slice(1);break}if(r===s(i)){a=n.push,i=i.slice(0,-1).reverse();break}if(t==s(i)){a=n.unshift,i=i.slice(0,-1);break}if(t==u(i)){a=n.unshift,i=i.slice(1).reverse();break}i=a=null}if(!i)break;e.splice(o,1),a.apply(n,i)}return l}function o(e){var n,t,r=function(e,n){for(var t=0;t<n.length;t++)if(a(n[t],e))return!0;return!1},o=function(e){return e.map(function(e){return[+e.lat,+e.lon]})},a=function(e,n){for(var t=e[0],r=e[1],o=!1,a=0,i=n.length-1;a<n.length;i=a++){var u=n[a][0],s=n[a][1],l=n[i][0],f=n[i][1],c=s>r!=f>r&&(l-u)*(r-s)/(f-s)+u>t;c&&(o=!o)}return o};for(e=o(e),n=0;n<s.length;n++)if(t=o(s[n]),r(t,e))return n}var a,i=!1;a=n.members.filter(function(e){return"way"===e.type}),a=a.map(function(e){var n=d[e.ref];return void 0===n?(i=!0,void 0):{id:e.ref,role:e.role||"outer",way:n,nodes:n.nodes.filter(function(e){return void 0!==e?!0:(i=!0,!1)})}}),a=t.compact(a);var s,l;s=r(a.filter(function(e){return"outer"===e.role})),l=r(a.filter(function(e){return"inner"===e.role}));var f;f=s.map(function(e){return[e]});for(var c=0;c<l.length;c++){var p=o(l[c]);void 0!==p&&f[p].push(l[c])}var g=[];if(g=t.compact(f.map(function(e){var n=t.compact(e.map(function(e){return e.length<4?void 0:t.compact(e.map(function(e){return[+e.lon,+e.lat]}))}));if(0!=n.length)return n})),0==g.length)return!1;var y="MultiPolygon";1===g.length&&(y="Polygon",g=g[0]);var m={type:"Feature",id:e.type+"/"+e.id,properties:{type:e.type,id:e.id,tags:e.tags||{},relations:b[e.type][e.id]||[],meta:u(e)},geometry:{type:y,coordinates:g}};return i&&(m.properties.tainted=!0),m}for(var f=new Object,c=0;c<e.length;c++)void 0!==e[c].lat&&(f[e[c].id]=e[c]);for(var p=new Object,c=0;c<e.length;c++)"undefined"!=typeof e[c].tags&&i(e[c].tags)&&(p[e[c].id]=!0);for(var c=0;c<a.length;c++)if(t.isArray(a[c].members))for(var g=0;g<a[c].members.length;g++)"node"==a[c].members[g].type&&(p[a[c].members[g].ref]=!0);for(var d=new Object,y=new Object,c=0;c<o.length;c++)if(t.isArray(o[c].nodes)){d[o[c].id]=o[c];for(var g=0;g<o[c].nodes.length;g++)y[o[c].nodes[g]]=!0,o[c].nodes[g]=f[o[c].nodes[g]]}for(var m=new Array,c=0;c<e.length;c++)(!y[e[c].id]||p[e[c].id])&&m.push(e[c]);for(var h=new Array,c=0;c<a.length;c++)t.isArray(a[c].members)&&(h[a[c].id]=a[c]);for(var b={node:{},way:{},relation:{}},c=0;c<a.length;c++)if(t.isArray(a[c].members))for(var g=0;g<a[c].members.length;g++){var v;switch(a[c].members[g].type){case"node":v=f[a[c].members[g].ref];break;case"way":v=d[a[c].members[g].ref];break;case"relation":v=h[a[c].members[g].ref]}if(v){var w=a[c].members[g].type,x=a[c].members[g].ref;"undefined"==typeof b[w][x]&&(b[w][x]=[]),b[w][x].push({role:a[c].members[g].role,rel:a[c].id,reltags:a[c].tags})}}var j,A={type:"FeatureCollection",features:new Array};for(c=0;c<m.length;c++)"undefined"!=typeof m[c].lon&&"undefined"!=typeof m[c].lat&&A.features.push({type:"Feature",id:"node/"+m[c].id,properties:{type:"node",id:m[c].id,tags:m[c].tags||{},relations:b.node[m[c].id]||[],meta:u(m[c])},geometry:{type:"Point",coordinates:[+m[c].lon,+m[c].lat]}});for(var P={type:"FeatureCollection",features:new Array},_={type:"FeatureCollection",features:new Array},c=0;c<a.length;c++)if("undefined"!=typeof a[c].tags&&("multipolygon"==a[c].tags.type||"boundary"==a[c].tags.type)){if(!t.isArray(a[c].members))continue;for(var E=0,g=0;g<a[c].members.length;g++)"outer"==a[c].members[g].role&&E++;if(a[c].members.forEach(function(e){d[e.ref]&&("outer"!==e.role||i(d[e.ref].tags,a[c].tags)||(d[e.ref].is_multipolygon_outline=!0),"inner"!==e.role||i(d[e.ref].tags)||(d[e.ref].is_multipolygon_outline=!0))}),0==E)continue;var O=!1;1!=E||i(a[c].tags,{type:!0})||(O=!0);var S=null;if(O){var C=a[c].members.filter(function(e){return"outer"===e.role})[0];if(C=d[C.ref],void 0===C)continue;C.is_multipolygon_outline=!0,S=l(C,a[c])}else S=l(a[c],a[c]);if(S===!1)continue;_.features.push(S)}for(var c=0;c<o.length;c++)if(t.isArray(o[c].nodes)&&!o[c].is_multipolygon_outline){for(o[c].tainted=!1,o[c].hidden=!1,coords=new Array,g=0;g<o[c].nodes.length;g++)"object"==typeof o[c].nodes[g]?coords.push([+o[c].nodes[g].lon,+o[c].nodes[g].lat]):o[c].tainted=!0;if(!(coords.length<=1)){var T="LineString";"undefined"!=typeof o[c].nodes[0]&&o[c].nodes[0]===o[c].nodes[o[c].nodes.length-1]&&"undefined"!=typeof o[c].tags&&s(o[c].tags)&&(T="Polygon",coords=[coords]);var S={type:"Feature",id:"way/"+o[c].id,properties:{type:"way",id:o[c].id,tags:o[c].tags||{},relations:b.way[o[c].id]||[],meta:u(o[c])},geometry:{type:T,coordinates:coords}};o[c].tainted&&(S.properties.tainted=!0),"LineString"==T?P.features.push(S):_.features.push(S)}}return j={type:"FeatureCollection",features:[]},j.features=j.features.concat(_.features),j.features=j.features.concat(P.features),j.features=j.features.concat(A.features),n.flatProperties&&j.features.forEach(function(e){e.properties=t.merge(e.properties.meta,e.properties.tags,{id:e.properties.type+"/"+e.properties.id})}),j=r(j,!0)}function s(e){var t=n.polygonFeatures;if("function"==typeof t)return t(e);if("no"===e.area)return!1;for(var r in e){var o=e[r],a=t[r];if("undefined"!=typeof a&&"no"!==o){if(a===!0)return!0;if(a.included_values&&a.included_values[o]===!0)return!0;if(a.excluded_values&&a.excluded_values[o]!==!0)return!0}}return!1}n=t.merge({flatProperties:!1,uninterestingTags:{source:!0,source_ref:!0,"source:ref":!0,history:!0,attribution:!0,created_by:!0,"tiger:county":!0,"tiger:tlid":!0,"tiger:upload_uuid":!0},polygonFeatures:o},n);var l;return l="undefined"!=typeof XMLDocument&&e instanceof XMLDocument||"undefined"==typeof XMLDocument&&e.childNodes?i(e):a(e)},a.toGeojson=a,n.exports=a},{"./lodash.custom.js":2,"./polygon_features.json":6,"geojson-rewind":3}],2:[function(e,n,t){var r="undefined"!=typeof self?self:"undefined"!=typeof window?window:{};(function(){function e(){return T.pop()||[]}function o(e){return"function"!=typeof e.toString&&"string"==typeof(e+"")}function a(e){e.length=0,T.length<N&&T.push(e)}function i(e,n,t){n||(n=0),"undefined"==typeof t&&(t=e?e.length:0);for(var r=-1,o=t-n||0,a=Array(0>o?0:o);++r<o;)a[r]=e[n+r];return a}function u(){}function s(e){function n(){if(r){var e=i(r);gn.apply(e,arguments)}if(this instanceof n){var a=f(t.prototype),u=t.apply(a,e||arguments);return j(u)?u:a}return t.apply(o,e||arguments)}var t=e[0],r=e[2],o=e[4];return Pn(n,e),n}function l(n,t,r,u,s){if(r){var f=r(n);if("undefined"!=typeof f)return f}var c=j(n);if(!c)return n;var p=sn.call(n);if(!z[p]||!jn.nodeClass&&o(n))return n;var g=wn[p];switch(p){case H:case q:return new g(+n);case X:case W:return new g(n);case V:return f=g(n.source,F.exec(n)),f.lastIndex=n.lastIndex,f}var d=kn(n);if(t){var y=!u;u||(u=e()),s||(s=e());for(var m=u.length;m--;)if(u[m]==n)return s[m];f=d?g(n.length):{}}else f=d?i(n):Ln({},n);return d&&(pn.call(n,"index")&&(f.index=n.index),pn.call(n,"input")&&(f.input=n.input)),t?(u.push(n),s.push(f),(d?Tn:Fn)(n,function(e,n){f[n]=l(e,t,r,u,s)}),y&&(a(u),a(s)),f):f}function f(e){return j(e)?hn(e):{}}function c(e,n,t){if("function"!=typeof e)return S;if("undefined"==typeof n||!("prototype"in e))return e;var r=e.__bindData__;if("undefined"==typeof r&&(jn.funcNames&&(r=!e.name),r=r||!jn.funcDecomp,!r)){var o=fn.call(e);jn.funcNames||(r=!I.test(o)),r||(r=D.test(o),Pn(e,r))}if(r===!1||r!==!0&&1&r[1])return e;switch(t){case 1:return function(t){return e.call(n,t)};case 2:return function(t,r){return e.call(n,t,r)};case 3:return function(t,r,o){return e.call(n,t,r,o)};case 4:return function(t,r,o,a){return e.call(n,t,r,o,a)}}return O(e,n)}function p(e){function n(){var e=l?u:this;if(o){var m=i(o);gn.apply(m,arguments)}if((a||g)&&(m||(m=i(arguments)),a&&gn.apply(m,a),g&&m.length<s))return r|=16,p([t,d?r:-4&r,m,null,u,s]);if(m||(m=arguments),c&&(t=e[y]),this instanceof n){e=f(t.prototype);var h=t.apply(e,m);return j(h)?h:e}return t.apply(e,m)}var t=e[0],r=e[1],o=e[2],a=e[3],u=e[4],s=e[5],l=1&r,c=2&r,g=4&r,d=8&r,y=t;return Pn(n,e),n}function g(e,n,t,r,o){(kn(n)?_:Fn)(n,function(n,a){var i,u,s=n,l=e[a];if(n&&((u=kn(n))||In(n))){for(var f=r.length;f--;)if(i=r[f]==n){l=o[f];break}if(!i){var c;t&&(s=t(l,n),(c="undefined"!=typeof s)&&(l=s)),c||(l=u?kn(l)?l:[]:In(l)?l:{}),r.push(n),o.push(l),c||g(l,n,t,r,o)}}else t&&(s=t(l,n),"undefined"==typeof s&&(s=n)),"undefined"!=typeof s&&(l=s);e[a]=l})}function d(e,n,t,r,o,a){var u=1&n,l=2&n,f=4&n,c=16&n,g=32&n;if(!l&&!x(e))throw new TypeError;c&&!t.length&&(n&=-17,c=t=!1),g&&!r.length&&(n&=-33,g=r=!1);var y=e&&e.__bindData__;if(y&&y!==!0)return y=i(y),y[2]&&(y[2]=i(y[2])),y[3]&&(y[3]=i(y[3])),!u||1&y[1]||(y[4]=o),!u&&1&y[1]&&(n|=8),!f||4&y[1]||(y[5]=a),c&&gn.apply(y[2]||(y[2]=[]),t),g&&yn.apply(y[3]||(y[3]=[]),r),y[1]|=n,d.apply(null,y);var m=1==n||17===n?s:p;return m([e,n,t,r,o,a])}function y(){K.shadowedProps=M,K.array=K.bottom=K.loop=K.top="",K.init="iterable",K.useHas=!0;for(var e,n=0;e=arguments[n];n++)for(var t in e)K[t]=e[t];var r=K.args;K.firstArg=/^[^,]+/.exec(r)[0];var o=Function("baseCreateCallback, errorClass, errorProto, hasOwnProperty, indicatorObject, isArguments, isArray, isString, keys, objectProto, objectTypes, nonEnumProps, stringClass, stringProto, toString","return function("+r+") {\n"+An(K)+"\n}");return o(c,U,on,pn,L,b,kn,A,K.keys,an,Q,xn,W,un,sn)}function m(e){return"function"==typeof e&&ln.test(e)}function h(e){var n,t;return!e||sn.call(e)!=G||(n=e.constructor,x(n)&&!(n instanceof n))||!jn.argsClass&&b(e)||!jn.nodeClass&&o(e)?!1:jn.ownLast?(Nn(e,function(e,n,r){return t=pn.call(r,n),!1}),t!==!1):(Nn(e,function(e,n){t=n}),"undefined"==typeof t||pn.call(e,t))}function b(e){return e&&"object"==typeof e&&"number"==typeof e.length&&sn.call(e)==B||!1}function v(e,n,t,r){return"boolean"!=typeof n&&null!=n&&(r=t,t=n,n=!1),l(e,n,"function"==typeof t&&c(t,r,1))}function w(e){var n=!0;if(!e)return n;var t=sn.call(e),r=e.length;return t==R||t==W||(jn.argsClass?t==B:b(e))||t==G&&"number"==typeof r&&x(e.splice)?!r:(Fn(e,function(){return n=!1}),n)}function x(e){return"function"==typeof e}function j(e){return!(!e||!Q[typeof e])}function A(e){return"string"==typeof e||e&&"object"==typeof e&&sn.call(e)==W||!1}function P(n){var t=arguments,r=2;if(!j(n))return n;if("number"!=typeof t[2]&&(r=t.length),r>3&&"function"==typeof t[r-2])var o=c(t[--r-1],t[r--],2);else r>2&&"function"==typeof t[r-1]&&(o=t[--r]);for(var u=i(arguments,1,r),s=-1,l=e(),f=e();++s<r;)g(n,u[s],o,l,f);return a(l),a(f),n}function _(e,n,t){if(n&&"undefined"==typeof t&&kn(e))for(var r=-1,o=e.length;++r<o&&n(e[r],r,e)!==!1;);else Tn(e,n,t);return e}function E(e){for(var n=-1,t=e?e.length:0,r=[];++n<t;){var o=e[n];o&&r.push(o)}return r}function O(e,n){return arguments.length>2?d(e,17,i(arguments,2),null,n):d(e,1,null,null,n)}function S(e){return e}function C(){}var T=[],L={},N=40,F=/\w*$/,I=/^\s*function[ \n\r\t]+\w/,D=/\bthis\b/,M=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"],B="[object Arguments]",R="[object Array]",H="[object Boolean]",q="[object Date]",U="[object Error]",$="[object Function]",X="[object Number]",G="[object Object]",V="[object RegExp]",W="[object String]",z={};z[$]=!1,z[B]=z[R]=z[H]=z[q]=z[X]=z[G]=z[V]=z[W]=!0;var J={configurable:!1,enumerable:!1,value:null,writable:!1},K={args:"",array:null,bottom:"",firstArg:"",init:"",keys:null,loop:"",shadowedProps:null,support:null,top:"",useHas:!1},Q={"boolean":!1,"function":!0,object:!0,number:!1,string:!1,undefined:!1},Y=Q[typeof window]&&window||this,Z=Q[typeof t]&&t&&!t.nodeType&&t,en=Q[typeof n]&&n&&!n.nodeType&&n,nn=en&&en.exports===Z&&Z,tn=Q[typeof r]&&r;!tn||tn.global!==tn&&tn.window!==tn||(Y=tn);var rn=[],on=Error.prototype,an=Object.prototype,un=String.prototype,sn=an.toString,ln=RegExp("^"+String(sn).replace(/[.*+?^${}()|[\]\\]/g,"\\$&").replace(/toString| for [^\]]+/g,".*?")+"$"),fn=Function.prototype.toString,cn=m(cn=Object.getPrototypeOf)&&cn,pn=an.hasOwnProperty,gn=rn.push,dn=an.propertyIsEnumerable,yn=rn.unshift,mn=function(){try{var e={},n=m(n=Object.defineProperty)&&n,t=n(e,e,e)&&n}catch(r){}return t}(),hn=m(hn=Object.create)&&hn,bn=m(bn=Array.isArray)&&bn,vn=m(vn=Object.keys)&&vn,wn={};wn[R]=Array,wn[H]=Boolean,wn[q]=Date,wn[$]=Function,wn[G]=Object,wn[X]=Number,wn[V]=RegExp,wn[W]=String;var xn={};xn[R]=xn[q]=xn[X]={constructor:!0,toLocaleString:!0,toString:!0,valueOf:!0},xn[H]=xn[W]={constructor:!0,toString:!0,valueOf:!0},xn[U]=xn[$]=xn[V]={constructor:!0,toString:!0},xn[G]={constructor:!0},function(){for(var e=M.length;e--;){var n=M[e];for(var t in xn)pn.call(xn,t)&&!pn.call(xn[t],n)&&(xn[t][n]=!1)}}();var jn=u.support={};!function(){var e=function(){this.x=1},n={0:1,length:1},t=[];e.prototype={valueOf:1,y:1};for(var r in new e)t.push(r);for(r in arguments);jn.argsClass=sn.call(arguments)==B,jn.argsObject=arguments.constructor==Object&&!(arguments instanceof Array),jn.enumErrorProps=dn.call(on,"message")||dn.call(on,"name"),jn.enumPrototypes=dn.call(e,"prototype"),jn.funcDecomp=!m(Y.WinRTError)&&D.test(function(){return this}),jn.funcNames="string"==typeof Function.name,jn.nonEnumArgs=0!=r,jn.nonEnumShadows=!/valueOf/.test(t),jn.ownLast="x"!=t[0],jn.spliceObjects=(rn.splice.call(n,0,1),!n[0]),jn.unindexedChars="x"[0]+Object("x")[0]!="xx";try{jn.nodeClass=!(sn.call(document)==G&&!({toString:0}+""))}catch(o){jn.nodeClass=!0}}(1);var An=function(e){var n="var index, iterable = "+e.firstArg+", result = "+e.init+";\nif (!iterable) return result;\n"+e.top+";";e.array?(n+="\nvar length = iterable.length; index = -1;\nif ("+e.array+") { ",jn.unindexedChars&&(n+="\n if (isString(iterable)) {\n iterable = iterable.split('')\n } "),n+="\n while (++index < length) {\n "+e.loop+";\n }\n}\nelse { "):jn.nonEnumArgs&&(n+="\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += '';\n "+e.loop+";\n }\n } else { "),jn.enumPrototypes&&(n+="\n var skipProto = typeof iterable == 'function';\n "),jn.enumErrorProps&&(n+="\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n ");var t=[];if(jn.enumPrototypes&&t.push('!(skipProto && index == "prototype")'),jn.enumErrorProps&&t.push('!(skipErrorProps && (index == "message" || index == "name"))'),e.useHas&&e.keys)n+="\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n",t.length&&(n+=" if ("+t.join(" && ")+") {\n "),n+=e.loop+"; ",t.length&&(n+="\n }"),n+="\n } ";else if(n+="\n for (index in iterable) {\n",e.useHas&&t.push("hasOwnProperty.call(iterable, index)"),t.length&&(n+=" if ("+t.join(" && ")+") {\n "),n+=e.loop+"; ",t.length&&(n+="\n }"),n+="\n } ",jn.nonEnumShadows){for(n+="\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n ",k=0;7>k;k++)n+="\n index = '"+e.shadowedProps[k]+"';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))",e.useHas||(n+=" || (!nonEnum[index] && iterable[index] !== objectProto[index])"),n+=") {\n "+e.loop+";\n } ";n+="\n } "}return(e.array||jn.nonEnumArgs)&&(n+="\n}"),n+=e.bottom+";\nreturn result"};hn||(f=function(){function e(){}return function(n){if(j(n)){e.prototype=n;var t=new e;e.prototype=null}return t||Y.Object()}}());var Pn=mn?function(e,n){J.value=n,mn(e,"__bindData__",J)}:C;jn.argsClass||(b=function(e){return e&&"object"==typeof e&&"number"==typeof e.length&&pn.call(e,"callee")&&!dn.call(e,"callee")||!1});var kn=bn||function(e){return e&&"object"==typeof e&&"number"==typeof e.length&&sn.call(e)==R||!1},_n=y({args:"object",init:"[]",top:"if (!(objectTypes[typeof object])) return result",loop:"result.push(index)"}),En=vn?function(e){return j(e)?jn.enumPrototypes&&"function"==typeof e||jn.nonEnumArgs&&e.length&&b(e)?_n(e):vn(e):[]}:_n,On={args:"collection, callback, thisArg",top:"callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",array:"typeof length == 'number'",keys:En,loop:"if (callback(iterable[index], index, collection) === false) return result"},Sn={args:"object, source, guard",top:"var args = arguments,\n argsIndex = 0,\n argsLength = typeof guard == 'number' ? 2 : args.length;\nwhile (++argsIndex < argsLength) {\n iterable = args[argsIndex];\n if (iterable && objectTypes[typeof iterable]) {",keys:En,loop:"if (typeof result[index] == 'undefined') result[index] = iterable[index]",bottom:" }\n}"},Cn={top:"if (!objectTypes[typeof iterable]) return result;\n"+On.top,array:!1},Tn=y(On),Ln=y(Sn,{top:Sn.top.replace(";",";\nif (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n callback = args[--argsLength];\n}"),loop:"result[index] = callback ? callback(result[index], iterable[index]) : iterable[index]"}),Nn=y(On,Cn,{useHas:!1}),Fn=y(On,Cn);x(/x/)&&(x=function(e){return"function"==typeof e&&sn.call(e)==$});var In=cn?function(e){if(!e||sn.call(e)!=G||!jn.argsClass&&b(e))return!1;var n=e.valueOf,t=m(n)&&(t=cn(n))&&cn(t);return t?e==t||cn(e)==t:h(e)}:h;u.assign=Ln,u.bind=O,u.compact=E,u.forEach=_,u.forIn=Nn,u.forOwn=Fn,u.keys=En,u.merge=P,u.each=_,u.extend=Ln,u.clone=v,u.identity=S,u.isArguments=b,u.isArray=kn,u.isEmpty=w,u.isFunction=x,u.isObject=j,u.isPlainObject=In,u.isString=A,u.noop=C,u.VERSION="2.4.1",Z&&en&&nn&&((en.exports=u)._=u)}).call(this)},{}],3:[function(e,n){function t(e,n){switch(e&&e.type||null){case"FeatureCollection":return e.features=e.features.map(r(t,n)),e;case"Feature":return e.geometry=t(e.geometry,n),e;case"Polygon":case"MultiPolygon":return o(e,n);default:return e}}function r(e,n){return function(t){return e(t,n)}}function o(e,n){return"Polygon"===e.type?e.coordinates=a(e.coordinates,n):"MultiPolygon"===e.type&&(e.coordinates=e.coordinates.map(r(a,n))),e}function a(e,n){n=!!n,e[0]=i(e[0],!n);for(var t=1;t<e.length;t++)e[t]=i(e[t],n);return e}function i(e,n){return u(e)===n?e:e.reverse()}function u(e){return s.ring(e)>=0}var s=e("geojson-area");n.exports=t},{"geojson-area":4}],4:[function(e,n){function t(e){if("Polygon"===e.type)return r(e.coordinates);if("MultiPolygon"===e.type){for(var n=0,t=0;t<e.coordinates.length;t++)n+=r(e.coordinates[t]);return n}return null}function r(e){var n=0;if(e&&e.length>0){n+=Math.abs(o(e[0]));for(var t=1;t<e.length;t++)n-=Math.abs(o(e[t]))}return n}function o(e){var n=0;if(e.length>2){for(var t,r,o=0;o<e.length-1;o++)t=e[o],r=e[o+1],n+=a(r[0]-t[0])*(2+Math.sin(a(t[1]))+Math.sin(a(r[1])));n=n*i.RADIUS*i.RADIUS/2}return n}function a(e){return e*Math.PI/180}var i=e("wgs84");n.exports.geometry=t,n.exports.ring=o},{wgs84:5}],5:[function(e,n){n.exports.RADIUS=6378137,n.exports.FLATTENING=1/298.257223563,n.exports.POLAR_RADIUS=6356752.3142},{}],6:[function(e,n){n.exports={building:!0,highway:{included_values:{services:!0,rest_area:!0,escape:!0}},natural:{excluded_values:{coastline:!0,ridge:!0,arete:!0,tree_row:!0}},landuse:!0,waterway:{included_values:{riverbank:!0,dock:!0,boatyard:!0,dam:!0}},amenity:!0,leisure:!0,barrier:{included_values:{city_wall:!0,ditch:!0,hedge:!0,retaining_wall:!0,wall:!0,spikes:!0}},railway:{included_values:{station:!0,turntable:!0,roundhouse:!0,platform:!0}},area:!0,boundary:!0,man_made:{excluded_values:{cutline:!0,embankment:!0,pipeline:!0}},power:{included_values:{generator:!0,station:!0,sub_station:!0,transformer:!0}},place:!0,shop:!0,aeroway:{excluded_values:{taxiway:!0}},tourism:!0,historic:!0,public_transport:!0,office:!0,"building:part":!0,military:!0,ruins:!0,"area:highway":!0,craft:!0}},{}]},{},[1])(1)}); \ No newline at end of file