<commit_before>var fs = require('fs');
var path = require('path');
var tilelive = require('tilelive');
var settings = Bones.plugin.config;

server = Bones.Server.extend({});

server.prototype.initialize = function() {
    _.bindAll(this, 'load', 'grid', 'getArtifact', 'mbtiles', 'fromCache');
    this.get('/1.0.0/:id.mbtiles/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.mbtiles);
    this.get('/1.0.0/:id.mbtiles/:z/:x/:y.:format(grid.json)', this.mbtiles);
    this.get('/1.0.0/:id/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.fromCache, this.load, this.getArtifact);
    this.get('/1.0.0/:id/:z/:x/:y.:format(grid.json)', this.fromCache, this.load, this.grid, this.getArtifact);
};

server.prototype.load = function(req, res, next) {
    res.project = new models.Project({ id: req.param('id') });
    res.project.fetch({
        success: function(model, resp) {
            model.localize(resp, next);
        },
        error: function(model, resp) {
            next(resp);
        }
    });
};

server.prototype.getArtifact = function(req, res, next) {
    // This is the cache key in tilelive-mapnik, so make sure it
    // contains the mtime with _updated.
    var id = req.params.id;
    var uri = {
        protocol: 'mapnik:',
        slashes: true,

        // This file does not exist; but we pass in literal strings below.
        // This is used as a cache key.
        pathname: path.join(settings.files, 'project', id, id + '.xml'),
        search: '?' + res.project.mml._updated,

        xml: res.project.xml,
        mml: res.project.mml
    };

    tilelive.load(uri, function(err, source) {
        if (err) return next(err);

        var z = req.params.z, x = +req.params.x, y = +req.params.y;

        // The interface is still TMS.
        y = (1 << z) - 1 - y;

        var fn = req.params.format === 'grid.json' ? 'getGrid' : 'getTile';
        source[fn](z, x, y, function(err, tile, headers) {
            if (err) return next(err);
            if (res.cache) fs.writeFile(res.cache, tile);
            if (headers) headers['max-age'] = 3600;
            res.send(tile, headers);
        });
    });
};

server.prototype.grid = function(req, res, next) {
    // Early exit. tilelive-mapnik would catch that too.
    if (!res.project.get('interactivity'))
        return next(new Error.HTTP('Not found.', 404));

    // Force jsonp.
    req.query.callback = 'grid';
    next();
};

server.prototype.mbtiles = function(req, res, next) {
    var uri = 'mbtiles://' + path.join(settings.files, 'export', req.param('id') + '.mbtiles');
    tilelive.load(uri, function(err, source) {
        if (err) return next(err);

        var z = req.params.z, x = +req.params.x, y = +req.params.y;

        // The interface is still TMS.
        y = (1 << z) - 1 - y;

        var fn = req.params.format === 'grid.json' ? 'getGrid' : 'getTile';
        source[fn](z, x, y, function(err, tile, headers) {
            if (err) return next(err);
            if (headers) headers['max-age'] = 3600;
            res.send(tile, headers);
        });
    });
};

server.prototype.fromCache = function(req, res, next) {
    if (!req.param('cache')) return next();

    var filename = [
        req.param('id'),
        req.param('z'),
        req.param('x'),
        req.param('y'),
        req.param('format')
    ].join('.');
    res.cache = path.join(settings.files, 'cache', 'tile', filename);
    fs.stat(res.cache, function(err, stat) {
        if (!err && +stat.mtime > req.param('updated')) {
            return res.sendfile(res.cache);
        } else {
            return next();
        }
    });<commit_msg>Use 404 rather than 500 for tile errors to prevent Bones from spewing console messages.<commit_after>var fs = require('fs');
var path = require('path');
var tilelive = require('tilelive');
var settings = Bones.plugin.config;

server = Bones.Server.extend({});

server.prototype.initialize = function() {
    _.bindAll(this, 'load', 'grid', 'getArtifact', 'mbtiles', 'fromCache');
    this.get('/1.0.0/:id.mbtiles/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.mbtiles);
    this.get('/1.0.0/:id.mbtiles/:z/:x/:y.:format(grid.json)', this.mbtiles);
    this.get('/1.0.0/:id/:z/:x/:y.:format(png8|png|jpeg[\\d]+|jpeg)', this.fromCache, this.load, this.getArtifact);
    this.get('/1.0.0/:id/:z/:x/:y.:format(grid.json)', this.fromCache, this.load, this.grid, this.getArtifact);
};

server.prototype.load = function(req, res, next) {
    res.project = new models.Project({ id: req.param('id') });
    res.project.fetch({
        success: function(model, resp) {
            model.localize(resp, next);
        },
        error: function(model, resp) {
            next(resp);
        }
    });
};

server.prototype.getArtifact = function(req, res, next) {
    // This is the cache key in tilelive-mapnik, so make sure it
    // contains the mtime with _updated.
    var id = req.params.id;
    var uri = {
        protocol: 'mapnik:',
        slashes: true,

        // This file does not exist; but we pass in literal strings below.
        // This is used as a cache key.
        pathname: path.join(settings.files, 'project', id, id + '.xml'),
        search: '?' + res.project.mml._updated,

        xml: res.project.xml,
        mml: res.project.mml
    };

    tilelive.load(uri, function(err, source) {
        if (err) return next(err);

        var z = req.params.z, x = +req.params.x, y = +req.params.y;

        // The interface is still TMS.
        y = (1 << z) - 1 - y;

        var fn = req.params.format === 'grid.json' ? 'getGrid' : 'getTile';
        source[fn](z, x, y, function(err, tile, headers) {
            if (err) return next(new Error.HTTP(err.message, 404));
            if (res.cache) fs.writeFile(res.cache, tile);
            if (headers) headers['max-age'] = 3600;
            res.send(tile, headers);
        });
    });
};

server.prototype.grid = function(req, res, next) {
    // Early exit. tilelive-mapnik would catch that too.
    if (!res.project.get('interactivity'))
        return next(new Error.HTTP('Not found.', 404));

    // Force jsonp.
    req.query.callback = 'grid';
    next();
};

server.prototype.mbtiles = function(req, res, next) {
    var uri = 'mbtiles://' + path.join(settings.files, 'export', req.param('id') + '.mbtiles');
    tilelive.load(uri, function(err, source) {
        if (err) return next(err);

        var z = req.params.z, x = +req.params.x, y = +req.params.y;

        // The interface is still TMS.
        y = (1 << z) - 1 - y;

        var fn = req.params.format === 'grid.json' ? 'getGrid' : 'getTile';
        source[fn](z, x, y, function(err, tile, headers) {
            if (err) return next(new Error.HTTP(err.message, 404));
            if (headers) headers['max-age'] = 3600;
            res.send(tile, headers);
        });
    });
};

server.prototype.fromCache = function(req, res, next) {
    if (!req.param('cache')) return next();

    var filename = [
        req.param('id'),
        req.param('z'),
        req.param('x'),
        req.param('y'),
        req.param('format')
    ].join('.');
    res.cache = path.join(settings.files, 'cache', 'tile', filename);
    fs.stat(res.cache, function(err, stat) {
        if (!err && +stat.mtime > req.param('updated')) {
            return res.sendfile(res.cache);
        } else {
            return next();
        }
    });
{'fraction_non_alphanumeric': 0.18527027027027027, 'fraction_numerical': 0.00945945945945946, 'mean_word_length': 2.367151956323931, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3992847', 'n_tokens_mistral': 2523, 'n_tokens_neox': 2492, 'n_words': 572}