<commit_before>module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);

  // Add in time grunt
  require('time-grunt')(grunt);

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    dest: grunt.option('target') || 'dist',
    basePath: 'App_Plugins/<%= pkg.name %>',

    concat: {
      dist: {
        src: [
          'app/js/cms.environment.indicator.js'
        ],
        dest: '<%= dest %>/<%= basePath %>/js/cms.environment.indicator.js',
        nonull: true
      }
    },

    less: {
      dist: {
        options: {
          paths: ["app/css"],
        },
        files: {
          '<%= dest %>/<%= basePath %>/css/cms.environment.indicator.css': 'app/css/cms.environment.indicator.less',
        }
      }
    },

    watch: {
      less: {
        files: ['app/css/**/*.less'],
        tasks: ['less:dist'],
        options: {
          spawn: false
        }
      },

      js: {
        files: ['app/js/**/*.js'],
        tasks: ['concat:dist'],
        options: {
          spawn: false
        }
      },

      html: {
        files: ['app/views/**/*.html'],
        tasks: ['copy:views'],
        options: {
          spawn: false
        }
      }
    },

    copy: {
      config: {
        src: 'config/package.manifest',
        dest: '<%= dest %>/<%= basePath %>/package.manifest',
      },

      views: {
        expand: true,
        cwd: 'app/views/',
        src: '**',
        dest: '<%= dest %>/<%= basePath %>/views/'
      },

      nuget: {
        expand: true,
        cwd: '<%= dest %>',
        src: '**',
        dest: 'tmp/nuget/content/'
      },

      umbraco: {
        expand: true,
        cwd: '<%= dest %>/',
        src: '**',
        dest: 'tmp/umbraco/'
      }
    },

    template: {
      nuspec: {
        options: {
          data: {
            name:        '<%= pkg.name %>',
            version:     '<%= pkg.version %>',
            author:      '<%= pkg.author.name %>',
            description: '<%= pkg.description %>'
          }
        },
        files: {
          'tmp/nuget/<%= pkg.name %>.nuspec': 'config/package.nuspec'
        }
      }
    },

    mkdir: {
      pkg: {
        options: {
          create: ['pkg/nuget', 'pkg/umbraco']
        },
      },
    },

    nugetpack: {
      dist: {
        src: 'tmp/nuget/<%= pkg.name %>.nuspec',
        dest: 'pkg/nuget/'
      }
    },

    umbracoPackage: {
      options: {
        name:        '<%= pkg.name %>',
        version:     '<%= pkg.version %>',
        url:         '<%= pkg.url %>',
        license:     '<%= pkg.license %>',
        licenseUrl:  '<%= pkg.licenseUrl %>',
        author:      '<%= pkg.author %>',
        authorUrl:   '<%= pkg.authorUrl %>',
        manifest:    'config/package.xml',
        readme:      'config/readme.txt',
        sourceDir:   'tmp/umbraco',
        outputDir:   'pkg/umbraco',
      }
    },

    clean: {
      dist: '<%= dest %>'
    }
  });

  //Legacy - now below so we can run our validation check first...
  //grunt.registerTask('default', ['concat', 'less', 'copy:config', 'copy:views']);
  //grunt.registerTask('nuget', ['clean', 'default', 'copy:nuget', 'template:nuspec', 'mkdir:pkg', 'nugetpack']);
  //grunt.registerTask('package', ['clean', 'default', 'copy:umbraco', 'mkdir:pkg', 'umbracoPackage']);

  //TASK: default
  grunt.registerTask('default', 'Concat files, build Less & copy config & views', function(){
    validateTarget();
    grunt.task.run(['concat', 'less', 'copy:config', 'copy:views']);
  });

  //TASK nuget
  grunt.registerTask('nuget', 'Clean, rebuild, copy files for nuget & create it', function(){
    validateTarget();
    grunt.task.run(['clean', 'default', 'copy:nuget', 'template:nuspec', 'mkdir:pkg', 'nugetpack']);
  });

  //TASK umbraco
  grunt.registerTask('package', 'Clean, rebuild, copy files for umbraco package & create it', function(){
    validateTarget();
    grunt.task.run(['clean', 'default', 'copy:umbraco', 'mkdir:pkg', 'umbracoPackage']);
  });

  //Validation for --target option
  function validateTarget() {

    var destTarget = grunt.config.get('dest');

    //Debug
    grunt.log.oklns('Target (dest) is: ' + destTarget);

    //If dest is not set to dist then a target option was set
    if(destTarget != 'dist') {

      //Happens when grunt --target is called
      if(destTarget === true) {
        //Error message & stop processing task
        grunt.fail.warn('You need to specify a folder for target: grunt --target=c:/mysite/');
      }

      //Ensure that the dest value the --target is actually a directory that exists
      if(!grunt.file.isDir(destTarget)){

        //Error message & stop processing task
        grunt.fail.warn('The target passed in is not a folder path.');
      }
    }
  }

};

<commit_msg>Corrected filename typo in gruntfile<commit_after>module.exports = function(grunt) {
  require('load-grunt-tasks')(grunt);

  // Add in time grunt
  require('time-grunt')(grunt);

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    dest: grunt.option('target') || 'dist',
    basePath: 'App_Plugins/<%= pkg.name %>',

    concat: {
      dist: {
        src: [
          'app/js/cms-environment-indicator.js'
        ],
        dest: '<%= dest %>/<%= basePath %>/js/cms-environment-indicator.js',
        nonull: true
      }
    },

    less: {
      dist: {
        options: {
          paths: ["app/css"],
        },
        files: {
          '<%= dest %>/<%= basePath %>/css/cms-environment-indicator.css': 'app/css/cms.environment.indicator.less',
        }
      }
    },

    watch: {
      less: {
        files: ['app/css/**/*.less'],
        tasks: ['less:dist'],
        options: {
          spawn: false
        }
      },

      js: {
        files: ['app/js/**/*.js'],
        tasks: ['concat:dist'],
        options: {
          spawn: false
        }
      },

      html: {
        files: ['app/views/**/*.html'],
        tasks: ['copy:views'],
        options: {
          spawn: false
        }
      }
    },

    copy: {
      config: {
        src: 'config/package.manifest',
        dest: '<%= dest %>/<%= basePath %>/package.manifest',
      },

      views: {
        expand: true,
        cwd: 'app/views/',
        src: '**',
        dest: '<%= dest %>/<%= basePath %>/views/'
      },

      nuget: {
        expand: true,
        cwd: '<%= dest %>',
        src: '**',
        dest: 'tmp/nuget/content/'
      },

      umbraco: {
        expand: true,
        cwd: '<%= dest %>/',
        src: '**',
        dest: 'tmp/umbraco/'
      }
    },

    template: {
      nuspec: {
        options: {
          data: {
            name:        '<%= pkg.name %>',
            version:     '<%= pkg.version %>',
            author:      '<%= pkg.author.name %>',
            description: '<%= pkg.description %>'
          }
        },
        files: {
          'tmp/nuget/<%= pkg.name %>.nuspec': 'config/package.nuspec'
        }
      }
    },

    mkdir: {
      pkg: {
        options: {
          create: ['pkg/nuget', 'pkg/umbraco']
        },
      },
    },

    nugetpack: {
      dist: {
        src: 'tmp/nuget/<%= pkg.name %>.nuspec',
        dest: 'pkg/nuget/'
      }
    },

    umbracoPackage: {
      options: {
        name:        '<%= pkg.name %>',
        version:     '<%= pkg.version %>',
        url:         '<%= pkg.url %>',
        license:     '<%= pkg.license %>',
        licenseUrl:  '<%= pkg.licenseUrl %>',
        author:      '<%= pkg.author %>',
        authorUrl:   '<%= pkg.authorUrl %>',
        manifest:    'config/package.xml',
        readme:      'config/readme.txt',
        sourceDir:   'tmp/umbraco',
        outputDir:   'pkg/umbraco',
      }
    },

    clean: {
      dist: '<%= dest %>'
    }
  });

  //Legacy - now below so we can run our validation check first...
  //grunt.registerTask('default', ['concat', 'less', 'copy:config', 'copy:views']);
  //grunt.registerTask('nuget', ['clean', 'default', 'copy:nuget', 'template:nuspec', 'mkdir:pkg', 'nugetpack']);
  //grunt.registerTask('package', ['clean', 'default', 'copy:umbraco', 'mkdir:pkg', 'umbracoPackage']);

  //TASK: default
  grunt.registerTask('default', 'Concat files, build Less & copy config & views', function(){
    validateTarget();
    grunt.task.run(['concat', 'less', 'copy:config', 'copy:views']);
  });

  //TASK nuget
  grunt.registerTask('nuget', 'Clean, rebuild, copy files for nuget & create it', function(){
    validateTarget();
    grunt.task.run(['clean', 'default', 'copy:nuget', 'template:nuspec', 'mkdir:pkg', 'nugetpack']);
  });

  //TASK umbraco
  grunt.registerTask('package', 'Clean, rebuild, copy files for umbraco package & create it', function(){
    validateTarget();
    grunt.task.run(['clean', 'default', 'copy:umbraco', 'mkdir:pkg', 'umbracoPackage']);
  });

  //Validation for --target option
  function validateTarget() {

    var destTarget = grunt.config.get('dest');

    //Debug
    grunt.log.oklns('Target (dest) is: ' + destTarget);

    //If dest is not set to dist then a target option was set
    if(destTarget != 'dist') {

      //Happens when grunt --target is called
      if(destTarget === true) {
        //Error message & stop processing task
        grunt.fail.warn('You need to specify a folder for target: grunt --target=c:/mysite/');
      }

      //Ensure that the dest value the --target is actually a directory that exists
      if(!grunt.file.isDir(destTarget)){

        //Error message & stop processing task
        grunt.fail.warn('The target passed in is not a folder path.');
      }
    }
  }

};

<|endoftext|>


<commit_before>/* jshint indent: 2 */

