<commit_before>/*
 * There here is YOUR config
 * This var is an example of the assets you can use in your own application.
 * The array KEYS correspond to the OUTPUT files/directories,
 * The array VALUES contain a LIST OF SOURCE FILES
 */
const config = {

    // The base output directory for all your assets
    "output_directory": "web",

    /**
     * This option is used to simply copy files into a new directory.
     * This is very useful when copying dist files of external components.
     * Example:
     *     "fonts/": [
     *         "node_modules/materialize-css/dist/fonts/*",
     *         "node_modules/bootstrap/dist/fonts/*"
     *     ]
     */
    "copy": {
    },

    /**
     * Here you can add other files to watch when using "gulp watch".
     * They will automatically run the "dump" command when modified.
     * It is VERY useful when you use massively less/sass "import" rules, for example.
     * Example:
     *     "src/AppBundle/Resources/public/less/*.less"
     */
    "files_to_watch": [
    ],

    /**
     * All files here are images that will be optimized/compressed with imagemin.
     * The key corresponds to the output directory (prepended with "output_directory" previous option).
     * Example:
     *     "images/": [
     *         "src/AppBundle/Resources/public/images/*"
     *     ]
     */
    "images": {
    },

    /**
     * All files from this section are parsed with LESS plugin and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main_less.css": [
     *         "node_modules/bootstrap/less/bootstrap.less",
     *         "src/AppBundle/Resources/public/less/main.less"
     *     ]
     */
    "less": {
    },

    /**
     * All files from this section are parsed with SASS plugin and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main_sass.css": [
     *         "src/AppBundle/Resources/public/less/main.scss"
     *     ]
     */
    "sass": {
    },

    /**
     * All files from this section are just concatenated and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main.css": [
     *         "src/AppBundle/Resources/public/css/main.css"
     *     ]
     */
    "css": {
    },

    /**
     * All files from this section are just concatenated and dumped into a JS file.
     * If using "--prod" in command line, will minify with "uglyflyjs".
     * Example:
     *     "js/main.js": [
     *         "web/components/bootstrap/dist/bootstrap-src.js",
     *         "src/AppBundle/Resources/public/css/main.js"
     *     ]
     */
    "js": {
    }
};

/*************** End config ***************/

// Everything AFTER this line of code is updatable to the latest version of this gulpfile.
// Check it out there if you need: https://github.com/Orbitale/Gulpfile

/************* Some helpers *************/

var GulpfileHelpers = {};

/**
 * @param {Object} object
 * @returns {Number}
 */
GulpfileHelpers.objectSize = function(object) {
    "use strict";

    let size = 0, key;
    for (key in object) {
        if (object.hasOwnProperty(key)) {
            size++;
        }
    }
    return size;
};

/**
 * @param {Object} object
 * @param {Function} callback
 * @returns {Object}
 */
GulpfileHelpers.objectForEach = function(object, callback) {
    "use strict";

    let key;
    for (key in object) {
        if (object.hasOwnProperty(key)) {
            callback.apply(object, [key, object[key]]);
        }
    }
    return object;
};

/*************** Global vars ***************/

// These data are mostly used to introduce logic that will save memory and time.
const isProd    = process.argv.indexOf('--prod') >= 0;
const hasImages = GulpfileHelpers.objectSize(config.images) > 0;
const hasCopy   = GulpfileHelpers.objectSize(config.copy) > 0;
const hasLess   = GulpfileHelpers.objectSize(config.less) > 0;
const hasSass   = GulpfileHelpers.objectSize(config.sass) > 0;
const hasCss    = GulpfileHelpers.objectSize(config.css) > 0;
const hasJs     = GulpfileHelpers.objectSize(config.js) > 0;

// Required extensions
var fs         = require('fs');
var gulp       = require('gulp4');
var gulpif     = require('gulp-if');
var watch      = require('gulp-watch');
var concat     = require('gulp-concat');
var uglyfly    = require('gulp-uglyfly');
var cleancss   = require('gulp-clean-css');
var sourcemaps = require('gulp-sourcemaps');

// Load other extensions only when having specific components. Saves memory & time execution.
var less     = hasLess   ? require('gulp-less')     : function(){ return {}; };
var sass     = hasSass   ? require('gulp-sass')     : function(){ return {}; };
var imagemin = hasImages ? require('gulp-imagemin') : function(){ return {}; };

/************** Files checks **************/

var erroredFiles = [];

var checkCallback = function(key, values) {
    values.forEach(function(fileName) {
        try {
            fs.statSync(fileName);
        } catch (e) {
            if (e.code === 'ENOENT' || (e.message && e.message.match(/no such file/i)) || e.match(/no such file/i)) {
                erroredFiles.push(fileName);
            } else {
                throw e;
            }
        }
    })
};

GulpfileHelpers.objectForEach(config.css, checkCallback);
GulpfileHelpers.objectForEach(config.js, checkCallback);
GulpfileHelpers.objectForEach(config.images, checkCallback);
GulpfileHelpers.objectForEach(config.copy, checkCallback);
GulpfileHelpers.objectForEach(config.sass, checkCallback);
GulpfileHelpers.objectForEach(config.less, checkCallback);

if (erroredFiles.length) {
    process.stderr.write("\nMissing files: \n"+erroredFiles.join("\n")+"\n");
    process.exit(1);
}

/*************** Gulp tasks ***************/

/**
 * Dumps the LESS assets
 */
