<commit_before>'use strict';

var archiver   = require('archiver'),
    mediaQuery = require('css-mediaquery'),
    rework     = require('rework'),
    grids      = require('rework-pure-grids'),
    path       = require('path');

var config     = require('../config'),
    hbs        = require('../lib/hbs'),
    utils      = require('../lib/utils'),
    middleware = require('../middleware');

exports.index = [
    normalizeOptions,
    middleware.exposeTemplates('start'),
    generateCSS,
    showStart
];

exports.download = [
    normalizeOptions,
    generateHTML,
    generateCSS,
    downloadStart
];

// -----------------------------------------------------------------------------

var LIMITS = {
    cols        : {min: 2, max: 100},
    prefix      : {min: 0, max: 80},
    mediaQueries: {min: 0, max: 10}
};

var SELECTED_GRIDS_UNITS = {
    med: new GridUnits(config.pure.grid.med),
    lrg: new GridUnits(config.pure.grid.lrg)
};

function GridUnits(mq) {
    utils.extend(this, {mq: mq}, mediaQuery.parse(mq)[0]);
}

GridUnits.prototype.toString = function () {
    return this.mq;
};

function normalizeOptions(req, res, next) {
    var mediaQueries = [],
        cols, prefix;

    function badRequest(label, message) {
        res.locals.message = message;
        throw utils.error(400, 'Bad Request: ' + label);
    }

    Object.keys(req.query).forEach(function (param) {
        var val = req.query[param];

        if (Array.isArray(val)) {
            badRequest('Duplicate param',
                '"' + param + '" must only have a single value.');
        }

        switch (param.toLowerCase()) {
            case 'cols':
                val = parseInt(val, 10);

                if (val < LIMITS.cols.min || val > LIMITS.cols.max) {
                    badRequest('Column range',
                        '"cols" must be between 2—100, inclusively.');
                }

                cols = val;
                break;

            case 'prefix':
                if (val.length > LIMITS.prefix.max) {
                    badRequest('Prefix length',
                        '"prefix" must be between 0—80 characters.');
                }

                prefix = val;
                break;

            // Assume it's a media query.
            default:
                try {
                    val = normalizeMediaQuery(val);
                } catch (e) {
                    badRequest('Media Query',
                        'Invalid CSS Media Query: "' + val + '".');
                }

                mediaQueries.push({
                    id: param,
                    mq: val
                });

                break;
        }
    });

    if (mediaQueries.length > LIMITS.mediaQueries.max) {
        badRequest('Media Query',
            'More than 10 CSS Media Queries were provided.');
    }

    req.startOptions = {
        cols        : cols,
        prefix      : prefix,
        mediaQueries: mediaQueries
    };
    next();
}

function normalizeMediaQuery(mq, options) {
    mq = mq.trim();
    var expand = options && options.expand;

    if (expand) {
        mq = 'screen and (min-width: ' + mq + ')';
    }

    try {
        mediaQuery.parse(mq);
        return mq;
    } catch (e) {
        // When we've already expanded the short-hand MQ syntax, or when the
        // short-hand form doesn't look like a length value, re-throw the error.
        if (expand || !/^(\d|\.)/.test(mq)) {
            throw e;
        }
    }

    // Try again, this time expanding the `mq` assuming it's in the short-hand.
    return normalizeMediaQuery(mq, {expand: true});
}

function generateHTML(req, res, next) {
    var template = path.join(config.dirs.shared, 'start', 'html' + hbs.extname);

    hbs.render(template, {
        cache: req.app.enabled('view cache')
    }, function (err, html) {
        if (err) { return next(err); }
        res.html = html;
        next();
    });
}

function generateCSS(req, res, next) {
    var options = req.startOptions;

    res.css = rework('').use(grids.units(options.cols, {
        mediaQueries: options.mediaQueries.reduce(function (map, mq) {
            map[mq.id] = mq.mq;
            return map;
        }, {})
    })).toString({indent: '    '});

    next();
}

function showStart(req, res, next) {
    var options = req.startOptions;

    res.locals.selectedUnits = SELECTED_GRIDS_UNITS;
    res.locals.css           = res.css;
    res.locals(options);

    res.expose(LIMITS, 'start.limits');
    res.expose(options, 'start.options');
    res.render('start');
}

function downloadStart(req, res, next) {
    var archive = archiver('zip');

    archive.append(res.html,           {name: 'index.html'});
    archive.append(res.css || '\r\n',  {name: 'grid.css'});

    res.set('Content-Disposition', 'attachment; filename="pure-start.zip"');
    archive.finalize().pipe(res);
}
<commit_msg>Pass `pure.version` to Get Started download HTML template<commit_after>'use strict';

