<commit_before>/*!
 * Copyright 2014 Digital Services, University of Cambridge Licensed
 * under the Educational Community License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

var _ = require('lodash');
var fs = require('fs');
var util = require('util');
var vm = require('vm');

module.exports = function(grunt) {

    ///////////////////
    // CONFIGURATION //
    ///////////////////

    grunt.initConfig({
        'target': 'target',
        'clean': ['<%= target %>'],
        'exec': {
            'removeTarget': {
                'cmd': 'rm -rf <%= target %>/optimized/<%= target %>'
            }
        },
        'copy': {
            'main': {
                'files': [
                    {
                        'expand': true,
                        'src': [
                            '**',
                            '!<%= target %>/.*/**',
                            '!node_modules/**'
                        ],
                        'dest': '<%= target %>/original'
                    }
                ]
            }
        },
        'requirejs': {
            'optimize': {
                'options': {
                    'appDir': './',
                    'baseUrl': './shared',
                    'mainConfigFile': './shared/gh/api/gh.bootstrap.js',
                    'dir': '<%= target %>/optimized',
                    'optimize': 'uglify',
                    'preserveLicenseComments': false,
                    'optimizeCss': 'standard',
                    // TODO: Replace this with a saner value
                    // @see https://github.com/jrburke/r.js/pull/653
                    'cssImportIgnore': '//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,300,600,700&subset=latin,cyrillic-ext,latin-ext,greek-ext',
                    'inlineText': true,
                    'useStrict': false,
                    'pragmas': {},
                    'skipPragmas': false,
                    'skipModuleInsertion': false,
                    'modules': [{
                        'name': 'gh.core'
                    }],
                    'fileExclusionRegExp': /^(\.|apache|etc|node_modules|tools)/,
                    'logLevel': 2
                }
            }
        },
        'ver': {
            'gh': {
                'basedir': '<%= target %>/optimized',
                'phases': [

                    // 1. Hash all the vendor fonts
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/fonts'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/css',
                            ],
                            'includeExts': ['css']
                        })
                    },

                    // 2. Hash all the vendor CSS and JS
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/css',
                                '<%= target %>/optimized/shared/vendor/js'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/apps',
                                '<%= target %>/optimized/shared',
                                '<%= target %>/optimized/tests'
                            ],
                            'includeExts': ['html']
                        })
                    },

                    // 3. Hash the GH CSS and JS files
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/gh/**'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/apps',
                                '<%= target %>/optimized/shared',
                                '<%= target %>/optimized/tests'
                            ],
                            'includeExts': ['html']
                        })
                    }
                ],
                'version': '<%= target %>/optimized/hashes.json'
            }
        },
        'coveralls': {
            'gh': {
                'src': 'coverage/lcov/lcov.info',
                'options': {
                    'src': 'coverage/lcov/lcov.info'
                }
            }
        },
        'ghost': {
            'dist': {
                'filesSrc': [
                    'tests/casperjs/tests/*.js'
                ],
                // CasperJS test command options
                'options': {
                    // Specify the files to be included in each test
                    'includes': [
                        'tests/casperjs/util/include/gh.api.admin.js',
                        'tests/casperjs/util/include/gh.api.app.js',
                        'tests/casperjs/util/include/gh.api.authentication.js',
                        'tests/casperjs/util/include/gh.api.config.js',
                        'tests/casperjs/util/include/gh.api.event.js',
                        'tests/casperjs/util/include/gh.api.orgunit.js',
                        'tests/casperjs/util/include/gh.api.series.js',
                        'tests/casperjs/util/include/gh.api.tenant.js',
                        'tests/casperjs/util/include/gh.api.user.js',
                        'tests/casperjs/util/include/util.js'
                    ],
                    // Prepare te testing environment before starting the tests
                    'pre': ['tests/casperjs/util/prep.js'],
                    // Don't stop casperjs after first test failure
                    'failFast': false
                }
            }
        },
        'csslint': {
            'options': {
                'ids': false // ignore "Don't use IDs in CSS selectors" warning
            },
            'files': [
                'apps/**/*.css',
                'shared/gh/**/*.css'
            ]
        },
        'jshint': {
            'options': {
                'sub': true
            },
            'files': [
                'grunt.js',
                'apps/**/*.js',
                'shared/gh/**/*.js',
            ]
        },
        'qunit': {
            'gh': {
                'urls': ['http://admin.grasshopper.com/tests/qunit/tests/api.html'],
                'options': {
                    'urls': ['http://admin.grasshopper.com/tests/qunit/tests/api.html'],
                    'coverage': {
                        'disposeCollector': true,
                        'baseUrl': ".",
                        'src': ['shared/gh/api/*.js'],
                        'instrumentedFiles': 'target/coverage',
                        'lcovReport': 'coverage/lcov',
                        'htmlReport': 'coverage/html',
                        'linesThresholdPct': 85
                    }
                }
            }
        }
    });

    ///////////////
    // NPM TASKS //
    ///////////////

    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-csslint');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-coveralls');
    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-ghost');
    grunt.loadNpmTasks('grunt-qunit-istanbul');
    grunt.loadNpmTasks('grunt-text-replace');
    grunt.loadNpmTasks('grunt-ver');

    //////////////////
    // GRUNT TASKS  //
    //////////////////

    // Lint tasks for JavaScript and CSS
    grunt.registerTask('lint', ['jshint', 'csslint']);
    grunt.registerTask('test', ['lint', 'qunit', 'ghost']);

    /**
     * Task that changes the paths in the optimized Apache configuration files
     */
    grunt.registerTask('changePaths', function() {

        // Get all the apps
        var apps = fs.readdirSync('apps');
        var basedir = grunt.config('target') + '/optimized/';

        // Loop the Apache configuration files for every app
        _.each(apps, function(appName) {
            var file = basedir + 'apache/app_' + appName + '.conf';
            var fileContent = grunt.file.read(file);
            fileContent = fileContent.replace(/grasshopper-ui/g, 'grasshopper-ui/' + grunt.config('target') + '/optimized');
            grunt.file.write(file, fileContent);
            grunt.log.writeln(String('Apache file changed for app_' + appName + '.conf').green);
        });
    });

    /**
     * Task to fill out the Apache config template
     */
    grunt.registerTask('configApache', function() {
        var infile = './apache/apache.js';

        // Get all the apps
        var apps = fs.readdirSync('apps');

        // Get the config
        var apacheConfig = require('./apache/apache.js');

        // Get each apps config and overlay it
        _.each(apps, function(app) {
            apacheConfig[app] = require('./apps/' + app + '/apache/apache.js');
        });
        grunt.config.set('apacheConf', apacheConfig);

        // Render the httpd config
        var httpdTemplate = grunt.file.read('apache/httpd.conf');
        var renderedConfig = grunt.template.process(httpdTemplate);
        var outfile = grunt.config('target') + '/optimized/apache/httpd.conf';
        grunt.file.write(outfile, renderedConfig);
        grunt.log.writeln('httpd.conf rendered at '.green + outfile.green);

        // Render each app/vhost
        _.each(apps, function(appName) {
            apacheConfig[appName].errorLog = apacheConfig.logDirectory + appName + '_error.log';
            apacheConfig[appName].customLog = apacheConfig.logDirectory + appName + '_custom.log';

            var template = grunt.file.read('apps/' + appName + '/apache/app.conf');
            var renderedConfig = grunt.template.process(template);
            var outfile = grunt.config('target') + '/optimized/apache/app_' + appName + '.conf';
            grunt.file.write(outfile, renderedConfig);
            grunt.log.writeln(appName + '.conf rendered at '.green + outfile.green);
        });
    });

    /**
     * Task to hash files
     */
    grunt.registerTask('hashFiles', function() {
        this.requires('requirejs');

        // Hash the GH files
        grunt.task.run('ver:gh');

        // Update the files in the bootstrap
        grunt.task.run('updateBootstrapPaths');
    });

    /**
     * Task that creates a release build
     *
     * @param  {String}    outputDir    The directory where the build should be stored
     *
     *  * Example:
     *  * grunt release:/tmp/release
     *  *
     *  * This will run the entire UI build (minification, hashing, apache config, etc, ..) and create the following folders:
     *  * /tmp/release/optimized  -  contains the minified UI sources
     *  * /tmp/release/original   -  contains the original UI files
     *  *
     */
    grunt.registerTask('release', function(outputDir) {
        if (!outputDir) {
            return grunt.log.writeln('Please provide a path where the release files should be copied to'.red);
        }
        grunt.config.target = outputDir;

        // Run the default production build task
        grunt.task.run('default');

        // Change the paths in the optimized Apache files
        grunt.task.run('changePaths');
    });

    /**
     * Task to update the paths in gh.bootstrap to the hashed versions
     */
    grunt.registerTask('updateBootstrapPaths', function() {
        this.requires('ver:gh');

        var basedir = grunt.config('target') + '/optimized/';
        var hashedPaths = require('./' + grunt.config.get('ver.gh.version'));
        var bootstrapPath = basedir + hashedPaths['/shared/gh/api/gh.bootstrap.js'];
        var bootstrap = grunt.file.read(bootstrapPath);
        var regex = /("|')?paths("|')?: ?\{[^}]*\}/;
        var scriptPaths = 'paths = {' + bootstrap.match(regex)[0] + '}';

        var paths = vm.runInThisContext(scriptPaths).paths;

        // Update the bootstrap file with the hashed paths
        Object.keys(paths).forEach(function(key) {
            var prefix = '/shared/';
            var path = prefix + paths[key] + '.js';
            var hashedPath = '';
            if (hashedPaths[path]) {
                hashedPath = hashedPaths[path];
                // trim off prefix and .js
                paths[key] = hashedPath.substring(prefix.length, hashedPath.length - 3);
            }
        });
        bootstrap = bootstrap.replace(regex, 'paths:' + JSON.stringify(paths));
        grunt.file.write(bootstrapPath, bootstrap);
        grunt.log.writeln('Boots strapped'.green);
    });

    // Default task for production build
    grunt.registerTask('default', ['clean', 'copy', 'requirejs', 'hashFiles', 'exec:removeTarget', 'configApache']);
};

/**
 * Generate the glob expressions to match all extensions of files in the provided set of
 * directories. Any file with an extension that is found in the `excludeExts` option  will not be
 * hashed
 *
 * @param  {Object}     options                 An options object that specifies what files to hash
 * @param  {String[]}   options.directories     The list of directories whose files to hash
 * @param  {String[]}   [options.excludeExts]   The extensions of files to ignore when hashing files
 * @param  {String[]}   [options.extra]         Extra glob patterns to append, in addition to the ones added for the extensions
 * @return {String[]}                           An array of glob expressions that match the files to hash in the directories
 * @api private
 */