gulp.task('less', function(done) {
    "use strict";

    let list = config.less,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(less())
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the SASS assets
 */
gulp.task('sass', function(done) {
    "use strict";

    let list = config.sass,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(sass().on('error', sass.logError))
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Simply copy files into another directory.
 * Useful for simple "dist" files from node_modules directory, for example.
 */
gulp.task('copy', function(done) {
    "use strict";

    let list = config.copy,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(gulp.dest(outputDir + assets_output))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Compress images.
 * Thanks to @docteurklein.
 */
gulp.task('images', function(done) {
    "use strict";

    let list = config.images,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(imagemin({
                optimizationLevel: 7,
                progressive: true,
                interlaced: true,
                verbose: true
            }))
            .pipe(gulp.dest(outputDir + assets_output))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the CSS assets.
 */
gulp.task('css', function(done) {
    "use strict";

    let list = config.css,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the JS assets
 */
gulp.task('js', function(done) {
    "use strict";

    let list = config.js,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(sourcemaps.init())
            .pipe(concat({path: assets_output, cwd: ''}))
            .pipe(gulpif(isProd, uglyfly()))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Runs all the needed commands to dump all assets and manifests
 */
gulp.task('dump', gulp.series('images', 'copy', 'less', 'sass', 'css', 'js', function(done){
    done();
}));

/**
 * Will watch for files and run "dump" for each modification
 */
gulp.task('watch', gulp.series('dump', gulp.parallel(function(done) {
    "use strict";

    let files_less = [],
        files_images = [],
        files_css = [],
        files_sass = [],
        files_js = [],
        callback = function(event) {
            console.log('File "' + event.path + '" updated');
        },
        other_files_to_watch = config.files_to_watch || [],
        files_to_watch = []
    ;

    console.info('Night gathers, and now my watch begins...');

    GulpfileHelpers.objectForEach(config.images, function(key, images){
        files_images.push(images);
        files_to_watch.push(images);
    });
    GulpfileHelpers.objectForEach(config.less, function(key, less){
        files_less.push(less);
        files_to_watch.push(less);
    });
    GulpfileHelpers.objectForEach(config.sass, function(key, sass){
        files_sass.push(sass);
        files_to_watch.push(sass);
    });
    GulpfileHelpers.objectForEach(config.css, function(key, css){
        files_css.push(css);
        files_to_watch.push(css);
    });
    GulpfileHelpers.objectForEach(config.js, function(key, js){
        files_js.push(js);
        files_to_watch.push(js);
    });

    if (files_to_watch.length) {
        console.info('Watching file(s):');
        // Flatten the array
        files_to_watch = [].concat.apply([], files_to_watch).sort();
        console.info("       > "+files_to_watch.join("\n       > "));
    }

    if (other_files_to_watch.length) {
        gulp.watch(other_files_to_watch, gulp.parallel('dump')).on('change', callback);
    }
    if (hasImages) {
        gulp.watch(files_images, gulp.parallel('images')).on('change', callback);
    }
    if (hasLess) {
        gulp.watch(files_less, gulp.parallel('less')).on('change', callback);
    }
    if (hasSass) {
        gulp.watch(files_sass, gulp.parallel('sass')).on('change', callback);
    }
    if (hasCss) {
        gulp.watch(files_css, gulp.parallel('css')).on('change', callback);
    }
    if (hasJs) {
        gulp.watch(files_js, gulp.parallel('js')).on('change', callback);
    }

    done();
})));

/**
 * Small user guide
 */
gulp.task('default', function(done){
    console.info("");
    console.info("usage: gulp [command] [--prod]");
    console.info("");
    console.info("Options:");
    console.info("    --prod       If specified, will run clean-css and uglyfyjs when dumping the assets.");
    console.info("");
    console.info("Commands:");
    console.info("    copy         Copy the sources in the `config.copy` into a destination folder.");
    console.info("    images       Dumps the sources in the `config.images` parameter from image files.");
    console.info("    less         Dumps the sources in the `config.less` parameter from LESS files.");
    console.info("    sass         Dumps the sources in the `config.sass` parameter from SCSS files.");
    console.info("    css          Dumps the sources in the `config.css` parameter from plain CSS files.");
    console.info("    js           Dumps the sources in the `config.js` parameter from plain JS files.");
    console.info("    dump         Executes all the above commands.");
    console.info("    watch        Executes 'dump', then watches all sources, and dumps all assets once any file is updated.");
    console.info("");
    done();
});

// Gulpfile with a single var as configuration.
// License: MIT
// Author: 2016 - Alex "Pierstoval" Rock Ancelet <alex@orbitale.io>
// Repository: https://github.com/Orbitale/Gulpfile
<commit_msg>Remove wildcards when checking missing files, fix imagemin & add copy<commit_after>/*
 * There here is YOUR config
 * This var is an example of the assets you can use in your own application.
 * The array KEYS correspond to the OUTPUT files/directories,
 * The array VALUES contain a LIST OF SOURCE FILES
 */
const config = {

    // The base output directory for all your assets
    "output_directory": "web",

    /**
     * This option is used to simply copy files into a new directory.
     * This is very useful when copying dist files of external components.
     * Example:
     *     "fonts/": [
     *         "node_modules/materialize-css/dist/fonts/*",
     *         "node_modules/bootstrap/dist/fonts/*"
     *     ]
     */
    "copy": {
    },

    /**
     * Here you can add other files to watch when using "gulp watch".
     * They will automatically run the "dump" command when modified.
     * It is VERY useful when you use massively less/sass "import" rules, for example.
     * Example:
     *     "src/AppBundle/Resources/public/less/*.less"
     */
    "files_to_watch": [
    ],

    /**
     * All files here are images that will be optimized/compressed with imagemin.
     * The key corresponds to the output directory (prepended with "output_directory" previous option).
     * Example:
     *     "images/": [
     *         "src/AppBundle/Resources/public/images/*"
     *     ]
     */
    "images": {
    },

    /**
     * All files from this section are parsed with LESS plugin and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main_less.css": [
     *         "node_modules/bootstrap/less/bootstrap.less",
     *         "src/AppBundle/Resources/public/less/main.less"
     *     ]
     */
    "less": {
    },

    /**
     * All files from this section are parsed with SASS plugin and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main_sass.css": [
     *         "src/AppBundle/Resources/public/less/main.scss"
     *     ]
     */
    "sass": {
    },

    /**
     * All files from this section are just concatenated and dumped into a CSS file.
     * If using "--prod" in command line, will minify with "clean-css".
     * Example:
     *     "css/main.css": [
     *         "src/AppBundle/Resources/public/css/main.css"
     *     ]
     */
    "css": {
    },

    /**
     * All files from this section are just concatenated and dumped into a JS file.
     * If using "--prod" in command line, will minify with "uglyflyjs".
     * Example:
     *     "js/main.js": [
     *         "web/components/bootstrap/dist/bootstrap-src.js",
     *         "src/AppBundle/Resources/public/css/main.js"
     *     ]
     */
    "js": {
    }
};

/*************** End config ***************/

// Everything AFTER this line of code is updatable to the latest version of this gulpfile.
// Check it out there if you need: https://github.com/Orbitale/Gulpfile

/************* Some helpers *************/

var GulpfileHelpers = {};

/**
 * @param {Object} object
 * @returns {Number}
 */
GulpfileHelpers.objectSize = function(object) {
    "use strict";

    let size = 0, key;
    for (key in object) {
        if (object.hasOwnProperty(key)) {
            size++;
        }
    }
    return size;
};

/**
 * @param {Object} object
 * @param {Function} callback
 * @returns {Object}
 */
GulpfileHelpers.objectForEach = function(object, callback) {
    "use strict";

    let key;
    for (key in object) {
        if (object.hasOwnProperty(key)) {
            callback.apply(object, [key, object[key]]);
        }
    }
    return object;
};

/*************** Global vars ***************/

// These data are mostly used to introduce logic that will save memory and time.
const isProd    = process.argv.indexOf('--prod') >= 0;
const hasImages = GulpfileHelpers.objectSize(config.images) > 0;
const hasCopy   = GulpfileHelpers.objectSize(config.copy) > 0;
const hasLess   = GulpfileHelpers.objectSize(config.less) > 0;
const hasSass   = GulpfileHelpers.objectSize(config.sass) > 0;
const hasCss    = GulpfileHelpers.objectSize(config.css) > 0;
const hasJs     = GulpfileHelpers.objectSize(config.js) > 0;

// Required extensions
var fs         = require('fs');
var gulp       = require('gulp4');
var gulpif     = require('gulp-if');
var watch      = require('gulp-watch');
var concat     = require('gulp-concat');
var uglyfly    = require('gulp-uglyfly');
var cleancss   = require('gulp-clean-css');
var sourcemaps = require('gulp-sourcemaps');

// Load other extensions only when having specific components. Saves memory & time execution.
var less     = hasLess   ? require('gulp-less')     : function(){ return {}; };
var sass     = hasSass   ? require('gulp-sass')     : function(){ return {}; };
var imagemin = hasImages ? require('gulp-imagemin') : function(){ return {}; };

/************** Files checks **************/

var erroredFiles = [];

var checkCallback = function(key, values) {
    values.forEach(function(fileName) {
        try {
            // Remove wildcards
            fileName = fileName.replace(/(?:(?:\*\.\w{2,4}(?:$|\/))|(?:\/\*+(?:$|\/)))/gi, '');
            fs.statSync(fileName);
        } catch (e) {
            if (e.code === 'ENOENT' || (e.message && e.message.match(/no such file/i)) || String(e).match(/no such file/i)) {
                erroredFiles.push(fileName);
            } else {
                throw e;
            }
        }
    })
};

GulpfileHelpers.objectForEach(config.css, checkCallback);
GulpfileHelpers.objectForEach(config.js, checkCallback);
GulpfileHelpers.objectForEach(config.images, checkCallback);
GulpfileHelpers.objectForEach(config.copy, checkCallback);
GulpfileHelpers.objectForEach(config.sass, checkCallback);
GulpfileHelpers.objectForEach(config.less, checkCallback);

if (erroredFiles.length) {
    process.stderr.write("\nMissing files: \n"+erroredFiles.join("\n")+"\n");
    process.exit(1);
}

/*************** Gulp tasks ***************/

/**
 * Dumps the LESS assets
 */
gulp.task('less', function(done) {
    "use strict";

    let list = config.less,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(less())
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the SASS assets
 */
gulp.task('sass', function(done) {
    "use strict";

    let list = config.sass,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(sass().on('error', sass.logError))
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Simply copy files into another directory.
 * Useful for simple "dist" files from node_modules directory, for example.
 */
gulp.task('copy', function(done) {
    "use strict";

    let list = config.copy,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(gulp.dest(outputDir + assets_output))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Compress images.
 * Thanks to @docteurklein.
 */
gulp.task('images', function(done) {
    "use strict";

    let list = config.images,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(imagemin([
                imagemin.gifsicle({interlaced: true}),
                imagemin.jpegtran({progressive: true}),
                imagemin.optipng({optimizationLevel: 7}),
                imagemin.svgo({plugins: [{removeViewBox: true}]})
            ], { verbose: true }))
            .pipe(gulp.dest(outputDir + assets_output))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the CSS assets.
 */
gulp.task('css', function(done) {
    "use strict";

    let list = config.css,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(concat(assets_output))
            .pipe(gulpif(isProd, cleancss()))
            .pipe(concat(assets_output))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Dumps the JS assets
 */
gulp.task('js', function(done) {
    "use strict";

    let list = config.js,
        outputDir = config.output_directory+'/',
        assets_output, assets, pipes, i, l
    ;
    for (assets_output in list) {
        if (!list.hasOwnProperty(assets_output)) { continue; }
        assets = list[assets_output];
        pipes = gulp
            .src(assets)
            .pipe(sourcemaps.init())
            .pipe(concat({path: assets_output, cwd: ''}))
            .pipe(gulpif(isProd, uglyfly()))
            .pipe(gulp.dest(outputDir))
        ;

        console.info(" [file+] "+assets_output+" >");
        for (i = 0, l = assets.length; i < l; i++) {
            console.info("       > "+assets[i]);
        }
    }

    pipes ? pipes.on('end', function(){done();}) : done();
});

/**
 * Runs all the needed commands to dump all assets and manifests
 */
gulp.task('dump', gulp.series('images', 'copy', 'less', 'sass', 'css', 'js', function(done){
    done();
}));

/**
 * Will watch for files and run "dump" for each modification
 */
gulp.task('watch', gulp.series('dump', gulp.parallel(function(done) {
    "use strict";

    let files_less = [],
        files_images = [],
        files_copy = [],
        files_css = [],
        files_sass = [],
        files_js = [],
        callback = function(event) {
            console.log('File "' + event.path + '" updated');
        },
        other_files_to_watch = config.files_to_watch || [],
        files_to_watch = []
    ;

    console.info('Night gathers, and now my watch begins...');

    GulpfileHelpers.objectForEach(config.images, function(key, images){
        files_images.push(images);
        files_to_watch.push(images);
    });
    GulpfileHelpers.objectForEach(config.copy, function(key, copy){
        files_copy.push(copy);
        files_to_watch.push(copy);
    });
    GulpfileHelpers.objectForEach(config.less, function(key, less){
        files_less.push(less);
        files_to_watch.push(less);
    });
    GulpfileHelpers.objectForEach(config.sass, function(key, sass){
        files_sass.push(sass);
        files_to_watch.push(sass);
    });
    GulpfileHelpers.objectForEach(config.css, function(key, css){
        files_css.push(css);
        files_to_watch.push(css);
    });
    GulpfileHelpers.objectForEach(config.js, function(key, js){
        files_js.push(js);
        files_to_watch.push(js);
    });

    if (files_to_watch.length) {
        console.info('Watching file(s):');
        // Flatten the array
        files_to_watch = [].concat.apply([], files_to_watch).sort();
        console.info("       > "+files_to_watch.join("\n       > "));
    }

    if (other_files_to_watch.length) {
        gulp.watch(other_files_to_watch, gulp.parallel('dump')).on('change', callback);
    }
    if (hasImages) {
        gulp.watch(files_images, gulp.parallel('images')).on('change', callback);
    }
    if (hasCopy) {
        gulp.watch(files_copy, gulp.parallel('copy')).on('change', callback);
    }
    if (hasLess) {
        gulp.watch(files_less, gulp.parallel('less')).on('change', callback);
    }
    if (hasSass) {
        gulp.watch(files_sass, gulp.parallel('sass')).on('change', callback);
    }
    if (hasCss) {
        gulp.watch(files_css, gulp.parallel('css')).on('change', callback);
    }
    if (hasJs) {
        gulp.watch(files_js, gulp.parallel('js')).on('change', callback);
    }

    done();
})));

/**
 * Small user guide
 */
gulp.task('default', function(done){
    console.info("");
    console.info("usage: gulp [command] [--prod]");
    console.info("");
    console.info("Options:");
    console.info("    --prod       If specified, will run clean-css and uglyfyjs when dumping the assets.");
    console.info("");
    console.info("Commands:");
    console.info("    copy         Copy the sources in the `config.copy` into a destination folder.");
    console.info("    images       Dumps the sources in the `config.images` parameter from image files.");
    console.info("    less         Dumps the sources in the `config.less` parameter from LESS files.");
    console.info("    sass         Dumps the sources in the `config.sass` parameter from SCSS files.");
    console.info("    css          Dumps the sources in the `config.css` parameter from plain CSS files.");
    console.info("    js           Dumps the sources in the `config.js` parameter from plain JS files.");
    console.info("    dump         Executes all the above commands.");
    console.info("    watch        Executes 'dump', then watches all sources, and dumps all assets once any file is updated.");
    console.info("");
    done();
});

// Gulpfile with a single var as configuration.
// License: MIT
// Author: 2016 - Alex "Pierstoval" Rock Ancelet <alex@orbitale.io>
// Repository: https://github.com/Orbitale/Gulpfile
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    require("time-grunt")(grunt);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        opt: {
            client: {
                "tsMain": "lib",
                "tsTest": "test",

                "jsMainOut": "lib",
                "jsTestOut": "test"
            }
        },

        ts: {
            options: {
                compile: true,                 // perform compilation. [true (default) | false]
                comments: false,               // same as !removeComments. [true | false (default)]
                target: 'es5',                 // target javascript language. [es3 (default) | es5]
                module: 'commonjs',            // target javascript module style. [amd (default) | commonjs]
                noImplicitAny: true,
                sourceMap: true,              // generate a source map for every output js file. [true (default) | false]
                sourceRoot: '',                // where to locate TypeScript files. [(default) '' == source ts location]
                mapRoot: '',                   // where to locate .map.js files. [(default) '' == generated js location.]
                declaration: false             // generate a declaration .d.ts file for every output js file. [true | false (default)]
            },
            clientMain: {
                src: ['<%= opt.client.tsMain %>/cli.ts'],
                out: '<%= opt.client.jsMainOut %>/cli.js',
                options: {
                    declaration: true
                }
            },
            clientTest: {
                src: ['<%= opt.client.tsTest %>/index_spec.ts'],
                out: '<%= opt.client.jsTestOut %>/index_spec.js'
            }
        },
        tslint: {
            options: {
                configuration: grunt.file.readJSON("tslint.json")
            },
            files: {
                src: [
                    '<%= opt.client.tsMain %>/**/*.ts',
                    '<%= opt.client.tsTest %>/**/*.ts',
                    '!<%= opt.client.tsMain %>/**/*.d.ts'
                ]
            }
        },
        typedoc: {
            main: {
                options: {
                    module: "<%= ts.options.module %>",
                    out: './docs',
                    name: '<%= pkg.name %>',
                    target: "<%= ts.options.target %>"
                },
                src: [
                    '<%= opt.client.tsMain %>/**/*.ts'
                ]
            }
        },
        dtsm: {
            client: {
                options: {
                    // optional: specify config file
                    confog: './dtsm.json'
                }
            }
        },
        clean: {
            clientScript: {
                src: [
                    // client
                    '<%= opt.client.jsMainOut %>/*.js',
                    '<%= opt.client.jsMainOut %>/*.d.ts',
                    '<%= opt.client.jsMainOut %>/*.js.map',
                    '!<%= opt.client.jsMainOut %>/insight.d.ts',
                    // client test
                    '<%= opt.client.jsTestOut %>/*.js',
                    '<%= opt.client.jsTestOut %>/*.js.map',
                    '<%= opt.client.jsTestOut %>/*.d.ts',
                    // peg.js
                    '<%= opt.client.peg %>/grammar.js'
                ]
            },
            dtsm: {
                src: [
                    // dtsm installed
                    "typings/"
                ]
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec',
                    timeout: 20000,
                    require: [
                        function () {
                            require('espower-loader')({
                                cwd: process.cwd() + '/' + grunt.config.get("opt.client.jsTestOut"),
                                pattern: '**/*.js'
                            });
                        },
                        function () {
                            assert = require('power-assert');
                        }
                    ]
                },
                src: [
                    '<%= opt.client.jsTestOut %>/**/*_spec.js'
                ]
            }
        }
    });

    grunt.registerTask(
        'setup',
        ['clean', 'dtsm']);

    grunt.registerTask(
        'default',
        ['ts:clientMain', 'tslint']);

    grunt.registerTask(
        'test',
        ['default', 'ts:clientTest', 'mochaTest']);

    require('load-grunt-tasks')(grunt);
};
<commit_msg>try fixing circle-ci<commit_after>module.exports = function (grunt) {
    require("time-grunt")(grunt);

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        opt: {
            client: {
                "tsMain": "lib",
                "tsTest": "test",

                "jsMainOut": "lib",
                "jsTestOut": "test"
            }
        },

        ts: {
            options: {
                compile: true,                 // perform compilation. [true (default) | false]
                comments: false,               // same as !removeComments. [true | false (default)]
                target: 'es5',                 // target javascript language. [es3 (default) | es5]
                module: 'commonjs',            // target javascript module style. [amd (default) | commonjs]
                noImplicitAny: true,
                sourceMap: true,              // generate a source map for every output js file. [true (default) | false]
                sourceRoot: '',                // where to locate TypeScript files. [(default) '' == source ts location]
                mapRoot: '',                   // where to locate .map.js files. [(default) '' == generated js location.]
                declaration: false             // generate a declaration .d.ts file for every output js file. [true | false (default)]
            },
            clientMain: {
                src: ['<%= opt.client.tsMain %>/cli.ts'],
                out: '<%= opt.client.jsMainOut %>/cli.js',
                options: {
                    declaration: true
                }
            },
            clientTest: {
                src: ['<%= opt.client.tsTest %>/index_spec.ts'],
                out: '<%= opt.client.jsTestOut %>/index_spec.js'
            }
        },
        tslint: {
            options: {
                configuration: grunt.file.readJSON("tslint.json")
            },
            files: {
                src: [
                    '<%= opt.client.tsMain %>/**/*.ts',
                    '<%= opt.client.tsTest %>/**/*.ts',
                    '!<%= opt.client.tsMain %>/**/*.d.ts'
                ]
            }
        },
        typedoc: {
            main: {
                options: {
                    module: "<%= ts.options.module %>",
                    out: './docs',
                    name: '<%= pkg.name %>',
                    target: "<%= ts.options.target %>"
                },
                src: [
                    '<%= opt.client.tsMain %>/**/*.ts'
                ]
            }
        },
        dtsm: {
            client: {
                options: {
                    // optional: specify config file
                    confog: './dtsm.json'
                }
            }
        },
        clean: {
            clientScript: {
                src: [
                    // client
                    '<%= opt.client.jsMainOut %>/*.js',
                    '<%= opt.client.jsMainOut %>/*.d.ts',
                    '<%= opt.client.jsMainOut %>/*.js.map',
                    '!<%= opt.client.jsMainOut %>/insight.d.ts',
                    // client test
                    '<%= opt.client.jsTestOut %>/*.js',
                    '<%= opt.client.jsTestOut %>/*.js.map',
                    '<%= opt.client.jsTestOut %>/*.d.ts',
                    // peg.js
                    '<%= opt.client.peg %>/grammar.js'
                ]
            },
            dtsm: {
                src: [
                    // dtsm installed
                    "typings/"
                ]
            }
        },
        mochaTest: {
            test: {
                options: {
                    reporter: 'spec',
                    timeout: 60000,
                    require: [
                        function () {
                            require('espower-loader')({
                                cwd: process.cwd() + '/' + grunt.config.get("opt.client.jsTestOut"),
                                pattern: '**/*.js'
                            });
                        },
                        function () {
                            assert = require('power-assert');
                        }
                    ]
                },
                src: [
                    '<%= opt.client.jsTestOut %>/**/*_spec.js'
                ]
            }
        }
    });

    grunt.registerTask(
        'setup',
        ['clean', 'dtsm']);

    grunt.registerTask(
        'default',
        ['ts:clientMain', 'tslint']);

    grunt.registerTask(
        'test',
        ['default', 'ts:clientTest', 'mochaTest']);

    require('load-grunt-tasks')(grunt);
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    clean: ['dist'],
    copy: {
      main: {
        files: [
          {expand: true, cwd: 'html/', src: ['**/*.html'], dest: 'dist/', filter: 'isFile'}
        ]
      }
    },
    useminPrepare: {
      html: 'dist/**/*.html'
    },
    requirejs: {
      compile: {
        options: {
          baseUrl: 'game/client',
          paths:{
            underscore: '../lib/underscore/underscore-min',
            stats: '../lib/stats/build/stats.min'
          },
          shim: {
            underscore: {
              exports: '_'
            },
            stats: {
              exports: 'Stats'
            }
          },
          optimize: 'none',
          name: 'init',
          out: 'build/client/init.js'
        }
      }
    },
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['build/**/*.js'],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },
    uglify: {
      dist: {
        files: {
          'dist/js/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },
    cssmin: {
      options: {
        report: 'min'
      },
      compress: {
        files: {
          'dist/css/<%= pkg.name %>.css': ['public/css/**/*.css']
        }
      }
    },
    rev: {
      options: {
        algorithm: 'sha1',
        length: 8
      },
      files: {
        src: [
          'dist/**/*.{js,css,jpg,jpeg,gif,png,svg,eot,ttf,woff}'
        ]
      }
    },
    usemin: {
      html: ['dist/**/*.html'],
      css: ['dist/**/*.css']
    },
    jshint: {
      files: ['gruntfile.js', 'game/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true
        }
      }
    },
    csslint: {
      strict: {
        src: ['public/css/**/*.css']
      }
    }
  });

  // test
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-csslint');

  grunt.registerTask('test', [
    'jshint',
    'csslint'
  ]);

  // build
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-rev');
  grunt.loadNpmTasks('grunt-usemin');
  grunt.loadNpmTasks('grunt-manifest');

  grunt.registerTask('html', [
    'clean',
    'copy'
  ]);

  grunt.registerTask('usemin', [
    'clean',
    'copy',
    'useminPrepare',
    'requirejs',
    'concat',
    'uglify',
    'cssmin',
    'rev',
    'usemin'
  ]);

  grunt.registerTask('default', [
    'clean',
    'copy',
    'requirejs',
    'concat',
    'uglify',
    'cssmin',
    'rev'
  ]);

};
<commit_msg>fixing usemin config in Gruntfile<commit_after>module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    clean: ['dist'],
    copy: {
      main: {
        files: [
          {expand: true, cwd: 'html/', src: ['**/*.html'], dest: 'dist/', filter: 'isFile'},
          {expand: true, cwd: 'public/', src: ['vendor/**/*.js'], dest: 'dist/', filter: 'isFile'}
        ]
      }
    },
    useminPrepare: {
      html: 'dist/**/*.html'
    },
    requirejs: {
      compile: {
        options: {
          baseUrl: 'game/client',
          paths:{
            underscore: '../lib/underscore/underscore-min',
            stats: '../lib/stats/build/stats.min'
          },
          shim: {
            underscore: {
              exports: '_'
            },
            stats: {
              exports: 'Stats'
            }
          },
          optimize: 'none',
          name: 'init',
          out: 'build/client/init.js'
        }
      }
    },
    concat: {
      options: {
        separator: ';'
      },
      dist: {
        src: ['build/**/*.js'],
        dest: 'dist/js/<%= pkg.name %>.js'
      }
    },
    uglify: {
      dist: {
        files: {
          'dist/js/<%= pkg.name %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },
    cssmin: {
      options: {
        report: 'min'
      },
      compress: {
        files: {
          'dist/css/<%= pkg.name %>.css': ['public/css/**/*.css']
        }
      }
    },
    rev: {
      options: {
        algorithm: 'sha1',
        length: 8
      },
      files: {
        src: [
          'dist/**/*.{js,css,jpg,jpeg,gif,png,svg,eot,ttf,woff}'
        ]
      }
    },
    usemin: {
      html: ['dist/**/*.html'],
      css: ['dist/**/*.css']
    },
    jshint: {
      files: ['gruntfile.js', 'game/**/*.js', 'test/**/*.js'],
      options: {
        globals: {
          jQuery: true,
          console: true,
          module: true,
          document: true
        }
      }
    },
    csslint: {
      strict: {
        src: ['public/css/**/*.css']
      }
    }
  });

  // test
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-csslint');

  grunt.registerTask('test', [
    'jshint',
    'csslint'
  ]);

  // build
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-cssmin');
  grunt.loadNpmTasks('grunt-rev');
  grunt.loadNpmTasks('grunt-usemin');
  grunt.loadNpmTasks('grunt-manifest');

  grunt.registerTask('html', [
    'clean',
    'copy'
  ]);

  grunt.registerTask('default', [
    'clean',
    'copy',
    'useminPrepare',
    'requirejs',
    'concat',
    'uglify',
    'cssmin',
    'rev',
    'usemin'
  ]);

};
<|endoftext|>


<commit_before>import * as I     from 'immutable';
import * as THREE from 'three';
import * as csp   from 'plexus-csp';

import { matrices } from '../arithmetic/types';
const ops = matrices;

import * as delaney  from '../dsymbols/delaney';
import * as props    from '../dsymbols/properties';
import * as periodic from '../pgraphs/periodic';

import tiling from '../dsymbols/tilings';

import * as webworkers from '../common/webworkers';

const worker = webworkers.create('js/sceneWorker.js');
const callWorker = csp.nbind(worker, null);

const _normalized = v => ops.div(v, ops.norm(v));

const encode = value => JSON.stringify(ops.repr(value));
const decode = value => ops.fromRepr(JSON.parse(value));

const CoverVertex = I.Record({
  v: undefined,
  s: undefined
});

const graphPortion = (graph, start, dist) => {
  const adj  = periodic.adjacencies(graph);

  const v0 = new CoverVertex({ v: start, s: encode(ops.vector(graph.dim)) });
  let vertices = I.Map([[v0, 0]]);
  let edges = I.Set();
  let thisShell = I.List([v0]);

  I.Range(1, dist+1).forEach(i => {
    let nextShell = I.Set();
    thisShell.forEach(v => {
      const i = vertices.get(v);

      adj.get(v.v).forEach(t => {
        const w = new CoverVertex({
          v: t.v,
          s: encode(ops.plus(decode(v.s), t.s))
        });

        if (vertices.get(w) == null) {
          vertices = vertices.set(w, vertices.size);
          nextShell = nextShell.add(w);
        }

        const j = vertices.get(w);

        if (!edges.contains(I.List([i, j])) && !edges.contains(I.List([j, i])))
          edges = edges.add(I.List([i, j]));
      });
    });

    thisShell = nextShell;
  });

  let verts = I.List().asMutable();
  vertices.keySeq().forEach(v => {
    verts.set(vertices.get(v), { v: v.v, s: decode(v.s) });
  });

  return {
    vertices: verts.asImmutable(),
    edges   : edges.sort().map(e => e.toArray())
  };
};

const geometry = (vertices, faces) => {
  const geom = new THREE.Geometry();

  vertices.forEach(v => {
    geom.vertices.push(new THREE.Vector3(v[0], v[1], v[2]));
  });

  faces.forEach(f => {
    f.forEach((v, i) => {
      if (i > 0 && i+1 < f.length)
        geom.faces.push(new THREE.Face3(f[0], f[i], f[i+1]));
    });
  });

  geom.computeFaceNormals();
  geom.computeVertexNormals();
  return geom;
};

const stick = (p, q, radius, segments) => {
  const n = segments;
  const d = _normalized(ops.minus(q, p));
  const ex = [1,0,0];
  const ey = [0,1,0];
  const t = Math.abs(ops.times(d, ex)) > 0.9 ? ey : ex;
  const u = _normalized(ops.crossProduct(d, t));
  const v = _normalized(ops.crossProduct(d, u));
  const a = Math.PI * 2 / n;

  const section = I.Range(0, n).map(i => {
    const x = a * i;
    const c = Math.cos(x) * radius;
    const s = Math.sin(x) * radius;
    return ops.plus(ops.times(c, u), ops.times(s, v));
  });

  return geometry(
    I.List().concat(section.map(c => ops.plus(c, p)),
                    section.map(c => ops.plus(c, q))),
    I.Range(0, n).map(i => {
      const j = (i + 1) % n;
      return [i, j, j+n, i+n];
    })
  );
};

const ballAndStick = (
  name, positions, edges, ballRadius, stickRadius, ballMaterial, stickMaterial
) => {
  const model = new THREE.Object3D();
  const ball  = new THREE.SphereGeometry(ballRadius, 16, 8);

  positions.forEach(p => {
    const s = new THREE.Mesh(ball, ballMaterial);
    s.position.x = p[0];
    s.position.y = p[1];
    s.position.z = p[2];
    model.add(s);
  });

  edges.forEach(e => {
    const u = positions[e[0]];
    const v = positions[e[1]];
    const s = stick(u, v, stickRadius, 8);
    s.computeVertexNormals();
    model.add(new THREE.Mesh(s, stickMaterial));
  });

  return model;
};

const interpolate = (f, v, w) => ops.plus(w, ops.times(f, ops.minus(v, w)));

const chamberBasis = (pos, D) => {
  const t = pos.get(D).valueSeq();
  return t.rest().map(v => ops.minus(v, t.get(0)));
};

const tileSurface = (til, D0) => {
  const cov = til.cover;
  const ori = props.partialOrientation(cov);
  const pos = til.positions;
  const elms = props.orbit(cov, [0, 1, 2], D0);

  const sgn = ori.get(D0) *
    ops.sgn(ops.determinant(ops.cleanup(
      ops.times(chamberBasis(pos, D0).toJS(), til.basis))));

  const cornerOrbits =
    props.orbitReps(cov, [1, 2], elms).map(D => props.orbit(cov, [1, 2], D));

  const cornerPositions = I.List(cornerOrbits.map(orb => {
    const ps = pos.get(orb.first());
    return ops.times(interpolate(0.8, ps.get(0), ps.get(3)), til.basis);
  }));

  const cornerIndex = I.Map(cornerOrbits.flatMap(
    (orb, i) => orb.map(D => [D, i])));

  const faces = I.List(props.orbitReps(cov, [0, 1], elms)
    .map(D => sgn * ori.get(D) < 0 ? D : cov.s(0, D))
    .map(D => (
      props.orbit(cov, [0, 1], D)
        .filter((D, i) => i % 2 == 0)
        .map(D => cornerIndex.get(D)))));

  return {
    pos    : cornerPositions.map(p => ops.toJS(p)).toJS(),
    faces  : faces.toJS(),
    isFixed: I.Range(0, cornerPositions.size).map(i => true).toJS()
  };
};

const tileSurfaces = til => {
  return props.orbitReps(til.cover, [0, 1, 2])
    .map(D => tileSurface(til, D))
    .toJS();
};

const tilingModel = (surfaces, tileMaterial) => {
  const model = new THREE.Object3D();

  for (const { pos, faces } of surfaces) {
    const geom = geometry(pos, faces);
    const tileMesh = new THREE.Mesh(geom, tileMaterial);
    model.add(tileMesh);
    //model.add(new THREE.WireframeHelper(tilesMesh, 0x00ff00));
  }

  return model;
};

const netModel = (t, ballMaterial, stickMaterial) => {
  const net = t.graph;
  const g   = graphPortion(net, 0, 2);
  const pos = t.positions;
  let verts = g.vertices.map(v => {
    const p = ops.plus(pos.getIn([t.node2chamber.get(v.v), 0]), v.s);
    return ops.times(p, t.basis);
  }).toArray();
  if (delaney.dim(t.cover) == 2)
    verts = verts.map(p => [p[0], p[1], 0]);

  return ballAndStick(
    'cube',
    verts,
    g.edges,
    0.04,
    0.01,
    ballMaterial,
    stickMaterial
  );
};

const light = (color, x, y, z) => {
  const light = new THREE.PointLight(color);

  light.position.set(x, y, z);

  return light;
};

const ballMaterial = new THREE.MeshPhongMaterial({
  color: 0xe8d880,
  shininess: 50
});

const stickMaterial = new THREE.MeshPhongMaterial({
  color: 0x404080,
  shininess: 50
});

const tileMaterial = new THREE.MeshPhongMaterial({
  color: 0x00ffff,
  shininess: 5
});

const makeScene = function*(ds, log) {
  log('Finding the pseudo-toroidal cover...');
  const cov = delaney.parse(yield callWorker({
    cmd: 'dsCover',
    val: `${ds}`
  }));

  log('Building the tiling object...');
  const til = tiling(ds, cov);

  log('Generating the net geometry...');
  const netObject3D = netModel(til, ballMaterial, stickMaterial);

  log('Making the tiling geometry...');
  const surfaces = yield callWorker({
    cmd: 'processSolids',
    val: tileSurfaces(til)
  });
  const tilingObject3D = tilingModel(surfaces, tileMaterial);

  log('Composing the scene...');
  const distance = 6;
  const camera = new THREE.PerspectiveCamera(25, 1, 0.1, 10000);
  camera.name = 'camera';
  camera.position.z = distance;

  camera.add(light(0xaaaaaa,  distance, 0.5*distance, distance));
  camera.add(light(0x555555, -0.5*distance, -0.25*distance, distance));
  camera.add(light(0x000033, 0.25*distance, 0.25*distance, -distance));

  const scene = new THREE.Scene();

  scene.add(netObject3D);
  scene.add(tilingObject3D);
  scene.add(camera);

  log('Scene complete!');
  return scene;
};

export default function(ds, log = console.log) {
  return csp.go(makeScene, ds, log);
};
<commit_msg>use a separate color for each tile<commit_after>import * as I     from 'immutable';
import * as THREE from 'three';
import * as csp   from 'plexus-csp';

import { matrices } from '../arithmetic/types';
const ops = matrices;

import * as delaney  from '../dsymbols/delaney';
import * as props    from '../dsymbols/properties';
import * as periodic from '../pgraphs/periodic';

import tiling from '../dsymbols/tilings';

import * as webworkers from '../common/webworkers';

const worker = webworkers.create('js/sceneWorker.js');
const callWorker = csp.nbind(worker, null);

const _normalized = v => ops.div(v, ops.norm(v));

const encode = value => JSON.stringify(ops.repr(value));
const decode = value => ops.fromRepr(JSON.parse(value));

const CoverVertex = I.Record({
  v: undefined,
  s: undefined
});

const graphPortion = (graph, start, dist) => {
  const adj  = periodic.adjacencies(graph);

  const v0 = new CoverVertex({ v: start, s: encode(ops.vector(graph.dim)) });
  let vertices = I.Map([[v0, 0]]);
  let edges = I.Set();
  let thisShell = I.List([v0]);

  I.Range(1, dist+1).forEach(i => {
    let nextShell = I.Set();
    thisShell.forEach(v => {
      const i = vertices.get(v);

      adj.get(v.v).forEach(t => {
        const w = new CoverVertex({
          v: t.v,
          s: encode(ops.plus(decode(v.s), t.s))
        });

        if (vertices.get(w) == null) {
          vertices = vertices.set(w, vertices.size);
          nextShell = nextShell.add(w);
        }

        const j = vertices.get(w);

        if (!edges.contains(I.List([i, j])) && !edges.contains(I.List([j, i])))
          edges = edges.add(I.List([i, j]));
      });
    });

    thisShell = nextShell;
  });

  let verts = I.List().asMutable();
  vertices.keySeq().forEach(v => {
    verts.set(vertices.get(v), { v: v.v, s: decode(v.s) });
  });

  return {
    vertices: verts.asImmutable(),
    edges   : edges.sort().map(e => e.toArray())
  };
};

const geometry = (vertices, faces) => {
  const geom = new THREE.Geometry();

  vertices.forEach(v => {
    geom.vertices.push(new THREE.Vector3(v[0], v[1], v[2]));
  });

  faces.forEach(f => {
    f.forEach((v, i) => {
      if (i > 0 && i+1 < f.length)
        geom.faces.push(new THREE.Face3(f[0], f[i], f[i+1]));
    });
  });

  geom.computeFaceNormals();
  geom.computeVertexNormals();
  return geom;
};

const stick = (p, q, radius, segments) => {
  const n = segments;
  const d = _normalized(ops.minus(q, p));
  const ex = [1,0,0];
  const ey = [0,1,0];
  const t = Math.abs(ops.times(d, ex)) > 0.9 ? ey : ex;
  const u = _normalized(ops.crossProduct(d, t));
  const v = _normalized(ops.crossProduct(d, u));
  const a = Math.PI * 2 / n;

  const section = I.Range(0, n).map(i => {
    const x = a * i;
    const c = Math.cos(x) * radius;
    const s = Math.sin(x) * radius;
    return ops.plus(ops.times(c, u), ops.times(s, v));
  });

  return geometry(
    I.List().concat(section.map(c => ops.plus(c, p)),
                    section.map(c => ops.plus(c, q))),
    I.Range(0, n).map(i => {
      const j = (i + 1) % n;
      return [i, j, j+n, i+n];
    })
  );
};

const ballAndStick = (
  name, positions, edges, ballRadius, stickRadius, ballMaterial, stickMaterial
) => {
  const model = new THREE.Object3D();
  const ball  = new THREE.SphereGeometry(ballRadius, 16, 8);

  positions.forEach(p => {
    const s = new THREE.Mesh(ball, ballMaterial);
    s.position.x = p[0];
    s.position.y = p[1];
    s.position.z = p[2];
    model.add(s);
  });

  edges.forEach(e => {
    const u = positions[e[0]];
    const v = positions[e[1]];
    const s = stick(u, v, stickRadius, 8);
    s.computeVertexNormals();
    model.add(new THREE.Mesh(s, stickMaterial));
  });

  return model;
};

const interpolate = (f, v, w) => ops.plus(w, ops.times(f, ops.minus(v, w)));

const chamberBasis = (pos, D) => {
  const t = pos.get(D).valueSeq();
  return t.rest().map(v => ops.minus(v, t.get(0)));
};

const tileSurface = (til, D0) => {
  const cov = til.cover;
  const ori = props.partialOrientation(cov);
  const pos = til.positions;
  const elms = props.orbit(cov, [0, 1, 2], D0);

  const sgn = ori.get(D0) *
    ops.sgn(ops.determinant(ops.cleanup(
      ops.times(chamberBasis(pos, D0).toJS(), til.basis))));

  const cornerOrbits =
    props.orbitReps(cov, [1, 2], elms).map(D => props.orbit(cov, [1, 2], D));

  const cornerPositions = I.List(cornerOrbits.map(orb => {
    const ps = pos.get(orb.first());
    return ops.times(interpolate(0.8, ps.get(0), ps.get(3)), til.basis);
  }));

  const cornerIndex = I.Map(cornerOrbits.flatMap(
    (orb, i) => orb.map(D => [D, i])));

  const faces = I.List(props.orbitReps(cov, [0, 1], elms)
    .map(D => sgn * ori.get(D) < 0 ? D : cov.s(0, D))
    .map(D => (
      props.orbit(cov, [0, 1], D)
        .filter((D, i) => i % 2 == 0)
        .map(D => cornerIndex.get(D)))));

  return {
    pos    : cornerPositions.map(p => ops.toJS(p)).toJS(),
    faces  : faces.toJS(),
    isFixed: I.Range(0, cornerPositions.size).map(i => true).toJS()
  };
};

const tileSurfaces = til => {
  return props.orbitReps(til.cover, [0, 1, 2])
    .map(D => tileSurface(til, D))
    .toJS();
};

const tilingModel = surfaces => {
  const model = new THREE.Object3D();
  const hue0 = Math.random();
  const n = surfaces.length;

  for (const i in surfaces) {
    const { pos, faces } = surfaces[i];
    const geom = geometry(pos, faces);
    const c = new THREE.Color();
    c.setHSL((hue0 + i / n) % 1, 1.0, 0.7);
    const mat = new THREE.MeshPhongMaterial({
      color: c,
      shininess: 15
    });
    const tileMesh = new THREE.Mesh(geom, mat);
    model.add(tileMesh);
    //model.add(new THREE.WireframeHelper(tilesMesh, 0x00ff00));
  }

  return model;
};

const netModel = (t, ballMaterial, stickMaterial) => {
  const net = t.graph;
  const g   = graphPortion(net, 0, 2);
  const pos = t.positions;
  let verts = g.vertices.map(v => {
    const p = ops.plus(pos.getIn([t.node2chamber.get(v.v), 0]), v.s);
    return ops.times(p, t.basis);
  }).toArray();
  if (delaney.dim(t.cover) == 2)
    verts = verts.map(p => [p[0], p[1], 0]);

  return ballAndStick(
    'cube',
    verts,
    g.edges,
    0.04,
    0.01,
    ballMaterial,
    stickMaterial
  );
};

const light = (color, x, y, z) => {
  const light = new THREE.PointLight(color);

  light.position.set(x, y, z);

  return light;
};

const ballMaterial = new THREE.MeshPhongMaterial({
  color: 0xe8d880,
  shininess: 50
});

const stickMaterial = new THREE.MeshPhongMaterial({
  color: 0x404080,
  shininess: 50
});

const makeScene = function*(ds, log) {
  log('Finding the pseudo-toroidal cover...');
  const cov = delaney.parse(yield callWorker({
    cmd: 'dsCover',
    val: `${ds}`
  }));

  log('Building the tiling object...');
  const til = tiling(ds, cov);

  log('Generating the net geometry...');
  const netObject3D = netModel(til, ballMaterial, stickMaterial);

  log('Making the tiling geometry...');
  const surfaces = yield callWorker({
    cmd: 'processSolids',
    val: tileSurfaces(til)
  });
  const tilingObject3D = tilingModel(surfaces);

  log('Composing the scene...');
  const distance = 6;
  const camera = new THREE.PerspectiveCamera(25, 1, 0.1, 10000);
  camera.name = 'camera';
  camera.position.z = distance;

  camera.add(light(0xaaaaaa,  distance, 0.5*distance, distance));
  camera.add(light(0x555555, -0.5*distance, -0.25*distance, distance));
  camera.add(light(0x000033, 0.25*distance, 0.25*distance, -distance));

  const scene = new THREE.Scene();

  scene.add(netObject3D);
  scene.add(tilingObject3D);
  scene.add(camera);

  log('Scene complete!');
  return scene;
};

export default function(ds, log = console.log) {
  return csp.go(makeScene, ds, log);
};
<|endoftext|>


<commit_before>/******************************************************
 * PATTERN LAB NODE
 * EDITION-NODE-GULP
 * The gulp wrapper around patternlab-node core, providing tasks to interact with the core library and move supporting frontend assets.
******************************************************/
var gulp = require('gulp'),
  path = require('path'),
  del = require('del'),
  uglify = require('gulp-uglify'),
  rename = require('gulp-rename'),
  concat = require('gulp-concat'),
  cssmin = require('gulp-cssnano'),
  sassLint = require('gulp-sass-lint'),
  cssLint = require('gulp-csslint'),
  sourcemaps = require('gulp-sourcemaps'),
  sass = require('gulp-sass'),
  browserSync = require('browser-sync').create(),
  argv = require('minimist')(process.argv.slice(2));

/******************************************************
 * COPY TASKS - stream assets from source to public
******************************************************/
// JS copy
gulp.task('pl-copy:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)} )
    .pipe(gulp.dest(path.resolve(paths().public.js)));
});

// Images copy
gulp.task('pl-copy:img', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().source.images)} )
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Favicon copy
gulp.task('pl-copy:favicon', function(){
  return gulp.src('favicon.ico', {cwd: path.resolve(paths().source.root)} )
    .pipe(gulp.dest(path.resolve(paths().public.root)));
});

// Fonts copy
gulp.task('pl-copy:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().source.fonts)})
    .pipe(gulp.dest(path.resolve(paths().public.fonts)));
});

// AJAX Copy
gulp.task('pl-copy:ajax', function(){
  return gulp.src(path.resolve(paths().source.ajax, '*.json'))
    .pipe(gulp.dest(path.resolve(paths().public.ajax)));
});

// CSS Copy
gulp.task('pl-copy:css', function(){
  return gulp.src(path.resolve(paths().source.css, '*.css'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream());
});

// Vendors copy
gulp.task('pl-copy:vendors', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().source.vendors)} )
    .pipe(gulp.dest(path.resolve(paths().public.vendors)));
});

// Styleguide Copy everything but css
gulp.task('pl-copy:styleguide', function(){
  return gulp.src(path.resolve(paths().source.styleguide, '**/!(*.css)'))
    .pipe(gulp.dest(path.resolve(paths().public.root)))
    .pipe(browserSync.stream());
});

// Styleguide Copy and flatten css
gulp.task('pl-copy:styleguide-css', function(){
  return gulp.src(path.resolve(paths().source.styleguide, '**/*.css'))
    .pipe(gulp.dest(function(file){
      //flatten anything inside the styleguide into a single output dir per http://stackoverflow.com/a/34317320/1790362
      file.path = path.join(file.base, path.basename(file.path));
      return path.resolve(path.join(paths().public.styleguide, 'css'));
    }))
    .pipe(browserSync.stream());
});

gulp.task('pl-compile:sass', function(){
  return gulp.src('*.scss',{cwd: path.resolve(paths().source.css)} )
    .pipe(sourcemaps.init())
    .pipe(sass({
      outputStyle: 'expanded',
      precision: 8
    }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream({match: '**/*.css'}));
})

gulp.task('pl-compile:validate-sass', function() {
  return gulp.src('**/*.scss',{cwd: path.resolve(paths().source.css)} )
  .pipe(sassLint())
  .pipe(sassLint.format());
})

gulp.task('pl-compile:validate-css', function() {
  return gulp.src('**/*.css',{cwd: path.resolve(paths().source.css)} )
  .pipe(cssLint())
  .pipe(cssLint.format());
})

/******************************************************
 * CLEAN TASKS - Clean assets
******************************************************/
// Clean
gulp.task('pl-clean:publish', function(){
  return del([path.resolve(paths().publish.root) + '**/*']);
});

gulp.task('pl-clean:public', function(){
  return del([path.resolve(paths().public.root) + '**/*']);
});

/******************************************************
 * PUBLISH TASKS - stream assets from public to dist
******************************************************/
// JS copy
gulp.task('p-dist:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().public.js)} )
    .pipe(gulp.dest(path.resolve(paths().publish.js)))
    .pipe(uglify())
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest(path.resolve(paths().publish.js)))
    .pipe(concat(paths().publish.combineName + '.min.js'))
    .pipe(gulp.dest(path.resolve(paths().publish.js)));
});

// Images copy
gulp.task('p-dist:img', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().public.images)} )
    .pipe(gulp.dest(path.resolve(paths().publish.images)));
});

// Favicon copy
gulp.task('p-dist:favicon', function(){
  return gulp.src('favicon.ico', {cwd: path.resolve(paths().public.root)} )
    .pipe(gulp.dest(path.resolve(paths().publish.root)));
});

// Fonts copy
gulp.task('p-dist:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().public.fonts)})
    .pipe(gulp.dest(path.resolve(paths().publish.fonts)));
});

// CSS Copy
gulp.task('p-dist:css', function(){
  return gulp.src(path.resolve(paths().public.css, '*.css'))
    .pipe(gulp.dest(path.resolve(paths().publish.css)))
    .pipe(cssmin({zindex: false}))
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest(path.resolve(paths().publish.css)))
    .pipe(concat(paths().publish.combineName + '.min.css'))
    .pipe(gulp.dest(path.resolve(paths().publish.css)));
});

/******************************************************
 * PATTERN LAB CONFIGURATION - API with core library
******************************************************/
//read all paths from our namespaced config file
var config = require('./patternlab-config.json'),
  patternlab = require('patternlab-node')(config);

function paths() {
  return config.paths;
}

function getConfiguredCleanOption() {
  return config.cleanPublic;
}

function build(done) {
  patternlab.build(done, getConfiguredCleanOption());
}

gulp.task('pl-stylesheets', gulp.series(
  'pl-copy:css',
  'pl-compile:sass',
  function(done){
    done();
  })
);

gulp.task('pl-assets', gulp.series(
  gulp.parallel(
    'pl-copy:js',
    'pl-copy:img',
    'pl-copy:favicon',
    'pl-copy:font',
    'pl-stylesheets',
    'pl-copy:ajax',
    'pl-copy:vendors',
    'pl-copy:styleguide',
    'pl-copy:styleguide-css'
  ),
  function(done){
    done();
  })
);

gulp.task('p-dist', gulp.series(
  gulp.parallel(
    'p-dist:js',
    'p-dist:img',
    'p-dist:favicon',
    'p-dist:font',
    'p-dist:css'
  ),
  function(done){
    done();
  })
);

gulp.task('pl-clean', gulp.series(
  gulp.parallel(
    'pl-clean:public',
    'pl-clean:publish'
  ),
  function(done){
    done();
  })
);

gulp.task('patternlab:version', function (done) {
  patternlab.version();
  done();
});

gulp.task('patternlab:help', function (done) {
  patternlab.help();
  done();
});

gulp.task('patternlab:patternsonly', function (done) {
  patternlab.patternsonly(done, getConfiguredCleanOption());
});

gulp.task('patternlab:liststarterkits', function (done) {
  patternlab.liststarterkits();
  done();
});

gulp.task('patternlab:loadstarterkit', function (done) {
  patternlab.loadstarterkit(argv.kit, argv.clean);
  done();
});

gulp.task('patternlab:build', gulp.series('pl-assets', build, function(done){
  done();
}));

/******************************************************
 * TESTS TASKS
******************************************************/
//unit test
gulp.task('pl-nodeunit', function(){
  return gulp.src('./test/**/*_tests.js')
    .pipe(nodeunit());
})

/******************************************************
 * SERVER AND WATCH TASKS
******************************************************/
// watch task utility functions
function getSupportedTemplateExtensions() {
  var engines = require('./node_modules/patternlab-node/core/lib/pattern_engines');
  return engines.getSupportedFileExtensions();
}
function getTemplateWatches() {
  return getSupportedTemplateExtensions().map(function (dotExtension) {
    return path.resolve(paths().source.patterns, '**/*' + dotExtension);
  });
}

function reload() {
  browserSync.reload();
}

function reloadCSS() {
  browserSync.reload('*.css');
}

function watch() {
  gulp.watch(path.resolve(paths().source.css, '**/*.{css,scss}'), { awaitWriteFinish: false }).on('change', gulp.series('pl-stylesheets'));
  gulp.watch(path.resolve(paths().source.js, '**/*.js'), { awaitWriteFinish: false }).on('change', gulp.series('pl-copy:js'));
  gulp.watch(path.resolve(paths().source.styleguide, '**/*.*'), { awaitWriteFinish: true }).on('change', gulp.series('pl-copy:styleguide', 'pl-copy:styleguide-css', reloadCSS));

  var patternWatches = [
    path.resolve(paths().source.patterns, '**/*.{json,mustache,md}'),
    path.resolve(paths().source.data, '*.json'),
    path.resolve(paths().source.ajax, '*.json'),
    path.resolve(paths().source.fonts + '/*'),
    path.resolve(paths().source.images + '/*'),
    path.resolve(paths().source.meta, '*'),
    path.resolve(paths().source.annotations + '/*')
  ].concat(getTemplateWatches());

  gulp.watch(patternWatches, { awaitWriteFinish: false }).on('change', gulp.series(build, reload));
}

gulp.task('patternlab:connect', gulp.series(function(done) {
  browserSync.init({
    server: {
      baseDir: path.resolve(paths().public.root)
    },
    snippetOptions: {
      // Ignore all HTML files within the templates folder
      blacklist: ['/index.html', '/', '/?*']
    },
    notify: {
      styles: [
        'display: none',
        'padding: 15px',
        'font-family: sans-serif',
        'position: fixed',
        'font-size: 1em',
        'z-index: 9999',
        'bottom: 0px',
        'right: 0px',
        'border-top-left-radius: 5px',
        'background-color: #1B2032',
        'opacity: 0.4',
        'margin: 0',
        'color: white',
        'text-align: center'
      ]
    }
  }, function(){
    console.log('PATTERN LAB NODE WATCHING FOR CHANGES');
    done();
  });
}));

/******************************************************
 * COMPOUND TASKS
******************************************************/
gulp.task('default', gulp.series('patternlab:build'));
gulp.task('patternlab:watch', gulp.series('patternlab:build', watch));
gulp.task('patternlab:serve', gulp.series('patternlab:build', 'patternlab:connect', watch));
gulp.task('patternlab:dist', gulp.series('p-dist'));
gulp.task('patternlab:clean', gulp.series('pl-clean'));
gulp.task('serve', gulp.series('patternlab:serve'));
gulp.task('clean', gulp.series('patternlab:clean'));
gulp.task('publish', gulp.series('patternlab:clean', 'patternlab:build', 'patternlab:dist'));
<commit_msg>Fix gulp tasks<commit_after>/******************************************************
 * PATTERN LAB NODE
 * EDITION-NODE-GULP
 * The gulp wrapper around patternlab-node core, providing tasks to interact with the core library and move supporting frontend assets.
******************************************************/
var gulp = require('gulp'),
  path = require('path'),
  del = require('del'),
  uglify = require('gulp-uglify'),
  rename = require('gulp-rename'),
  concat = require('gulp-concat'),
  cssmin = require('gulp-cssnano'),
  sassLint = require('gulp-sass-lint'),
  cssLint = require('gulp-csslint'),
  sourcemaps = require('gulp-sourcemaps'),
  sass = require('gulp-sass'),
  browserSync = require('browser-sync').create(),
  argv = require('minimist')(process.argv.slice(2));

/******************************************************
 * COPY TASKS - stream assets from source to public
******************************************************/
// JS copy
gulp.task('pl-copy:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().source.js)} )
    .pipe(gulp.dest(path.resolve(paths().public.js)));
});