var archiver   = require('archiver'),
    mediaQuery = require('css-mediaquery'),
    rework     = require('rework'),
    grids      = require('rework-pure-grids'),
    path       = require('path');

var config     = require('../config'),
    hbs        = require('../lib/hbs'),
    utils      = require('../lib/utils'),
    middleware = require('../middleware');

exports.index = [
    normalizeOptions,
    middleware.exposeTemplates('start'),
    generateCSS,
    showStart
];

exports.download = [
    normalizeOptions,
    generateHTML,
    generateCSS,
    downloadStart
];

// -----------------------------------------------------------------------------

var LIMITS = {
    cols        : {min: 2, max: 100},
    prefix      : {min: 0, max: 80},
    mediaQueries: {min: 0, max: 10}
};

var SELECTED_GRIDS_UNITS = {
    med: new GridUnits(config.pure.grid.med),
    lrg: new GridUnits(config.pure.grid.lrg)
};

function GridUnits(mq) {
    utils.extend(this, {mq: mq}, mediaQuery.parse(mq)[0]);
}

GridUnits.prototype.toString = function () {
    return this.mq;
};

function normalizeOptions(req, res, next) {
    var mediaQueries = [],
        cols, prefix;

    function badRequest(label, message) {
        res.locals.message = message;
        throw utils.error(400, 'Bad Request: ' + label);
    }

    Object.keys(req.query).forEach(function (param) {
        var val = req.query[param];

        if (Array.isArray(val)) {
            badRequest('Duplicate param',
                '"' + param + '" must only have a single value.');
        }

        switch (param.toLowerCase()) {
            case 'cols':
                val = parseInt(val, 10);

                if (val < LIMITS.cols.min || val > LIMITS.cols.max) {
                    badRequest('Column range',
                        '"cols" must be between 2—100, inclusively.');
                }

                cols = val;
                break;

            case 'prefix':
                if (val.length > LIMITS.prefix.max) {
                    badRequest('Prefix length',
                        '"prefix" must be between 0—80 characters.');
                }

                prefix = val;
                break;

            // Assume it's a media query.
            default:
                try {
                    val = normalizeMediaQuery(val);
                } catch (e) {
                    badRequest('Media Query',
                        'Invalid CSS Media Query: "' + val + '".');
                }

                mediaQueries.push({
                    id: param,
                    mq: val
                });

                break;
        }
    });

    if (mediaQueries.length > LIMITS.mediaQueries.max) {
        badRequest('Media Query',
            'More than 10 CSS Media Queries were provided.');
    }

    req.startOptions = {
        cols        : cols,
        prefix      : prefix,
        mediaQueries: mediaQueries
    };
    next();
}

function normalizeMediaQuery(mq, options) {
    mq = mq.trim();
    var expand = options && options.expand;

    if (expand) {
        mq = 'screen and (min-width: ' + mq + ')';
    }

    try {
        mediaQuery.parse(mq);
        return mq;
    } catch (e) {
        // When we've already expanded the short-hand MQ syntax, or when the
        // short-hand form doesn't look like a length value, re-throw the error.
        if (expand || !/^(\d|\.)/.test(mq)) {
            throw e;
        }
    }

    // Try again, this time expanding the `mq` assuming it's in the short-hand.
    return normalizeMediaQuery(mq, {expand: true});
}

function generateHTML(req, res, next) {
    var template = path.join(config.dirs.shared, 'start', 'html' + hbs.extname);

    hbs.render(template, {
        cache: req.app.enabled('view cache'),
        pure : config.pure
    }, function (err, html) {
        if (err) { return next(err); }
        res.html = html;
        next();
    });
}

function generateCSS(req, res, next) {
    var options = req.startOptions;

    res.css = rework('').use(grids.units(options.cols, {
        mediaQueries: options.mediaQueries.reduce(function (map, mq) {
            map[mq.id] = mq.mq;
            return map;
        }, {})
    })).toString({indent: '    '});

    next();
}

function showStart(req, res, next) {
    var options = req.startOptions;

    res.locals.selectedUnits = SELECTED_GRIDS_UNITS;
    res.locals.css           = res.css;
    res.locals(options);

    res.expose(LIMITS, 'start.limits');
    res.expose(options, 'start.options');
    res.render('start');
}

function downloadStart(req, res, next) {
    var archive = archiver('zip');

    archive.append(res.html,         {name: 'index.html'});
    archive.append(res.css || '\n',  {name: 'grid.css'});

    res.set('Content-Disposition', 'attachment; filename="pure-start.zip"');
    archive.finalize().pipe(res);
}

{'fraction_non_alphanumeric': 0.15566612510154346, 'fraction_numerical': 0.005077173030056864, 'mean_word_length': 1.7434540389972144, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1405325', 'n_tokens_mistral': 3032, 'n_tokens_neox': 2881, 'n_words': 665}