<commit_before>var _ = require('underscore')._;

module.exports = function(app, settings) {
    /**
     * Map loader, express route middleware.
     */
    function loadMap(req, res, next) {
        if (req.param('mapfile_64')) {
            var path = require('path');
            var Map = require('tilelive.js').Map;
            var map = new Map(req.param('mapfile_64'), path.join(__dirname, settings.mapfile_dir), true);
            map.localize(function() {
                res.map = map.mapnik_map();
                next();
            });
        }
        else {
            next(new Error('Map could not be loaded.'));
        }
    }

    /**
     * Layer loader, express route middleware.
     */
    function loadLayer(req, res, next) {
        res.layers = [];
        var layers = res.map.layers();
        var data = res.map.describe_data();
        for (var i = 0; i < layers.length; i++) {
            var id = layers[i].datasource.id;
            var layer = {
                id: id,
                fields: {},
                features: res.map.features(i)
            };

            for (var fieldId in data[id].fields) {
                layer.fields[fieldId] = {type: data[id].fields[fieldId]};
                var field = layer.fields[fieldId];
                var values = _.pluck(layer.features, fieldId);
                if (field.type == 'Number') {
                    field.min = Math.min.apply(Math, values);
                    field.max = Math.max.apply(Math, values);
                }
                else if (layer.fields[fieldId].type == 'String') {
                    field.min = _.min(values, function(value) { return value.length; }).length;
                    field.max = _.max(values, function(value) { return value.length; }).length;
                }
            }

            if (!req.param('layer_id')) {
                res.layers.push(layer);
            }
            else if (req.param('layer_id') === layer.id) {
                res.layers.push(layer);
            }
        }
        if (req.param('layer_id') && res.layers.length === 0) {
            next(new Error('Layer could not be loaded.'));
        }
        next();
    }

    /**
     * Inspect abilities.
     */
    app.get('/abilities', function(req, res) {
        var mapnik = require('mapnik');
        res.send(
            {
                fonts: mapnik.fonts(),
                datasources: mapnik.datasources()
            }
        );
    });

    /**
     * Load layer model.
     */
    app.get('/:mapfile_64/:layer_id?', loadMap, loadLayer, function(req, res, next) {
        if (req.param('layer_id')) {
            res.send(res.layers.pop());
        }
        else {
            res.send(res.layers);
        }
    });

    /**
     * @TODO datasource SRS autodetection endpoint.
     */
    /*
    app.get('/:datasource_64', loadDatasource, function(req, res, next) {
        res.send({});
    });
    */
};
<commit_msg>Don't crash on invalid mapfiles. Fixes #91<commit_after>var _ = require('underscore')._;

module.exports = function(app, settings) {
    /**
     * Map loader, express route middleware.
     */
    function loadMap(req, res, next) {
        if (req.param('mapfile_64')) {
            var path = require('path');
            var Map = require('tilelive.js').Map;
            var map = new Map(req.param('mapfile_64'), path.join(__dirname, settings.mapfile_dir), true);
            map.localize(function(err) {
                if (err) {
                    next(new Error('Error loading map file'));
                    return;
                }
                res.map = map.mapnik_map();
                next();
            });
        }
        else {
            next(new Error('Map could not be loaded.'));
        }
    }

    /**
     * Layer loader, express route middleware.
     */
    function loadLayer(req, res, next) {
        res.layers = [];
        var layers = res.map.layers();
        var data = res.map.describe_data();
        for (var i = 0; i < layers.length; i++) {
            var id = layers[i].datasource.id;
            var layer = {
                id: id,
                fields: {},
                features: res.map.features(i)
            };

            for (var fieldId in data[id].fields) {
                layer.fields[fieldId] = {type: data[id].fields[fieldId]};
                var field = layer.fields[fieldId];
                var values = _.pluck(layer.features, fieldId);
                if (field.type == 'Number') {
                    field.min = Math.min.apply(Math, values);
                    field.max = Math.max.apply(Math, values);
                }
                else if (layer.fields[fieldId].type == 'String') {
                    field.min = _.min(values, function(value) { return value.length; }).length;
                    field.max = _.max(values, function(value) { return value.length; }).length;
                }
            }

            if (!req.param('layer_id')) {
                res.layers.push(layer);
            }
            else if (req.param('layer_id') === layer.id) {
                res.layers.push(layer);
            }
        }
        if (req.param('layer_id') && res.layers.length === 0) {
            next(new Error('Layer could not be loaded.'));
        }
        next();
    }

    /**
     * Inspect abilities.
     */
    app.get('/abilities', function(req, res) {
        var mapnik = require('mapnik');
        res.send(
            {
                fonts: mapnik.fonts(),
                datasources: mapnik.datasources()
            }
        );
    });

    /**
     * Load layer model.
     */
    app.get('/:mapfile_64/:layer_id?', loadMap, loadLayer, function(req, res, next) {
        if (req.param('layer_id')) {
            res.send(res.layers.pop());
        }
        else {
            res.send(res.layers);
        }
    });

    /**
     * @TODO datasource SRS autodetection endpoint.
     */
    /*
    app.get('/:datasource_64', loadDatasource, function(req, res, next) {
        res.send({});
    });
    */
};

{'fraction_non_alphanumeric': 0.14847089773100955, 'fraction_numerical': 0.0036172311739559354, 'mean_word_length': 1.4235059760956175, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, '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': '4383482', 'n_tokens_mistral': 1808, 'n_tokens_neox': 1721, 'n_words': 354}