// Generated on 2014-06-19 using generator-angular-fullstack 1.4.3
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },
    express: {
      options: {
        port: process.env.PORT || 9000
      },
      dev: {
        options: {
          script: 'server.js',
          debug: true
        }
      },
      prod: {
        options: {
          script: 'server.js',
          node_env: 'production'
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:<%= express.options.port %>'
      }
    },
    watch: {
      js: {
        files: ['<%= yeoman.app %>/js/**/*.js'],
        tasks: ['newer:jshint:client'],
        options: {
          livereload: true
        }
      },
      jsTest: {
        files: ['test/spec/**/*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      sass: {
        files: ['<%= yeoman.app %>/styles/**/*.{scss,sass}'],
        tasks: ['sass', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        files: [
          '<%= yeoman.app %>/views/{,*//*}*.html',
          '{.tmp,<%= yeoman.app %>}/styles/{,*//*}*.css',
          '{.tmp,<%= yeoman.app %>}/js/{,*//*}*.js',
          '<%= yeoman.app %>/img/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'
        ],

        options: {
          livereload: true
        }
      },
      express: {
        files: [
          'server.js',
          'index.js'
        ],
        tasks: ['newer:jshint:node', 'express:dev', 'wait'],
        options: {
          livereload: true,
          nospawn: true //Without this option specified express won't be reloaded
        }
      }
    },
    jscs: {
        src: ['<%= yeoman.app %>/js/**/*.js'],
        options: {
            config: '.jscsrc',
            verbose: true // If you need output with rule names http://jscs.info/overview.html#verbose
        }
    },
    jshint: {
      options: {
        reporter: require('jshint-stylish'),
        node: true,
        bitwise: true,
        immed: true,
        indent: 4,
        latedef: true,
        newcap: true,
        noarg: true,
        quotmark: 'single',
        regexp: true,
        undef: true,
        unused: true
      },
      node: ['*.js'],
      client: {
        files: {
          src: ['<%= yeoman.app %>/js/**/*.js']
        },
        options: {
          browser: true,
          esnext: true,
          camelcase: true,
          strict: true,
          globalstrict: true,
          globals: {
            angular: true,
            moment: true,
            _: true,
            _s: true
          }
        }
      },
      test: {
        files: {
          src: ['test/spec/**/*.js']
        },
        options: {
          esnext: true,
          camelcase: false,
          curly: true,
          strict: true,
          globals: {
            after: false,
            afterEach: false,
            angular: false,
            before: false,
            beforeEach: false,
            browser: false,
            describe: false,
            expect: false,
            inject: false,
            it: false,
            jasmine: false,
            spyOn: false
          }
        }
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version', 'firefox >= 20']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Debugging with node inspector
    'node-inspector': {
      custom: {
        options: {
          'web-host': 'localhost'
        }
      }
    },

    // Use nodemon to run server in debug mode with an initial breakpoint
    nodemon: {
      debug: {
        script: 'server.js',
        options: {
          nodeArgs: ['--debug-brk'],
          env: {
            PORT: process.env.PORT || 9000
          },
          callback: function (nodemon) {
            nodemon.on('log', function (event) {
              console.log(event.colour);
            });

            // opens browser on initial server start
            nodemon.on('config:update', function () {
              setTimeout(function () {
                require('open')('http://localhost:8080/debug?port=5858');
              }, 500);
            });
          }
        }
      }
    },

    // Automatically inject Bower components into the app
    'bower-install': {
      app: {
        html: '<%= yeoman.app %>/views/front.html',
        ignorePath: '<%= yeoman.app %>/',
        exclude: ['bootstrap-sass', 'jquery']
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    sass: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/styles',
          src: '**/*.scss',
          dest: '.tmp/styles',
          ext: '.css'
        }],
        options: {
          includePaths: ['<%= yeoman.app %>/bower_components']
        }
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= yeoman.dist %>/js/{,*/}*.js',
            '<%= yeoman.dist %>/styles/{,*/}*.css',
            '<%= yeoman.dist %>/styles/fonts/*'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/views/front.html', '<%= yeoman.app %>/views/embed.html'],
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/views/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>']
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/img',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/img'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          //collapseWhitespace: true,
          //collapseBooleanAttributes: true,
          //removeCommentsFromCDATA: true,
          //removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/views',
          src: ['*.html', 'partials/**/*.html'],
          dest: '<%= yeoman.dist %>/views'
        }]
      }
    },

    // Allow the use of non-minsafe AngularJS files. Automatically makes it
    // minsafe compatible so Uglify does not destroy the ng references
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/js',
          src: '*.js',
          dest: '.tmp/concat/js'
        }]
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            'bower_components/**/*',
            'img/{,*/}*.{png,jpg,jpeg,gif}',
            'fonts/**/*',
            'resources/**/*',
            'documents/**/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/img',
          dest: '<%= yeoman.dist %>/img',
          src: ['generated/*']
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'sass'
      ],
      test: [
        'sass'
      ],
      debug: {
        tasks: [
          'nodemon',
          'node-inspector'
        ],
        options: {
          logConcurrentOutput: true
        }
      },
      dist: [
        'sass:dist',
        'svgmin',
        'htmlmin'
      ]
    },

    // By default, your `index.html`'s <!-- Usemin block --> will take care of
    // minification. These next options are pre-configured if you do not wish
    // to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css',
    //         '<%= yeoman.app %>/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/js/js.js': [
    //         '<%= yeoman.dist %>/js/js.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    // Test settings
    karma: {
      unit: {
        configFile: 'karma.conf.js',
        singleRun: true
      }
    },

    env: {
      test: {
        NODE_ENV: 'test'
      }
    },

    htmlrefs: {
      dist: {
        src: './dist/views/front.html',
        dest: './dist/views/front.html',
        options: {
          includes: {
            piwik: './piwik.inc'
          }
        }
      }
    }
  });

  // Used for delaying livereload until after server has restarted
  grunt.registerTask('wait', function () {
    grunt.log.ok('Waiting for server reload…');

    var done = this.async();

    setTimeout(function () {
      grunt.log.writeln('Done waiting!');
      done();
    }, 500);
  });

  grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
    this.async();
  });

  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'express:prod', 'open', 'express-keepalive']);
    }

    if (target === 'debug') {
      return grunt.task.run([
        'clean:server',
        'bower-install',
        'concurrent:server',
        'autoprefixer',
        'concurrent:debug'
      ]);
    }

    grunt.task.run([
      'clean:server',
      'bower-install',
      'concurrent:server',
      'autoprefixer',
      'express:dev',
      'open',
      'watch'
    ]);
  });

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

  grunt.registerTask('build', [
    'clean:dist',
    'bower-install',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'cssmin',
    'uglify',
    'rev',
    'usemin',
    'htmlrefs:dist'
  ]);

  grunt.registerTask('default', [
    'jshint',
    'jscs',
    'test',
    'build'
  ]);
};
<commit_msg>Allow unconventional line breaks in jshint<commit_after>/* jshint indent: 2 */

// Generated on 2014-06-19 using generator-angular-fullstack 1.4.3
'use strict';

// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to recursively match all subfolders:
// 'test/spec/**/*.js'

module.exports = function (grunt) {

  // Load grunt tasks automatically
  require('load-grunt-tasks')(grunt);

  // Time how long tasks take. Can help when optimizing build times
  require('time-grunt')(grunt);

  // Define the configuration for all the tasks
  grunt.initConfig({

    // Project settings
    yeoman: {
      // configurable paths
      app: require('./bower.json').appPath || 'app',
      dist: 'dist'
    },
    express: {
      options: {
        port: process.env.PORT || 9000
      },
      dev: {
        options: {
          script: 'server.js',
          debug: true
        }
      },
      prod: {
        options: {
          script: 'server.js',
          node_env: 'production'
        }
      }
    },
    open: {
      server: {
        url: 'http://localhost:<%= express.options.port %>'
      }
    },
    watch: {
      js: {
        files: ['<%= yeoman.app %>/js/**/*.js'],
        tasks: ['newer:jshint:client'],
        options: {
          livereload: true
        }
      },
      jsTest: {
        files: ['test/spec/**/*.js'],
        tasks: ['newer:jshint:test', 'karma']
      },
      sass: {
        files: ['<%= yeoman.app %>/styles/**/*.{scss,sass}'],
        tasks: ['sass', 'autoprefixer']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        files: [
          '<%= yeoman.app %>/views/{,*//*}*.html',
          '{.tmp,<%= yeoman.app %>}/styles/{,*//*}*.css',
          '{.tmp,<%= yeoman.app %>}/js/{,*//*}*.js',
          '<%= yeoman.app %>/img/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}'
        ],

        options: {
          livereload: true
        }
      },
      express: {
        files: [
          'server.js',
          'index.js'
        ],
        tasks: ['newer:jshint:node', 'express:dev', 'wait'],
        options: {
          livereload: true,
          nospawn: true //Without this option specified express won't be reloaded
        }
      }
    },
    jscs: {
        src: ['<%= yeoman.app %>/js/**/*.js'],
        options: {
            config: '.jscsrc',
            verbose: true // If you need output with rule names http://jscs.info/overview.html#verbose
        }
    },
    jshint: {
      options: {
        reporter: require('jshint-stylish'),
        node: true,
        bitwise: true,
        immed: true,
        indent: 4,
        latedef: true,
        newcap: true,
        noarg: true,
        quotmark: 'single',
        regexp: true,
        undef: true,
        unused: true,
        laxbreak: true
      },
      node: ['*.js'],
      client: {
        files: {
          src: ['<%= yeoman.app %>/js/**/*.js']
        },
        options: {
          browser: true,
          esnext: true,
          camelcase: true,
          strict: true,
          globalstrict: true,
          globals: {
            angular: true,
            moment: true,
            _: true,
            _s: true
          }
        }
      },
      test: {
        files: {
          src: ['test/spec/**/*.js']
        },
        options: {
          esnext: true,
          camelcase: false,
          curly: true,
          strict: true,
          globals: {
            after: false,
            afterEach: false,
            angular: false,
            before: false,
            beforeEach: false,
            browser: false,
            describe: false,
            expect: false,
            inject: false,
            it: false,
            jasmine: false,
            spyOn: false
          }
        }
      }
    },

    // Empties folders to start fresh
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '.tmp',
            '<%= yeoman.dist %>/*'
          ]
        }]
      },
      server: '.tmp'
    },

    // Add vendor prefixed styles
    autoprefixer: {
      options: {
        browsers: ['last 1 version', 'firefox >= 20']
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/styles/',
          src: '{,*/}*.css',
          dest: '.tmp/styles/'
        }]
      }
    },

    // Debugging with node inspector
    'node-inspector': {
      custom: {
        options: {
          'web-host': 'localhost'
        }
      }
    },

    // Use nodemon to run server in debug mode with an initial breakpoint
    nodemon: {
      debug: {
        script: 'server.js',
        options: {
          nodeArgs: ['--debug-brk'],
          env: {
            PORT: process.env.PORT || 9000
          },
          callback: function (nodemon) {
            nodemon.on('log', function (event) {
              console.log(event.colour);
            });

            // opens browser on initial server start
            nodemon.on('config:update', function () {
              setTimeout(function () {
                require('open')('http://localhost:8080/debug?port=5858');
              }, 500);
            });
          }
        }
      }
    },

    // Automatically inject Bower components into the app
    'bower-install': {
      app: {
        html: '<%= yeoman.app %>/views/front.html',
        ignorePath: '<%= yeoman.app %>/',
        exclude: ['bootstrap-sass', 'jquery']
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    sass: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/styles',
          src: '**/*.scss',
          dest: '.tmp/styles',
          ext: '.css'
        }],
        options: {
          includePaths: ['<%= yeoman.app %>/bower_components']
        }
      }
    },

    // Renames files for browser caching purposes
    rev: {
      dist: {
        files: {
          src: [
            '<%= yeoman.dist %>/js/{,*/}*.js',
            '<%= yeoman.dist %>/styles/{,*/}*.css',
            '<%= yeoman.dist %>/styles/fonts/*'
          ]
        }
      }
    },

    // Reads HTML for usemin blocks to enable smart builds that automatically
    // concat, minify and revision files. Creates configurations in memory so
    // additional tasks can operate on them
    useminPrepare: {
      html: ['<%= yeoman.app %>/views/front.html', '<%= yeoman.app %>/views/embed.html'],
      options: {
        dest: '<%= yeoman.dist %>'
      }
    },

    // Performs rewrites based on rev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/views/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
      options: {
        assetsDirs: ['<%= yeoman.dist %>']
      }
    },

    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/img',
          src: '{,*/}*.svg',
          dest: '<%= yeoman.dist %>/img'
        }]
      }
    },

    htmlmin: {
      dist: {
        options: {
          //collapseWhitespace: true,
          //collapseBooleanAttributes: true,
          //removeCommentsFromCDATA: true,
          //removeOptionalTags: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/views',
          src: ['*.html', 'partials/**/*.html'],
          dest: '<%= yeoman.dist %>/views'
        }]
      }
    },

    // Allow the use of non-minsafe AngularJS files. Automatically makes it
    // minsafe compatible so Uglify does not destroy the ng references
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/js',
          src: '*.js',
          dest: '.tmp/concat/js'
        }]
      }
    },

    // Copies remaining files to places other tasks can use
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          dest: '<%= yeoman.dist %>',
          src: [
            '*.{ico,png,txt}',
            'bower_components/**/*',
            'img/{,*/}*.{png,jpg,jpeg,gif}',
            'fonts/**/*',
            'resources/**/*',
            'documents/**/*'
          ]
        }, {
          expand: true,
          cwd: '.tmp/img',
          dest: '<%= yeoman.dist %>/img',
          src: ['generated/*']
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/styles',
        dest: '.tmp/styles/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'sass'
      ],
      test: [
        'sass'
      ],
      debug: {
        tasks: [
          'nodemon',
          'node-inspector'
        ],
        options: {
          logConcurrentOutput: true
        }
      },
      dist: [
        'sass:dist',
        'svgmin',
        'htmlmin'
      ]
    },

    // By default, your `index.html`'s <!-- Usemin block --> will take care of
    // minification. These next options are pre-configured if you do not wish
    // to use the Usemin blocks.
    // cssmin: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/styles/main.css': [
    //         '.tmp/styles/{,*/}*.css',
    //         '<%= yeoman.app %>/styles/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/js/js.js': [
    //         '<%= yeoman.dist %>/js/js.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    // Test settings
    karma: {
      unit: {
        configFile: 'karma.conf.js',
        singleRun: true
      }
    },

    env: {
      test: {
        NODE_ENV: 'test'
      }
    },

    htmlrefs: {
      dist: {
        src: './dist/views/front.html',
        dest: './dist/views/front.html',
        options: {
          includes: {
            piwik: './piwik.inc'
          }
        }
      }
    }
  });

  // Used for delaying livereload until after server has restarted
  grunt.registerTask('wait', function () {
    grunt.log.ok('Waiting for server reload…');

    var done = this.async();

    setTimeout(function () {
      grunt.log.writeln('Done waiting!');
      done();
    }, 500);
  });

  grunt.registerTask('express-keepalive', 'Keep grunt running', function() {
    this.async();
  });

  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'express:prod', 'open', 'express-keepalive']);
    }

    if (target === 'debug') {
      return grunt.task.run([
        'clean:server',
        'bower-install',
        'concurrent:server',
        'autoprefixer',
        'concurrent:debug'
      ]);
    }

    grunt.task.run([
      'clean:server',
      'bower-install',
      'concurrent:server',
      'autoprefixer',
      'express:dev',
      'open',
      'watch'
    ]);
  });

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

  grunt.registerTask('build', [
    'clean:dist',
    'bower-install',
    'useminPrepare',
    'concurrent:dist',
    'autoprefixer',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'cssmin',
    'uglify',
    'rev',
    'usemin',
    'htmlrefs:dist'
  ]);

  grunt.registerTask('default', [
    'jshint',
    'jscs',
    'test',
    'build'
  ]);
};
<|endoftext|>