// Images copy
gulp.task('pl-copy:img', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().source.images)} )
    .pipe(gulp.dest(path.resolve(paths().public.images)));
});

// Favicon copy
gulp.task('pl-copy:favicon', function(){
  return gulp.src('favicon.ico', {cwd: path.resolve(paths().source.root)} )
    .pipe(gulp.dest(path.resolve(paths().public.root)));
});

// Fonts copy
gulp.task('pl-copy:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().source.fonts)})
    .pipe(gulp.dest(path.resolve(paths().public.fonts)));
});

// AJAX Copy
gulp.task('pl-copy:ajax', function(){
  return gulp.src(path.resolve(paths().source.ajax, '*.json'))
    .pipe(gulp.dest(path.resolve(paths().public.ajax)));
});

// CSS Copy
gulp.task('pl-copy:css', function(){
  return gulp.src(path.resolve(paths().source.css, '*.css'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream());
});

// Vendors copy
gulp.task('pl-copy:vendors', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().source.vendors)} )
    .pipe(gulp.dest(path.resolve(paths().public.vendors)));
});

// Styleguide Copy everything but css
gulp.task('pl-copy:styleguide', function(){
  return gulp.src(path.resolve(paths().source.styleguide, '**/!(*.css)'))
    .pipe(gulp.dest(path.resolve(paths().public.root)))
    .pipe(browserSync.stream());
});

