text: (function (window, document, undefined) {
  // Load data tiles from an AJAX data source
  L.TileLayer.Ajax = L.TileLayer.extend({
      _requests: [],
      _addTile: function (tilePoint) {
          var tile = { datum: null, processed: false };
          this._tiles[tilePoint.x + ':' + tilePoint.y] = tile;
          this._loadTile(tile, tilePoint);
      },
      // XMLHttpRequest handler; closure over the XHR object, the layer, and the tile
      _xhrHandler: function (req, layer, tile, tilePoint) {
          return function () {
              if (req.readyState !== 4) {
                  return;
              }
              var s = req.status;
              if ((s >= 200 && s < 300) || s === 304) {
                  tile.datum = JSON.parse(req.responseText);
                  layer._tileLoaded(tile, tilePoint);
              } else {
                  layer._tileLoaded(tile, tilePoint);
              }
          };
      },
      // Load the requested tile via AJAX
      _loadTile: function (tile, tilePoint) {
          this._adjustTilePoint(tilePoint);
          var layer = this;
          var req = new XMLHttpRequest();
          this._requests.push(req);
          req.onreadystatechange = this._xhrHandler(req, layer, tile, tilePoint);
          req.open('GET', this.getTileUrl(tilePoint), true);
          req.send();
      },
      _reset: function () {
          L.TileLayer.prototype._reset.apply(this, arguments);
          for (var i = 0; i < this._requests.length; i++) {
              this._requests[i].abort();
          }
          this._requests = [];
      },
      _update: function () {
          if (this._map && this._map._panTransition && this._map._panTransition._inProgress) { return; }
          if (this._tilesToLoad < 0) { this._tilesToLoad = 0; }
          L.TileLayer.prototype._update.apply(this, arguments);
      }
  });
  
  
  L.TileLayer.GeoJSON = L.TileLayer.Ajax.extend({
      // Store each GeometryCollection's layer by key, if options.unique function is present
      _keyLayers: {},
  
      // Used to calculate svg path string for clip path elements
      _clipPathRectangles: {},
  
      initialize: function (url, options, geojsonOptions) {
          L.TileLayer.Ajax.prototype.initialize.call(this, url, options);
          this.geojsonLayer = new L.GeoJSON(null, geojsonOptions);
      },
      onAdd: function (map) {
          this._map = map;
          L.TileLayer.Ajax.prototype.onAdd.call(this, map);
          map.addLayer(this.geojsonLayer);
      },
      onRemove: function (map) {
          map.removeLayer(this.geojsonLayer);
          L.TileLayer.Ajax.prototype.onRemove.call(this, map);
      },
      _reset: function () {
          this.geojsonLayer.clearLayers();
          this._keyLayers = {};
          this._removeOldClipPaths();
          L.TileLayer.Ajax.prototype._reset.apply(this, arguments);
      },
  
      // Remove clip path elements from other earlier zoom levels
      _removeOldClipPaths: function  () {
          for (var clipPathId in this._clipPathRectangles) {
              var clipPathZXY = clipPathId.split('_').slice(1);
              var zoom = parseInt(clipPathZXY[0], 10);
              if (zoom !== this._map.getZoom()) {
                  var rectangle = this._clipPathRectangles[clipPathId];
                  this._map.removeLayer(rectangle);
                  var clipPath = document.getElementById(clipPathId);
                  if (clipPath !== null) {
                      clipPath.parentNode.removeChild(clipPath);
                  }
                  delete this._clipPathRectangles[clipPathId];
              }
          }
      },
  
      // Recurse LayerGroups and call func() on L.Path layer instances
      _recurseLayerUntilPath: function (func, layer) {
          if (layer instanceof L.Path) {
              func(layer);
          }
          else if (layer instanceof L.LayerGroup) {
              // Recurse each child layer
              layer.getLayers().forEach(this._recurseLayerUntilPath.bind(this, func), this);
          }
      },
  
      _clipLayerToTileBoundary: function (layer, tilePoint) {
          // Only perform SVG clipping if the browser is using SVG
          if (!L.Path.SVG) { return; }
          if (!this._map) { return; }
  
          if (!this._map._pathRoot) {
              this._map._pathRoot = L.Path.prototype._createElement('svg');
              this._map._panes.overlayPane.appendChild(this._map._pathRoot);
          }
          var svg = this._map._pathRoot;
  
          // create the defs container if it doesn't exist
          var defs = null;
          if (svg.getElementsByTagName('defs').length === 0) {
              defs = document.createElementNS(L.Path.SVG_NS, 'defs');
              svg.insertBefore(defs, svg.firstChild);
          }
          else {
              defs = svg.getElementsByTagName('defs')[0];
          }
  
          // Create the clipPath for the tile if it doesn't exist
          var clipPathId = 'tileClipPath_' + tilePoint.z + '_' + tilePoint.x + '_' + tilePoint.y;
          var clipPath = document.getElementById(clipPathId);
          if (clipPath === null) {
              clipPath = document.createElementNS(L.Path.SVG_NS, 'clipPath');
              clipPath.id = clipPathId;
  
              // Create a hidden L.Rectangle to represent the tile's area
              var tileSize = this.options.tileSize,
              nwPoint = tilePoint.multiplyBy(tileSize),
              sePoint = nwPoint.add([tileSize, tileSize]),
              nw = this._map.unproject(nwPoint),
              se = this._map.unproject(sePoint);
              this._clipPathRectangles[clipPathId] = new L.Rectangle(new L.LatLngBounds([nw, se]), {
                  opacity: 0,
                  fillOpacity: 0,
                  clickable: false,
                  noClip: true
              });
              this._map.addLayer(this._clipPathRectangles[clipPathId]);
  
              // Add a clip path element to the SVG defs element
              // With a path element that has the hidden rectangle's SVG path string
              var path = document.createElementNS(L.Path.SVG_NS, 'path');
              var pathString = this._clipPathRectangles[clipPathId].getPathString();
              path.setAttribute('d', pathString);
              clipPath.appendChild(path);
              defs.appendChild(clipPath);
          }
  
          // Add the clip-path attribute to reference the id of the tile clipPath
          this._recurseLayerUntilPath(function (pathLayer) {
              pathLayer._container.setAttribute('clip-path', 'url(#' + clipPathId + ')');
          }, layer);
      },
  
      // Add a geojson object from a tile to the GeoJSON layer
      // * If the options.unique function is specified, merge geometries into GeometryCollections
      // grouped by the key returned by options.unique(feature) for each GeoJSON feature
      // * If options.clipTiles is set, and the browser is using SVG, perform SVG clipping on each
      // tile's GeometryCollection
      addTileData: function (geojson, tilePoint) {
          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.addTileData(features[i], tilePoint);
                  }
              }
              return this;
          }
  
          var options = this.geojsonLayer.options;
  
          if (options.filter && !options.filter(geojson)) { return; }
  
          var parentLayer = this.geojsonLayer;
          var incomingLayer = null;
          if (this.options.unique && typeof(this.options.unique) === 'function') {
              var key = this.options.unique(geojson);
  
              // When creating the layer for a unique key,
              // Force the geojson to be a geometry collection
              if (!(key in this._keyLayers && geojson.geometry.type !== 'GeometryCollection')) {
                  geojson.geometry = {
                      type: 'GeometryCollection',
                      geometries: [geojson.geometry]
                  };
              }
  
              // Transform the geojson into a new Layer
              try {
                  incomingLayer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
              }
              // Ignore GeoJSON objects that could not be parsed
              catch (e) {
                  return this;
              }
  
              incomingLayer.feature = L.GeoJSON.asFeature(geojson);
              // Add the incoming Layer to existing key's GeometryCollection
              if (key in this._keyLayers) {
                  parentLayer = this._keyLayers[key];
                  parentLayer.feature.geometry.geometries.push(geojson.geometry);
              }
              // Convert the incoming GeoJSON feature into a new GeometryCollection layer
              else {
                  this._keyLayers[key] = incomingLayer;
              }
          }
          // Add the incoming geojson feature to the L.GeoJSON Layer
          else {
              // Transform the geojson into a new layer
              try {
                  incomingLayer = L.GeoJSON.geometryToLayer(geojson, options.pointToLayer, options.coordsToLatLng);
              }
              // Ignore GeoJSON objects that could not be parsed
              catch (e) {
                  return this;
              }
              incomingLayer.feature = L.GeoJSON.asFeature(geojson);
          }
          incomingLayer.defaultOptions = incomingLayer.options;
  
          this.geojsonLayer.resetStyle(incomingLayer);
  
          if (options.onEachFeature) {
              options.onEachFeature(geojson, incomingLayer);
          }
          parentLayer.addLayer(incomingLayer);
  
          // If options.clipTiles is set and the browser is using SVG
          // then clip the layer using SVG clipping
          if (this.options.clipTiles) {
              this._clipLayerToTileBoundary(incomingLayer, tilePoint);
          }
          return this;
      },
  
      _tileLoaded: function (tile, tilePoint) {
          L.TileLayer.Ajax.prototype._tileLoaded.apply(this, arguments);
          if (tile.datum === null) { return null; }
          this.addTileData(tile.datum, tilePoint);
      }
  });
  
  }.call(this, window, document));
  