<commit_before>// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
  // show elapsed time at the end
  require('time-grunt')(grunt);
  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // configurable paths
  var config = {
      app: 'src/main/javascript',
      test: 'src/test',
      dist: 'dist'
  };

  grunt.registerMultiTask('echo', 'Echo back input', function(){
    var data = this.data;

    if (typeof (data) === 'string') {
      if (grunt.file.exists(data)) {
        grunt.log.writeln(grunt.file.read(data));
      } else {
        grunt.log.writeln(data);
      }
    }

    if (typeof (data) === 'object') {
      var key;
      for (key in data) {
        if (data.hasOwnProperty(key)) {
          grunt.log.writeln(data[key]);
        }
      }
    }
  });

  var pkg = grunt.file.readJSON('package.json');
  grunt.initConfig({
    pkg: pkg,
    config: config,

    echo: {
      help: 'README.md'
    },

    clean: {
      options: {
        force: true
      },
      links: ["dist/**", "coverage/**"]
    },

    jsdoc : {
      dist : {
        src: ['<%= config.app %>/*.js', '<%= config.app %>/**/*.js', 'README.md'],
        options: {
          destination: 'docs/jsdoc',
          configure: './conf/jsdoc.json',
          template: './node_modules/jsdoc-oblivion/template'
        }
      }
    },

    copy: {
      dist: {
        src: '<%= config.app %>/<%= pkg.name %>.js',
        dest: '<%= config.dist %>/<%= pkg.name %>.js',
        options: {
          process: function (content) {
            return '/* ' + pkg.name + ' v' + pkg.version + ' ' + grunt.template.today("yyyy-mm-dd") + ' - Copyright 2015, Johannes Fischer */\n' + content;
          },
        },
      }
    },

    jshint: {
        options: {
            jshintrc: '.jshintrc',
            reporter: require('jshint-stylish')
        },
        all: [
            'Gruntfile.js',
            '<%= config.app %>/{,*/}*.js'
        ]
    },

    karma: {
      options: {
        configFile: '<%= config.test %>/karma.conf.js',
      },
      unit: {
        singleRun: true,
        browsers: ['PhantomJS'],
        reporters: ['dots', 'coverage']
      },
      watch: {
        browsers: ['PhantomJS'],
        reporters: ['dots', 'coverage']
      },
      debug: {
        reporters: ['progress']
      }
    },

    checkDependencies: {
      'this': {
        options: {
          npmInstall: true
        }
      }
    },

    shell: {
      "create-site": {
        command: [
          "rm -rf site",
          "generate-md --layout mixu-gray --input ./README.md --output ./site",
          "mv site/README.html site/index.html",
          "cp -r docs/jsdoc site/docs"
        ].join("&&")
      }
    }
  });

  // Print help
  grunt.registerTask('help', ['echo:help']);

  // Verify installation
  grunt.registerTask('verify', ['checkDependencies']);

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

  // Build
  grunt.registerTask('build', [
    'clean',
    'jshint',
    'karma:unit'
  ]);

  grunt.registerTask('release', [
    'build',
    'copy:dist',
    'jsdoc'
    // add more tasks like update version, npm publish, etc.
  ]);

  grunt.registerTask('website', [
    "shell:create-site"
  ]);

  // Setup default task that runs when you just run 'grunt'
  grunt.registerTask('default', ['build']);
};<commit_msg>Removed copyright info from copy:dist task and finished release task<commit_after>// # Globbing
// for performance reasons we're only matching one level down:
// 'test/spec/{,*/}*.js'
// use this if you want to match all subfolders:
// 'test/spec/**/*.js'
module.exports = function (grunt) {
  // show elapsed time at the end
  require('time-grunt')(grunt);
  // load all grunt tasks
  require('load-grunt-tasks')(grunt);

  // configurable paths
  var config = {
      app: 'src/main/javascript',
      test: 'src/test',
      dist: 'dist'
  };

  grunt.registerMultiTask('echo', 'Echo back input', function(){
    var data = this.data;

    if (typeof (data) === 'string') {
      if (grunt.file.exists(data)) {
        grunt.log.writeln(grunt.file.read(data));
      } else {
        grunt.log.writeln(data);
      }
    }

    if (typeof (data) === 'object') {
      var key;
      for (key in data) {
        if (data.hasOwnProperty(key)) {
          grunt.log.writeln(data[key]);
        }
      }
    }
  });

  var pkg = grunt.file.readJSON('package.json');
  grunt.initConfig({
    pkg: pkg,
    config: config,

    echo: {
      help: 'README.md'
    },

    clean: {
      options: {
        force: true
      },
      links: ["dist/**", "coverage/**"]
    },

    jsdoc : {
      dist : {
        src: ['<%= config.app %>/*.js', '<%= config.app %>/**/*.js', 'README.md'],
        options: {
          destination: 'docs/jsdoc',
          configure: './conf/jsdoc.json',
          template: './node_modules/jsdoc-oblivion/template'
        }
      }
    },

    copy: {
      dist: {
        src: '<%= config.app %>/<%= pkg.name %>.js',
        dest: '<%= config.dist %>/<%= pkg.name %>.js'
      }
    },

    jshint: {
        options: {
            jshintrc: '.jshintrc',
            reporter: require('jshint-stylish')
        },
        all: [
            'Gruntfile.js',
            '<%= config.app %>/{,*/}*.js'
        ]
    },

    karma: {
      options: {
        configFile: '<%= config.test %>/karma.conf.js',
      },
      unit: {
        singleRun: true,
        browsers: ['PhantomJS'],
        reporters: ['dots', 'coverage']
      },
      watch: {
        browsers: ['PhantomJS'],
        reporters: ['dots', 'coverage']
      },
      debug: {
        reporters: ['progress']
      }
    },

    checkDependencies: {
      'this': {
        options: {
          npmInstall: true
        }
      }
    },

    shell: {
      "create-site": {
        command: [
          "rm -rf site",
          "generate-md --layout mixu-gray --input ./README.md --output ./site",
          "mv site/README.html site/index.html",
          "cp -r docs/jsdoc site/docs"
        ].join("&&")
      },
      "version": {
        command: function (newVersion) {
          var versionRegex = /^\d+\.\d+\.\d+$/;
          if (!versionRegex.test(newVersion)) {
            grunt.fail.fatal(newVersion + " is not a proper version.");
          }

          return "npm version " + newVersion;
        }
      },
      "publish": {
        command: "npm publish"
      }
    }
  });

  // Print help
  grunt.registerTask('help', ['echo:help']);

  // Verify installation
  grunt.registerTask('verify', ['checkDependencies']);

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

  // Build
  grunt.registerTask('build', [
    'clean',
    'jshint',
    'karma:unit'
  ]);

  grunt.registerTask('release', 'Build a new version and publish to NPM', function (newVersion) {
    var tasks = [
      'build',
      'copy:dist',
      'jsdoc'
    ];

    tasks.push('shell:version:' + newVersion);
    tasks.push('shell:publish');

    grunt.task.run(tasks);
  });

  grunt.registerTask('website', [
    "shell:create-site"
  ]);

  // Setup default task that runs when you just run 'grunt'
  grunt.registerTask('default', ['build']);
};<|endoftext|>


