text: /*
   * @class GeoJSON
   * @aka L.GeoJSON
   * @inherits FeatureGroup
   *
   * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
   * GeoJSON data and display it on the map. Extends `FeatureGroup`.
   *
   * @example
   *
   * ```js
   * L.geoJSON(data, {
   * 	style: function (feature) {
   * 		return {color: feature.properties.color};
   * 	}
   * }).bindPopup(function (layer) {
   * 	return layer.feature.properties.description;
   * }).addTo(map);
   * ```
   */
  
  L.GeoJSON = L.FeatureGroup.extend({
  
  	/* @section
  	 * @aka GeoJSON options
  	 *
  	 * @option pointToLayer: Function = *
  	 * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
  	 * called when data is added, passing the GeoJSON point feature and its `LatLng`.
  	 * The default is to spawn a default `Marker`:
  	 * ```js
  	 * function(geoJsonPoint, latlng) {
  	 * 	return L.marker(latlng);
  	 * }
  	 * ```
  	 *
  	 * @option style: Function = *
  	 * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
  	 * called internally when data is added.
  	 * The default value is to not override any defaults:
  	 * ```js
  	 * function (geoJsonFeature) {
  	 * 	return {}
  	 * }
  	 * ```
  	 *
  	 * @option onEachFeature: Function = *
  	 * A `Function` that will be called once for each created `Feature`, after it has
  	 * been created and styled. Useful for attaching events and popups to features.
  	 * The default is to do nothing with the newly created layers:
  	 * ```js
  	 * function (feature, layer) {}
  	 * ```
  	 *
  	 * @option filter: Function = *
  	 * A `Function` that will be used to decide whether to include a feature or not.
  	 * The default is to include all features:
  	 * ```js
  	 * function (geoJsonFeature) {
  	 * 	return true;
  	 * }
  	 * ```
  	 * Note: dynamically changing the `filter` option will have effect only on newly
  	 * added data. It will _not_ re-evaluate already included features.
  	 *
  	 * @option coordsToLatLng: Function = *
  	 * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
  	 * The default is the `coordsToLatLng` static method.
  	 */
  
  	initialize: function (geojson, options) {
  		L.setOptions(this, options);
  
  		this._layers = {};
  
  		if (geojson) {
  			this.addData(geojson);
  		}
  	},
  
  	// @method addData( <GeoJSON> data ): Layer
  	// Adds a GeoJSON object to the layer.
  	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(feature);
  				}
  			}
  			return this;
  		}
  
  		var options = this.options;
  
  		if (options.filter && !options.filter(geojson)) { return this; }
  
  		var layer = L.GeoJSON.geometryToLayer(geojson, options);
  		if (!layer) {
  			return this;
  		}
  		layer.feature = L.GeoJSON.asFeature(geojson);
  
  		layer.defaultOptions = layer.options;
  		this.resetStyle(layer);
  
  		if (options.onEachFeature) {
  			options.onEachFeature(geojson, layer);
  		}
  
  		return this.addLayer(layer);
  	},
  
  	// @method resetStyle( <Path> layer ): Layer
  	// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
  	resetStyle: function (layer) {
  		// reset any custom styles
  		layer.options = L.Util.extend({}, layer.defaultOptions);
  		this._setLayerStyle(layer, this.options.style);
  		return this;
  	},
  
  	// @method setStyle( <Function> style ): Layer
  	// Changes styles of GeoJSON vector layers with the given style function.
  	setStyle: function (style) {
  		return 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);
  		}
  	}
  });
  
  // @section
  // There are several static functions which can be called without instantiating L.GeoJSON:
  L.extend(L.GeoJSON, {
  	// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
  	// Creates a `Layer` from a given GeoJSON feature. Can use a custom
  	// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
  	// functions if provided as options.
  	geometryToLayer: function (geojson, options) {
  
  		var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
  		    coords = geometry ? geometry.coordinates : null,
  		    layers = [],
  		    pointToLayer = options && options.pointToLayer,
  		    coordsToLatLng = options && options.coordsToLatLng || this.coordsToLatLng,
  		    latlng, latlngs, i, len;
  
  		if (!coords && !geometry) {
  			return null;
  		}
  
  		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':
  		case 'MultiLineString':
  			latlngs = this.coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, coordsToLatLng);
  			return new L.Polyline(latlngs, options);
  
  		case 'Polygon':
  		case 'MultiPolygon':
  			latlngs = this.coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, coordsToLatLng);
  			return new L.Polygon(latlngs, options);
  
  		case 'GeometryCollection':
  			for (i = 0, len = geometry.geometries.length; i < len; i++) {
  				var layer = this.geometryToLayer({
  					geometry: geometry.geometries[i],
  					type: 'Feature',
  					properties: geojson.properties
  				}, options);
  
  				if (layer) {
  					layers.push(layer);
  				}
  			}
  			return new L.FeatureGroup(layers);
  
  		default:
  			throw new Error('Invalid GeoJSON object.');
  		}
  	},
  
  	// @function coordsToLatLng(coords: Array): LatLng
  	// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
  	// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
  	coordsToLatLng: function (coords) {
  		return new L.LatLng(coords[1], coords[0], coords[2]);
  	},
  
  	// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
  	// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
  	// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
  	// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
  	coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) {
  		var latlngs = [];
  
  		for (var i = 0, len = coords.length, latlng; i < len; i++) {
  			latlng = levelsDeep ?
  			        this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) :
  			        (coordsToLatLng || this.coordsToLatLng)(coords[i]);
  
  			latlngs.push(latlng);
  		}
  
  		return latlngs;
  	},
  
  	// @function latLngToCoords(latlng: LatLng): Array
  	// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
  	latLngToCoords: function (latlng) {
  		return latlng.alt !== undefined ?
  				[latlng.lng, latlng.lat, latlng.alt] :
  				[latlng.lng, latlng.lat];
  	},
  
  	// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
  	// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
  	// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
  	latLngsToCoords: function (latlngs, levelsDeep, closed) {
  		var coords = [];
  
  		for (var i = 0, len = latlngs.length; i < len; i++) {
  			coords.push(levelsDeep ?
  				L.GeoJSON.latLngsToCoords(latlngs[i], levelsDeep - 1, closed) :
  				L.GeoJSON.latLngToCoords(latlngs[i]));
  		}
  
  		if (!levelsDeep && closed) {
  			coords.push(coords[0]);
  		}
  
  		return coords;
  	},
  
  	getFeature: function (layer, newGeometry) {
  		return layer.feature ?
  				L.extend({}, layer.feature, {geometry: newGeometry}) :
  				L.GeoJSON.asFeature(newGeometry);
  	},
  
  	// @function asFeature(geojson: Object): Object
  	// Normalize GeoJSON geometries/features into GeoJSON features.
  	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())
  		});
  	}
  };
  
  // @namespace Marker
  // @method toGeoJSON(): Object
  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
  L.Marker.include(PointToGeoJSON);
  
  // @namespace CircleMarker
  // @method toGeoJSON(): Object
  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
  L.Circle.include(PointToGeoJSON);
  L.CircleMarker.include(PointToGeoJSON);
  
  
  // @namespace Polyline
  // @method toGeoJSON(): Object
  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
  L.Polyline.prototype.toGeoJSON = function () {
  	var multi = !L.Polyline._flat(this._latlngs);
  
  	var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);
  
  	return L.GeoJSON.getFeature(this, {
  		type: (multi ? 'Multi' : '') + 'LineString',
  		coordinates: coords
  	});
  };
  
  // @namespace Polygon
  // @method toGeoJSON(): Object
  // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
  L.Polygon.prototype.toGeoJSON = function () {
  	var holes = !L.Polyline._flat(this._latlngs),
  	    multi = holes && !L.Polyline._flat(this._latlngs[0]);
  
  	var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true);
  
  	if (!holes) {
  		coords = [coords];
  	}
  
  	return L.GeoJSON.getFeature(this, {
  		type: (multi ? 'Multi' : '') + 'Polygon',
  		coordinates: coords
  	});
  };
  
  
  // @namespace LayerGroup
  L.LayerGroup.include({
  	toMultiPoint: function () {
  		var coords = [];
  
  		this.eachLayer(function (layer) {
  			coords.push(layer.toGeoJSON().geometry.coordinates);
  		});
  
  		return L.GeoJSON.getFeature(this, {
  			type: 'MultiPoint',
  			coordinates: coords
  		});
  	},
  
  	// @method toGeoJSON(): Object
  	// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `GeometryCollection`).
  	toGeoJSON: function () {
  
  		var type = this.feature && this.feature.geometry && this.feature.geometry.type;
  
  		if (type === 'MultiPoint') {
  			return this.toMultiPoint();
  		}
  
  		var isGeometryCollection = type === 'GeometryCollection',
  		    jsons = [];
  
  		this.eachLayer(function (layer) {
  			if (layer.toGeoJSON) {
  				var 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
  		};
  	}
  });
  
  // @namespace GeoJSON
  // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
  // Creates a GeoJSON layer. Optionally accepts an object in
  // [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map
  // (you can alternatively add it later with `addData` method) and an `options` object.
  L.geoJSON = function (geojson, options) {
  	return new L.GeoJSON(geojson, options);
  };
  // Backward compatibility.
  L.geoJson = L.geoJSON;
  