// Styleguide Copy and flatten css
gulp.task('pl-copy:styleguide-css', function(){
  return gulp.src(path.resolve(paths().source.styleguide, '**/*.css'))
    .pipe(gulp.dest(function(file){
      //flatten anything inside the styleguide into a single output dir per http://stackoverflow.com/a/34317320/1790362
      file.path = path.join(file.base, path.basename(file.path));
      return path.resolve(path.join(paths().public.styleguide, 'css'));
    }))
    .pipe(browserSync.stream());
});

gulp.task('pl-compile:sass', function(){
  return gulp.src('*.scss',{cwd: path.resolve(paths().source.css)} )
    .pipe(sourcemaps.init())
    .pipe(sass({
      outputStyle: 'expanded',
      precision: 8
    }))
    .pipe(sourcemaps.write('.'))
    .pipe(gulp.dest(path.resolve(paths().public.css)))
    .pipe(browserSync.stream({match: '**/*.css'}));
})

gulp.task('pl-compile:validate-sass', function() {
  return gulp.src('**/*.scss',{cwd: path.resolve(paths().source.css)} )
  .pipe(sassLint())
  .pipe(sassLint.format());
})

gulp.task('pl-compile:validate-css', function() {
  return gulp.src('**/*.css',{cwd: path.resolve(paths().source.css)} )
  .pipe(cssLint())
  .pipe(cssLint.format());
})