<commit_before>module.exports = function(grunt) {
    grunt.initConfig({
        bower: {
            main: {
                rjsConfig: 'js/main.js'
            }
        },
        jshint: {
            files: ['Gruntfile.js', 'js/**/*.js', 'specs/**/*.js'],
            options: {
                ignores: ['js/vendor/*.js']
            }
        },
        jasmine: {
            src: ['js/**/*.js'],
            options: {
                specs: ['specs/**/*.spec.js'],
                template: require('grunt-template-jasmine-requirejs'),
                templateOptions: {
                    requireConfigFile: 'js/main.js',
                    requireConfig: {
                        baseUrl: 'js'
                    }
                }
            }
        },
        watch: {
            files: ['Gruntfile.js', 'js/**/*.js', 'specs/**/*.js'],
            tasks: ['jshint', 'jasmine']
        }
    });

    grunt.loadNpmTasks('grunt-bower-requirejs');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-watch');

	grunt.registerTask('travis', ['jshint', 'jasmine']);
};<commit_msg>Added a default grunt task The idea is to run grunt when you open the project. It will run the jshint and jasmine tasks then, assuming there were no errors, start the watch task.<commit_after>module.exports = function(grunt) {
    grunt.initConfig({
        bower: {
            main: {
                rjsConfig: 'js/main.js'
            }
        },
        jshint: {
            files: ['Gruntfile.js', 'js/**/*.js', 'specs/**/*.js'],
            options: {
                ignores: ['js/vendor/*.js']
            }
        },
        jasmine: {
            src: ['js/**/*.js'],
            options: {
                specs: ['specs/**/*.spec.js'],
                template: require('grunt-template-jasmine-requirejs'),
                templateOptions: {
                    requireConfigFile: 'js/main.js',
                    requireConfig: {
                        baseUrl: 'js'
                    }
                }
            }
        },
        watch: {
            files: ['Gruntfile.js', 'js/**/*.js', 'specs/**/*.js'],
            tasks: ['jshint', 'jasmine']
        }
    });

    grunt.loadNpmTasks('grunt-bower-requirejs');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-jasmine');
    grunt.loadNpmTasks('grunt-contrib-watch');

	grunt.registerTask('travis', ['jshint', 'jasmine']);
	grunt.registerTask('default', ['jshint', 'jasmine', 'watch']);
};<|endoftext|>


<commit_before>/* global module: true */
module.exports = function (grunt) {
   'use strict';

   // Project configuration.
   grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      meta: {
         banner: [
                '/**',
                ' * <%= pkg.name %>',
                ' * <%= pkg.description %>',
                ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>' +
                ' * @link <%= pkg.homepage %>',
                ' * @author <%= pkg.author %>',
                ' * @license MIT License, http://www.opensource.org/licenses/MIT',
                ' */'
            ].join('\n'),
      },
      dirs: {
         dest: 'dist',
         dep: '<%= dirs.dest %>/dependencies',
         source: 'src',
         test: 'spec'
      },
      files: {
         src: [
               '<%= dirs.source %>/moduleLoader/moduleLoader.js',
               '<%= dirs.source %>/moduleLoader/moduleBuilder.js',
               '<%= dirs.source %>/moduleLoader/partAccess.js',
               '<%= dirs.source %>/moduleLoader/moduleAccess.js',
               '<%= dirs.source %>/eventBus/eventBus.js',
               '<%= dirs.source %>/moduleLoader/moduleSystem.js',
               '<%= dirs.source %>/moduleLoader/moduleLoader.js'
         ]
      },
      bower: {
         dev: {
            dest: '<%= dirs.dep %>'
         }
      },
      concat: {
         options: {
            banner: '<%= meta.banner %>'
         },
         dist: {
            src: [
               '<%= dirs.source %>/intro.js',
               '<%= files.src %>',
               '<%= dirs.source %>/outro.js'
            ],
            dest: '<%= dirs.dest %>/<%= pkg.name %>.<%= pkg.version %>.js'
         }
      },
      bowerInstall: {
         install: {}
      },
      uglify: {
         options: {
            banner: '<%= meta.banner %>'
         },
         dist: {
            src: ['<%= concat.dist.dest %>'],
            dest: '<%= dirs.dest %>/<%= pkg.name %>.<%= pkg.version %>.min.js'
         }
      },
      jshint: {
         files: ['<%= dirs.source %>/**/*.js'],
         options: {
            jshintrc: true
         }
      },
      jasmine: {
         options: {
            vendor: [
               '<%= dirs.dep %>/dist/jquery.js',
               '<%= dirs.dep %>/lib/jasmine-jquery.js'
            ],
            specs: [
               '<%= dirs.test %>/**/*Spec.js'
            ]
         },
         test: {
            src: '<%= files.src %>',
            options: '<%= jasmine.options %>'
         },
         prod: {
            src: '<%= concat.dist.dest %>',
            options: '<%= jasmine.options %>'
         },
         prodMin: {
            src: '<%= uglify.dist.dest %>',
            options: '<%= jasmine.options %>'
         }
      },
      bump: {
         options: {
            files: ['package.json', 'bower.json'],
            updateConfigs: ['pkg'],
            commit: true,
            commitMessage: 'Release v%VERSION%',
            commitFiles: ['-a'],
            createTag: true,
            tagName: 'v%VERSION%',
            tagMessage: 'Version %VERSION%',
            push: true,
            pushTo: 'origin',
            gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
         }
      },
      copy: {
        release: {
          src: '<%= concat.dist.dest %>',
          dest: '<%= dirs.dest %>/<%= pkg.name %>.js',
        },
        releaseMin: {
          src: '<%= uglify.dist.dest %>',
          dest: '<%= dirs.dest %>/<%= pkg.name %>.min.js',
        },
      },
      exec: {
         gitAddAll: 'git add --all'
      }
   });

   // Load the plugin that provides the "jshint" task.
   grunt.loadNpmTasks('grunt-contrib-jshint');

   // Load the plugin that provides the "concat" task.
   grunt.loadNpmTasks('grunt-contrib-concat');

   // Load the plugin that provides the "uglify" task.
   grunt.loadNpmTasks('grunt-contrib-uglify');

   grunt.loadNpmTasks('grunt-contrib-jasmine');

   grunt.loadNpmTasks('grunt-contrib-copy');

   grunt.loadNpmTasks('grunt-bower-task');

   grunt.renameTask('bower', 'bowerInstall');

   grunt.loadNpmTasks('grunt-bower');

   grunt.loadNpmTasks('grunt-bump');

   grunt.loadNpmTasks('grunt-exec');

   // Default task.
   grunt.registerTask('default', ['build']);

   grunt.registerTask('releasePatch', ['bump-only:patch', 'build', 'copy', 'exec', 'bump-commit']);

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

   grunt.registerTask('releaseMajor', ['bump-only:major', 'build', 'copy', 'exec', 'bump-commit']);

   // Build task.
   grunt.registerTask('build', ['bowerInstall', 'bower', 'jshint', 'test', 'concat', 'uglify', 'testProd']);

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

   grunt.registerTask('testProd', ['jasmine:prod','jasmine:prodMin']);

   grunt.registerTask('createSpecRunner', [
        'jasmine:test:build'
    ]);
};<commit_msg>clean up gruntfile<commit_after>/* global module: true */
module.exports = function (grunt) {
   'use strict';

   // Project configuration.
   grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      meta: {
         banner: [
                '/**',
                ' * <%= pkg.name %>',
                ' * <%= pkg.description %>',
                ' * @version v<%= pkg.version %> - <%= grunt.template.today("yyyy-mm-dd") %>' +
                ' * @link <%= pkg.homepage %>',
                ' * @author <%= pkg.author %>',
                ' * @license MIT License, http://www.opensource.org/licenses/MIT',
                ' */'
            ].join('\n')
      },
      dirs: {
         dest: 'dist',
         dep: '<%= dirs.dest %>/dependencies',
         source: 'src',
         test: 'spec'
      },
      files: {
         src: [
               '<%= dirs.source %>/moduleLoader/moduleLoader.js',
               '<%= dirs.source %>/moduleLoader/moduleBuilder.js',
               '<%= dirs.source %>/moduleLoader/partAccess.js',
               '<%= dirs.source %>/moduleLoader/moduleAccess.js',
               '<%= dirs.source %>/eventBus/eventBus.js',
               '<%= dirs.source %>/moduleLoader/moduleSystem.js',
               '<%= dirs.source %>/moduleLoader/moduleLoader.js'
         ]
      },
      bower: {
         dev: {
            dest: '<%= dirs.dep %>'
         }
      },
      concat: {
         options: {
            banner: '<%= meta.banner %>'
         },
         dist: {
            src: [
               '<%= dirs.source %>/intro.js',
               '<%= files.src %>',
               '<%= dirs.source %>/outro.js'
            ],
            dest: '<%= dirs.dest %>/<%= pkg.name %>.<%= pkg.version %>.js'
         }
      },
      bowerInstall: {
         install: {}
      },
      uglify: {
         options: {
            banner: '<%= meta.banner %>'
         },
         dist: {
            src: ['<%= concat.dist.dest %>'],
            dest: '<%= dirs.dest %>/<%= pkg.name %>.<%= pkg.version %>.min.js'
         }
      },
      jshint: {
         files: ['<%= dirs.source %>/**/*.js'],
         options: {
            jshintrc: true
         }
      },
      jasmine: {
         options: {
            vendor: [
               '<%= dirs.dep %>/dist/jquery.js',
               '<%= dirs.dep %>/lib/jasmine-jquery.js'
            ],
            specs: [
               '<%= dirs.test %>/**/*Spec.js'
            ]
         },
         test: {
            src: '<%= files.src %>',
            options: '<%= jasmine.options %>'
         },
         prod: {
            src: '<%= concat.dist.dest %>',
            options: '<%= jasmine.options %>'
         },
         prodMin: {
            src: '<%= uglify.dist.dest %>',
            options: '<%= jasmine.options %>'
         }
      },
      bump: {
         options: {
            files: ['package.json', 'bower.json'],
            updateConfigs: ['pkg'],
            commit: true,
            commitMessage: 'Release v%VERSION%',
            commitFiles: ['-a'],
            createTag: true,
            tagName: 'v%VERSION%',
            tagMessage: 'Version %VERSION%',
            push: true,
            pushTo: 'origin',
            gitDescribeOptions: '--tags --always --abbrev=1 --dirty=-d'
         }
      },
      copy: {
        release: {
          src: '<%= concat.dist.dest %>',
          dest: '<%= dirs.dest %>/<%= pkg.name %>.js'
        },
        releaseMin: {
          src: '<%= uglify.dist.dest %>',
          dest: '<%= dirs.dest %>/<%= pkg.name %>.min.js'
        }
      },
      exec: {
         gitAddAll: 'git add --all'
      }
   });

   // Load the plugin that provides the "jshint" task.
   grunt.loadNpmTasks('grunt-contrib-jshint');

   // Load the plugin that provides the "concat" task.
   grunt.loadNpmTasks('grunt-contrib-concat');

   // Load the plugin that provides the "uglify" task.
   grunt.loadNpmTasks('grunt-contrib-uglify');

   grunt.loadNpmTasks('grunt-contrib-jasmine');

   grunt.loadNpmTasks('grunt-contrib-copy');

   grunt.loadNpmTasks('grunt-bower-task');

   grunt.renameTask('bower', 'bowerInstall');

   grunt.loadNpmTasks('grunt-bower');

   grunt.loadNpmTasks('grunt-bump');

   grunt.loadNpmTasks('grunt-exec');

   // Default task.
   grunt.registerTask('default', ['build']);

   grunt.registerTask('releasePatch', ['bump-only:patch', 'build', 'copy', 'exec', 'bump-commit']);

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

   grunt.registerTask('releaseMajor', ['bump-only:major', 'build', 'copy', 'exec', 'bump-commit']);

   // Build task.
   grunt.registerTask('build', ['bowerInstall', 'bower', 'jshint', 'test', 'concat', 'uglify', 'testProd']);

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

   grunt.registerTask('testProd', ['jasmine:prod','jasmine:prodMin']);

   grunt.registerTask('createSpecRunner', [
        'jasmine:test:build'
    ]);
};<|endoftext|>


