text: /*
   * @class Polyline
   * @aka L.Polyline
   * @inherits Path
   *
   * A class for drawing polyline overlays on a map. Extends `Path`.
   *
   * @example
   *
   * ```js
   * // create a red polyline from an array of LatLng points
   * var latlngs = [
   * 	[-122.68, 45.51],
   * 	[-122.43, 37.77],
   * 	[-118.2, 34.04]
   * ];
   *
   * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
   *
   * // zoom the map to the polyline
   * map.fitBounds(polyline.getBounds());
   * ```
   *
   * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
   *
   * ```js
   * // create a red polyline from an array of arrays of LatLng points
   * var latlngs = [
   * 	[[-122.68, 45.51],
   * 	 [-122.43, 37.77],
   * 	 [-118.2, 34.04]],
   * 	[[-73.91, 40.78],
   * 	 [-87.62, 41.83],
   * 	 [-96.72, 32.76]]
   * ];
   * ```
   */
  
  L.Polyline = L.Path.extend({
  
  	options: {
  		// @option smoothFactor: Number = 1.0
  		// How much to simplify the polyline on each zoom level. More means
  		// better performance and smoother look, and less means more accurate representation.
  		smoothFactor: 1.0,
  
  		// @option noClip: Boolean: false
  		// Disable polyline clipping.
  		noClip: false
  	},
  
  	initialize: function (latlngs, options) {
  		L.setOptions(this, options);
  		this._setLatLngs(latlngs);
  	},
  
  	// @method getLatLngs(): LatLng[]
  	// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
  	getLatLngs: function () {
  		return this._latlngs;
  	},
  
  	// @method setLatLngs(latlngs: LatLng[]): this
  	// Replaces all the points in the polyline with the given array of geographical points.
  	setLatLngs: function (latlngs) {
  		this._setLatLngs(latlngs);
  		return this.redraw();
  	},
  
  	// @method isEmpty(): Boolean
  	// Returns `true` if the Polyline has no LatLngs.
  	isEmpty: function () {
  		return !this._latlngs.length;
  	},
  
  	closestLayerPoint: function (p) {
  		var minDistance = Infinity,
  		    minPoint = null,
  		    closest = L.LineUtil._sqClosestPointOnSegment,
  		    p1, p2;
  
  		for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
  			var points = this._parts[j];
  
  			for (var i = 1, len = points.length; i < len; i++) {
  				p1 = points[i - 1];
  				p2 = points[i];
  
  				var sqDist = closest(p, p1, p2, true);
  
  				if (sqDist < minDistance) {
  					minDistance = sqDist;
  					minPoint = closest(p, p1, p2);
  				}
  			}
  		}
  		if (minPoint) {
  			minPoint.distance = Math.sqrt(minDistance);
  		}
  		return minPoint;
  	},
  
  	// @method getCenter(): LatLng
  	// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
  	getCenter: function () {
  		var i, halfDist, segDist, dist, p1, p2, ratio,
  		    points = this._rings[0],
  		    len = points.length;
  
  		if (!len) { return null; }
  
  		// polyline centroid algorithm; only uses the first ring if there are multiple
  
  		for (i = 0, halfDist = 0; i < len - 1; i++) {
  			halfDist += points[i].distanceTo(points[i + 1]) / 2;
  		}
  
  		// The line is so small in the current view that all points are on the same pixel.
  		if (halfDist === 0) {
  			return this._map.layerPointToLatLng(points[0]);
  		}
  
  		for (i = 0, dist = 0; i < len - 1; i++) {
  			p1 = points[i];
  			p2 = points[i + 1];
  			segDist = p1.distanceTo(p2);
  			dist += segDist;
  
  			if (dist > halfDist) {
  				ratio = (dist - halfDist) / segDist;
  				return this._map.layerPointToLatLng([
  					p2.x - ratio * (p2.x - p1.x),
  					p2.y - ratio * (p2.y - p1.y)
  				]);
  			}
  		}
  	},
  
  	// @method getBounds(): LatLngBounds
  	// Returns the `LatLngBounds` of the path.
  	getBounds: function () {
  		return this._bounds;
  	},
  
  	// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
  	// Adds a given point to the polyline. By default, adds to the first ring of
  	// the polyline in case of a multi-polyline, but can be overridden by passing
  	// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
  	addLatLng: function (latlng, latlngs) {
  		latlngs = latlngs || this._defaultShape();
  		latlng = L.latLng(latlng);
  		latlngs.push(latlng);
  		this._bounds.extend(latlng);
  		return this.redraw();
  	},
  
  	_setLatLngs: function (latlngs) {
  		this._bounds = new L.LatLngBounds();
  		this._latlngs = this._convertLatLngs(latlngs);
  	},
  
  	_defaultShape: function () {
  		return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
  	},
  
  	// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
  	_convertLatLngs: function (latlngs) {
  		var result = [],
  		    flat = L.Polyline._flat(latlngs);
  
  		for (var i = 0, len = latlngs.length; i < len; i++) {
  			if (flat) {
  				result[i] = L.latLng(latlngs[i]);
  				this._bounds.extend(result[i]);
  			} else {
  				result[i] = this._convertLatLngs(latlngs[i]);
  			}
  		}
  
  		return result;
  	},
  
  	_project: function () {
  		var pxBounds = new L.Bounds();
  		this._rings = [];
  		this._projectLatlngs(this._latlngs, this._rings, pxBounds);
  
  		var w = this._clickTolerance(),
  		    p = new L.Point(w, w);
  
  		if (this._bounds.isValid() && pxBounds.isValid()) {
  			pxBounds.min._subtract(p);
  			pxBounds.max._add(p);
  			this._pxBounds = pxBounds;
  		}
  	},
  
  	// recursively turns latlngs into a set of rings with projected coordinates
  	_projectLatlngs: function (latlngs, result, projectedBounds) {
  		var flat = latlngs[0] instanceof L.LatLng,
  		    len = latlngs.length,
  		    i, ring;
  
  		if (flat) {
  			ring = [];
  			for (i = 0; i < len; i++) {
  				ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
  				projectedBounds.extend(ring[i]);
  			}
  			result.push(ring);
  		} else {
  			for (i = 0; i < len; i++) {
  				this._projectLatlngs(latlngs[i], result, projectedBounds);
  			}
  		}
  	},
  
  	// clip polyline by renderer bounds so that we have less to render for performance
  	_clipPoints: function () {
  		var bounds = this._renderer._bounds;
  
  		this._parts = [];
  		if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
  			return;
  		}
  
  		if (this.options.noClip) {
  			this._parts = this._rings;
  			return;
  		}
  
  		var parts = this._parts,
  		    i, j, k, len, len2, segment, points;
  
  		for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
  			points = this._rings[i];
  
  			for (j = 0, len2 = points.length; j < len2 - 1; j++) {
  				segment = L.LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);
  
  				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[j + 1]) || (j === len2 - 2)) {
  					parts[k].push(segment[1]);
  					k++;
  				}
  			}
  		}
  	},
  
  	// simplify each clipped part of the polyline for performance
  	_simplifyPoints: function () {
  		var parts = this._parts,
  		    tolerance = this.options.smoothFactor;
  
  		for (var i = 0, len = parts.length; i < len; i++) {
  			parts[i] = L.LineUtil.simplify(parts[i], tolerance);
  		}
  	},
  
  	_update: function () {
  		if (!this._map) { return; }
  
  		this._clipPoints();
  		this._simplifyPoints();
  		this._updatePath();
  	},
  
  	_updatePath: function () {
  		this._renderer._updatePoly(this);
  	}
  });
  
  // @factory L.polyline(latlngs: LatLng[], options?: Path options)
  // Instantiates a polyline object given an array of geographical points and
  // optionally an options object. You can create a `Polyline` object with
  // multiple separate lines (`MultiPolyline`) by passing an array of arrays
  // of geographic points.
  L.polyline = function (latlngs, options) {
  	return new L.Polyline(latlngs, options);
  };
  
  L.Polyline._flat = function (latlngs) {
  	// true if it's a flat array of latlngs; false if nested
  	return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
  };
  