/******************************************************
 * CLEAN TASKS - Clean assets
******************************************************/
// Clean
gulp.task('pl-clean:publish', function(){
  return del([path.resolve(paths().publish.root) + '**/*']);
});

gulp.task('pl-clean:public', function(){
  return del([path.resolve(paths().public.root) + '**/*']);
});

/******************************************************
 * PUBLISH TASKS - stream assets from public to dist
******************************************************/
// JS copy
gulp.task('pl-dist:js', function(){
  return gulp.src('**/*.js', {cwd: path.resolve(paths().public.js)} )
    .pipe(gulp.dest(path.resolve(paths().publish.js)))
    .pipe(uglify())
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest(path.resolve(paths().publish.js)))
    .pipe(concat(paths().publish.combineName + '.min.js'))
    .pipe(gulp.dest(path.resolve(paths().publish.js)));
});

// Images copy
gulp.task('pl-dist:img', function(){
  return gulp.src('**/*.*',{cwd: path.resolve(paths().public.images)} )
    .pipe(gulp.dest(path.resolve(paths().publish.images)));
});

// Favicon copy
gulp.task('pl-dist:favicon', function(){
  return gulp.src('favicon.ico', {cwd: path.resolve(paths().public.root)} )
    .pipe(gulp.dest(path.resolve(paths().publish.root)));
});