<commit_before>'use strict';

// Directory reference:
//   css: styles
//   sass: _scss
//   javascript: scripts
//   images: images
//   fonts: fonts

module.exports = function (grunt) {
  // Show elapsed time after tasks run
  require('time-grunt')(grunt);
  // Load all Grunt tasks
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    // Configurable paths
    yeoman: {
      app: 'app',
      dist: 'dist'
    },
    devUpdate: {
      check: {
        options: {
          reportUpdated: false,
          updateType: 'report'
        }
      }
    },
    watch: {
      sass: {
        files: ['<%= yeoman.app %>/_scss/**/*.scss'],
        tasks: ['sass', 'autoprefixer:server']
      },
      autoprefixer: {
        files: ['<%= yeoman.app %>/styles/**/*.css'],
        tasks: ['copy:stageCss', 'autoprefixer:server']
      },
      jekyll: {
        files: [
          '<%= yeoman.app %>/**/*.{html,rb,svg,xml,yml}',
          '!<%= yeoman.app %>/_bower_components/**/*'
        ],
        tasks: ['jekyll:server']
      }
    },
    browserSync: {
      server: {
        bsFiles: {
          src: [
            '.jekyll/**/*.html',
            '.tmp/styles/**/*.css',
            '{.tmp,<%= yeoman.app %>}/js/**/*.js',
            '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg}'
          ]
        },
        options: {
          server: {
            baseDir: [
              '.jekyll',
              '.tmp',
              '<%= yeoman.app %>'
            ]
          },
          watchTask: true
        }
      },
      dist: {
        options: {
          server: {
            baseDir: '<%= yeoman.dist %>'
          }
        }
      },
      test: {
        bsFiles: {
          src: [
            '.jekyll/**/*.html',
            '.tmp/styles/**/*.css',
            '{.tmp,<%= yeoman.app %>}/js/**/*.js',
            '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg}'
          ]
        },
        options: {
          server: {
            baseDir: [
              '.jekyll',
              '.tmp',
              '<%= yeoman.app %>'
            ]
          },
          watchTask: true
        }
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%= yeoman.dist %>/*',
            // Running Jekyll also cleans the target directory.  Exclude any
            // non-standard `keep_files` here (e.g., the generated files
            // directory from Jekyll Picture Tag).
            '!<%= yeoman.dist %>/.git*',
            '!<%= yeoman.dist %>/generated' // Jekyll Picture Tag
          ]
        }]
      },
      server: [
        '.tmp',
        '.jekyll'
      ]
    },
    sass: {
      options: {
        bundleExec: true
      },
      dist: {
        files: {
          '.tmp/styles/application.css': '<%= yeoman.app %>/_scss/application.scss'
        }
      },
    },
    uncss: {
      options: {
        htmlroot: '.tmp',
        // 1. Ignored by UnCSS?
        // 2. Added by Google Search in 404.html
        // 3. Added by keyboardNavigation function in application.js
        ignore: [
          'b', // 2
          /#goog.+/, // 2
          /h[1-6](.+)?/, // 1
          /input(.+)?/, // 2
          /\.is-.+/, // 3
        ],
        report: 'min'
      },
      dist: {
        files: {'.tmp/concat/styles/application.css': ['<%= yeoman.dist %>/**/*.html']}
      }
    },
    autoprefixer: {
      options: {
        browsers: [
          'last 2 version',
          'safari 6',
          'ie 9',
          'opera 12.1',
          'ios 6',
          'android 4'
        ]
      },
      dist: {
        expand: true,
        cwd: '.tmp',
        src: 'concat/styles/*.css',
        dest: '.tmp'
      },
      server: {
        expand: true,
        cwd: '.tmp',
        src: 'styles/*.css',
        dest: '.tmp'
      }
    },
    jekyll: {
      options: {
        bundleExec: true,
        config: '_config.yml,_config.build.yml',
        src: '<%= yeoman.app %>'
      },
      dist: {
        options: {
          dest: '<%= yeoman.dist %>',
        }
      },
      server: {
        options: {
          config: '_config.yml',
          dest: '.jekyll'
        }
      },
      check: {
        options: {
          doctor: true
        }
      }
    },
    useminPrepare: {
      options: {
        dest: '<%= yeoman.dist %>'
      },
      html: '<%= yeoman.dist %>/index.html'
    },
    usemin: {
      options: {
        assetsDirs: '<%= yeoman.dist %>'
      },
      html: ['<%= yeoman.dist %>/**/*.html'],
      css: ['<%= yeoman.dist %>/styles/**/*.css']
    },
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true,
          removeRedundantAttributes: true,
          keepClosingSlash: true,
          minifyCSS: true,
          minifyJS: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.html',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'min'
        }
      }
    },
    imageoptim: {
      options: {
        quitAfter: true
      },
      distLossless: {
        options: {
          jpegMini: false,
          imageAlpha: true
        },
        src: ['<%= yeoman.dist %>/*.{gif,png}','<%= yeoman.dist %>/generated/*.{gif,png}']
      },
      distLossy: {
        options: {
          jpegMini: true,
          imageAlpha: false
        },
        src: ['<%= yeoman.dist %>/*.{jpg,jpeg}','<%= yeoman.dist %>/generated/*.{jpg,jpeg}']
      }
    },
    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.svg',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    xmlmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.xml',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          src: [
            // Jekyll processes and moves HTML and text files
            // Usemin moves CSS and javascript inside of Usemin blocks
            // Copy moves asset files and directories
            'images/**/*',
            'fonts/**/*',
            // Like Jekyll, exclude files & folders prefixed with an underscore
            '!**/_*{,/**}',
            // Explicitly add any files your site needs for distribution here.
            'favicon*.{ico,png}'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      // Copy CSS into .tmp directory for Autoprefixer processing
      stageCss: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>/styles',
          src: '**/*.css',
          dest: '.tmp/styles'
        }]
      }
    },
    buildcontrol: {
      dist: {
        options: {
          remote: 'git@github.com:davidensinger/webworke.rs.git',
          branch: 'gh-pages',
          commit: true,
          push: true
        }
      }
    },
    filerev: {
      options: {
        length: 4
      },
      dist: {
        files: [{
          src: [
            '<%= yeoman.dist %>/scripts/**/*.js',
            '<%= yeoman.dist %>/styles/**/*.css',
            '<%= yeoman.dist %>/images/**/*.{gif,jpg,jpeg,png,svg}',
            '!<%= yeoman.dist %>/images/originals/**/*.{gif,jpg,jpeg,png,svg}',
            '<%= yeoman.dist %>/fonts/**/*.{woff,woff2}'
          ]
        }]
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/**/*.js',
        'test/spec/**/*.js',
        '!<%= yeoman.app %>/scripts/_vendor/**/*'
      ]
    },
    pagespeed: {
      options: {
        locale: 'en_GB',
        nokey: true,
        url: 'http://webworke.rs'
      },
      desktop: {
        options: {
          strategy: 'desktop'
        }
      },
      mobile: {
        options: {
          strategy: 'mobile'
        }
      }
    },
    phantomas: {
      site: {
        options: {
          indexPath: '<%= yeoman.app %>/perf/phantomas/',
          options   : {
            'no-externals': true,
            'timeout': 60
          },
          url: 'http://webworke.rs/',
          buildUi: true
        }
      }
    },
    concurrent: {
      server: [
        'sass',
        'copy:stageCss',
        'jekyll:server'
      ],
      dist: [
        'sass',
        'copy:dist'
      ]
    }
  });

  // Define Tasks
  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'browserSync:dist']);
    }

    grunt.task.run([
      'clean:server',
      'concurrent:server',
      'autoprefixer:server',
      'browserSync:server',
      'watch'
    ]);
  });

  grunt.registerTask('check', [
    'devUpdate',
    'clean:server',
    'jekyll:check',
    'jshint:all'
  ]);

  grunt.registerTask('perf', [
    'pagespeed',
    'phantomas'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    // Jekyll cleans files from the target directory, so must run first
    'jekyll:dist',
    'concurrent:dist',
    'useminPrepare',
    'concat',
    'uncss',
    'autoprefixer:dist',
    'cssmin',
    'uglify',
    'newer:imageoptim',
    'svgmin',
    'filerev',
    'usemin',
    'htmlmin',
    'xmlmin'
  ]);

  grunt.registerTask('deploy', [
    'perf',
    'build',
    'buildcontrol'
  ]);

  grunt.registerTask('default', [
    'check',
    'test',
    'build'
  ]);
};
<commit_msg>Add `'film-strip': false` to grunt-phantomas task as it’s not needed.<commit_after>'use strict';