var _hashFiles = function(options) {
    options.excludeExts = options.excludeExts || [];
    options.extra = options.extra || [];

    var globs = [];
    _.each(options.directories, function(directory) {
        globs.push(util.format('%s/**', directory));
        _.each(options.excludeExts, function(ext) {
            // Exclude both direct children of the excluded extensions, and all grand-children
            globs.push(util.format('!%s/*.%s', directory, ext));
            globs.push(util.format('!%s/**/*.%s', directory, ext));
        });
    });

    return _.union(globs, options.extra);
};

/**
 * Generate the standard replacement references for the given resource directories, and also
 * include the provided "extra" replacement files.
 *
 * @param  {Object}     options                 An options object that specifies what files to hash
 * @param  {String[]}   options.directories     A list of directories whose resource paths should be replaced
 * @param  {String[]}   [options.includeExts]   The file extensions that should have replacement performed
 * @param  {String[]}   [options.extra]         Additional replacements to perform
 * @return {String[]}                           The full derived list of all resources that replacement should be performed
 * @api private
 */
var _replacementReferences = function(options) {
    options.includeExts = options.includeExts || [];
    options.extra = options.extra || [];

    var globs = [];
    _.each(options.directories, function(directory) {
        _.each(options.includeExts, function(ext) {
            globs.push(util.format('%s/**/*.%s', directory, ext));
        });
    });

    return _.union(globs, options.extra);
};
<commit_msg>Add a 'grunt coverage' task that generates coverage reports<commit_after>/*!
 * Copyright 2014 Digital Services, University of Cambridge Licensed
 * under the Educational Community License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

var _ = require('lodash');
var fs = require('fs');
var util = require('util');
var vm = require('vm');

module.exports = function(grunt) {

    ///////////////////
    // CONFIGURATION //
    ///////////////////

    grunt.initConfig({
        'target': 'target',
        'clean': ['<%= target %>'],
        'exec': {
            'removeTarget': {
                'cmd': 'rm -rf <%= target %>/optimized/<%= target %>'
            }
        },
        'copy': {
            'main': {
                'files': [
                    {
                        'expand': true,
                        'src': [
                            '**',
                            '!<%= target %>/.*/**',
                            '!node_modules/**'
                        ],
                        'dest': '<%= target %>/original'
                    }
                ]
            }
        },
        'requirejs': {
            'optimize': {
                'options': {
                    'appDir': './',
                    'baseUrl': './shared',
                    'mainConfigFile': './shared/gh/api/gh.bootstrap.js',
                    'dir': '<%= target %>/optimized',
                    'optimize': 'uglify',
                    'preserveLicenseComments': false,
                    'optimizeCss': 'standard',
                    // TODO: Replace this with a saner value
                    // @see https://github.com/jrburke/r.js/pull/653
                    'cssImportIgnore': '//fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,400,300,600,700&subset=latin,cyrillic-ext,latin-ext,greek-ext',
                    'inlineText': true,
                    'useStrict': false,
                    'pragmas': {},
                    'skipPragmas': false,
                    'skipModuleInsertion': false,
                    'modules': [{
                        'name': 'gh.core'
                    }],
                    'fileExclusionRegExp': /^(\.|apache|etc|node_modules|tools)/,
                    'logLevel': 2
                }
            }
        },
        'ver': {
            'gh': {
                'basedir': '<%= target %>/optimized',
                'phases': [

                    // 1. Hash all the vendor fonts
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/fonts'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/css',
                            ],
                            'includeExts': ['css']
                        })
                    },

                    // 2. Hash all the vendor CSS and JS
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/vendor/css',
                                '<%= target %>/optimized/shared/vendor/js'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/apps',
                                '<%= target %>/optimized/shared',
                                '<%= target %>/optimized/tests'
                            ],
                            'includeExts': ['html']
                        })
                    },

                    // 3. Hash the GH CSS and JS files
                    {
                        'files': _hashFiles({
                            'directories': [
                                '<%= target %>/optimized/shared/gh/**'
                            ]
                        }),
                        'references': _replacementReferences({
                            'directories': [
                                '<%= target %>/optimized/apps',
                                '<%= target %>/optimized/shared',
                                '<%= target %>/optimized/tests'
                            ],
                            'includeExts': ['html']
                        })
                    }
                ],
                'version': '<%= target %>/optimized/hashes.json'
            }
        },
        'coveralls': {
            'gh': {
                'src': 'coverage/lcov/lcov.info',
                'options': {
                    'src': 'coverage/lcov/lcov.info'
                }
            }
        },
        'ghost': {
            'dist': {
                'filesSrc': [
                    'tests/casperjs/tests/*.js'
                ],
                // CasperJS test command options
                'options': {
                    // Specify the files to be included in each test
                    'includes': [
                        'tests/casperjs/util/include/gh.api.admin.js',
                        'tests/casperjs/util/include/gh.api.app.js',
                        'tests/casperjs/util/include/gh.api.authentication.js',
                        'tests/casperjs/util/include/gh.api.config.js',
                        'tests/casperjs/util/include/gh.api.event.js',
                        'tests/casperjs/util/include/gh.api.orgunit.js',
                        'tests/casperjs/util/include/gh.api.series.js',
                        'tests/casperjs/util/include/gh.api.tenant.js',
                        'tests/casperjs/util/include/gh.api.user.js',
                        'tests/casperjs/util/include/util.js'
                    ],
                    // Prepare te testing environment before starting the tests
                    'pre': ['tests/casperjs/util/prep.js'],
                    // Don't stop casperjs after first test failure
                    'failFast': false
                }
            }
        },
        'csslint': {
            'options': {
                'ids': false // ignore "Don't use IDs in CSS selectors" warning
            },
            'files': [
                'apps/**/*.css',
                'shared/gh/**/*.css'
            ]
        },
        'jshint': {
            'options': {
                'sub': true
            },
            'files': [
                'grunt.js',
                'apps/**/*.js',
                'shared/gh/**/*.js',
            ]
        },
        'qunit': {
            'gh': {
                'urls': ['http://admin.grasshopper.com/tests/qunit/tests/api.html'],
                'options': {
                    'urls': ['http://admin.grasshopper.com/tests/qunit/tests/api.html'],
                    'coverage': {
                        'disposeCollector': true,
                        'baseUrl': ".",
                        'src': ['shared/gh/api/*.js'],
                        'instrumentedFiles': 'target/coverage',
                        'lcovReport': 'coverage/lcov',
                        'htmlReport': 'coverage/html',
                        'linesThresholdPct': 85
                    }
                }
            }
        }
    });

    ///////////////
    // NPM TASKS //
    ///////////////

    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-csslint');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-requirejs');
    grunt.loadNpmTasks('grunt-coveralls');
    grunt.loadNpmTasks('grunt-exec');
    grunt.loadNpmTasks('grunt-ghost');
    grunt.loadNpmTasks('grunt-qunit-istanbul');
    grunt.loadNpmTasks('grunt-text-replace');
    grunt.loadNpmTasks('grunt-ver');

    //////////////////
    // GRUNT TASKS  //
    //////////////////

    // Lint tasks for JavaScript and CSS
    grunt.registerTask('lint', ['jshint', 'csslint']);
    grunt.registerTask('test', ['lint', 'qunit', 'ghost']);

    // Coverage report task
    grunt.registerTask('coverage', ['qunit']);

    /**
     * Task that changes the paths in the optimized Apache configuration files
     */
    grunt.registerTask('changePaths', function() {

        // Get all the apps
        var apps = fs.readdirSync('apps');
        var basedir = grunt.config('target') + '/optimized/';

        // Loop the Apache configuration files for every app
        _.each(apps, function(appName) {
            var file = basedir + 'apache/app_' + appName + '.conf';
            var fileContent = grunt.file.read(file);
            fileContent = fileContent.replace(/grasshopper-ui/g, 'grasshopper-ui/' + grunt.config('target') + '/optimized');
            grunt.file.write(file, fileContent);
            grunt.log.writeln(String('Apache file changed for app_' + appName + '.conf').green);
        });
    });

    /**
     * Task to fill out the Apache config template
     */
    grunt.registerTask('configApache', function() {
        var infile = './apache/apache.js';

        // Get all the apps
        var apps = fs.readdirSync('apps');

        // Get the config
        var apacheConfig = require('./apache/apache.js');

        // Get each apps config and overlay it
        _.each(apps, function(app) {
            apacheConfig[app] = require('./apps/' + app + '/apache/apache.js');
        });
        grunt.config.set('apacheConf', apacheConfig);

        // Render the httpd config
        var httpdTemplate = grunt.file.read('apache/httpd.conf');
        var renderedConfig = grunt.template.process(httpdTemplate);
        var outfile = grunt.config('target') + '/optimized/apache/httpd.conf';
        grunt.file.write(outfile, renderedConfig);
        grunt.log.writeln('httpd.conf rendered at '.green + outfile.green);

        // Render each app/vhost
        _.each(apps, function(appName) {
            apacheConfig[appName].errorLog = apacheConfig.logDirectory + appName + '_error.log';
            apacheConfig[appName].customLog = apacheConfig.logDirectory + appName + '_custom.log';

            var template = grunt.file.read('apps/' + appName + '/apache/app.conf');
            var renderedConfig = grunt.template.process(template);
            var outfile = grunt.config('target') + '/optimized/apache/app_' + appName + '.conf';
            grunt.file.write(outfile, renderedConfig);
            grunt.log.writeln(appName + '.conf rendered at '.green + outfile.green);
        });
    });

    /**
     * Task to hash files
     */
    grunt.registerTask('hashFiles', function() {
        this.requires('requirejs');

        // Hash the GH files
        grunt.task.run('ver:gh');

        // Update the files in the bootstrap
        grunt.task.run('updateBootstrapPaths');
    });

    /**
     * Task that creates a release build
     *
     * @param  {String}    outputDir    The directory where the build should be stored
     *
     *  * Example:
     *  * grunt release:/tmp/release
     *  *
     *  * This will run the entire UI build (minification, hashing, apache config, etc, ..) and create the following folders:
     *  * /tmp/release/optimized  -  contains the minified UI sources
     *  * /tmp/release/original   -  contains the original UI files
     *  *
     */
    grunt.registerTask('release', function(outputDir) {
        if (!outputDir) {
            return grunt.log.writeln('Please provide a path where the release files should be copied to'.red);
        }
        grunt.config.target = outputDir;

        // Run the default production build task
        grunt.task.run('default');

        // Change the paths in the optimized Apache files
        grunt.task.run('changePaths');
    });

    /**
     * Task to update the paths in gh.bootstrap to the hashed versions
     */
    grunt.registerTask('updateBootstrapPaths', function() {
        this.requires('ver:gh');

        var basedir = grunt.config('target') + '/optimized/';
        var hashedPaths = require('./' + grunt.config.get('ver.gh.version'));
        var bootstrapPath = basedir + hashedPaths['/shared/gh/api/gh.bootstrap.js'];
        var bootstrap = grunt.file.read(bootstrapPath);
        var regex = /("|')?paths("|')?: ?\{[^}]*\}/;
        var scriptPaths = 'paths = {' + bootstrap.match(regex)[0] + '}';

        var paths = vm.runInThisContext(scriptPaths).paths;

        // Update the bootstrap file with the hashed paths
        Object.keys(paths).forEach(function(key) {
            var prefix = '/shared/';
            var path = prefix + paths[key] + '.js';
            var hashedPath = '';
            if (hashedPaths[path]) {
                hashedPath = hashedPaths[path];
                // trim off prefix and .js
                paths[key] = hashedPath.substring(prefix.length, hashedPath.length - 3);
            }
        });
        bootstrap = bootstrap.replace(regex, 'paths:' + JSON.stringify(paths));
        grunt.file.write(bootstrapPath, bootstrap);
        grunt.log.writeln('Boots strapped'.green);
    });

    // Default task for production build
    grunt.registerTask('default', ['clean', 'copy', 'requirejs', 'hashFiles', 'exec:removeTarget', 'configApache']);
};