// Fonts copy
gulp.task('pl-dist:font', function(){
  return gulp.src('*', {cwd: path.resolve(paths().public.fonts)})
    .pipe(gulp.dest(path.resolve(paths().publish.fonts)));
});

// CSS Copy
gulp.task('pl-dist:css', function(){
  return gulp.src(path.resolve(paths().public.css, '*.css'))
    .pipe(gulp.dest(path.resolve(paths().publish.css)))
    .pipe(cssmin({zindex: false}))
    .pipe(rename({suffix: '.min'}))
    .pipe(gulp.dest(path.resolve(paths().publish.css)))
    .pipe(concat(paths().publish.combineName + '.min.css'))
    .pipe(gulp.dest(path.resolve(paths().publish.css)));
});

/******************************************************
 * PATTERN LAB CONFIGURATION - API with core library
******************************************************/
//read all paths from our namespaced config file
var config = require('./patternlab-config.json'),
  patternlab = require('patternlab-node')(config);

function paths() {
  return config.paths;
}

function getConfiguredCleanOption() {
  return config.cleanPublic;
}

function build(done) {
  patternlab.build(done, getConfiguredCleanOption());
}

gulp.task('pl-stylesheets', gulp.series(
  'pl-copy:css',
  'pl-compile:sass',
  function(done){
    done();
  })
);