// Directory reference:
//   css: styles
//   sass: _scss
//   javascript: scripts
//   images: images
//   fonts: fonts

module.exports = function (grunt) {
  // Show elapsed time after tasks run
  require('time-grunt')(grunt);
  // Load all Grunt tasks
  require('load-grunt-tasks')(grunt);

  grunt.initConfig({
    // Configurable paths
    yeoman: {
      app: 'app',
      dist: 'dist'
    },
    devUpdate: {
      check: {
        options: {
          reportUpdated: false,
          updateType: 'report'
        }
      }
    },
    watch: {
      sass: {
        files: ['<%= yeoman.app %>/_scss/**/*.scss'],
        tasks: ['sass', 'autoprefixer:server']
      },
      autoprefixer: {
        files: ['<%= yeoman.app %>/styles/**/*.css'],
        tasks: ['copy:stageCss', 'autoprefixer:server']
      },
      jekyll: {
        files: [
          '<%= yeoman.app %>/**/*.{html,rb,svg,xml,yml}',
          '!<%= yeoman.app %>/_bower_components/**/*'
        ],
        tasks: ['jekyll:server']
      }
    },
    browserSync: {
      server: {
        bsFiles: {
          src: [
            '.jekyll/**/*.html',
            '.tmp/styles/**/*.css',
            '{.tmp,<%= yeoman.app %>}/js/**/*.js',
            '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg}'
          ]
        },
        options: {
          server: {
            baseDir: [
              '.jekyll',
              '.tmp',
              '<%= yeoman.app %>'
            ]
          },
          watchTask: true
        }
      },
      dist: {
        options: {
          server: {
            baseDir: '<%= yeoman.dist %>'
          }
        }
      },
      test: {
        bsFiles: {
          src: [
            '.jekyll/**/*.html',
            '.tmp/styles/**/*.css',
            '{.tmp,<%= yeoman.app %>}/js/**/*.js',
            '<%= yeoman.app %>/img/**/*.{gif,jpg,jpeg,png,svg}'
          ]
        },
        options: {
          server: {
            baseDir: [
              '.jekyll',
              '.tmp',
              '<%= yeoman.app %>'
            ]
          },
          watchTask: true
        }
      }
    },
    clean: {
      dist: {
        files: [{
          dot: true,
          src: [
            '<%= yeoman.dist %>/*',
            // Running Jekyll also cleans the target directory.  Exclude any
            // non-standard `keep_files` here (e.g., the generated files
            // directory from Jekyll Picture Tag).
            '!<%= yeoman.dist %>/.git*',
            '!<%= yeoman.dist %>/generated' // Jekyll Picture Tag
          ]
        }]
      },
      server: [
        '.tmp',
        '.jekyll'
      ]
    },
    sass: {
      options: {
        bundleExec: true
      },
      dist: {
        files: {
          '.tmp/styles/application.css': '<%= yeoman.app %>/_scss/application.scss'
        }
      },
    },
    uncss: {
      options: {
        htmlroot: '.tmp',
        // 1. Ignored by UnCSS?
        // 2. Added by Google Search in 404.html
        // 3. Added by keyboardNavigation function in application.js
        ignore: [
          'b', // 2
          /#goog.+/, // 2
          /h[1-6](.+)?/, // 1
          /input(.+)?/, // 2
          /\.is-.+/, // 3
        ],
        report: 'min'
      },
      dist: {
        files: {'.tmp/concat/styles/application.css': ['<%= yeoman.dist %>/**/*.html']}
      }
    },
    autoprefixer: {
      options: {
        browsers: [
          'last 2 version',
          'safari 6',
          'ie 9',
          'opera 12.1',
          'ios 6',
          'android 4'
        ]
      },
      dist: {
        expand: true,
        cwd: '.tmp',
        src: 'concat/styles/*.css',
        dest: '.tmp'
      },
      server: {
        expand: true,
        cwd: '.tmp',
        src: 'styles/*.css',
        dest: '.tmp'
      }
    },
    jekyll: {
      options: {
        bundleExec: true,
        config: '_config.yml,_config.build.yml',
        src: '<%= yeoman.app %>'
      },
      dist: {
        options: {
          dest: '<%= yeoman.dist %>',
        }
      },
      server: {
        options: {
          config: '_config.yml',
          dest: '.jekyll'
        }
      },
      check: {
        options: {
          doctor: true
        }
      }
    },
    useminPrepare: {
      options: {
        dest: '<%= yeoman.dist %>'
      },
      html: '<%= yeoman.dist %>/index.html'
    },
    usemin: {
      options: {
        assetsDirs: '<%= yeoman.dist %>'
      },
      html: ['<%= yeoman.dist %>/**/*.html'],
      css: ['<%= yeoman.dist %>/styles/**/*.css']
    },
    htmlmin: {
      dist: {
        options: {
          removeComments: true,
          collapseWhitespace: true,
          removeRedundantAttributes: true,
          keepClosingSlash: true,
          minifyCSS: true,
          minifyJS: true
        },
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.html',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    // Usemin adds files to concat
    concat: {},
    // Usemin adds files to uglify
    uglify: {},
    // Usemin adds files to cssmin
    cssmin: {
      dist: {
        options: {
          check: 'min'
        }
      }
    },
    imageoptim: {
      options: {
        quitAfter: true
      },
      distLossless: {
        options: {
          jpegMini: false,
          imageAlpha: true
        },
        src: ['<%= yeoman.dist %>/*.{gif,png}','<%= yeoman.dist %>/generated/*.{gif,png}']
      },
      distLossy: {
        options: {
          jpegMini: true,
          imageAlpha: false
        },
        src: ['<%= yeoman.dist %>/*.{jpg,jpeg}','<%= yeoman.dist %>/generated/*.{jpg,jpeg}']
      }
    },
    svgmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.svg',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    xmlmin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.dist %>',
          src: '**/*.xml',
          dest: '<%= yeoman.dist %>'
        }]
      }
    },
    copy: {
      dist: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>',
          src: [
            // Jekyll processes and moves HTML and text files
            // Usemin moves CSS and javascript inside of Usemin blocks
            // Copy moves asset files and directories
            'images/**/*',
            'fonts/**/*',
            // Like Jekyll, exclude files & folders prefixed with an underscore
            '!**/_*{,/**}',
            // Explicitly add any files your site needs for distribution here.
            'favicon*.{ico,png}'
          ],
          dest: '<%= yeoman.dist %>'
        }]
      },
      // Copy CSS into .tmp directory for Autoprefixer processing
      stageCss: {
        files: [{
          expand: true,
          dot: true,
          cwd: '<%= yeoman.app %>/styles',
          src: '**/*.css',
          dest: '.tmp/styles'
        }]
      }
    },
    buildcontrol: {
      dist: {
        options: {
          remote: 'git@github.com:davidensinger/webworke.rs.git',
          branch: 'gh-pages',
          commit: true,
          push: true
        }
      }
    },
    filerev: {
      options: {
        length: 4
      },
      dist: {
        files: [{
          src: [
            '<%= yeoman.dist %>/scripts/**/*.js',
            '<%= yeoman.dist %>/styles/**/*.css',
            '<%= yeoman.dist %>/images/**/*.{gif,jpg,jpeg,png,svg}',
            '!<%= yeoman.dist %>/images/originals/**/*.{gif,jpg,jpeg,png,svg}',
            '<%= yeoman.dist %>/fonts/**/*.{woff,woff2}'
          ]
        }]
      }
    },
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: [
        'Gruntfile.js',
        '<%= yeoman.app %>/scripts/**/*.js',
        'test/spec/**/*.js',
        '!<%= yeoman.app %>/scripts/_vendor/**/*'
      ]
    },
    pagespeed: {
      options: {
        locale: 'en_GB',
        nokey: true,
        url: 'http://webworke.rs'
      },
      desktop: {
        options: {
          strategy: 'desktop'
        }
      },
      mobile: {
        options: {
          strategy: 'mobile'
        }
      }
    },
    phantomas: {
      site: {
        options: {
          indexPath: '<%= yeoman.app %>/perf/phantomas/',
          options   : {
            'film-strip': false,
            'no-externals': true,
            'timeout': 60
          },
          url: 'http://webworke.rs/',
          buildUi: true
        }
      }
    },
    concurrent: {
      server: [
        'sass',
        'copy:stageCss',
        'jekyll:server'
      ],
      dist: [
        'sass',
        'copy:dist'
      ]
    }
  });

  // Define Tasks
  grunt.registerTask('serve', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'browserSync:dist']);
    }

    grunt.task.run([
      'clean:server',
      'concurrent:server',
      'autoprefixer:server',
      'browserSync:server',
      'watch'
    ]);
  });

  grunt.registerTask('check', [
    'devUpdate',
    'clean:server',
    'jekyll:check',
    'jshint:all'
  ]);

  grunt.registerTask('perf', [
    'pagespeed',
    'phantomas'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    // Jekyll cleans files from the target directory, so must run first
    'jekyll:dist',
    'concurrent:dist',
    'useminPrepare',
    'concat',
    'uncss',
    'autoprefixer:dist',
    'cssmin',
    'uglify',
    'newer:imageoptim',
    'svgmin',
    'filerev',
    'usemin',
    'htmlmin',
    'xmlmin'
  ]);

  grunt.registerTask('deploy', [
    'perf',
    'build',
    'buildcontrol'
  ]);

  grunt.registerTask('default', [
    'check',
    'test',
    'build'
  ]);
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {

  grunt.initConfig({
    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        'Gruntfile.js',
        'public/assets/js/*.js',
        '!/public/assets/js/build/common.min.js'
      ]
    },
    less: {
      dist: {
        files: {
          'public/assets/css/build/main.min.css': [
            'public/assets/less/app.less'
          ]
        },
        options: {
          compress: true
        }
      }
    },
    uglify: {
      dist: {
        files: {
          'public/assets/js/build/common.min.js': [
            'public/assets/js/vendor/bootstrap/alert.js',
            'public/assets/js/vendor/bootstrap/button.js',
            'public/assets/js/vendor/bootstrap/dropdown.js',
            'public/assets/js/vendor/bootstrap/tooltip.js',
            'public/assets/js/vendor/*.js',
          ]
        }
      }
    },
    imagemin: {
      files: {
      },
      dynamic: {
        options: {
          optimizationLevel: 7,
          cache: false
        },
        files: [{
          expand: true,
          cwd: 'public/assets/img/src',
          src: [
            '**/*.{png,jpg,gif}'
          ],
          dest: 'public/assets/img/build'
        }]
      }
    },
    watch: {
      less: {
        files: [
          'public/assets/less/*.less',
          'public/assets/less/vendor/bootstrap/*.less'
        ],
        tasks: ['less']
      },
      js: {
        files: [
          '<%= jshint.all %>'
        ],
        tasks: ['jshint', 'uglify']
      },
      livereload: {
        options: {
          livereload: true
        },
        files: [
          'public/assets/css/build/common.min.css',
          'public/assets/js/build/common.min.js'
        ]
      },
      imagemin: {
        files: [
          'public/assets/img/src/**/*'
        ],
      }
    }
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  // Register tasks
  grunt.registerTask('default', [
    'less',
    'uglify',
    'imagemin'
  ]);

  grunt.registerTask('dev', [
    'watch'
  ]);

};
<commit_msg>Update gruntfile<commit_after>'use strict';

