(function() {

var SUBDOMAINS = ["", "a.", "b.", "c.", "d."],
    PROVIDERS =  {
        "toner": {
            "url": "http://{S}tile.stamen.com/toner/{Z}/{X}/{Y}.png",
            "minZoom": 0,
            "maxZoom": 20
        },
        "terrain": {
            "url": "http://{S}tile.stamen.com/terrain/{Z}/{X}/{Y}.jpg",
            "minZoom": 4,
            "maxZoom": 18
        },
        "watercolor": {
            "url": "http://{S}tile.stamen.com/watercolor-mask_set_1/{Z}/{X}/{Y}.jpg",
            "minZoom": 0,
            "maxZoom": 18
        }
    };

if (typeof MM === "object") {
    MM.StamenTileLayer = function(name) {
        var provider = PROVIDERS[name];
        MM.Layer.call(this, new MM.TemplatedMapProvider(provider.url, SUBDOMAINS));
        this.provider.setZoomRange(provider.minZoom, provider.maxZoom);
    };
    MM.extend(MM.StamenTileLayer, MM.Layer);
}

if (typeof L === "object") {
    L.StamenTileLayer = L.TileLayer.extend({
        initialize: function(name) {
            var provider = PROVIDERS[name],
                url = provider.url.toLowerCase();
            L.TileLayer.prototype.initialize.call(this, url, {
                "minZoom":      provider.minZoom,
                "maxZoom":      provider.maxZoom,
                "subdomains":   SUBDOMAINS,
                "scheme":       "xyz",
                "attribution":  'Map tiles by <a href="http://stamen.com">Stamen Design</a>, under <a href="http://creativecommons.org/licenses/by/3.0">CC BY 3.0</a>. Data by <a href="http://openstreetmap.org">OpenStreetMap</a>, under <a href="http://creativecommons.org/licenses/by-sa/3.0">CC BY SA</a>.'
            });
        }
    });
}

if (typeof OpenLayers === "object") {
    // make a tile URL template OpenLayers-compatible
    function openlayerize(url) {
        return url.replace(/({.})/g, function(v) {
            return "$" + v.toLowerCase();
        });
    }

    // based on http://www.bostongis.com/PrinterFriendly.aspx?content_name=using_custom_osm_tiles
    OpenLayers.Layer.Stamen = OpenLayers.Class(OpenLayers.Layer.OSM, {
        initialize: function(name, options) {
            var provider = PROVIDERS[name],
                url = provider.url,
                hosts = [];
            if (url.indexOf("{S}") > -1) {
                for (var i = 0; i < SUBDOMAINS.length; i++) {
                    hosts.push(openlayerize(url.replace("{S}", SUBDOMAINS[i])));
                }
            } else {
                hosts.push(openlayerize(url));
            }
            options = OpenLayers.Util.extend({
                "numZoomLevels":    provider.maxZoom,
                "buffer":           0,
                "transitionEffect": "resize"
            }, options);
            return OpenLayers.Layer.OSM.prototype.initialize.call(this, name, hosts, options);
        }
    });
}

if (typeof google === "object" && typeof google.maps === "object") {
    google.maps.StamenMapType = function(name) {
        var provider = PROVIDERS[name];
        return google.maps.ImageMapType.call(this, {
            "getTileUrl": function(coord, zoom) {
                var index = (zoom + coord.x + coord.y) % SUBDOMAINS.length;
                return [
                    provider.url
                        .replace("{S}", SUBDOMAINS[index])
                        .replace("{Z}", zoom)
                        .replace("{X}", coord.x)
                        .replace("{Y}", coord.y)
                ];
            },
            "tileSize": new google.maps.Size(256, 256),
            "name":     name,
            "minZoom":  provider.minZoom,
            "maxZoom":  provider.maxZoom
        });
    };
    // FIXME: is there a better way to extend classes in Google land?
    google.maps.StamenMapType.prototype = new google.maps.ImageMapType("_");
}

})();

@@ -218,32 +218,362 @@
 : 20%0A        %7D,%0A
+        %22toner-lines%22: %7B%0A            %22url%22: %22http://%7BS%7Dtile.stamen.com/toner-lines/%7BZ%7D/%7BX%7D/%7BY%7D.png%22,%0A            %22minZoom%22: 0,%0A            %22maxZoom%22: 20%0A        %7D,%0A        %22toner-labels%22: %7B%0A            %22url%22: %22http://%7BS%7Dtile.stamen.com/toner-labels/%7BZ%7D/%7BX%7D/%7BY%7D.png%22,%0A            %22minZoom%22: 0,%0A            %22maxZoom%22: 20%0A        %7D,%0A
         %22terrain
@@ -573,24 +573,24 @@
 terrain%22: %7B%0A
-
             
@@ -796,19 +796,8 @@
 olor
--mask_set_1
 /%7BZ%7D
@@ -853,33 +853,33 @@
     %22maxZoom%22: 1
-8
+6
 %0A        %7D%0A    %7D

update watercolor, add toner-{lines,labels} layers