gulp.task('pl-assets', gulp.series(
  gulp.parallel(
    'pl-copy:js',
    'pl-copy:img',
    'pl-copy:favicon',
    'pl-copy:font',
    'pl-stylesheets',
    'pl-copy:ajax',
    'pl-copy:vendors',
    'pl-copy:styleguide',
    'pl-copy:styleguide-css'
  ),
  function(done){
    done();
  })
);

gulp.task('pl-dist', gulp.series(
  gulp.parallel(
    'pl-dist:js',
    'pl-dist:img',
    'pl-dist:favicon',
    'pl-dist:font',
    'pl-dist:css'
  ),
  function(done){
    done();
  })
);

gulp.task('pl-clean', gulp.series(
  gulp.parallel(
    'pl-clean:public',
    'pl-clean:publish'
  ),
  function(done){
    done();
  })
);

gulp.task('patternlab:version', function (done) {
  patternlab.version();
  done();
});

gulp.task('patternlab:help', function (done) {
  patternlab.help();
  done();
});

gulp.task('patternlab:patternsonly', function (done) {
  patternlab.patternsonly(done, getConfiguredCleanOption());
});

gulp.task('patternlab:liststarterkits', function (done) {
  patternlab.liststarterkits();
  done();
});

gulp.task('patternlab:loadstarterkit', function (done) {
  patternlab.loadstarterkit(argv.kit, argv.clean);
  done();
});

gulp.task('patternlab:build', gulp.series('pl-assets', build, function(done){
  done();
}));

/******************************************************
 * TESTS TASKS
******************************************************/
//unit test
gulp.task('pl-nodeunit', function(){
  return gulp.src('./test/**/*_tests.js')
    .pipe(nodeunit());
})

/******************************************************
 * SERVER AND WATCH TASKS
******************************************************/
// watch task utility functions
function getSupportedTemplateExtensions() {
  var engines = require('./node_modules/patternlab-node/core/lib/pattern_engines');
  return engines.getSupportedFileExtensions();
}
function getTemplateWatches() {
  return getSupportedTemplateExtensions().map(function (dotExtension) {
    return path.resolve(paths().source.patterns, '**/*' + dotExtension);
  });
}

function reload() {
  browserSync.reload();
}

function reloadCSS() {
  browserSync.reload('*.css');
}

function watch() {
  gulp.watch(path.resolve(paths().source.css, '**/*.{css,scss}'), { awaitWriteFinish: false }).on('change', gulp.series('pl-stylesheets'));
  gulp.watch(path.resolve(paths().source.js, '**/*.js'), { awaitWriteFinish: false }).on('change', gulp.series('pl-copy:js'));
  gulp.watch(path.resolve(paths().source.styleguide, '**/*.*'), { awaitWriteFinish: true }).on('change', gulp.series('pl-copy:styleguide', 'pl-copy:styleguide-css', reloadCSS));

  var patternWatches = [
    path.resolve(paths().source.patterns, '**/*.{json,mustache,md}'),
    path.resolve(paths().source.data, '*.json'),
    path.resolve(paths().source.ajax, '*.json'),
    path.resolve(paths().source.fonts + '/*'),
    path.resolve(paths().source.images + '/*'),
    path.resolve(paths().source.meta, '*'),
    path.resolve(paths().source.annotations + '/*')
  ].concat(getTemplateWatches());

  gulp.watch(patternWatches, { awaitWriteFinish: false }).on('change', gulp.series(build, reload));
}

gulp.task('patternlab:connect', gulp.series(function(done) {
  browserSync.init({
    server: {
      baseDir: path.resolve(paths().public.root)
    },
    snippetOptions: {
      // Ignore all HTML files within the templates folder
      blacklist: ['/index.html', '/', '/?*']
    },
    notify: {
      styles: [
        'display: none',
        'padding: 15px',
        'font-family: sans-serif',
        'position: fixed',
        'font-size: 1em',
        'z-index: 9999',
        'bottom: 0px',
        'right: 0px',
        'border-top-left-radius: 5px',
        'background-color: #1B2032',
        'opacity: 0.4',
        'margin: 0',
        'color: white',
        'text-align: center'
      ]
    }
  }, function(){
    console.log('PATTERN LAB NODE WATCHING FOR CHANGES');
    done();
  });
}));

/******************************************************
 * COMPOUND TASKS
******************************************************/
gulp.task('default', gulp.series('patternlab:build'));
gulp.task('patternlab:watch', gulp.series('patternlab:build', watch));
gulp.task('patternlab:serve', gulp.series('patternlab:build', 'patternlab:connect', watch));
gulp.task('patternlab:dist', gulp.series('pl-dist'));
gulp.task('patternlab:clean', gulp.series('pl-clean'));
gulp.task('serve', gulp.series('patternlab:serve'));
gulp.task('clean', gulp.series('patternlab:clean'));
gulp.task('publish', gulp.series('patternlab:clean', 'patternlab:build', 'patternlab:dist'));
<|endoftext|>


<commit_before>'use strict'

module.exports = function (grunt) {
  var node = grunt.option('node') || process.env.nodejs_version || process.env.TRAVIS_NODE_VERSION || ''
  var platform = grunt.option('platform') || process.env.PLATFORM || process.env.TRAVIS ? 'x64' : ''
  var os = grunt.option('os') || process.env.APPVEYOR ? 'windows' : process.env.TRAVIS ? 'linux' : ''

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    uglify: {
      js: {
        files: {
          'app/tmp/juice-shop.min.js': [ 'app/tmp/juice-shop.js' ]
        },
        options: {
          mangle: true
        }
      },
      dist: {
        files: {
          'app/dist/juice-shop.min.js': [ 'app/tmp/juice-shop.min.js' ]
        }
      }
    },

    ngtemplates: {
      juiceShop: {
        cwd: 'app',
        src: [ 'views/*.html' ],
        dest: 'app/tmp/views.js'
      }
    },

    clean: {
      temp: {
        src: [ 'app/tmp' ]
      },
      dist: {
        src: [ 'app/dist' ]
      },
      pckg: {
        src: [ 'dist' ]
      }
    },

    concat: {
      options: {
        separator: ';'
      },
      js: {
        src: [ 'app/js/**/*.js' ],
        dest: 'app/tmp/juice-shop.js'
      },
      dist: {
        src: [ 'app/tmp/juice-shop.min.js', 'app/tmp/*.js' ],
        dest: 'app/tmp/juice-shop.min.js'
      }
    },

    compress: {
      pckg: {
        options: {
          mode: os === 'linux' ? 'tgz' : 'zip',
          archive: 'dist/<%= pkg.name %>-<%= pkg.version %>' + (node ? ('_node' + node) : '') + (os ? ('_' + os) : '') + (platform ? ('_' + platform) : '') + (os === 'linux' ? '.tgz' : '.zip')
        },
        files: [
          {
            src: [
              '*.md',
              'app.js',
              'server.js',
              'package.json',
              'ctf.key',
              'swagger.yml',
              'app/index.template.html',
              'app/node_modules/**',
              'app/css/*.css',
              'app/css/geo-bootstrap/**',
              'app/dist/juice-shop.min.js',
              'app/i18n/*.json',
              'app/private/**',
              'app/public/**',
              'config/*.yml',
              'data/*.js',
              'encryptionkeys/**',
              'ftp/**',
              'lib/*.js',
              'models/*.js',
              'routes/*.js',
              'node_modules/**'
            ]
          }
        ]
      }
    }
  })

  grunt.loadNpmTasks('grunt-angular-templates')
  grunt.loadNpmTasks('grunt-contrib-clean')
  grunt.loadNpmTasks('grunt-contrib-concat')
  grunt.loadNpmTasks('grunt-contrib-uglify')
  grunt.loadNpmTasks('grunt-contrib-compress')

  grunt.registerTask('minify', [ 'clean:dist', 'concat:js', 'uglify:js', 'ngtemplates:juiceShop', 'concat:dist', 'uglify:dist', 'clean:temp' ])
  grunt.registerTask('package', [ 'clean:pckg', 'minify', 'compress:pckg' ])
}
<commit_msg>Include YAML data files when packaging<commit_after>'use strict'