/**
 * Generate the glob expressions to match all extensions of files in the provided set of
 * directories. Any file with an extension that is found in the `excludeExts` option  will not be
 * hashed
 *
 * @param  {Object}     options                 An options object that specifies what files to hash
 * @param  {String[]}   options.directories     The list of directories whose files to hash
 * @param  {String[]}   [options.excludeExts]   The extensions of files to ignore when hashing files
 * @param  {String[]}   [options.extra]         Extra glob patterns to append, in addition to the ones added for the extensions
 * @return {String[]}                           An array of glob expressions that match the files to hash in the directories
 * @api private
 */
var _hashFiles = function(options) {
    options.excludeExts = options.excludeExts || [];
    options.extra = options.extra || [];

    var globs = [];
    _.each(options.directories, function(directory) {
        globs.push(util.format('%s/**', directory));
        _.each(options.excludeExts, function(ext) {
            // Exclude both direct children of the excluded extensions, and all grand-children
            globs.push(util.format('!%s/*.%s', directory, ext));
            globs.push(util.format('!%s/**/*.%s', directory, ext));
        });
    });

    return _.union(globs, options.extra);
};

/**
 * Generate the standard replacement references for the given resource directories, and also
 * include the provided "extra" replacement files.
 *
 * @param  {Object}     options                 An options object that specifies what files to hash
 * @param  {String[]}   options.directories     A list of directories whose resource paths should be replaced
 * @param  {String[]}   [options.includeExts]   The file extensions that should have replacement performed
 * @param  {String[]}   [options.extra]         Additional replacements to perform
 * @return {String[]}                           The full derived list of all resources that replacement should be performed
 * @api private
 */
var _replacementReferences = function(options) {
    options.includeExts = options.includeExts || [];
    options.extra = options.extra || [];

    var globs = [];
    _.each(options.directories, function(directory) {
        _.each(options.includeExts, function(ext) {
            globs.push(util.format('%s/**/*.%s', directory, ext));
        });
    });

    return _.union(globs, options.extra);
};
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

var makeup = require( 'make-up' );

module.exports = function( grunt ) {

	// project configuration
	grunt.initConfig( {
		jshint: {
			options: {
				jshintrc: makeup( 'jshintrc.json' )
			},
			core: {
				src: ['*.js']
			},
			test: {
				src: ['test/**/*.js']
			}
		},
		jscs: {
			options: {
				config: makeup( 'jscsrc.json' )
			},
			src: ['<%= jshint.core.src %>', '<%= jshint.test.src %>']
		}
	} );

	// load tasks from the specified grunt plugins...
	grunt.loadNpmTasks( 'grunt-contrib-jshint' );
	grunt.loadNpmTasks( 'grunt-jscs' );

};<commit_msg>Updating Gruntfile to lint all the things<commit_after>/* jslint node: true */
'use strict';

var makeup = require( 'make-up' );

module.exports = function( grunt ) {

	// project configuration
	grunt.initConfig( {
		jshint: {
			options: {
				jshintrc: makeup( 'jshintrc.json' )
			},
			core: {
				src: [ '**/*.js', '!node_modules/**', '!coverage/**' ]
			}
		},
		jscs: {
			options: {
				config: makeup( 'jscsrc.json' )
			},
			src: ['<%= jshint.core.src %>']
		}
	} );

	// load tasks from the specified grunt plugins...
	grunt.loadNpmTasks( 'grunt-contrib-jshint' );
	grunt.loadNpmTasks( 'grunt-jscs' );

};<|endoftext|>


<commit_before>
'use strict';