module.exports = function(grunt) {

  grunt.initConfig({
    jshint: {
      options: {
        jshintrc: '.jshintrc'
      },
      all: [
        'Gruntfile.js',
        'public/assets/js/*.js',
        '!/public/assets/js/build/common.min.js'
      ]
    },
    less: {
      dist: {
        files: {
          'public/assets/css/build/common.min.css': [
            'public/assets/less/app.less'
          ]
        },
        options: {
          compress: true
        }
      }
    },
    uglify: {
      dist: {
        files: {
          'public/assets/js/build/common.min.js': [
            'public/assets/js/vendor/bootstrap/alert.js',
            'public/assets/js/vendor/bootstrap/button.js',
            'public/assets/js/vendor/bootstrap/dropdown.js',
            'public/assets/js/vendor/bootstrap/tooltip.js',
            'public/assets/js/vendor/*.js',
          ]
        }
      }
    },
    imagemin: {
      files: {
      },
      dynamic: {
        options: {
          optimizationLevel: 7,
          cache: false
        },
        files: [{
          expand: true,
          cwd: 'public/assets/img/src',
          src: [
            '**/*.{png,jpg,gif}'
          ],
          dest: 'public/assets/img/build'
        }]
      }
    },
    watch: {
      less: {
        files: [
          'public/assets/less/*.less',
          'public/assets/less/burthorpe/*.less',
          'public/assets/less/vendor/bootstrap/*.less',
          'public/assets/less/vendor/font-awesome/*.less'
        ],
        options: {
          livereload: true
        },
        tasks: ['less']
      },
      js: {
        files: [
          '<%= jshint.all %>'
        ],
        options: {
          livereload: true
        },
        tasks: ['jshint', 'uglify']
      },
      imagemin: {
        files: [
          'public/assets/img/src/**/*'
        ],
        options: {
          livereload: true
        }
      }
    }
  });

  // Load tasks
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  // Register tasks
  grunt.registerTask('default', [
    'less',
    'uglify',
    'imagemin'
  ]);

  grunt.registerTask('dev', [
    'watch'
  ]);

};
<|endoftext|>


<commit_before>"use strict";

treeherder.controller('FilterPanelCtrl', [
    '$scope', '$rootScope', '$route', '$routeParams', '$location', 'ThLog',
    'localStorageService', 'thResultStatusList', 'thEvents', 'thJobFilters',
    'ThResultSetModel', 'thPinboard', 'thNotify',
    function FilterPanelCtrl(
        $scope, $rootScope, $route, $routeParams, $location, ThLog,
        localStorageService, thResultStatusList, thEvents, thJobFilters,
        ThResultSetModel, thPinboard, thNotify) {

        var $log = new ThLog(this.constructor.name);

        $scope.filterOptions = thResultStatusList.all();

        $scope.filterGroups = {
            failures: {
                value: "failures",
                name: "failures",
                resultStatuses: ["testfailed", "busted", "exception"]
            },
            nonfailures: {
                value: "nonfailures",
                name: "non-failures",
                resultStatuses: ["success", "retry", "usercancel", "coalesced"]
            },
            inProgress: {
                value: "inProgress",
                name: "in progress",
                resultStatuses: ["pending", "running"]
            }
        };

        $scope.resultStatusFilters = {};

        // field filters
        $scope.newFieldFilter = null;
        $scope.fieldFilters = [];

        $scope.fieldChoices = thJobFilters.fieldChoices;

        /**
         * Handle checking the "all" button for a result status group
         *
         * quiet - whether or not to broadcast a message about this change.
         */
        $scope.toggleResultStatusGroup = function(group) {
            var check = function(rs) {
                $scope.resultStatusFilters[rs] = group.allChecked;
            };

            _.each(group.resultStatuses, check);
            thJobFilters.toggleFilters(
                thJobFilters.resultStatus,
                group.resultStatuses,
                group.allChecked
            );
        };

        /**
         * Handle toggling one of the individual result status filters in
         * the filter panel.
         *
         * @param group
         * @param filter
         */
        $scope.toggleResultStatusFilter = function(group, filter) {
            if (!$scope.resultStatusFilters[filter]) {
                thJobFilters.removeFilter(thJobFilters.resultStatus, filter);
            } else {
                thJobFilters.addFilter(thJobFilters.resultStatus, filter);
            }
        };

        /**
         * Toggle the filters to show either unclassified or classified jobs,
         * neither or both.
         */
        $scope.toggleClassificationFilter = function(isClassified) {
            var isChecked = !(isClassified? $scope.classifiedFilter: $scope.unClassifiedFilter);
            $scope.setClassificationFilter(isClassified, isChecked, false);
        };

        /**
         * Toggle the filters to show either unclassified or classified jobs,
         * neither or both.
         * @param isClassified - whether to toggle the filter on/off for
         *                       ``classified`` (when true) or ``unclassified``
         *                       (when false)
         */
        $scope.setClassificationFilter = function(isClassified, isChecked) {
            var field = "isClassified";
            // this function is called before the checkbox value has actually
            // changed the scope model value, so change to the inverse.
            var func = isChecked? thJobFilters.addFilter: thJobFilters.removeFilter;
            var target = isClassified? "classified": "unclassified";

            func(field, isClassified, thJobFilters.matchType.bool);
        };

        $scope.createFieldFilter = function() {
            $scope.newFieldFilter = {field: "", value: ""};
        };
        $scope.cancelFieldFilter = function() {
            $scope.newFieldFilter = null;
        };

        // we have to set the field match type here so that the UI can either
        // show a text field for entering a value, or switch to a drop-down select.
        $scope.setFieldMatchType = function() {
            $scope.newFieldFilter.matchType=$scope.fieldChoices[$scope.newFieldFilter.field].matchType;
            $scope.newFieldFilter.choices=$scope.fieldChoices[$scope.newFieldFilter.field].choices;

        };

        // for most match types we want to show just the raw value.  But for
        // choice value type, we want to show the string representation of the
        // value.  For example, failure_classification_id is an int, but we
        // want to show the text.
        $scope.getFilterValue = function(field, value) {
            if ($scope.fieldChoices[field].matchType === 'choice') {
                return $scope.fieldChoices[field].choices[value].name;
            }
            return value;
        };

        $scope.addFieldFilter = function(quiet) {
            $log.debug("adding filter", $scope.newFieldFilter.field);
            var value = $scope.newFieldFilter.value;

            if (!$scope.newFieldFilter || $scope.newFieldFilter.field === "" || value === "") {
                return;
            }
            thJobFilters.addFilter(
                $scope.newFieldFilter.field,
                value,
                $scope.fieldChoices[$scope.newFieldFilter.field].matchType,
                quiet
            );
            $scope.fieldFilters.push({
                field: $scope.newFieldFilter.field,
                value: value
            });
            $scope.newFieldFilter = null;

        };

        $scope.removeAllFieldFilters = function() {
            $scope.fieldFilters = [];
            thJobFilters.removeAllFieldFilters();
        };

        $scope.removeFilter = function(index) {
            $log.debug("removing index", index);

            thJobFilters.removeFilter(
                $scope.fieldFilters[index].field,
                $scope.fieldFilters[index].value
            );
            $scope.fieldFilters.splice(index, 1);
        };

        $scope.pinAllShownJobs = function() {
            if (!thPinboard.spaceRemaining()) {
                thNotify.send("Pinboard is full.  Can not pin any more jobs.",
                    "danger",
                    true);
                return;
            }
            var shownJobs = ThResultSetModel.getAllShownJobs(
                $rootScope.repoName,
                thPinboard.spaceRemaining()
            );
            thPinboard.pinJobs(shownJobs);

            if (!$rootScope.selectedJob) {
                $rootScope.selectedJob = shownJobs[0];
            }
        };

        $scope.thJobFilters = thJobFilters;

        var updateToggleFilters = function() {
            for (var i = 0; i < $scope.filterOptions.length; i++) {
                var opt = $scope.filterOptions[i];
                $scope.resultStatusFilters[opt] = _.contains(
                    thJobFilters.filters.resultStatus.values, opt);
            }

            // whether or not to show classified jobs
            // these are a special case of filtering because we're not checking
            // for a value, just whether the job has any value set or not.
            // just a boolean check either way
            $scope.classifiedFilter = _.contains(thJobFilters.filters.isClassified.values, true);
            $scope.unClassifiedFilter = _.contains(thJobFilters.filters.isClassified.values, false);

            // update "all checked" boxes for groups
            _.each($scope.filterGroups, function(group) {
                group.allChecked = _.difference(group.resultStatuses, thJobFilters.filters.resultStatus.values).length === 0;
            });
        };

        updateToggleFilters();

        /*
         * We need to prevent reloading the route under certain conditions.
         * Like when we change the filter params on the url.  So we have set
         * the route to skip ``reloadOnSearch`` changes.  We can't simply
         * turn it to skip before the ``$location.search("key", val)`` call
         * and then turn it back to not skip after the call because the event
         * chain that happens with changing the location and the ``$routeUpdate``
         * won't have happened until after we have turned off the skipping.
         * Thereby it will never skip, and always reload the route.
         *
         * So what we must do is tell it to skip the "next" one before each
         * search change and then when it's skipped, it will turn skipping back
         * off each time.
         */
        $rootScope.skipNextSearchChangeReload = false;
        $scope.$on('$routeUpdate', function(){
            $log.debug("route updated", $location.search());
            if (!$rootScope.skipNextSearchChangeReload) {
                // when switching repos via the repos panel, you click a link
                // that is a new route.  So it comes here, and we reload
                // the route.  But the filters will be left on in thJobFilters
                // but not in the URL.  So we reset all the filters here.
                // If we wanted to retain the filters (like set to unclassified
                // failures only) then we'd take out the next line and rebuild
                // the url from the filters that are set.  Possibly just with
                // a broadcast of ``globalFilterChanged``.
                thJobFilters.buildFiltersFromQueryString();
                $log.debug("route reloading");
                $route.reload();
            } else {
                $log.debug("route NOT reloading");
            }
            $rootScope.skipNextSearchChangeReload = false;
        });

        $scope.$on(thEvents.globalFilterChanged, function() {
            updateToggleFilters();
            thJobFilters.buildQueryStringFromFilters();
        });

    }
]);