module.exports = function (grunt) {
  var node = grunt.option('node') || process.env.nodejs_version || process.env.TRAVIS_NODE_VERSION || ''
  var platform = grunt.option('platform') || process.env.PLATFORM || process.env.TRAVIS ? 'x64' : ''
  var os = grunt.option('os') || process.env.APPVEYOR ? 'windows' : process.env.TRAVIS ? 'linux' : ''

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    uglify: {
      js: {
        files: {
          'app/tmp/juice-shop.min.js': [ 'app/tmp/juice-shop.js' ]
        },
        options: {
          mangle: true
        }
      },
      dist: {
        files: {
          'app/dist/juice-shop.min.js': [ 'app/tmp/juice-shop.min.js' ]
        }
      }
    },

    ngtemplates: {
      juiceShop: {
        cwd: 'app',
        src: [ 'views/*.html' ],
        dest: 'app/tmp/views.js'
      }
    },

    clean: {
      temp: {
        src: [ 'app/tmp' ]
      },
      dist: {
        src: [ 'app/dist' ]
      },
      pckg: {
        src: [ 'dist' ]
      }
    },

    concat: {
      options: {
        separator: ';'
      },
      js: {
        src: [ 'app/js/**/*.js' ],
        dest: 'app/tmp/juice-shop.js'
      },
      dist: {
        src: [ 'app/tmp/juice-shop.min.js', 'app/tmp/*.js' ],
        dest: 'app/tmp/juice-shop.min.js'
      }
    },

    compress: {
      pckg: {
        options: {
          mode: os === 'linux' ? 'tgz' : 'zip',
          archive: 'dist/<%= pkg.name %>-<%= pkg.version %>' + (node ? ('_node' + node) : '') + (os ? ('_' + os) : '') + (platform ? ('_' + platform) : '') + (os === 'linux' ? '.tgz' : '.zip')
        },
        files: [
          {
            src: [
              '*.md',
              'app.js',
              'server.js',
              'package.json',
              'ctf.key',
              'swagger.yml',
              'app/index.template.html',
              'app/node_modules/**',
              'app/css/*.css',
              'app/css/geo-bootstrap/**',
              'app/dist/juice-shop.min.js',
              'app/i18n/*.json',
              'app/private/**',
              'app/public/**',
              'config/*.yml',
              'data/*.js',
              'data/static/*.yml',
              'encryptionkeys/**',
              'ftp/**',
              'lib/*.js',
              'models/*.js',
              'routes/*.js',
              'node_modules/**'
            ]
          }
        ]
      }
    }
  })

  grunt.loadNpmTasks('grunt-angular-templates')
  grunt.loadNpmTasks('grunt-contrib-clean')
  grunt.loadNpmTasks('grunt-contrib-concat')
  grunt.loadNpmTasks('grunt-contrib-uglify')
  grunt.loadNpmTasks('grunt-contrib-compress')

  grunt.registerTask('minify', [ 'clean:dist', 'concat:js', 'uglify:js', 'ngtemplates:juiceShop', 'concat:dist', 'uglify:dist', 'clean:temp' ])
  grunt.registerTask('package', [ 'clean:pckg', 'minify', 'compress:pckg' ])
}
<|endoftext|>


<commit_before>/*jslint indent:2, node:true*/
module.exports = function (grunt) {
  "use strict";
  grunt.initConfig({

    concurrent: {
      background: ['connect', 'watch'],
      options: {
        logConcurrentOutput: true
      }
    },

    connect: {
      server: {
        options: {
          port: 9999
        }
      },
      keepalive: {
        options: {
          port: 9999,
          keepalive: true
        }
      }
    },

    watch: {
      source: {
        files: ['scripts/**', 'tests/**'],
        tasks: ['default'],
        options: {
          livereload: true
        }
      }
    },

    jslint: {
      all: {
        src: [
          'scripts/**/*.js',
          '!scripts/frag/05-implementations.js',
          '!**/vendor/**/*'
        ],
        directives: {
          "browser": true,
          "es5": true,
          "nomen": true,
          "indent": 2,
          "stupid": true,
          "predef" : [
            "define",
            "require",
            "requirejs",
            "$",
            "_",
            "Backbone",
            "Mustache",
            "Pouch",
            "BlinkForms",
            "jquerymobile",
            "BMP",
            "Modernizr"
          ]
        },
        options: {
          errorsOnly: true
        }
      }
    },

    mocha: {
      all: {
        options: {
          urls: [
            'http://localhost:9999/tests/index.html',
            'http://localhost:9999/tests/build.html'
          ]
        }
      },
      options: {
        bail: true,
        log: true
      }
    },

    clean: ['build'],

    requirejs: {
      feature: {
        options: {
          baseUrl: 'scripts',
          name: 'feature',
          out: 'build/feature.js',
          optimize: "none",
          paths: {
            feature: '../bower_components/amd-feature/feature'
          }
        }
      },
      compile: {
        options: {
          baseUrl: 'scripts',
          name: '../bower_components/almond/almond',
          include: ['main', 'router'],
          out: 'build/bic.js',
          optimize: "none",
          paths: {
            pouchdb: '../bower_components/pouchdb/dist/pouchdb-nightly',
            text: '../bower_components/requirejs-text/text',
            domReady: '../bower_components/requirejs-domready/domReady',
            feature: '../bower_components/amd-feature/feature',
            'es5-shim': 'empty:'
          },
          wrap: {
            startFile: [
              'scripts/frag/00-config.js',
              'scripts/frag/05-implementations.js',
              'build/feature.js',
              'scripts/frag/10-start.frag'
            ],
            endFile: 'scripts/frag/99-end.frag'
          }//,
          // wrap: true,
          //insertRequire: ["main"]
        }
      },
      formsdeps: {
        options: {
          baseUrl: "bower_components",
          include: ['picker.date', 'picker.time', 'moment'],
          out: 'js/formsdeps.min.js',
          paths: {
            jquery: 'empty:',
            "picker": 'pickadate/lib/picker',
            "picker.date": 'pickadate/lib/picker.date',
            "picker.time": 'pickadate/lib/picker.time',
            "moment": 'momentjs/min/moment.min'
          }
        }
      },
      options: {
        uglify: {
          max_line_length: 80
        },
        uglify2: {
          output: {
            max_line_len: 80
          },
          warnings: false
        }
      }
    },

    'saucelabs-mocha': {
      all: { options: require('./saucelabs') }
    },

    copy: {
      main: {
        files: [
          {
            src: 'build/bic.js',
            dest: 'js/bic.js'
          }
        ]
      }
    },

    uglify: {
      bic: {
        files: {
          'js/bic.min.js': [
            'js/bic.js'
          ]
        }
      },
      options: {
        sourceMap: true,
        sourceMapIncludeSources: true,
        preserveComments: 'some',
        beautify: {
          ascii_only: true,
          max_line_len: 80
        },
        compress: {
          screw_ie8: false,
          properties: false
        },
        mangle: {
          screw_ie8: false
        }
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-jslint');
  grunt.loadNpmTasks('grunt-mocha');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-concurrent');
  grunt.loadNpmTasks('grunt-saucelabs');

  grunt.registerTask('test', ['build', 'jslint', 'connect:server', 'mocha']);
  grunt.registerTask('travis', ['test', 'saucelabs-mocha']);

  grunt.registerTask('build', ['clean', 'requirejs', 'copy', 'clean', 'uglify']);
  grunt.registerTask('develop', ['concurrent']);
  grunt.registerTask('default', ['test']);

};
<commit_msg>BIC-33 # fix accidental leak of internal "implementations" AMD module<commit_after>/*jslint indent:2, node:true*/
module.exports = function (grunt) {
  "use strict";
  grunt.initConfig({

    concurrent: {
      background: ['connect', 'watch'],
      options: {
        logConcurrentOutput: true
      }
    },

    connect: {
      server: {
        options: {
          port: 9999
        }
      },
      keepalive: {
        options: {
          port: 9999,
          keepalive: true
        }
      }
    },

    watch: {
      source: {
        files: ['scripts/**', 'tests/**'],
        tasks: ['default'],
        options: {
          livereload: true
        }
      }
    },

    jslint: {
      all: {
        src: [
          'scripts/**/*.js',
          '!scripts/frag/05-implementations.js',
          '!**/vendor/**/*'
        ],
        directives: {
          "browser": true,
          "es5": true,
          "nomen": true,
          "indent": 2,
          "stupid": true,
          "predef" : [
            "define",
            "require",
            "requirejs",
            "$",
            "_",
            "Backbone",
            "Mustache",
            "Pouch",
            "BlinkForms",
            "jquerymobile",
            "BMP",
            "Modernizr"
          ]
        },
        options: {
          errorsOnly: true
        }
      }
    },

    mocha: {
      all: {
        options: {
          urls: [
            'http://localhost:9999/tests/index.html',
            'http://localhost:9999/tests/build.html'
          ]
        }
      },
      options: {
        bail: true,
        log: true
      }
    },

    clean: ['build'],

    requirejs: {
      feature: {
        options: {
          baseUrl: 'scripts',
          name: 'feature',
          exclude: ['implementations'],
          out: 'build/feature.js',
          optimize: "none",
          paths: {
            feature: '../bower_components/amd-feature/feature'
          }
        }
      },
      compile: {
        options: {
          baseUrl: 'scripts',
          name: '../bower_components/almond/almond',
          include: ['main', 'router'],
          out: 'build/bic.js',
          optimize: "none",
          paths: {
            pouchdb: '../bower_components/pouchdb/dist/pouchdb-nightly',
            text: '../bower_components/requirejs-text/text',
            domReady: '../bower_components/requirejs-domready/domReady',
            feature: '../bower_components/amd-feature/feature',
            'es5-shim': 'empty:'
          },
          wrap: {
            startFile: [
              'scripts/frag/00-config.js',
              'scripts/frag/05-implementations.js',
              'build/feature.js',
              'scripts/frag/10-start.frag'
            ],
            endFile: 'scripts/frag/99-end.frag'
          }//,
          // wrap: true,
          //insertRequire: ["main"]
        }
      },
      formsdeps: {
        options: {
          baseUrl: "bower_components",
          include: ['picker.date', 'picker.time', 'moment'],
          out: 'js/formsdeps.min.js',
          paths: {
            jquery: 'empty:',
            "picker": 'pickadate/lib/picker',
            "picker.date": 'pickadate/lib/picker.date',
            "picker.time": 'pickadate/lib/picker.time',
            "moment": 'momentjs/min/moment.min'
          }
        }
      },
      options: {
        uglify: {
          max_line_length: 80
        },
        uglify2: {
          output: {
            max_line_len: 80
          },
          warnings: false
        }
      }
    },

    'saucelabs-mocha': {
      all: { options: require('./saucelabs') }
    },

    copy: {
      main: {
        files: [
          {
            src: 'build/bic.js',
            dest: 'js/bic.js'
          }
        ]
      }
    },

    uglify: {
      bic: {
        files: {
          'js/bic.min.js': [
            'js/bic.js'
          ]
        }
      },
      options: {
        sourceMap: true,
        sourceMapIncludeSources: true,
        preserveComments: 'some',
        beautify: {
          ascii_only: true,
          max_line_len: 80
        },
        compress: {
          screw_ie8: false,
          properties: false
        },
        mangle: {
          screw_ie8: false
        }
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-jslint');
  grunt.loadNpmTasks('grunt-mocha');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-requirejs');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-concurrent');
  grunt.loadNpmTasks('grunt-saucelabs');

  grunt.registerTask('test', ['build', 'jslint', 'connect:server', 'mocha']);
  grunt.registerTask('travis', ['test', 'saucelabs-mocha']);

  grunt.registerTask('build', ['clean', 'requirejs', 'copy', 'clean', 'uglify']);
  grunt.registerTask('develop', ['concurrent']);
  grunt.registerTask('default', ['test']);

};
<|endoftext|>