text: /*
   * L.TileLayer is used for standard xyz-numbered tile layers.
   */
  
  L.TileLayer = L.GridLayer.extend({
  
  	options: {
  		minZoom: 0,
  		maxZoom: 18,
  
  		subdomains: 'abc',
  		// errorTileUrl: '',
  		zoomOffset: 0
  
  		/*
  		maxNativeZoom: <Number>,
  		tms: <Boolean>,
  		zoomReverse: <Number>,
  		detectRetina: <Number>,
  		*/
  	},
  
  	initialize: function (url, options) {
  
  		this._url = url;
  
  		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++;
  
  			options.minZoom = Math.max(0, options.minZoom);
  			options.maxZoom--;
  		}
  
  		if (typeof options.subdomains === 'string') {
  			options.subdomains = options.subdomains.split('');
  		}
  	},
  
  	setUrl: function (url, noRedraw) {
  		this._url = url;
  
  		if (!noRedraw) {
  			this.redraw();
  		}
  		return this;
  	},
  
  	createTile: function (coords, done) {
  		var tile = document.createElement('img');
  
  		tile.onload = L.bind(this._tileOnLoad, this, done, tile);
  		tile.onerror = L.bind(this._tileOnError, this, done, tile);
  
  		tile.src = this.getTileUrl(coords);
  
  		return tile;
  	},
  
  	getTileUrl: function (coords) {
  		return L.Util.template(this._url, L.extend({
  			r: this.options.detectRetina && L.Browser.retina && this.options.maxZoom > 0 ? '@2x' : '',
  			s: this._getSubdomain(coords),
  			x: coords.x,
  			y: this.options.tms ? this._tileNumBounds.max.y - coords.y : coords.y,
  			z: this._getZoomForUrl()
  		}, this.options));
  	},
  
  	_tileOnLoad: function (done, tile) {
  		done(null, tile);
  	},
  
  	_tileOnError: function (done, tile, e) {
  		var errorUrl = this.options.errorTileUrl;
  		if (errorUrl) {
  			tile.src = errorUrl;
  		}
  		done(e, tile);
  	},
  
  	_getTileSize: function () {
  		var map = this._map,
  		    options = this.options,
  		    zoom = map.getZoom() + options.zoomOffset,
  		    zoomN = options.maxNativeZoom;
  
  		// increase tile size when overscaling
  		return zoomN && zoom > zoomN ?
  				Math.round(map.getZoomScale(zoom) / map.getZoomScale(zoomN) * options.tileSize) :
  				options.tileSize;
  	},
  
  	_removeTile: function (key) {
  		var tile = this._tiles[key];
  
  		L.GridLayer.prototype._removeTile.call(this, key);
  
  		// for https://github.com/Leaflet/Leaflet/issues/137
  		if (!L.Browser.android) {
  			tile.onload = null;
  			tile.src = L.Util.emptyImageUrl;
  		}
  	},
  
  	_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;
  	},
  
  	_getSubdomain: function (tilePoint) {
  		var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
  		return this.options.subdomains[index];
  	},
  
  	// stops loading all tiles in the background layer
  	_abortLoading: function () {
  		var i, tile;
  		for (i in this._tiles) {
  			tile = this._tiles[i];
  
  			if (!tile.complete) {
  				tile.onload = L.Util.falseFn;
  				tile.onerror = L.Util.falseFn;
  				tile.src = L.Util.emptyImageUrl;
  
  				L.DomUtil.remove(tile);
  			}
  		}
  	}
  });
  
  L.tileLayer = function (url, options) {
  	return new L.TileLayer(url, options);
  };
  