treeherder.controller('SearchCtrl', [
    '$scope', '$rootScope', 'thEvents', 'thJobFilters', '$location',
    function SearchCtrl(
        $scope, $rootScope, thEvents, thJobFilters, $location){

        $scope.$watch(
            function(){
                return thJobFilters.getSearchQuery().searchQueryStr;
            },
            function(searchQueryStr){

                $scope.searchQueryStr = searchQueryStr;

                $rootScope.skipNextSearchChangeReload = true;

                if($scope.searchQueryStr === ""){

                    $location.search("searchQuery", null);

                    //jobname here is for backwards compatibility with
                    //tbpl url parameters
                    $location.search("jobname", null);

                }else{
                    $location.search("searchQuery", searchQueryStr);

                    //jobname here is for backwords compatibility with
                    //tbpl url parameters
                    $location.search("jobname", null);
                }

                $rootScope.$broadcast(
                    thEvents.searchPage,
                    { searchQuery: thJobFilters.getSearchQuery() }
                    );
            }
        );

        $scope.search = function(ev){
            //User hit enter
            if( (ev.keyCode === 13) ||
                ($scope.searchQueryStr === "") ){

                thJobFilters.setSearchQuery($scope.searchQueryStr);
            }
        };
    }
]);
<commit_msg>fixed spelling mistake<commit_after>"use strict";

treeherder.controller('FilterPanelCtrl', [
    '$scope', '$rootScope', '$route', '$routeParams', '$location', 'ThLog',
    'localStorageService', 'thResultStatusList', 'thEvents', 'thJobFilters',
    'ThResultSetModel', 'thPinboard', 'thNotify',
    function FilterPanelCtrl(
        $scope, $rootScope, $route, $routeParams, $location, ThLog,
        localStorageService, thResultStatusList, thEvents, thJobFilters,
        ThResultSetModel, thPinboard, thNotify) {

        var $log = new ThLog(this.constructor.name);

        $scope.filterOptions = thResultStatusList.all();

        $scope.filterGroups = {
            failures: {
                value: "failures",
                name: "failures",
                resultStatuses: ["testfailed", "busted", "exception"]
            },
            nonfailures: {
                value: "nonfailures",
                name: "non-failures",
                resultStatuses: ["success", "retry", "usercancel", "coalesced"]
            },
            inProgress: {
                value: "inProgress",
                name: "in progress",
                resultStatuses: ["pending", "running"]
            }
        };

        $scope.resultStatusFilters = {};

        // field filters
        $scope.newFieldFilter = null;
        $scope.fieldFilters = [];

        $scope.fieldChoices = thJobFilters.fieldChoices;

        /**
         * Handle checking the "all" button for a result status group
         *
         * quiet - whether or not to broadcast a message about this change.
         */
        $scope.toggleResultStatusGroup = function(group) {
            var check = function(rs) {
                $scope.resultStatusFilters[rs] = group.allChecked;
            };

            _.each(group.resultStatuses, check);
            thJobFilters.toggleFilters(
                thJobFilters.resultStatus,
                group.resultStatuses,
                group.allChecked
            );
        };

        /**
         * Handle toggling one of the individual result status filters in
         * the filter panel.
         *
         * @param group
         * @param filter
         */
        $scope.toggleResultStatusFilter = function(group, filter) {
            if (!$scope.resultStatusFilters[filter]) {
                thJobFilters.removeFilter(thJobFilters.resultStatus, filter);
            } else {
                thJobFilters.addFilter(thJobFilters.resultStatus, filter);
            }
        };

        /**
         * Toggle the filters to show either unclassified or classified jobs,
         * neither or both.
         */
        $scope.toggleClassificationFilter = function(isClassified) {
            var isChecked = !(isClassified? $scope.classifiedFilter: $scope.unClassifiedFilter);
            $scope.setClassificationFilter(isClassified, isChecked, false);
        };

        /**
         * Toggle the filters to show either unclassified or classified jobs,
         * neither or both.
         * @param isClassified - whether to toggle the filter on/off for
         *                       ``classified`` (when true) or ``unclassified``
         *                       (when false)
         */
        $scope.setClassificationFilter = function(isClassified, isChecked) {
            var field = "isClassified";
            // this function is called before the checkbox value has actually
            // changed the scope model value, so change to the inverse.
            var func = isChecked? thJobFilters.addFilter: thJobFilters.removeFilter;
            var target = isClassified? "classified": "unclassified";

            func(field, isClassified, thJobFilters.matchType.bool);
        };

        $scope.createFieldFilter = function() {
            $scope.newFieldFilter = {field: "", value: ""};
        };
        $scope.cancelFieldFilter = function() {
            $scope.newFieldFilter = null;
        };

        // we have to set the field match type here so that the UI can either
        // show a text field for entering a value, or switch to a drop-down select.
        $scope.setFieldMatchType = function() {
            $scope.newFieldFilter.matchType=$scope.fieldChoices[$scope.newFieldFilter.field].matchType;
            $scope.newFieldFilter.choices=$scope.fieldChoices[$scope.newFieldFilter.field].choices;

        };

        // for most match types we want to show just the raw value.  But for
        // choice value type, we want to show the string representation of the
        // value.  For example, failure_classification_id is an int, but we
        // want to show the text.
        $scope.getFilterValue = function(field, value) {
            if ($scope.fieldChoices[field].matchType === 'choice') {
                return $scope.fieldChoices[field].choices[value].name;
            }
            return value;
        };

        $scope.addFieldFilter = function(quiet) {
            $log.debug("adding filter", $scope.newFieldFilter.field);
            var value = $scope.newFieldFilter.value;

            if (!$scope.newFieldFilter || $scope.newFieldFilter.field === "" || value === "") {
                return;
            }
            thJobFilters.addFilter(
                $scope.newFieldFilter.field,
                value,
                $scope.fieldChoices[$scope.newFieldFilter.field].matchType,
                quiet
            );
            $scope.fieldFilters.push({
                field: $scope.newFieldFilter.field,
                value: value
            });
            $scope.newFieldFilter = null;

        };

        $scope.removeAllFieldFilters = function() {
            $scope.fieldFilters = [];
            thJobFilters.removeAllFieldFilters();
        };

        $scope.removeFilter = function(index) {
            $log.debug("removing index", index);

            thJobFilters.removeFilter(
                $scope.fieldFilters[index].field,
                $scope.fieldFilters[index].value
            );
            $scope.fieldFilters.splice(index, 1);
        };

        $scope.pinAllShownJobs = function() {
            if (!thPinboard.spaceRemaining()) {
                thNotify.send("Pinboard is full.  Can not pin any more jobs.",
                    "danger",
                    true);
                return;
            }
            var shownJobs = ThResultSetModel.getAllShownJobs(
                $rootScope.repoName,
                thPinboard.spaceRemaining()
            );
            thPinboard.pinJobs(shownJobs);

            if (!$rootScope.selectedJob) {
                $rootScope.selectedJob = shownJobs[0];
            }
        };

        $scope.thJobFilters = thJobFilters;

        var updateToggleFilters = function() {
            for (var i = 0; i < $scope.filterOptions.length; i++) {
                var opt = $scope.filterOptions[i];
                $scope.resultStatusFilters[opt] = _.contains(
                    thJobFilters.filters.resultStatus.values, opt);
            }

            // whether or not to show classified jobs
            // these are a special case of filtering because we're not checking
            // for a value, just whether the job has any value set or not.
            // just a boolean check either way
            $scope.classifiedFilter = _.contains(thJobFilters.filters.isClassified.values, true);
            $scope.unClassifiedFilter = _.contains(thJobFilters.filters.isClassified.values, false);

            // update "all checked" boxes for groups
            _.each($scope.filterGroups, function(group) {
                group.allChecked = _.difference(group.resultStatuses, thJobFilters.filters.resultStatus.values).length === 0;
            });
        };

        updateToggleFilters();

        /*
         * We need to prevent reloading the route under certain conditions.
         * Like when we change the filter params on the url.  So we have set
         * the route to skip ``reloadOnSearch`` changes.  We can't simply
         * turn it to skip before the ``$location.search("key", val)`` call
         * and then turn it back to not skip after the call because the event
         * chain that happens with changing the location and the ``$routeUpdate``
         * won't have happened until after we have turned off the skipping.
         * Thereby it will never skip, and always reload the route.
         *
         * So what we must do is tell it to skip the "next" one before each
         * search change and then when it's skipped, it will turn skipping back
         * off each time.
         */
        $rootScope.skipNextSearchChangeReload = false;
        $scope.$on('$routeUpdate', function(){
            $log.debug("route updated", $location.search());
            if (!$rootScope.skipNextSearchChangeReload) {
                // when switching repos via the repos panel, you click a link
                // that is a new route.  So it comes here, and we reload
                // the route.  But the filters will be left on in thJobFilters
                // but not in the URL.  So we reset all the filters here.
                // If we wanted to retain the filters (like set to unclassified
                // failures only) then we'd take out the next line and rebuild
                // the url from the filters that are set.  Possibly just with
                // a broadcast of ``globalFilterChanged``.
                thJobFilters.buildFiltersFromQueryString();
                $log.debug("route reloading");
                $route.reload();
            } else {
                $log.debug("route NOT reloading");
            }
            $rootScope.skipNextSearchChangeReload = false;
        });

        $scope.$on(thEvents.globalFilterChanged, function() {
            updateToggleFilters();
            thJobFilters.buildQueryStringFromFilters();
        });

    }
]);

treeherder.controller('SearchCtrl', [
    '$scope', '$rootScope', 'thEvents', 'thJobFilters', '$location',
    function SearchCtrl(
        $scope, $rootScope, thEvents, thJobFilters, $location){

        $scope.$watch(
            function(){
                return thJobFilters.getSearchQuery().searchQueryStr;
            },
            function(searchQueryStr){

                $scope.searchQueryStr = searchQueryStr;

                $rootScope.skipNextSearchChangeReload = true;

                if($scope.searchQueryStr === ""){

                    $location.search("searchQuery", null);

                    //jobname here is for backwards compatibility with
                    //tbpl url parameters
                    $location.search("jobname", null);

                }else{
                    $location.search("searchQuery", searchQueryStr);

                    //jobname here is for backwards compatibility with
                    //tbpl url parameters
                    $location.search("jobname", null);
                }

                $rootScope.$broadcast(
                    thEvents.searchPage,
                    { searchQuery: thJobFilters.getSearchQuery() }
                    );
            }
        );

        $scope.search = function(ev){
            //User hit enter
            if( (ev.keyCode === 13) ||
                ($scope.searchQueryStr === "") ){

                thJobFilters.setSearchQuery($scope.searchQueryStr);
            }
        };
    }
]);
<|endoftext|>