module.exports = function(grunt) {
  // commenting this out for now until used
  //var dist = '' + (process.env.SERVER_BASE || 'dist_dev');

  var path = require('path');
  var pconfig = require('./src/lib/pconfig');

  var config = {
    pkg: grunt.file.readJSON('package.json'),
    files: {
      html: {
        src: 'src/index.html'
      },
      js: {
        src: [
          'src/modules/*/*.js',
          'src/app.js'
        ]
      },
      templates: {
        src: 'src/**/*.html'
      },
      less: {
        src: [
          'src/css/style.less'
        ]
      }
    },
    bump: {
      options: {
        files: ['package.json', 'bower.json'],
        updateConfigs: [],
        commit: true,
        commitMessage: 'Release v%VERSION%',
        commitFiles: ['package.json', 'bower.json'],
        createTag: true,
        tagName: 'v%VERSION%',
        tagMessage: 'Version %VERSION%',
        push: false
      }
    },
    compress: {
      win32: {
        options: {
          archive: 'built/kalabox-win32-dev.zip'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/win32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      win64: {
        options: {
          archive: 'built/kalabox-win64-dev.zip'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/win64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      osx32: {
        options: {
          archive: 'built/kalabox-osx32-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/osx32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      osx64: {
        options: {
          archive: 'built/kalabox-osx64-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/osx64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      linux32: {
        options: {
          archive: 'built/kalabox-linux32-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/linux32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      linux64: {
        options: {
          archive: 'built/kalabox-linux64-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/linux64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      }
    },
    shell: {
      nw: {
        command: pconfig.devBinary + ' generated/'
      },
      build: {
        command: 'cd ./generated && npm install --production --ignore-scripts'
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: ['Gruntfile.js', '<%= files.js.src %>']
    },
    jscs: {
      src: ['Gruntfile.js', '<%= files.js.src %>'],
      options: {
        config: '.jscsrc'
      }
    },
    protractor: {
      options: {
        configFile: 'test/protractor.conf.js',
        args: {
          chromeDriver: 'test/support/chromedriver',
          chromeOnly: true,
          baseUrl: 'file://' + path.resolve('src/index.html') + '#',
          rootElement: 'body'
        }
      },
      default: {
        specs: [
          'test/e2e/**/*.spec.js',
          'src/modules/*/test/e2e/**/*.spec.js'
        ]
      }
    },
    /**
     * Simple server for testing and dev.
     */
    connect: {
      options: {
        base: 'src'
      },
      serve: {},
      keepAlive: {
        options: {
          keepalive: true
        }
      }
    },
    less: {
      options: {
        paths: ['src/css'],
        ieCompat: false
      },
      dev: {
        src: '<%= files.less.src %>',
        dest: 'src/css/style.css'
      },
      dist: {
        options: {
          cleancss: true,
          compress: true
        },
        src: '<%= files.less.src %>',
        dest: 'src/css/style.css'
      }
    },
    watch: {
      options: {
        livereload: false
      },
      less: {
        files: ['<%= files.less.src %>'],
        tasks: ['less:dev']
      }
    },
    copy: {
      main: {
        files: [
          {
            expand: true,
            src: ['src/**'],
            dest: 'generated/'
          },
          {
            expand: true,
            src: ['config/**'],
            dest: 'generated/'
          },
          {src: ['package.json'], dest: 'generated/package.json'}
        ]
      }
    },
    clean: {
      workspaces: ['built', 'dist', 'generated', 'src/downloads']
    },
    nodewebkit: {
      options: {
        // Versions listed here: http://dl.node-webkit.org/
        version: 'v0.11.6',
        platforms: [
          'win32',
          'win64',
          'osx32',
          'osx64',
          'linux32',
          'linux64'
        ],
        buildDir: 'dist'
      },
      src: ['generated/**/**']
    },
    /**
     * Karma unit test runner.
     */
    karma: {
      options: {
        configFile: 'test/karma.conf.js'
      },
      // Required by grunt, can override later.
      unit: {
        options: {
          singleRun: true,
          browsers: ['NodeWebkit']
        }
      }
    },
    /**
     * Basic bower task that uses
     * Bower's API's directly.
     */
    'bower-install-simple' : {
      install: {
        options: {
          directory: 'src/lib/vendor'
        },
      },
      ci: {
        options: {
          directory: 'src/lib/vendor',
          interactive: false
        }
      }
    }
  };

  // initialize task config
  grunt.initConfig(config);

  // load local tasks
  if (grunt.file.exists('tasks')) {
    grunt.loadTasks('tasks');
  }

  // loads all grunt-* tasks based on package.json definitions
  require('matchdep').filterAll('grunt-*').forEach(grunt.loadNpmTasks);

  // create workflows
  grunt.registerTask('default', [
    'clean',
    'bower-install-simple:install',
    'jshint',
    'less:dev',
    'copy',
    'shell:nw'
  ]);

  grunt.registerTask('test', [
    'jshint',
    'jscs',
    'bower-install-simple:ci',
    'test:unit',
    'test:e2e'
  ]);

  grunt.registerTask('test:js', [
    'jshint',
    'jscs',
  ]);

  grunt.registerTask('test:unit', [
    'karma:unit'
  ]);

  grunt.registerTask('test:e2e', [
    'protractor-setup',
    'protractor:default'
  ]);

  grunt.registerTask('build', [
    'clean',
    'bower-install-simple:install',
    'test',
    'less:dist',
    'copy',
    'shell:build',
    'nodewebkit',
    'compress:win32',
    'compress:win64',
    'compress:osx32',
    'compress:osx64',
    'compress:linux32',
    'compress:linux64'
  ]);

  grunt.registerTask('bump-patch', [
    'bump-only:patch'
  ]);

  grunt.registerTask('bump-minor', [
    'bump-only:minor',
    'bump-commit'
  ]);

};
<commit_msg>Added an infinite maxBuffer for nw grunt command. It was throwing a warning of exceeded max buffer during provision testing, and the warning was causing a failure.<commit_after>
'use strict';

module.exports = function(grunt) {
  // commenting this out for now until used
  //var dist = '' + (process.env.SERVER_BASE || 'dist_dev');

  var path = require('path');
  var pconfig = require('./src/lib/pconfig');

  var config = {
    pkg: grunt.file.readJSON('package.json'),
    files: {
      html: {
        src: 'src/index.html'
      },
      js: {
        src: [
          'src/modules/*/*.js',
          'src/app.js'
        ]
      },
      templates: {
        src: 'src/**/*.html'
      },
      less: {
        src: [
          'src/css/style.less'
        ]
      }
    },
    bump: {
      options: {
        files: ['package.json', 'bower.json'],
        updateConfigs: [],
        commit: true,
        commitMessage: 'Release v%VERSION%',
        commitFiles: ['package.json', 'bower.json'],
        createTag: true,
        tagName: 'v%VERSION%',
        tagMessage: 'Version %VERSION%',
        push: false
      }
    },
    compress: {
      win32: {
        options: {
          archive: 'built/kalabox-win32-dev.zip'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/win32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      win64: {
        options: {
          archive: 'built/kalabox-win64-dev.zip'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/win64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      osx32: {
        options: {
          archive: 'built/kalabox-osx32-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/osx32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      osx64: {
        options: {
          archive: 'built/kalabox-osx64-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/osx64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      linux32: {
        options: {
          archive: 'built/kalabox-linux32-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/linux32/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      },
      linux64: {
        options: {
          archive: 'built/kalabox-linux64-dev.tar.gz',
          mode: 'tgz'
        },
        files: [
          {
            expand: true,
            cwd: 'dist/Kalabox/linux64/',
            src: ['**'],
            dest: 'Kalabox/'
          }
        ]
      }
    },
    shell: {
      nw: {
        command: pconfig.devBinary + ' generated/',
        options: {
          execOptions: {
            maxBuffer: Infinity
          }
        }
      },
      build: {
        command: 'cd ./generated && npm install --production --ignore-scripts'
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: ['Gruntfile.js', '<%= files.js.src %>']
    },
    jscs: {
      src: ['Gruntfile.js', '<%= files.js.src %>'],
      options: {
        config: '.jscsrc'
      }
    },
    protractor: {
      options: {
        configFile: 'test/protractor.conf.js',
        args: {
          chromeDriver: 'test/support/chromedriver',
          chromeOnly: true,
          baseUrl: 'file://' + path.resolve('src/index.html') + '#',
          rootElement: 'body'
        }
      },
      default: {
        specs: [
          'test/e2e/**/*.spec.js',
          'src/modules/*/test/e2e/**/*.spec.js'
        ]
      }
    },
    /**
     * Simple server for testing and dev.
     */
    connect: {
      options: {
        base: 'src'
      },
      serve: {},
      keepAlive: {
        options: {
          keepalive: true
        }
      }
    },
    less: {
      options: {
        paths: ['src/css'],
        ieCompat: false
      },
      dev: {
        src: '<%= files.less.src %>',
        dest: 'src/css/style.css'
      },
      dist: {
        options: {
          cleancss: true,
          compress: true
        },
        src: '<%= files.less.src %>',
        dest: 'src/css/style.css'
      }
    },
    watch: {
      options: {
        livereload: false
      },
      less: {
        files: ['<%= files.less.src %>'],
        tasks: ['less:dev']
      }
    },
    copy: {
      main: {
        files: [
          {
            expand: true,
            src: ['src/**'],
            dest: 'generated/'
          },
          {
            expand: true,
            src: ['config/**'],
            dest: 'generated/'
          },
          {src: ['package.json'], dest: 'generated/package.json'}
        ]
      }
    },
    clean: {
      workspaces: ['built', 'dist', 'generated', 'src/downloads']
    },
    nodewebkit: {
      options: {
        // Versions listed here: http://dl.node-webkit.org/
        version: 'v0.11.6',
        platforms: [
          'win32',
          'win64',
          'osx32',
          'osx64',
          'linux32',
          'linux64'
        ],
        buildDir: 'dist'
      },
      src: ['generated/**/**']
    },
    /**
     * Karma unit test runner.
     */
    karma: {
      options: {
        configFile: 'test/karma.conf.js'
      },
      // Required by grunt, can override later.
      unit: {
        options: {
          singleRun: true,
          browsers: ['NodeWebkit']
        }
      }
    },
    /**
     * Basic bower task that uses
     * Bower's API's directly.
     */
    'bower-install-simple' : {
      install: {
        options: {
          directory: 'src/lib/vendor'
        },
      },
      ci: {
        options: {
          directory: 'src/lib/vendor',
          interactive: false
        }
      }
    }
  };

  // initialize task config
  grunt.initConfig(config);

  // load local tasks
  if (grunt.file.exists('tasks')) {
    grunt.loadTasks('tasks');
  }

  // loads all grunt-* tasks based on package.json definitions
  require('matchdep').filterAll('grunt-*').forEach(grunt.loadNpmTasks);

  // create workflows
  grunt.registerTask('default', [
    'clean',
    'bower-install-simple:install',
    'jshint',
    'less:dev',
    'copy',
    'shell:nw'
  ]);

  grunt.registerTask('test', [
    'jshint',
    'jscs',
    'bower-install-simple:ci',
    'test:unit',
    'test:e2e'
  ]);

  grunt.registerTask('test:js', [
    'jshint',
    'jscs',
  ]);

  grunt.registerTask('test:unit', [
    'karma:unit'
  ]);

  grunt.registerTask('test:e2e', [
    'protractor-setup',
    'protractor:default'
  ]);

  grunt.registerTask('build', [
    'clean',
    'bower-install-simple:install',
    'test',
    'less:dist',
    'copy',
    'shell:build',
    'nodewebkit',
    'compress:win32',
    'compress:win64',
    'compress:osx32',
    'compress:osx64',
    'compress:linux32',
    'compress:linux64'
  ]);

  grunt.registerTask('bump-patch', [
    'bump-only:patch'
  ]);

  grunt.registerTask('bump-minor', [
    'bump-only:minor',
    'bump-commit'
  ]);

};
<|endoftext|>


<commit_before>/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    // Task configuration.
    uglify: {
      dist: {
        src: '<%= pkg.main %>',
        dest: '<%= pkg.gruntConfig.dist.js %>'
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: false,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {
          $ : true,
          Modernizr : true
        }
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      js: {
        src: '<%= pkg.main %>'
      },
      spec : {
        src: '<%= pkg.gruntConfig.spec %>',
        options : {
          globals : {
            console: false,
            $: false,
            _: false,
            _V_: false,
            afterEach: false,
            beforeEach: false,
            confirm: false,
            context: false,
            describe: false,
            expect: false,
            it: false,
            jasmine: false,
            JSHINT: false,
            mostRecentAjaxRequest: false,
            qq: false,
            runs: false,
            spyOn: false,
            spyOnEvent: false,
            waitsFor: false,
            xdescribe: false
          }
        }
      }
    },
    jasmine : {
      src : '<%= pkg.main %>',
      options : {
        specs : '<%= pkg.gruntConfig.spec %>',
        vendor : ['<%= pkg.gruntConfig.js.jquery %>'],
        styles : ['<%= pkg.gruntConfig.css.boostrap %>', '<%= pkg.gruntConfig.css.slider %>'],
        template : '<%= pkg.gruntConfig.tpl.SpecRunner %>'
      }
    },
    template : {
      'generate-index-page' : {
        options : {
          data : {
            js : {
              modernizr : '<%= pkg.gruntConfig.js.modernizr %>',
              jquery : '<%= pkg.gruntConfig.js.jquery %>',
              slider : '<%= pkg.main %>'
            },
            css : {
              bootstrap : '<%= pkg.gruntConfig.css.bootstrap %>',
              slider : '<%= pkg.gruntConfig.css.slider %>'
            }
          }
        },
        files : {
          'index.html' : ['<%= pkg.gruntConfig.tpl.index %>']
        }
      }
    },
    watch: {
      js : {
        files: '<%= pkg.main %>',
        tasks: ['jshint:js', 'jasmine']
      },
      gruntfile : {
        files: '<%= jshint.gruntfile %>',
        tasks: ['jshint:gruntfile']
      },
      spec : {
        files: '<%= jshint.spec %>',
        tasks: ['jshint:spec']
      },
      css : {
        files: '<%= pkg.gruntConfig.less.slider %>',
        tasks: ['less:development']
      },
      index : {
        files: '<%= pkg.gruntConfig.tpl.index %>',
        tasks: ['template:generate-index-page']
      }
    },
    connect: {
      server: {
        options: {
          port: "<%= pkg.gruntConfig.devPort %>"
        }
      }
    },
    open : {
      development : {
        path: 'http://localhost:<%= connect.server.options.port %>'
      }
    },
    less: {
      options: {
        paths: ["bower_components/bootstrap/less"]
      },
      development: {
        files: {
          '<%= pkg.gruntConfig.css.slider %>': '<%= pkg.gruntConfig.less.slider %>'
        }
      },
      production: {
        files: {
         '<%= pkg.gruntConfig.dist.css %>': '<%= pkg.gruntConfig.less.slider %>',
        }
      },
      "production-min": {
        options: {
          yuicompress: true
        },
        files: {
         '<%= pkg.gruntConfig.dist.cssMin %>': '<%= pkg.gruntConfig.less.slider %>'
        }
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-open');
  grunt.loadNpmTasks('grunt-template');
  grunt.loadNpmTasks('grunt-contrib-less');

  // Default task.
  grunt.registerTask('test', ['jshint', 'jasmine']);
  grunt.registerTask('build', ['less:development', 'test', 'template']);
  grunt.registerTask('development', ['build', 'connect', 'open:development', 'watch']);
  grunt.registerTask('production', ['less:production', 'less:production-min', 'test', 'uglify']);
  grunt.registerTask('dev', 'development');
  grunt.registerTask('dist', 'production');
};<commit_msg>fixed a typo (?)<commit_after>/*global module:false*/
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    // Metadata.
    pkg: grunt.file.readJSON('package.json'),
    // Task configuration.
    uglify: {
      dist: {
        src: '<%= pkg.main %>',
        dest: '<%= pkg.gruntConfig.dist.js %>'
      }
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: false,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        unused: true,
        boss: true,
        eqnull: true,
        browser: true,
        globals: {
          $ : true,
          Modernizr : true
        }
      },
      gruntfile: {
        src: 'Gruntfile.js'
      },
      js: {
        src: '<%= pkg.main %>'
      },
      spec : {
        src: '<%= pkg.gruntConfig.spec %>',
        options : {
          globals : {
            console: false,
            $: false,
            _: false,
            _V_: false,
            afterEach: false,
            beforeEach: false,
            confirm: false,
            context: false,
            describe: false,
            expect: false,
            it: false,
            jasmine: false,
            JSHINT: false,
            mostRecentAjaxRequest: false,
            qq: false,
            runs: false,
            spyOn: false,
            spyOnEvent: false,
            waitsFor: false,
            xdescribe: false
          }
        }
      }
    },
    jasmine : {
      src : '<%= pkg.main %>',
      options : {
        specs : '<%= pkg.gruntConfig.spec %>',
        vendor : ['<%= pkg.gruntConfig.js.jquery %>'],
        styles : ['<%= pkg.gruntConfig.css.bootstrap %>', '<%= pkg.gruntConfig.css.slider %>'],
        template : '<%= pkg.gruntConfig.tpl.SpecRunner %>'
      }
    },
    template : {
      'generate-index-page' : {
        options : {
          data : {
            js : {
              modernizr : '<%= pkg.gruntConfig.js.modernizr %>',
              jquery : '<%= pkg.gruntConfig.js.jquery %>',
              slider : '<%= pkg.main %>'
            },
            css : {
              bootstrap : '<%= pkg.gruntConfig.css.bootstrap %>',
              slider : '<%= pkg.gruntConfig.css.slider %>'
            }
          }
        },
        files : {
          'index.html' : ['<%= pkg.gruntConfig.tpl.index %>']
        }
      }
    },
    watch: {
      js : {
        files: '<%= pkg.main %>',
        tasks: ['jshint:js', 'jasmine']
      },
      gruntfile : {
        files: '<%= jshint.gruntfile %>',
        tasks: ['jshint:gruntfile']
      },
      spec : {
        files: '<%= jshint.spec %>',
        tasks: ['jshint:spec']
      },
      css : {
        files: '<%= pkg.gruntConfig.less.slider %>',
        tasks: ['less:development']
      },
      index : {
        files: '<%= pkg.gruntConfig.tpl.index %>',
        tasks: ['template:generate-index-page']
      }
    },
    connect: {
      server: {
        options: {
          port: "<%= pkg.gruntConfig.devPort %>"
        }
      }
    },
    open : {
      development : {
        path: 'http://localhost:<%= connect.server.options.port %>'
      }
    },
    less: {
      options: {
        paths: ["bower_components/bootstrap/less"]
      },
      development: {
        files: {
          '<%= pkg.gruntConfig.css.slider %>': '<%= pkg.gruntConfig.less.slider %>'
        }
      },
      production: {
        files: {
         '<%= pkg.gruntConfig.dist.css %>': '<%= pkg.gruntConfig.less.slider %>',
        }
      },
      "production-min": {
        options: {
          yuicompress: true
        },
        files: {
         '<%= pkg.gruntConfig.dist.cssMin %>': '<%= pkg.gruntConfig.less.slider %>'
        }
      }
    }
  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-jasmine');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-open');
  grunt.loadNpmTasks('grunt-template');
  grunt.loadNpmTasks('grunt-contrib-less');

  // Default task.
  grunt.registerTask('test', ['jshint', 'jasmine']);
  grunt.registerTask('build', ['less:development', 'test', 'template']);
  grunt.registerTask('development', ['build', 'connect', 'open:development', 'watch']);
  grunt.registerTask('production', ['less:production', 'less:production-min', 'test', 'uglify']);
  grunt.registerTask('dev', 'development');
  grunt.registerTask('dist', 'production');
};<|endoftext|>


<commit_before>/*
 * Scale-Out-Agile
 *
 * Arlo Belshee
 * https://github.com/Scale-Out-Agile/Scale-Out-Agile.github.io
 *
 * Copyright (c) 2014
 * Licensed under the MIT license.
 */

module.exports = function (grunt) {
	'use strict';

	grunt.initConfig({

		// Project metadata
		pkg: grunt.file.readJSON('package.json'),
		vendor: grunt.file.readJSON('.bowerrc').directory,
		site: grunt.file.readYAML('_config.yml'),
		bootstrap: '<%= vendor %>/bootstrap',
		durandal: '<%= vendor %>/durandal',

		// Before generating any new files, remove files from previous build.
		clean: {
			site: ['<%= site.dest %>/**/*.*', '<%= site.dest %>/**/.*', '!<%= site.dest %>/.git', '<%= site.dest %>/*/']
		},

		// Lint JavaScript
		jshint: {
			all: ['Gruntfile.js', 'templates/helpers/*.js'],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		// Build HTML from templates and data
		assemble: {
			options: {
				flatten: true,
				production: true,
				assets: '<%= site.assets %>',
				//				postprocess: require('pretty'),

				// Metadata
				pkg: '<%= pkg %>',
				site: '<%= site %>',
				data: ['<%= site.data %>'],

				// Templates
				partials: '<%= site.includes %>',
				layoutdir: '<%= site.layouts %>',
				layout: '<%= site.layout %>',

				// Extensions
				helpers: '<%= site.helpers %>',
				plugins: '<%= site.plugins %>'
			},
			site: {
				files: {
					'<%= site.dest %>/': ['<%= site.templates %>/*.hbs', '<%= site.content %>/*.md']
				}
			}
		},

		// Compile LESS to CSS
		less: {
			options: {
				vendor: 'vendor',
				paths: [
					'<%= site.theme %>',
					'<%= site.theme %>/paper',
					'<%= site.theme %>/bootstrap',
					'<%= site.theme %>/components',
					'<%= site.theme %>/utils'
				]
			},
			site: {
				src: ['<%= site.theme %>/site.less'],
				dest: '<%= site.assets %>/css/site.css'
			}
		},

		copy: {
			// Copy vendor assets to site assets
			assets: {
				files: [
					{ expand: true, cwd: '<%= vendor %>/font-awesome/fonts', src: ['*.*'], dest: '<%= site.assets %>/fonts/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/fonts', src: ['*.*'], dest: '<%= site.assets %>/fonts/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/js', src: ['*.min.*'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/css', src: ['*.min.*'], dest: '<%= site.assets %>/css/' },
					{ expand: true, cwd: '<%= durandal %>/js', src: ['**/*.*'], dest: '<%= site.assets %>/js/durandal/' },
					{ expand: true, cwd: '<%= durandal %>/img', src: ['*.*'], dest: '<%= site.assets %>/img/' },
					{ expand: true, cwd: '<%= durandal %>/css', src: ['**/*.*'], dest: '<%= site.assets %>/css/' },
					{ expand: true, cwd: '<%= vendor %>/require', src: ['require.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/require', src: ['text.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/knockout', src: ['knockout-3.1.0.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/jquery', src: ['*.min.*'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/font-awesome/css', src: ['*.min.css'], dest: '<%= site.assets %>/css/' },
				]
			},
			// Copy apps to the dest
			apps: {
				files: [
					{ expand: true, cwd: '<%= site.apps %>', src: ['*/**/*.*'], dest: '<%= site.dest %>' },
				]
			},
			// Copy production core files to dest.
			ghpages: {
				files: [
					{ src: ['README.md'], dest: '<%= site.dest %>/' },
					{ expand: true, cwd: 'static', src: ['*.*', '**/*.*'], dest: '<%= site.dest %>/', dot: true }
				]
			}
		},

		watch: {
			all: {
				files: ['<%= jshint.all %>'],
				tasks: ['jshint', 'nodeunit']
			},
			site: {
				files: ['Gruntfile.js', '<%= less.options.paths %>/*.less', 'templates/**/*.hbs', 'content/**/*.*'],
				tasks: ['design']
			}
		},

		buildcontrol: {
			options: {
				dir: '<%= site.dest %>',
				commit: true,
				push: true,
				tag: '<%= pkg.version %>',
				message: 'Built %sourceName% for production from %sourceCommit%.'
			},
			local: {
				options: {
					branch: 'master',
					remote: '../'
				}
			}
		}
	});

	// Load npm plugins to provide necessary tasks.
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-sync-pkg');
	grunt.loadNpmTasks('grunt-git');
	grunt.loadNpmTasks('grunt-build-control');
	grunt.loadNpmTasks('grunt-verb');
	grunt.loadNpmTasks('assemble-less');
	grunt.loadNpmTasks('assemble');

	grunt.registerTask('build', ['copy:assets', 'verb', 'assemble', 'copy:apps', 'less', 'sync', 'copy:ghpages']);

	// Build everything and watch for changes. You must first run "bower install"
	// or install Bootstrap to the "vendor" directory before running this command.
	grunt.registerTask('design', ['clean', 'build', 'watch:site']);

	grunt.registerTask('default', ['clean', 'jshint', 'build']);

	grunt.registerTask('deploy', ['buildcontrol:local']);
};<commit_msg>Preparing to be able to deploy.<commit_after>/*
 * Scale-Out-Agile
 *
 * Arlo Belshee
 * https://github.com/Scale-Out-Agile/Scale-Out-Agile.github.io
 *
 * Copyright (c) 2014
 * Licensed under the MIT license.
 */

module.exports = function (grunt) {
	'use strict';

	grunt.initConfig({

		// Project metadata
		pkg: grunt.file.readJSON('package.json'),
		vendor: grunt.file.readJSON('.bowerrc').directory,
		site: grunt.file.readYAML('_config.yml'),
		bootstrap: '<%= vendor %>/bootstrap',
		durandal: '<%= vendor %>/durandal',

		// Before generating any new files, remove files from previous build.
		clean: {
			site: ['<%= site.dest %>/**/*.*', '<%= site.dest %>/**/.*', '!<%= site.dest %>/.git', '<%= site.dest %>/*/']
		},

		// Lint JavaScript
		jshint: {
			all: ['Gruntfile.js', 'templates/helpers/*.js'],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		// Build HTML from templates and data
		assemble: {
			options: {
				flatten: true,
				production: true,
				assets: '<%= site.assets %>',
				//				postprocess: require('pretty'),

				// Metadata
				pkg: '<%= pkg %>',
				site: '<%= site %>',
				data: ['<%= site.data %>'],

				// Templates
				partials: '<%= site.includes %>',
				layoutdir: '<%= site.layouts %>',
				layout: '<%= site.layout %>',

				// Extensions
				helpers: '<%= site.helpers %>',
				plugins: '<%= site.plugins %>'
			},
			site: {
				files: {
					'<%= site.dest %>/': ['<%= site.templates %>/*.hbs', '<%= site.content %>/*.md']
				}
			}
		},

		// Compile LESS to CSS
		less: {
			options: {
				vendor: 'vendor',
				paths: [
					'<%= site.theme %>',
					'<%= site.theme %>/paper',
					'<%= site.theme %>/bootstrap',
					'<%= site.theme %>/components',
					'<%= site.theme %>/utils'
				]
			},
			site: {
				src: ['<%= site.theme %>/site.less'],
				dest: '<%= site.assets %>/css/site.css'
			}
		},

		copy: {
			// Copy vendor assets to site assets
			assets: {
				files: [
					{ expand: true, cwd: '<%= vendor %>/font-awesome/fonts', src: ['*.*'], dest: '<%= site.assets %>/fonts/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/fonts', src: ['*.*'], dest: '<%= site.assets %>/fonts/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/js', src: ['*.min.*'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= bootstrap %>/dist/css', src: ['*.min.*'], dest: '<%= site.assets %>/css/' },
					{ expand: true, cwd: '<%= durandal %>/js', src: ['**/*.*'], dest: '<%= site.assets %>/js/durandal/' },
					{ expand: true, cwd: '<%= durandal %>/img', src: ['*.*'], dest: '<%= site.assets %>/img/' },
					{ expand: true, cwd: '<%= durandal %>/css', src: ['**/*.*'], dest: '<%= site.assets %>/css/' },
					{ expand: true, cwd: '<%= vendor %>/require', src: ['require.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/require', src: ['text.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/knockout', src: ['knockout-3.1.0.js'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/jquery', src: ['*.min.*'], dest: '<%= site.assets %>/js/' },
					{ expand: true, cwd: '<%= vendor %>/font-awesome/css', src: ['*.min.css'], dest: '<%= site.assets %>/css/' },
				]
			},
			// Copy apps to the dest
			apps: {
				files: [
					{ expand: true, cwd: '<%= site.apps %>', src: ['*/**/*.*'], dest: '<%= site.dest %>' },
				]
			},
			// Copy production core files to dest.
			ghpages: {
				files: [
					{ src: ['README.md'], dest: '<%= site.dest %>/' },
					{ expand: true, cwd: 'static', src: ['*.*', '**/*.*'], dest: '<%= site.dest %>/', dot: true }
				]
			}
		},

		watch: {
			all: {
				files: ['<%= jshint.all %>'],
				tasks: ['jshint', 'nodeunit']
			},
			site: {
				files: ['Gruntfile.js', '<%= less.options.paths %>/*.less', 'templates/**/*.hbs', 'content/**/*.*'],
				tasks: ['design']
			}
		},

		buildcontrol: {
			options: {
				dir: '<%= site.dest %>',
				commit: true,
				push: true,
				tag: '<%= pkg.version %>',
				message: 'Built %sourceName% for production from %sourceCommit%.'
			},
			local: {
				options: {
					branch: 'gh_pages',
					remote: '../'
				}
			},
			live: {
				options: {
					branch: 'master',
					remote: '../'
				}
			}
		}
	});

	// Load npm plugins to provide necessary tasks.
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-sync-pkg');
	grunt.loadNpmTasks('grunt-git');
	grunt.loadNpmTasks('grunt-build-control');
	grunt.loadNpmTasks('grunt-verb');
	grunt.loadNpmTasks('assemble-less');
	grunt.loadNpmTasks('assemble');

	grunt.registerTask('build', ['copy:assets', 'verb', 'assemble', 'copy:apps', 'less', 'sync', 'copy:ghpages']);

	// Build everything and watch for changes. You must first run "bower install"
	// or install Bootstrap to the "vendor" directory before running this command.
	grunt.registerTask('design', ['clean', 'build', 'watch:site']);

	grunt.registerTask('default', ['clean', 'jshint', 'build']);

	grunt.registerTask('deploy', ['buildcontrol:local']);
	grunt.registerTask('ship', ['buildcontrol:live']);
};<|endoftext|>


<commit_before>/*
Author: James Cryer
Company: Huddle
Last updated date: 21 Feb 2013
URL: https://github.com/Huddle/PhantomCSS
*/

var fs = require('fs');

var _root = '.';
var _diffRoot = '.';
var _count = 0;
var _realPath;
var _diffsToProcess = [];
var _emptyPageToRunTestsOn;
var _libraryRoot = '.';
var exitStatus;
var _hideElements;

exports.screenshot = screenshot;
exports.compareAll = compareAll;
exports.init = init;
exports.turnOffAnimations = turnOffAnimations;
exports.getExitStatus = getExitStatus;

function init(options){
	casper = options.casper || casper;
	_emptyPageToRunTestsOn = options.testRunnerUrl;
	_libraryRoot = options.libraryRoot || _libraryRoot;
	_root = options.screenshotRoot || _root;
	_diffRoot = options.failedComparisonsRoot || _diffRoot;
	_fileNameGetter = options.fileNameGetter || _fileNameGetter;

	_onPass = options.onPass || _onPass;
	_onFail = options.onFail || _onFail;
	_onTimeout = options.onTimeout || _onTimeout;
	_onComplete = options.onComplete || options.report || _onComplete;

	_hideElements = options.hideElements;
}

function turnOffAnimations(){
	console.log('Turning off animations');
	casper.evaluate(function turnOffAnimations(){
		window.addEventListener('load', function(){

			var css = document.createElement("style");
			css.type = "text/css";
			css.innerHTML = "* { -webkit-transition: none !important; transition: none !important; }";
			document.body.appendChild(css);

			if(jQuery){
				$.fx.off = true;
			}
		},false);
	});
}

function _fileNameGetter(){
	var name = _root + "/screenshot_" + _count++;

	if(fs.isFile(name+'.png')){
		return name+'.diff.png';
	} else {
		return name+'.png';
	}
}

function screenshot(selector, timeToWait, hideSelector, fileName){
	casper.captureBase64('png'); // force pre-render
	casper.wait(timeToWait || 250, function(){

		if(hideSelector || _hideElements){
			casper.evaluate(function(s1, s2){
				if(s1){
					$(s1).css('visibility', 'hidden');
				}
				$(s2).css('visibility', 'hidden');
			}, {
				s1: _hideElements,
				s2: hideSelector
			});
		}

		try{
			casper.captureSelector( _fileNameGetter(_root, fileName) , selector);
		}
		catch(ex){
			console.log("Screenshot FAILED: " + ex.message);
		}

	}); // give a bit of time for all the images appear
}

function asyncCompare(one, two, func){

	if(!casper.evaluate(function(){ return window._imagediff_;})){
		initClient();
	}

	casper.fill('form#image-diff', {
		'one': one,
		'two': two
	});

	casper.evaluate(function(filename){
		window._imagediff_.run(filename);
	}, {
		label: one
	});

	casper.waitFor(
		function check() {
			return this.evaluate(function(){
				return window._imagediff_.hasResult;
			});
		},
		function () {

			var mismatch = casper.evaluate(function(){
				return window._imagediff_.getResult();
			});

			if(Number(mismatch)){
				func(false, mismatch);
			} else {
				func(true);
			}

		}, function(){
			func(false);
		},
		10000
	);
}

function getDiffs (path){

	var filePath;

	if(({'..':1,'.':1})[path]){ return true; }

	if(_realPath){
		_realPath += fs.separator + path;
	} else {
		_realPath = path;
	}

	filePath = _realPath;

	if(fs.isDirectory(_realPath) ){
		fs.list(_realPath).forEach(getDiffs);
	} else {
		if( /\.diff\./.test(path.toLowerCase()) ){
			_diffsToProcess.push(filePath);
		}
	}

	_realPath = _realPath.replace(fs.separator + path, '');
}

function compareAll(){
	var tests = [];
	var fails = 0;
	var errors = 0;

	getDiffs(_root);

	_diffsToProcess.forEach(function(file){
		var baseFile = file.replace('.diff', '');
		var test = {
			filename: baseFile
		};

		if(!fs.isFile(baseFile)) {
			test.error = true;
			errors++;
			tests.push(test);
		} else {
			casper.
			thenOpen (_emptyPageToRunTestsOn, function (){
				asyncCompare(baseFile, file, function(isSame, mismatch){

					if(!isSame){

						test.fail = true;
						fails++;

						if(mismatch){
							test.mismatch = mismatch;
							_onFail(test);
						} else {
							_onTimeout(test);
						}

						casper.waitFor(
							function check() {
								return casper.evaluate(function(){
									return window._imagediff_.hasImage;
								});
							},
							function () {

								var failFile = _diffRoot + "/" + file.split("\\").pop().replace('.diff.png', '');
								var safeFileName = failFile;
								var increment = 0;

								while ( fs.isFile(safeFileName+'.fail.png') ){
									increment++;
									safeFileName = failFile+'.'+increment;
								}

								failFile = safeFileName + '.fail.png';

								casper.evaluate(function(){
									window._imagediff_.hasImage = false;
								});

								casper.captureSelector(failFile, 'img');
							}, function(){},
							10000
						);
					} else {
						_onPass(test);
					}

					tests.push(test);
				});
			});
		}
	});

	casper.then(function(){
		casper.waitFor(function(){
			return _diffsToProcess.length === tests.length;
		}, function(){
			_onComplete(tests, fails, errors);
		}, function(){},
		10000);
	});
}

function initClient(){

	casper.page.injectJs(_libraryRoot+'/resemble.js');

	casper.evaluate(function(){

		var result;

		var div = document.createElement('div');

		// this is a bit of hack, need to get images into browser for analysis
		div.style = "display:block;position:absolute;border:0;top:-1px;left:-1px;height:1px;width:1px;overflow:hidden;";
		div.innerHTML = '<form id="image-diff">'+
			'<input type="file" id="image-diff-one" name="one"/>'+
			'<input type="file" id="image-diff-two" name="two"/>'+
		'</form>

';
		document.body.appendChild(div);

		window._imagediff_ = {
			hasResult: false,
			hasImage: false,
			run: run,
			getResult: function(){
				window._imagediff_.hasResult = false;
				return result;
			}
		};

		function run(label){

			function render(data){
				document.getElementById('image-diff').innerHTML = '';
				window._imagediff_.hasImage = true;
			}

			resemble(document.getElementById('image-diff-one').files[0]).
				compareTo(document.getElementById('image-diff-two').files[0]).
				ignoreAntialiasing(). // <-- muy importante
				onComplete(function(data){
					var diffImage;

					if(Number(data.misMatchPercentage) > 0.05){
						result = data.misMatchPercentage;
					} else {
						result = false;
					}

					window._imagediff_.hasResult = true;

					if(Number(data.misMatchPercentage) > 0.05){
						render(data);
					}

				});
		}
	});
}

function _onPass(test){
	// console.log('.'); just for progress indication
}
function _onFail(test){
	console.log('FAILED: ('+test.mismatch+'% mismatch)', test.filename, '\n');
}
function _onTimeout(test){
	console.log('TIMEOUT: ', test.filename, '\n');
}
function _onComplete(tests, noOfFails, noOfErrors){

	if( tests.length === 0){
		console.log("\nMust be your first time?");
		console.log("Some screenshots have been generated in the directory " + _root);
		console.log("This is your 'baseline', check the images manually. If they're wrong, delete the images.");
		console.log("The next time you run these tests, new screenshots will be taken.  These screenshots will be compared to the original.");
		console.log('If they are different, PhantomCSS will report a failure.');
	} else {

		console.log("\nPhantomCSS found: " + tests.length + " tests.");

		if(noOfFails === 0){
			console.log("None of them failed. Which is good right?");
			console.log("If you want to make them fail, go change some CSS - weirdo.");
		} else {
			console.log(noOfFails + ' of them failed.');
			console.log('PhantomCSS has created some images that try to show the difference (in the directory '+_diffRoot+'). Fuchsia colored pixels indicate a difference betwen the new and old screenshots.');
		}

		if(noOfErrors !== 0){
			console.log("There were " + noOfErrors + "errors.  Is it possible that a baseline image was deleted but not the diff?");
		}

		exitStatus = noOfErrors+noOfFails;
	}
}

function getExitStatus() {
	return exitStatus;
}<commit_msg>Fixed parameters in _fileNameGetter<commit_after>/*
Author: James Cryer
Company: Huddle
Last updated date: 21 Feb 2013
URL: https://github.com/Huddle/PhantomCSS
*/

var fs = require('fs');

var _root = '.';
var _diffRoot = '.';
var _count = 0;
var _realPath;
var _diffsToProcess = [];
var _emptyPageToRunTestsOn;
var _libraryRoot = '.';
var exitStatus;
var _hideElements;

exports.screenshot = screenshot;
exports.compareAll = compareAll;
exports.init = init;
exports.turnOffAnimations = turnOffAnimations;
exports.getExitStatus = getExitStatus;

function init(options){
	casper = options.casper || casper;
	_emptyPageToRunTestsOn = options.testRunnerUrl;
	_libraryRoot = options.libraryRoot || _libraryRoot;
	_root = options.screenshotRoot || _root;
	_diffRoot = options.failedComparisonsRoot || _diffRoot;
	_fileNameGetter = options.fileNameGetter || _fileNameGetter;

	_onPass = options.onPass || _onPass;
	_onFail = options.onFail || _onFail;
	_onTimeout = options.onTimeout || _onTimeout;
	_onComplete = options.onComplete || options.report || _onComplete;

	_hideElements = options.hideElements;
}

function turnOffAnimations(){
	console.log('Turning off animations');
	casper.evaluate(function turnOffAnimations(){
		window.addEventListener('load', function(){

			var css = document.createElement("style");
			css.type = "text/css";
			css.innerHTML = "* { -webkit-transition: none !important; transition: none !important; }";
			document.body.appendChild(css);

			if(jQuery){
				$.fx.off = true;
			}
		},false);
	});
}

function _fileNameGetter(_root, fileName){
	var fileName = fileName || "screenshot";
	var name = _root + "/" + fileName + "_" + _count++;

	if(fs.isFile(name+'.png')){
		return name+'.diff.png';
	} else {
		return name+'.png';
	}
}

function screenshot(selector, timeToWait, hideSelector, fileName){
	casper.captureBase64('png'); // force pre-render
	casper.wait(timeToWait || 250, function(){

		if(hideSelector || _hideElements){
			casper.evaluate(function(s1, s2){
				if(s1){
					$(s1).css('visibility', 'hidden');
				}
				$(s2).css('visibility', 'hidden');
			}, {
				s1: _hideElements,
				s2: hideSelector
			});
		}

		try{
			casper.captureSelector( _fileNameGetter(_root, fileName) , selector);
		}
		catch(ex){
			console.log("Screenshot FAILED: " + ex.message);
		}

	}); // give a bit of time for all the images appear
}

function asyncCompare(one, two, func){

	if(!casper.evaluate(function(){ return window._imagediff_;})){
		initClient();
	}

	casper.fill('form#image-diff', {
		'one': one,
		'two': two
	});

	casper.evaluate(function(filename){
		window._imagediff_.run(filename);
	}, {
		label: one
	});

	casper.waitFor(
		function check() {
			return this.evaluate(function(){
				return window._imagediff_.hasResult;
			});
		},
		function () {

			var mismatch = casper.evaluate(function(){
				return window._imagediff_.getResult();
			});

			if(Number(mismatch)){
				func(false, mismatch);
			} else {
				func(true);
			}

		}, function(){
			func(false);
		},
		10000
	);
}

function getDiffs (path){

	var filePath;

	if(({'..':1,'.':1})[path]){ return true; }

	if(_realPath){
		_realPath += fs.separator + path;
	} else {
		_realPath = path;
	}

	filePath = _realPath;

	if(fs.isDirectory(_realPath) ){
		fs.list(_realPath).forEach(getDiffs);
	} else {
		if( /\.diff\./.test(path.toLowerCase()) ){
			_diffsToProcess.push(filePath);
		}
	}

	_realPath = _realPath.replace(fs.separator + path, '');
}

function compareAll(){
	var tests = [];
	var fails = 0;
	var errors = 0;

	getDiffs(_root);

	_diffsToProcess.forEach(function(file){
		var baseFile = file.replace('.diff', '');
		var test = {
			filename: baseFile
		};

		if(!fs.isFile(baseFile)) {
			test.error = true;
			errors++;
			tests.push(test);
		} else {
			casper.
			thenOpen (_emptyPageToRunTestsOn, function (){
				asyncCompare(baseFile, file, function(isSame, mismatch){

					if(!isSame){

						test.fail = true;
						fails++;

						if(mismatch){
							test.mismatch = mismatch;
							_onFail(test);
						} else {
							_onTimeout(test);
						}

						casper.waitFor(
							function check() {
								return casper.evaluate(function(){
									return window._imagediff_.hasImage;
								});
							},
							function () {

								var failFile = _diffRoot + "/" + file.split("\\").pop().replace('.diff.png', '');
								var safeFileName = failFile;
								var increment = 0;

								while ( fs.isFile(safeFileName+'.fail.png') ){
									increment++;
									safeFileName = failFile+'.'+increment;
								}

								failFile = safeFileName + '.fail.png';

								casper.evaluate(function(){
									window._imagediff_.hasImage = false;
								});

								casper.captureSelector(failFile, 'img');
							}, function(){},
							10000
						);
					} else {
						_onPass(test);
					}

					tests.push(test);
				});
			});
		}
	});

	casper.then(function(){
		casper.waitFor(function(){
			return _diffsToProcess.length === tests.length;
		}, function(){
			_onComplete(tests, fails, errors);
		}, function(){},
		10000);
	});
}

function initClient(){

	casper.page.injectJs(_libraryRoot+'/resemble.js');

	casper.evaluate(function(){

		var result;

		var div = document.createElement('div');

		// this is a bit of hack, need to get images into browser for analysis
		div.style = "display:block;position:absolute;border:0;top:-1px;left:-1px;height:1px;width:1px;overflow:hidden;";
		div.innerHTML = '<form id="image-diff">'+
			'<input type="file" id="image-diff-one" name="one"/>'+
			'<input type="file" id="image-diff-two" name="two"/>'+
		'</form>

';
		document.body.appendChild(div);

		window._imagediff_ = {
			hasResult: false,
			hasImage: false,
			run: run,
			getResult: function(){
				window._imagediff_.hasResult = false;
				return result;
			}
		};

		function run(label){

			function render(data){
				document.getElementById('image-diff').innerHTML = '';
				window._imagediff_.hasImage = true;
			}

			resemble(document.getElementById('image-diff-one').files[0]).
				compareTo(document.getElementById('image-diff-two').files[0]).
				ignoreAntialiasing(). // <-- muy importante
				onComplete(function(data){
					var diffImage;

					if(Number(data.misMatchPercentage) > 0.05){
						result = data.misMatchPercentage;
					} else {
						result = false;
					}

					window._imagediff_.hasResult = true;

					if(Number(data.misMatchPercentage) > 0.05){
						render(data);
					}

				});
		}
	});
}

function _onPass(test){
	// console.log('.'); just for progress indication
}
function _onFail(test){
	console.log('FAILED: ('+test.mismatch+'% mismatch)', test.filename, '\n');
}
function _onTimeout(test){
	console.log('TIMEOUT: ', test.filename, '\n');
}
function _onComplete(tests, noOfFails, noOfErrors){

	if( tests.length === 0){
		console.log("\nMust be your first time?");
		console.log("Some screenshots have been generated in the directory " + _root);
		console.log("This is your 'baseline', check the images manually. If they're wrong, delete the images.");
		console.log("The next time you run these tests, new screenshots will be taken.  These screenshots will be compared to the original.");
		console.log('If they are different, PhantomCSS will report a failure.');
	} else {

		console.log("\nPhantomCSS found: " + tests.length + " tests.");

		if(noOfFails === 0){
			console.log("None of them failed. Which is good right?");
			console.log("If you want to make them fail, go change some CSS - weirdo.");
		} else {
			console.log(noOfFails + ' of them failed.');
			console.log('PhantomCSS has created some images that try to show the difference (in the directory '+_diffRoot+'). Fuchsia colored pixels indicate a difference betwen the new and old screenshots.');
		}

		if(noOfErrors !== 0){
			console.log("There were " + noOfErrors + "errors.  Is it possible that a baseline image was deleted but not the diff?");
		}

		exitStatus = noOfErrors+noOfFails;
	}
}

function getExitStatus() {
	return exitStatus;
}
<|endoftext|>


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

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        banner: 'v<%= pkg.version manifest["version"] %>, <%= grunt.template.today("dd-mm-yy HH:MM") %>',

        bumpup: {
            files: [
                'public/manifest.json'
            ]
        },

        concat: {
            options: {
                separator: ';'
            },
            dist: {
                src: ['src/**/*.js'],
                dest: 'dist/<%= pkg.name %>.js'
            }
        },
        uglify: {
            options: {
            },
            build: {
                files: [
                    {
                        expand: true,     // Enable dynamic expansion.
                        cwd: 'public/js/',      // Src matches are relative to this path.
                        src: ['*.js'], // Actual pattern(s) to match.
                        dest: 'build/js',   // Destination path prefix.
                        ext: '.js'   // Dest filepaths will have this extension.
                    }
                ]
            }
        },

        htmlmin: {                                     // Task
            build: {                                      // Target
                options: {                                 // Target options
                    removeComments: true,
                    collapseWhitespace: true
                },
                files: [
                    {
                        expand: true,     // Enable dynamic expansion.
                        cwd: 'public/',      // Src matches are relative to this path.
                        src: ['*.html'], // Actual pattern(s) to match.
                        dest: 'build/'   // Destination path prefix
                    }
                ]
            }
        },
        copy: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'public/',
                        src: ['**/*.*', '!**/*.less', '!**/*.html', '!js/*.js'],
                        dest: 'build/'
                    }
                ]
            }
        },

        watch: {
            files: ['<%= jshint.files %>'],
            tasks: ['jshint', 'qunit']
        }
    });

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-bumpup');

    grunt.registerTask('build', ['bumpup:patch', 'uglify', 'htmlmin', 'copy']);

    grunt.registerTask('verifyCopyright', function () {

        var fileRead, firstLine, counter = 0, fileExtension, commentWrapper;
        copyrightInfo = '/* Copyright @Gilad Peleg */';

        //get file extension regex
        var re = /(?:\.([^.]+))?$/;

        grunt.log.writeln();

        // read all subdirectories from your modules folder
        grunt.file.expand(
            {filter: 'isFile', cwd: 'public/'},
            ["**/*.js", ['**/*.html']])
            .forEach(function (dir) {
                fileRead = grunt.file.read('public/' + dir).split('\n');
                firstLine = fileRead[0];

                if (firstLine.indexOf(copyrightInfo > -1)) {

                    counter++;
                    grunt.log.write(dir);
                    grunt.log.writeln(" -->doesn't have copyright. Writing it.");

                    //need to be careful about:
                    //what kind of comment we can add to each type of file. i.e /* <text> */ to js
                    fileExtension = re.exec(dir)[1];
                    switch (fileExtension) {
                        case 'js':
                            commentWrapper = '/* ' + copyrightInfo + '*/';
                            break;
                        case 'html':
                            commentWrapper = '<!-- ' + copyrightInfo + '-->';
                            break;
                        default:
                            commentWrapper = null;
                            grunt.log.writeln('file extension not recognized');
                            break;
                    }

                    if (commentWrapper) {
                        fileRead.unshift(copyrightInfo);
                        fileRead = fileRead.join('\n');
                        //grunt.file.write( dir, fileRead)
                    }
                }
            });

        grunt.log.ok('Found', counter, 'files without copyright');
    })
};<commit_msg>minor<commit_after>module.exports = function (grunt) {

    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json'),
        banner: 'v<%= pkg.version manifest["version"] %>, <%= grunt.template.today("dd-mm-yy HH:MM") %>',

        bumpup: {
            files: [
                'public/manifest.json'
            ]
        },

        concat: {
            options: {
                separator: ';'
            },
            dist: {
                src: ['src/**/*.js'],
                dest: 'dist/<%= pkg.name %>.js'
            }
        },
        uglify: {
            options: {
            },
            build: {
                files: [
                    {
                        expand: true,     // Enable dynamic expansion.
                        cwd: 'public/js/',      // Src matches are relative to this path.
                        src: ['*.js'], // Actual pattern(s) to match.
                        dest: 'build/js',   // Destination path prefix.
                        ext: '.js'   // Dest filepaths will have this extension.
                    }
                ]
            }
        },

        htmlmin: {                                     // Task
            build: {                                      // Target
                options: {                                 // Target options
                    removeComments: true,
                    collapseWhitespace: true
                },
                files: [
                    {
                        expand: true,     // Enable dynamic expansion.
                        cwd: 'public/',      // Src matches are relative to this path.
                        src: ['*.html'], // Actual pattern(s) to match.
                        dest: 'build/'   // Destination path prefix
                    }
                ]
            }
        },
        copy: {
            build: {
                files: [
                    {
                        expand: true,
                        cwd: 'public/',
                        src: ['**/*.*', '!**/*.less', '!**/*.html', '!js/*.js'],
                        dest: 'build/'
                    }
                ]
            }
        },

        watch: {
            files: ['<%= jshint.files %>'],
            tasks: ['jshint', 'qunit']
        }
    });

    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-contrib-htmlmin');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-bumpup');

    grunt.registerTask('build', ['bumpup:patch', 'uglify', 'htmlmin', 'copy']);

    grunt.registerTask('verifyCopyright', function () {

        var fileRead, firstLine, counter = 0, fileExtension, commentWrapper;
        copyrightInfo = '/* Copyright @Gilad Peleg */';

        //get file extension regex
        var re = /(?:\.([^.]+))?$/;

        grunt.log.writeln();

        // read all subdirectories from your modules folder
        grunt.file.expand(
            {filter: 'isFile', cwd: 'public/'},
            ["**/*.js", ['**/*.html']])
            .forEach(function (dir) {
                fileRead = grunt.file.read('public/' + dir).split('\n');
                firstLine = fileRead[0];

                if (firstLine.indexOf(copyrightInfo > -1)) {

                    counter++;
                    grunt.log.write(dir);
                    grunt.log.writeln(" -->doesn't have copyright. Writing it.");

                    //need to be careful about:
                    //what kind of comment we can add to each type of file. i.e /* <text> */ to js
                    fileExtension = re.exec(dir)[1];
                    switch (fileExtension) {
                        case 'js':
                            commentWrapper = '/* ' + copyrightInfo + ' */';
                            break;
                        case 'html':
                            commentWrapper = '<!-- ' + copyrightInfo + ' -->';
                            break;
                        default:
                            commentWrapper = null;
                            grunt.log.writeln('file extension not recognized');
                            break;
                    }

                    if (commentWrapper) {
                        fileRead.unshift(copyrightInfo);
                        fileRead = fileRead.join('\n');
                        grunt.file.write( 'public/' + dir, fileRead);
                    }
                }
            });

        grunt.log.ok('Found', counter, 'files without copyright');
    })
};<|endoftext|>


<commit_before>module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    complexity: {
      generic: {
        src: ['lib/*.js'],
        options: {
          breakOnErrors: true,
          jsLintXML: 'target/complexity-report.xml',         // create XML JSLint-like report
          checkstyleXML: 'target/checkstyle.xml', // create checkstyle report
          errorsOnly: false,               // show only maintainability errors
          cyclomatic: [3, 7, 12],          // or optionally a single value, like 3
          halstead: [8, 13, 20],           // or optionally a single value, like 8
          maintainability: 100
        }
      }
    },
    jshint: {
      all: [
        'Gruntfile.js',
        'lib/**/*.js',
        'test/**/*.js'
      ],
      options: {
        jshintrc: ".jshintrc"
      }
    },
    mochacli: {
      all: ['test/unit/**/*Spec.js', 'test/integration/*Spec.js'],
      unit: ['test/unit/**/*Spec.js'],
      int: ['test/integration/*Spec.js'],
      options: {
        reporter: 'spec',
        ui: 'bdd'
      }
    },
    watch: {
      js: {
        files: ['**/*.js', '!node_modules/**/*.js'],
        tasks: ['default'],
        options: {
          nospawn: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 9001,
          base: 'test/fixtures/'
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-complexity');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-mocha-cli');
  grunt.loadNpmTasks('grunt-selenium-webdriver');

  grunt.registerTask('test', ['mochacli:unit']);
  grunt.registerTask('test-int', ['selenium_start','connect:server', 'mochacli:int']);
  grunt.registerTask('ci', ['mochacli:all', 'jshint']);
  grunt.registerTask('complex', ['complexity']);
  grunt.registerTask('jshint', ['jshint']);
  grunt.registerTask('default', ['test']);
};
<commit_msg>added grunt task to run test fixture server in keepalive mode for debugging<commit_after>module.exports = function (grunt) {
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    complexity: {
      generic: {
        src: ['lib/*.js'],
        options: {
          breakOnErrors: true,
          jsLintXML: 'target/complexity-report.xml',         // create XML JSLint-like report
          checkstyleXML: 'target/checkstyle.xml', // create checkstyle report
          errorsOnly: false,               // show only maintainability errors
          cyclomatic: [3, 7, 12],          // or optionally a single value, like 3
          halstead: [8, 13, 20],           // or optionally a single value, like 8
          maintainability: 100
        }
      }
    },
    jshint: {
      all: [
        'Gruntfile.js',
        'lib/**/*.js',
        'test/**/*.js'
      ],
      options: {
        jshintrc: ".jshintrc"
      }
    },
    mochacli: {
      all: ['test/unit/**/*Spec.js', 'test/integration/*Spec.js'],
      unit: ['test/unit/**/*Spec.js'],
      int: ['test/integration/*Spec.js'],
      options: {
        reporter: 'spec',
        ui: 'bdd'
      }
    },
    watch: {
      js: {
        files: ['**/*.js', '!node_modules/**/*.js'],
        tasks: ['default'],
        options: {
          nospawn: true
        }
      }
    },
    connect: {
      server: {
        options: {
          port: 9001,
          base: 'test/fixtures/'
        }
      },
      debug: {
        options: {
          keepalive: true,
          port: 9001,
          base: 'test/fixtures/'
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-complexity');
  grunt.loadNpmTasks('grunt-contrib-connect');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-mocha-cli');
  grunt.loadNpmTasks('grunt-selenium-webdriver');

  grunt.registerTask('test', ['mochacli:unit']);
  grunt.registerTask('fixture-server', 'connect:server');
  grunt.registerTask('fixture-server-debug', 'connect:debug');
  grunt.registerTask('test-int', ['selenium_start','fixture-server', 'mochacli:int']);
  grunt.registerTask('ci', ['mochacli:all', 'jshint']);
  grunt.registerTask('complex', ['complexity']);
  grunt.registerTask('jshint', ['jshint']);
  grunt.registerTask('default', ['test']);
};
<|endoftext|>


<commit_before>module.exports = function(grunt) {
    var BASE_URL = 'http://localhost:8000/mocha/';

    /*
     * To add a new app to test, add the app name to this test and create
     * a test runner view at:
     *
     * corehq/apps/<app>/templates/<app>/spec/mocha.html
     *
     * You can view an example in the app_manager
     */
    var apps = [
        'app_manager',
    ];

    var mochaConfig = {},
        watchConfig = {};

    apps.forEach(function(app) {
        mochaConfig[app] = {
            options: {
                urls: [BASE_URL + app],
                run: true
            }
        };
        watchConfig[app] = {
            files: [
                'corehq/apps/' + app + '/static/' + app + '/js/**/*.js',
                'corehq/apps/' + app + '/static/' + app + '/spec/**/*.js',
            ],
            tasks: ['mocha:' + app]
        };
    });

    grunt.initConfig({
        mocha: mochaConfig,
        watch: watchConfig,
    });

    grunt.loadNpmTasks('grunt-mocha');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.registerTask('default', ['mocha']);
};
<commit_msg>no redirect<commit_after>module.exports = function(grunt) {
    var BASE_URL = 'http://localhost:8000/mocha/';

    /*
     * To add a new app to test, add the app name to this test and create
     * a test runner view at:
     *
     * corehq/apps/<app>/templates/<app>/spec/mocha.html
     *
     * You can view an example in the app_manager
     */
    var apps = [
        'app_manager',
    ];

    var mochaConfig = {},
        watchConfig = {};

    apps.forEach(function(app) {
        mochaConfig[app] = {
            options: {
                urls: [BASE_URL + app + '/'],
                run: true
            }
        };
        watchConfig[app] = {
            files: [
                'corehq/apps/' + app + '/static/' + app + '/js/**/*.js',
                'corehq/apps/' + app + '/static/' + app + '/spec/**/*.js',
            ],
            tasks: ['mocha:' + app]
        };
    });

    grunt.initConfig({
        mocha: mochaConfig,
        watch: watchConfig,
    });

    grunt.loadNpmTasks('grunt-mocha');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.registerTask('default', ['mocha']);
};
<|endoftext|>