<commit_before>import chalk from 'chalk';
import setup from './setup.js';
import yargonaut from 'yargonaut';
import yargs from 'yargs';
import packageJson from '../package.json';
import * as Client from './cli/client.js';
import * as Host from './cli/host.js';

try {

    if (process.getuid() !== 0) {
        throw 'Avanti needs root privileges';
    }

    setup('/opt/avanti').then(() => {
        yargonaut
            .style('blue')
            .helpStyle('green')
            .errorsStyle('red.bold');

        var options = yargs
            .version(packageJson.version)

            .command('client', 'client manager', {
                list: {
                    alias: 'l',
                    describe: 'list clients',
                    type: 'boolean'
                },
                create: {
                    alias: 'c',
                    describe: 'client to create',
                    type: 'string'
                },
                remove: {
                    alias: 'r',
                    describe: 'client to remove',
                    type: 'string'
                }
            }, argv => {
                if (argv.list) {
                    Client.list();
                    return;
                }

                if (argv.create) {
                    Client.create(argv.create);
                    return;
                }

                if (argv.remove) {
                    Client.remove(argv.remove);
                    return;
                }
            })

            .command('host', 'host manager', {
                list: {
                    alias: 'l',
                    describe: 'list hosts',
                    type: 'boolean'
                },
                client: {
                    describe: 'client to use',
                    type: 'string'
                },
                create: {
                    alias: 'c',
                    describe: 'host to create',
                    type: 'string'
                },
                remove: {
                    alias: 'r',
                    describe: 'host to remove',
                    type: 'string'
                }
            }, argv => {
                if (argv.list) {
                    Host.list();
                    return;
                }

                if (argv.create) {
                    if (!argv.client) {
                        process.exitCode = 1;
                        process.stderr.write(chalk.red('Missing required argument: client') + '\n');
                    }
                    Host.create(argv.client, argv.create);
                    return;
                }

                if (argv.remove) {
                    if (!argv.client) {
                        process.exitCode = 1;
                        process.stderr.write(chalk.red('Missing required argument: client') + '\n');
                    }
                    Host.create(argv.client, argv.remove);
                    return;
                }
            })

            .recommendCommands()
            .help()
            .showHelpOnFail(false, 'Specify --help for available options')
            .argv;

        if (options._.length === 0) {
            yargs.showHelp();
        }

    });

} catch(e) {

    process.exitCode = 1;
    process.stderr.write(chalk.red(chalk.bold('ERROR:') + ' ' + e) + '\n');

}
<commit_msg>show help when no args<commit_after>import chalk from 'chalk';
import setup from './setup.js';
import yargonaut from 'yargonaut';
import yargs from 'yargs';
import packageJson from '../package.json';
import * as Client from './cli/client.js';
import * as Host from './cli/host.js';

try {

    if (process.getuid() !== 0) {
        throw 'Avanti needs root privileges';
    }

    setup('/opt/avanti').then(() => {
        yargonaut
            .style('blue')
            .helpStyle('green')
            .errorsStyle('red.bold');

        var options = yargs
            .version(packageJson.version)

            .command('client', 'client manager', {
                list: {
                    alias: 'l',
                    describe: 'list clients',
                    type: 'boolean'
                },
                create: {
                    alias: 'c',
                    describe: 'client to create',
                    type: 'string'
                },
                remove: {
                    alias: 'r',
                    describe: 'client to remove',
                    type: 'string'
                }
            }, argv => {
                if (argv.list) {
                    Client.list();
                    return;
                }

                if (argv.create) {
                    Client.create(argv.create);
                    return;
                }

                if (argv.remove) {
                    Client.remove(argv.remove);
                    return;
                }

                yargs.showHelp();
            })

            .command('host', 'host manager', {
                list: {
                    alias: 'l',
                    describe: 'list hosts',
                    type: 'boolean'
                },
                client: {
                    describe: 'client to use',
                    type: 'string'
                },
                create: {
                    alias: 'c',
                    describe: 'host to create',
                    type: 'string'
                },
                remove: {
                    alias: 'r',
                    describe: 'host to remove',
                    type: 'string'
                }
            }, argv => {
                if (argv.list) {
                    Host.list();
                    return;
                }

                if (argv.create) {
                    if (!argv.client) {
                        process.exitCode = 1;
                        process.stderr.write(chalk.red('Missing required argument: client') + '\n');
                    }
                    Host.create(argv.client, argv.create);
                    return;
                }

                if (argv.remove) {
                    if (!argv.client) {
                        process.exitCode = 1;
                        process.stderr.write(chalk.red('Missing required argument: client') + '\n');
                    }
                    Host.create(argv.client, argv.remove);
                    return;
                }

                yargs.showHelp();
            })

            .recommendCommands()
            .help()
            .showHelpOnFail(false, 'Specify --help for available options')
            .argv;

        if (options._.length === 0) {
            yargs.showHelp();
        }

    });

} catch(e) {

    process.exitCode = 1;
    process.stderr.write(chalk.red(chalk.bold('ERROR:') + ' ' + e) + '\n');

}
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        // Metadata.
        pkg: grunt.file.readJSON('package.json'),
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
            '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
            '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
            '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
            ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
        banner_undermore: grunt.file.read('src/_source/_.banner.tmpl'),
        foot_undermore: grunt.file.read('src/_source/_.foot.tmpl'),
        banner_jquery: grunt.file.read('src/jquery_source/$.banner.tmpl'),
        foot_jquery: grunt.file.read('src/jquery_source/$.foot.tmpl'),
        // Task configuration.
        concat: {
            options: {
                banner: '<%= banner %>'
            },
            undermore: {
                options: {
                    separator: ', \n ',
                    banner: '<%= banner_undermore %>',
                    footer: '<%= foot_undermore %>'
                },
                src: ['src/_source/_.*.js'],
                dest: 'src/_.build.js'
            },
            jquery: {
                options: {
                    separator: '\n\n',
                    banner: '<%= banner_jquery %>',
                    footer: '<%= foot_jquery %>'
                },
                src: ['src/jquery_source/$.*.js'],
                dest: 'src/$.build.js'
            },
            dist: {
                src: [
                    'src/_.build.js',
                    'src/$.build.js',
                    'src/safe.js',
                    'src/string.*.js'
                ],
                dest: 'dist/undermore.js'
            },
            bin: {
                src: ['src/*.js'],
                dest: 'bin/<%= pkg.name %>.js'
            }
        },
        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            dist: {
                src: '<%= concat.dist.dest %>',
                dest: 'dist/<%= pkg.name %>.min.js'
            }
        },
        qunit: {
            files: ['test/*.html']
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            src: {
                src: '<%= concat.dist.src %>'
            },
            test: {
                src: ['test/**/*.js']
            }
        },
        notify: {
            done: {
                options: {
                    message: 'Build Success!'
                }
            }
        },
        notify_hooks: {
            options: {
                enabled: true,
                max_jshint_notifications: 5
            }
        },
        jsdoc: {
            dist: {
                src: [
                    'dist/undermore.js'
                ],
                options: {
                    destination: 'dist/docs'
                }
            }
        },
        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            src: {
                files: [
                    '<%= concat.undermore.src %>',
                    '<%= concat.jquery.src %>',
                    '<%= concat.dist.src %>'
                ],
                tasks: ['concat', 'jshint:src', 'uglify', 'qunit']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test', 'qunit']
            },
            doc: {
                files: '<%= jsdoc.dist.src %>',
                tasks: ['jsdoc']
            }
        }
    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-jsdoc');
    // Automatic notifications when tasks fail.
    grunt.loadNpmTasks('grunt-notify');
    // grunt-notify options handler
    grunt.task.run('notify_hooks');

    // Default task (grunt will use this + any defined on watches)
    // TODO: figure out why and limit grunt watch
    grunt.registerTask('default', []);
    grunt.registerTask('build', ['concat', 'jshint', 'uglify', 'qunit', 'jsdoc', 'notify:done']);

};<commit_msg>improving gruntfile to make "grunt watch" not automatically create dist build files<commit_after>'use strict';

module.exports = function(grunt) {

    // Project configuration.
    grunt.initConfig({
        // Metadata.
        pkg: grunt.file.readJSON('package.json'),
        banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
            '<%= grunt.template.today("yyyy-mm-dd") %>\n' +
            '<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
            '* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
            ' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',
        banner_undermore: grunt.file.read('src/_source/_.banner.tmpl'),
        foot_undermore: grunt.file.read('src/_source/_.foot.tmpl'),
        banner_jquery: grunt.file.read('src/jquery_source/$.banner.tmpl'),
        foot_jquery: grunt.file.read('src/jquery_source/$.foot.tmpl'),
        // Task configuration.
        concat: {
            options: {
                banner: '<%= banner %>'
            },
            undermore: {
                options: {
                    separator: ', \n ',
                    banner: '<%= banner_undermore %>',
                    footer: '<%= foot_undermore %>'
                },
                src: ['src/_source/_.*.js'],
                dest: 'src/_.build.js'
            },
            jquery: {
                options: {
                    separator: '\n\n',
                    banner: '<%= banner_jquery %>',
                    footer: '<%= foot_jquery %>'
                },
                src: ['src/jquery_source/$.*.js'],
                dest: 'src/$.build.js'
            },
            dist: {
                src: [
                    'src/_.build.js',
                    'src/$.build.js',
                    'src/safe.js',
                    'src/string.*.js'
                ],
                dest: 'dist/undermore.js'
            },
            bin: {
                src: ['src/*.js'],
                dest: 'bin/<%= pkg.name %>.js'
            }
        },
        uglify: {
            options: {
                banner: '<%= banner %>'
            },
            dist: {
                src: '<%= concat.dist.dest %>',
                dest: 'dist/<%= pkg.name %>.min.js'
            }
        },
        qunit: {
            files: ['test/*.html']
        },
        jshint: {
            options: {
                jshintrc: '.jshintrc'
            },
            gruntfile: {
                src: 'Gruntfile.js'
            },
            src: {
                src: '<%= concat.dist.src %>'
            },
            test: {
                src: ['test/**/*.js']
            }
        },
        notify: {
            done: {
                options: {
                    message: 'Build Success!'
                }
            }
        },
        notify_hooks: {
            options: {
                enabled: true,
                max_jshint_notifications: 5
            }
        },
        jsdoc: {
            dist: {
                src: [
                    'dist/undermore.js'
                ],
                options: {
                    destination: 'dist/docs'
                }
            }
        },
        watch: {
            gruntfile: {
                files: '<%= jshint.gruntfile.src %>',
                tasks: ['jshint:gruntfile']
            },
            src: {
                files: [
                    '<%= concat.undermore.src %>',
                    '<%= concat.jquery.src %>',
                    '!src/*.build.js'
                ],
                tasks: ['concat', 'jshint:src', 'uglify', 'qunit', 'shell:clean']
            },
            test: {
                files: '<%= jshint.test.src %>',
                tasks: ['jshint:test', 'qunit']
            }
        },
        shell:{
            clean:{
                options: {
                    stderr: false
                },
                command: 'git checkout src/*build.js; git checkout bin; git checkout dist/docs; git checkout dist/undermore*'
            }
        }
    });

    // These plugins provide necessary tasks.
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-contrib-jshint');
    grunt.loadNpmTasks('grunt-contrib-watch');
    grunt.loadNpmTasks('grunt-jsdoc');
    grunt.loadNpmTasks('grunt-shell');
    // Automatic notifications when tasks fail.
    grunt.loadNpmTasks('grunt-notify');
    // grunt-notify options handler
    grunt.task.run('notify_hooks');

    // Default task (grunt will use this + any defined on watches)
    // TODO: figure out why and limit grunt watch
    grunt.registerTask('default', []);
    // actual distribution build
    grunt.registerTask('build', ['concat', 'jshint', 'uglify', 'qunit', 'jsdoc', 'notify:done']);

};<|endoftext|>


<commit_before>module.exports = function(grunt) {
	grunt.initConfig({
		express: {
			devServer: {
				options: {
					script: 'app.js'
				}
			}
		},
		clean: {
			styles: {
				options: {
					force: true
				},
				src: ['dist/styles/**/*.css']
			},
			scripts: {
				options: {
					force: true
				},
				src: ['dist/scripts/**/*']
			},
			images: {
				options: {
					force: true
				},
				src: ['dist/images/**/*']
			}
		},
		copy: {
			minimizedScripts: {
				expand: true,
				cwd: 'src/scripts/',
				src: '**/*.{min, map, compact}.js',
				dest: 'dist/scripts/'
			},
			otherImages: {
				expand: true,
				cwd: 'src/images/',
				src: ['**/*', '!{jpg, png, gif}'],
				dest: 'dist/images/'
			}
		},
		uglify: {
			jsMinimize: {
				files: [{
					expand: true,
					cwd: 'src/scripts/',
					src: ['controllers/**/*.js', '!**/*.{min, map, compact}.js'],
					dest: 'dist/scripts/',
					ext: '.min.js',
					extDot: 'last'
				}]
			}
		},
		sass: {
			cssCompile: {
				files: [{
					expand: true,
					cwd: 'src/styles/',
					src: ['*.scss', '!_*.scss'],
					dest: 'dist/styles',
					ext: '.css'
				}]
			}
		},
		imagemin: {
			imgMinimize: {
				files: [{
					expand: true,
					cwd: 'src/images/',
					src: '**/*.{jpg, png, gif}',
					dest: 'dist/images/',
					extDot: 'last'
				}]
			}
		},
		watch: {
			express: {
				files: ['app.js', 'Gruntfile.js', '**/*.json'],
				tasks: ['express:devServer'],
				options: {
					spawn: false,
					reload: true
				}
			},
			styles: {
				files: 'src/styles/**/*',
				tasks: ['clean:styles', 'sass'],
				options: {
					nospawn: true
				}
			},
			scripts: {
				files: 'src/scripts/**/*',
				tasks: ['clean:scripts', 'copy:minimizedScripts', 'uglify'],
				options: {
					nospawn: true
				}
			},
			images: {
				files: 'src/images/**/*',
				tasks: ['clean:images', 'copy:otherImages', 'imagemin'],
				options: {
					spawn: true
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-express-server');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-watch');

	grunt.registerTask('default', [
		'clean',
		'copy',
		'sass',
		'uglify',
		'imagemin',
		'express',
		'watch'
	]);
};
<commit_msg>grunt 라이브 스크립터 테스크를 분리<commit_after>module.exports = function(grunt) {
	grunt.initConfig({
		express: {
			devServer: {
				options: {
					script: 'app.js'
				}
			}
		},
		clean: {
			styles: {
				options: {
					force: true
				},
				src: ['dist/styles/**/*.css']
			},
			scripts: {
				options: {
					force: true
				},
				src: ['dist/scripts/**/*']
			},
			libScripts: {
				options: {
					force: true
				},
				src: ['dist/libs/**/*']
			},
			images: {
				options: {
					force: true
				},
				src: ['dist/images/**/*']
			}
		},
		copy: {
			libScripts: {
				expand: true,
				cwd: 'src/libs/',
				src: '**/*.{min, map, compact}.js',
				dest: 'dist/libs/'
			},
			otherImages: {
				expand: true,
				cwd: 'src/images/',
				src: ['**/*', '!{jpg, png, gif}'],
				dest: 'dist/images/'
			}
		},
		uglify: {
			jsMinimize: {
				files: [{
					expand: true,
					cwd: 'src/scripts/',
					src: ['**/*.js', '!**/*.{min, map, compact}.js'],
					dest: 'dist/scripts/',
					ext: '.min.js',
					extDot: 'last'
				}]
			}
		},
		sass: {
			cssCompile: {
				files: [{
					expand: true,
					cwd: 'src/styles/',
					src: ['*.scss', '!_*.scss'],
					dest: 'dist/styles',
					ext: '.css'
				}]
			}
		},
		imagemin: {
			imgMinimize: {
				files: [{
					expand: true,
					cwd: 'src/images/',
					src: '**/*.{jpg, png, gif}',
					dest: 'dist/images/',
					extDot: 'last'
				}]
			}
		},
		watch: {
			express: {
				files: ['app.js', 'Gruntfile.js', '**/*.json'],
				tasks: ['express:devServer'],
				options: {
					spawn: false,
					reload: true
				}
			},
			styles: {
				files: 'src/styles/**/*',
				tasks: ['clean:styles', 'sass'],
				options: {
					nospawn: true
				}
			},
			scripts: {
				files: 'src/scripts/**/*',
				tasks: ['clean:scripts', 'uglify'],
				options: {
					nospawn: true
				}
			},
			libScripts: {
				files: 'src/libs/**/*',
				tasks: ['clean:libScripts', 'copy:libScripts'],
				options: {
					nospawn: true
				}
			},
			images: {
				files: 'src/images/**/*',
				tasks: ['clean:images', 'copy:otherImages', 'imagemin'],
				options: {
					spawn: true
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-express-server');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-contrib-uglify');
	grunt.loadNpmTasks('grunt-contrib-watch');

	grunt.registerTask('default', [
		'clean',
		'copy',
		'sass',
		'uglify',
		'imagemin',
		'express',
		'watch'
	]);
};
<|endoftext|>


<commit_before>'use strict';

module.exports = function( grunt ) {

	// Project configuration.
	grunt.initConfig({
		// Metadata.
		pkg: grunt.file.readJSON( 'package.json' ),
		title: '<%= pkg.title || pkg.name %> - v<%= pkg.version %>',
		buildNumber: process.env.CI_BUILD_NUMBER || '<%= grunt.template.today("isoDateTime") %>',
		banner: '/*! <%= title %> - ' +
			'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
			'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
			'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
			' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',

		browsers: [
			{ browserName: 'Internet Explorer', version:  '6' },
			{ browserName: 'android', version: '4.0' }, // old, like Google Earth (maybe not quite that old)
			{ browserName: 'Internet Explorer', version:  '8' },
			{ browserName: 'Internet Explorer', version:  '9' },
			// modern browsers (polyfill should play nice)
			{ browserName: 'Internet Explorer' },
			{ browserName: 'Chrome' },
			{ browserName: 'iPhone' },
			{ browserName: 'android' },
			{ browserName: 'Firefox' }
		],

		// Task configuration.
		clean: {
			files: [ 'sc_*.log' ]
		},
		connect: {
			server: {
				options: {
					port: 8000,
					base: '.'
				}
			}
		},
		// production pipeline tasks
		concat: {
			options: {
				banner: '<%= banner %>',
				stripBanners: true
			},
			dist: {
				src: [ 'src/<%= pkg.name %>.js' ],
				dest: 'dist/<%= pkg.name %>.js'
			}
		},
		uglify: {
			options: {
				banner: '<%= banner %>'
			},
			dist: {
				src: 'dist/<%= pkg.name %>.js',
				dest: 'dist/<%= pkg.name %>.min.js'
			},
		},
		// code quality tasks
		qunit: {
			unit: [
				'test/*.html',
				'!test/google-earth.html'
			],
			// test other jquery versions
			jquery144: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/custom.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/disabled.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/email.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/invalid.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/pattern.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/required.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/submit.html?jquery=1.4.4'
					]
				}
			},
			jquery172: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/custom.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/disabled.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/email.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/invalid.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/pattern.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/required.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/submit.html?jquery=1.7.2'
					]
				}
			},
			jquery213: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/custom.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/disabled.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/email.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/invalid.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/pattern.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/required.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/submit.html?jquery=2.1.3'
					]
				}
			}
		},
		'saucelabs-qunit': {
			change: {
				options: {
					testname: 'change - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/change.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			checkValidity: {
				options: {
					testname: 'checkValidity() - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			customValidity: {
				options: {
					testname: 'customValidity - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/custom.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			disabled: {
				options: {
					testname: 'disabled - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/disabled.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			email: {
				options: {
					testname: 'email - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/email.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			invalid: {
				options: {
					testname: 'invalid - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/invalid.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			novalidate: {
				options: {
					testname: 'novalidate - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/novalidate.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			pattern: {
				options: {
					testname: 'pattern - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/pattern.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			required: {
				options: {
					testname: 'required - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/required.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			submit: {
				options: {
					testname: 'submit - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/submit.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			}
		},
		jshint: {
			gruntfile: {
				options: {
					jshintrc: '.jshintrc'
				},
				src: [
					'Gruntfile.js',
					'src/.jshintrc',
					'test/.jshintrc',
					'.jshintrc'
				]
			},
			src: {
				options: {
					jshintrc: 'src/.jshintrc'
				},
				src: [ 'src/**/*.js' ]
			},
			test: {
				options: {
					jshintrc: 'test/.jshintrc'
				},
				src: [ 'test/*.js' ]
			},
		},
		watch: {
			gruntfile: {
				files: '<%= jshint.gruntfile.src %>',
				tasks: [ 'jshint:gruntfile' ]
			},
			src: {
				files: '<%= jshint.src.src %>',
				tasks: [ 'jshint:src', 'qunit:unit' ]
			},
			test: {
				files: '<%= jshint.test.src %>',
				tasks: [ 'jshint:test', 'qunit:unit' ]
			},
		}
	});

	// These plugins provide necessary tasks.
	grunt.loadNpmTasks( 'grunt-contrib-clean' );
	grunt.loadNpmTasks( 'grunt-contrib-concat' );
	grunt.loadNpmTasks( 'grunt-contrib-uglify' );
	grunt.loadNpmTasks( 'grunt-contrib-connect' );
	grunt.loadNpmTasks( 'grunt-contrib-qunit' );
	grunt.loadNpmTasks( 'grunt-saucelabs' );
	grunt.loadNpmTasks( 'grunt-contrib-jshint' );
	grunt.loadNpmTasks( 'grunt-contrib-watch' );

	// Default task.
	grunt.registerTask( 'test', [ 'jshint', 'connect', 'qunit' ]);
	grunt.registerTask( 'test-remote', [ 'jshint', 'qunit:unit', 'connect', 'clean', 'saucelabs-qunit' ]);
	grunt.registerTask( 'produce', [ 'clean', 'concat', 'uglify' ]);
	grunt.registerTask( 'default', [ 'test', 'produce' ]);

};
<commit_msg>fix build number variable<commit_after>'use strict';

module.exports = function( grunt ) {

	// Project configuration.
	grunt.initConfig({
		// Metadata.
		pkg: grunt.file.readJSON( 'package.json' ),
		title: '<%= pkg.title || pkg.name %> - v<%= pkg.version %>',
		buildNumber: process.env.TRAVIS_BUILD_ID || grunt.template.today("isoUtcDateTime"),
		banner: '/*! <%= title %> - ' +
			'<%= grunt.template.today("yyyy-mm-dd") %>\n' +
			'<%= pkg.homepage ? "* " + pkg.homepage + "\\n" : "" %>' +
			'* Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author.name %>;' +
			' Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %> */\n',

		browsers: [
			{ browserName: 'Internet Explorer', version:  '6' },
			{ browserName: 'android', version: '4.0' }, // old, like Google Earth (maybe not quite that old)
			{ browserName: 'Internet Explorer', version:  '8' },
			{ browserName: 'Internet Explorer', version:  '9' },
			// modern browsers (polyfill should play nice)
			{ browserName: 'Internet Explorer' },
			{ browserName: 'Chrome' },
			{ browserName: 'iPhone' },
			{ browserName: 'android' },
			{ browserName: 'Firefox' }
		],

		// Task configuration.
		clean: {
			files: [ 'sc_*.log' ]
		},
		connect: {
			server: {
				options: {
					port: 8000,
					base: '.'
				}
			}
		},
		// production pipeline tasks
		concat: {
			options: {
				banner: '<%= banner %>',
				stripBanners: true
			},
			dist: {
				src: [ 'src/<%= pkg.name %>.js' ],
				dest: 'dist/<%= pkg.name %>.js'
			}
		},
		uglify: {
			options: {
				banner: '<%= banner %>'
			},
			dist: {
				src: 'dist/<%= pkg.name %>.js',
				dest: 'dist/<%= pkg.name %>.min.js'
			},
		},
		// code quality tasks
		qunit: {
			unit: [
				'test/*.html',
				'!test/google-earth.html'
			],
			// test other jquery versions
			jquery144: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/custom.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/disabled.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/email.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/invalid.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/pattern.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/required.html?jquery=1.4.4',
						'http://127.0.0.1:8000/test/submit.html?jquery=1.4.4'
					]
				}
			},
			jquery172: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/custom.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/disabled.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/email.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/invalid.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/pattern.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/required.html?jquery=1.7.2',
						'http://127.0.0.1:8000/test/submit.html?jquery=1.7.2'
					]
				}
			},
			jquery213: {
				options: {
					timeout: 12000,
					urls: [
						'http://127.0.0.1:8000/test/change.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/checkValidity.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/custom.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/disabled.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/email.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/invalid.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/novalidate.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/pattern.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/required.html?jquery=2.1.3',
						'http://127.0.0.1:8000/test/submit.html?jquery=2.1.3'
					]
				}
			}
		},
		'saucelabs-qunit': {
			change: {
				options: {
					testname: 'change - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/change.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			checkValidity: {
				options: {
					testname: 'checkValidity() - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/checkValidity.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			customValidity: {
				options: {
					testname: 'customValidity - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/custom.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			disabled: {
				options: {
					testname: 'disabled - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/disabled.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			email: {
				options: {
					testname: 'email - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/email.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			invalid: {
				options: {
					testname: 'invalid - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/invalid.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			novalidate: {
				options: {
					testname: 'novalidate - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/novalidate.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			pattern: {
				options: {
					testname: 'pattern - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/pattern.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			required: {
				options: {
					testname: 'required - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/required.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			},
			submit: {
				options: {
					testname: 'submit - <%= title %>',
					build: '<%= buildNumber %>',
					urls: [ 'http://127.0.0.1:8000/test/submit.html?jquery=1.7.2' ],
					browsers: '<%= browsers %>'
				}
			}
		},
		jshint: {
			gruntfile: {
				options: {
					jshintrc: '.jshintrc'
				},
				src: [
					'Gruntfile.js',
					'src/.jshintrc',
					'test/.jshintrc',
					'.jshintrc'
				]
			},
			src: {
				options: {
					jshintrc: 'src/.jshintrc'
				},
				src: [ 'src/**/*.js' ]
			},
			test: {
				options: {
					jshintrc: 'test/.jshintrc'
				},
				src: [ 'test/*.js' ]
			},
		},
		watch: {
			gruntfile: {
				files: '<%= jshint.gruntfile.src %>',
				tasks: [ 'jshint:gruntfile' ]
			},
			src: {
				files: '<%= jshint.src.src %>',
				tasks: [ 'jshint:src', 'qunit:unit' ]
			},
			test: {
				files: '<%= jshint.test.src %>',
				tasks: [ 'jshint:test', 'qunit:unit' ]
			},
		}
	});

	// These plugins provide necessary tasks.
	grunt.loadNpmTasks( 'grunt-contrib-clean' );
	grunt.loadNpmTasks( 'grunt-contrib-concat' );
	grunt.loadNpmTasks( 'grunt-contrib-uglify' );
	grunt.loadNpmTasks( 'grunt-contrib-connect' );
	grunt.loadNpmTasks( 'grunt-contrib-qunit' );
	grunt.loadNpmTasks( 'grunt-saucelabs' );
	grunt.loadNpmTasks( 'grunt-contrib-jshint' );
	grunt.loadNpmTasks( 'grunt-contrib-watch' );

	// Default task.
	grunt.registerTask( 'test', [ 'jshint', 'connect', 'qunit' ]);
	grunt.registerTask( 'test-remote', [ 'jshint', 'qunit:unit', 'connect', 'clean', 'saucelabs-qunit' ]);
	grunt.registerTask( 'produce', [ 'clean', 'concat', 'uglify' ]);
	grunt.registerTask( 'default', [ 'test', 'produce' ]);

};
<|endoftext|>


<commit_before>'use strict';

module.exports = function(grunt) {

  grunt.initConfig({

    pkg: grunt.file.readJSON('bower.json'),

    clean: {
      dev: [
        'browser_extensions/chrome_dev/',
        'browser_extensions/chrome_dist/'
      ],
      dist: [
        'dist/',
        'browser_extensions/chrome_dist/'
      ],
      all: [
        'dist/',
        'browser_extensions/chrome_dev/',
        'browser_extensions/chrome_dist/'
      ]
    },

    copy: {
      dev: {
        files: [
          {
            expand: true,
            cwd: 'browser_extensions/chrome/',
            src: [
              '_locales/**/*',
              'images/icon_*',
              'js/**/*',
              'pages/**/*',
              'sounds/**/*',
              'stylesheets/**/*.css',
              'vendors/**/*',
              'manifest.json'
            ],
            dest: 'browser_extensions/chrome_dev/'
          },
          {
            src: 'src/pangu.js',
            dest: 'browser_extensions/chrome_dev/vendors/pangu.min.js'
          }
        ]
      },
      dist: {
        files: [
          {
            src: 'dist/pangu.min.js',
            dest: 'browser_extensions/chrome/vendors/pangu.min.js'
          },
          {
            expand: true,
            cwd: 'browser_extensions/chrome/',
            src: [
              '_locales/**/*',
              'images/icon_*',
              'js/**/*',
              'pages/**/*',
              'sounds/**/*',
              'stylesheets/**/*.css',
              'vendors/**/*',
              'manifest.json'
            ],
            dest: 'browser_extensions/chrome_dist/'
          },
          {
            src: '/Users/vinta/Dropbox/Developer/Projects/paranoid-auto-spacing/key.pem',
            dest: 'browser_extensions/chrome_dist/key.pem'
          }
        ]
      }
    },

    coveralls: {
      options: {
        debug: true,
        coverage_dir: 'coverage/'
      }
    },

    karma: {
      dist: {
        options: {
          // base path, that will be used to resolve files and exclude
          basePath: '',
          // start these browsers
          browsers: [
            'PhantomJS'
          ],
          coverageReporter: {
            // multiple reporters
            reporters: [
              {type: 'lcov', dir:'coverage/'},
              {type: 'text'}
            ]
          },
          // list of files / patterns to load in the browser
          files: [
            'dist/pangu.js',
            'tests/lib/jquery/jquery-1.10.2.min.js',
            'tests/lib/jasmine-jquery/jasmine-jquery.js',
            'tests/spec/**/*.js',
            {
              pattern: 'tests/fixtures/**/*.html',
              included: false,
              served: true
            }
          ],
          // list of files to exclude
          exclude: [],
          // frameworks to use
          frameworks: [
            'jasmine'
          ],
          plugins: [
            'karma-*'
          ],
          // preprocessors allow you to do some work with your files before they get served to the browser.
          preprocessors: {
            '**/*.html': [],
            // source files, that you wanna generate coverage for
            'dist/pangu.js': [
              'coverage'
            ]
          },
          // test results reporter to use, possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
          reporters: [
            'progress',
            'coverage'
          ],
          // continuous Integration mode, if true, it capture browsers, run tests and exit
          singleRun: true
        }
      }
    },

    // remove console.log()
    strip: {
      dist: {
        src: 'src/pangu.js',
        dest: 'dist/pangu.js'
      },
      dist_chrome: {
        src: 'browser_extensions/chrome_dist/js/*.js',
        options: {
          inline: true
        }
      }
    },

    uglify: {
      options: {
        banner: grunt.file.read('src/banner.js')
      },
      dist: {
        src: 'dist/pangu.js',
        dest: 'dist/pangu.min.js'
      }
    },

    watch: {
      dev: {
        files: [
          'Gruntfile.js',
          'bower.json',
          'src/**/*',
          'browser_extensions/chrome/**/*',
          '!browser_extensions/chrome/vendors/pangu.min.js'
        ],
        tasks: [
          'dev'
        ]
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-karma');
  grunt.loadNpmTasks('grunt-karma-coveralls');
  grunt.loadNpmTasks('grunt-strip');

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

  // 準備打包到 Chrome Web Store
  // browser_extensions/chrome_dev/ 是開發用的
  // browser_extensions/chrome_dist/ 是打包用的
  grunt.registerTask('dist', [
    'clean:all',
    'strip:dist',
    'uglify',
    'copy:dist',
    'strip:dist_chrome'
  ]);

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

  grunt.registerTask('coverage', [
    'coveralls'
  ]);

  grunt.registerTask('default', [
    'test'
  ]);

};
<commit_msg>improve Gruntfile.js<commit_after>module.exports = function(grunt) {
  'use strict';

  grunt.initConfig({

    pkg: grunt.file.readJSON('bower.json'),

    clean: {
      dev: [
        'coverage/',
        'browser_extensions/chrome_dev/',
        'browser_extensions/chrome_dist/'
      ],
      dist: [
        'coverage/',
        'dist/',
        'browser_extensions/chrome_dev/',
        'browser_extensions/chrome_dist/'
      ]
    },

    copy: {
      dev: {
        files: [
          {
            expand: true,
            cwd: 'browser_extensions/chrome/',
            src: [
              '_locales/**/*',
              'images/icon_*',
              'js/**/*',
              'pages/**/*',
              'sounds/**/*',
              'stylesheets/**/*.css',
              'vendors/**/*',
              'manifest.json'
            ],
            dest: 'browser_extensions/chrome_dev/'
          },
          {
            src: 'src/pangu.js',
            dest: 'browser_extensions/chrome_dev/vendors/pangu.min.js'
          }
        ]
      },
      dist: {
        files: [
          {
            src: 'dist/pangu.min.js',
            dest: 'browser_extensions/chrome/vendors/pangu.min.js'
          },
          {
            expand: true,
            cwd: 'browser_extensions/chrome/',
            src: [
              '_locales/**/*',
              'images/icon_*',
              'js/**/*',
              'pages/**/*',
              'sounds/**/*',
              'stylesheets/**/*.css',
              'vendors/**/*',
              'manifest.json'
            ],
            dest: 'browser_extensions/chrome_dist/'
          },
          {
            src: '/Users/vinta/Dropbox/Developer/Projects/paranoid-auto-spacing/key.pem',
            dest: 'browser_extensions/chrome_dist/key.pem'
          }
        ]
      }
    },

    coveralls: {
      options: {
        debug: true,
        coverage_dir: 'coverage/'
      }
    },

    karma: {
      test: {
        options: {
          // base path, that will be used to resolve files and exclude
          basePath: '',
          // start these browsers
          browsers: [
            'PhantomJS'
          ],
          coverageReporter: {
            // multiple reporters
            reporters: [
              {type: 'lcov', dir:'coverage/'},
              {type: 'text'}
            ]
          },
          // list of files to exclude
          exclude: [],
          // list of files / patterns to load in the browser
          files: [
            'dist/pangu.js',
            'tests/lib/jquery/jquery-1.10.2.min.js',
            'tests/lib/jasmine-jquery/jasmine-jquery.js',
            'tests/spec/**/*.js',
            {
              pattern: 'tests/fixtures/**/*.html',
              included: false,
              served: true
            }
          ],
          // frameworks to use
          frameworks: [
            'jasmine'
          ],
          plugins: [
            'karma-*'
          ],
          // preprocessors allow you to do some work with your files before they get served to the browser.
          preprocessors: {
            '**/*.html': [],
            // source files, that you wanna generate coverage for
            'dist/pangu.js': [
              'coverage'
            ]
          },
          // test results reporter to use, possible values: 'dots', 'progress', 'junit', 'growl', 'coverage'
          reporters: [
            'progress',
            'coverage'
          ],
          // continuous Integration mode, if true, it capture browsers, run tests and exit
          singleRun: true
        }
      }
    },

    // remove console.log()
    strip: {
      common: {
        src: 'src/pangu.js',
        dest: 'dist/pangu.js'
      },
      dist_chrome: {
        src: 'browser_extensions/chrome_dist/js/*.js',
        options: {
          inline: true
        }
      }
    },

    uglify: {
      options: {
        banner: grunt.file.read('src/banner.js')
      },
      dist: {
        src: 'dist/pangu.js',
        dest: 'dist/pangu.min.js'
      }
    },

    watch: {
      dev: {
        files: [
          'Gruntfile.js',
          'bower.json',
          'src/**/*',
          'tests/fixtures/**/*',
          'tests/spec/**/*',
          'browser_extensions/chrome/**/*',
          '!browser_extensions/chrome/vendors/pangu.min.js'
        ],
        tasks: [
          'dev'
        ]
      }
    }

  });

  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-karma');
  grunt.loadNpmTasks('grunt-karma-coveralls');
  grunt.loadNpmTasks('grunt-strip');

  grunt.registerTask('dev', [
    'clean:dev',
    'strip:common',
    'copy:dev',
    'karma'
  ]);

  grunt.registerTask('dist', [
    'clean:dist',
    'strip:common',
    'uglify',
    'copy:dist',
    'strip:dist_chrome',
    'karma'
  ]);

  grunt.registerTask('test', [
    'dist'
  ]);

  grunt.registerTask('coverage', [
    'coveralls'
  ]);

  grunt.registerTask('default', [
    'dist'
  ]);

};
<|endoftext|>


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

    grunt.initConfig({
        shell: {
            npm: {
                command: function() {
                    grunt.log.writeln('Installing deps');
                    return 'cd client; npm install';
                }
            },
            bower: {
                command: function() {
                    grunt.log.writeln('Installing bower');
                    return 'cd client; ./node_modules/gulp/bin/gulp.js bower';
                }
            },
            build: {
                command: function() {
                    grunt.log.writeln('Running gulp');
                    return 'cd client; ./node_modules/gulp/bin/gulp.js build';
                }
            }
        }
    })

    grunt.loadNpmTasks('grunt-shell');

    grunt.registerTask('default', ['shell:npm', 'shell:bower', 'shell:build']);

};<commit_msg>rewrite git urls<commit_after>module.exports = function(grunt) {

    grunt.initConfig({
        shell: {
        	git: {
                command: function() {
                    grunt.log.writeln('Fixing git config');
                    return 'git config --global url."https://".insteadOf git://';
                }
            },
            npm: {
                command: function() {
                    grunt.log.writeln('Installing deps');
                    return 'cd client; npm install';
                }
            },
            bower: {
                command: function() {
                    grunt.log.writeln('Installing bower');
                    return 'cd client; ./node_modules/gulp/bin/gulp.js bower';
                }
            },
            build: {
                command: function() {
                    grunt.log.writeln('Running gulp');
                    return 'cd client; ./node_modules/gulp/bin/gulp.js build';
                }
            }
        }
    })

    grunt.loadNpmTasks('grunt-shell');

    grunt.registerTask('default', ['shell:git', 'shell:npm', 'shell:bower', 'shell:build']);

};<|endoftext|>


<commit_before>/*
 * grunt-translation-spreadsheet-sync
 * https://github.com/Andreas-Schoenefeldt/grunt-translation-spreadsheet-sync
 *
 * Copyright (c) 2019 Andreas Schönefeldt
 * Licensed under the MIT license.
 */

'use strict';

const semver = require('semver');

module.exports = function(grunt) {

  const pkg = grunt.file.readJSON('package.json');
  const currentVersion = pkg.version;

  // Project configuration.
  grunt.initConfig({
    pkg: pkg,

    bump: {
      options: {
        files: ['package.json'],
        commitFiles: ['-a'],
        pushTo: 'origin',
        globalReplace: true,
        // regExp: /(['|"]?version['|"]?[ ]*:[ ]*['|"]?|^framework:[\S\s]*?assets:[\s]*version:[ ]*)(\d+\.\d+\.\d+(-false\.\d+)?(-\d+)?)[\d||A-a|.|-]*(['|"]?)/gmi
      }
    },
    prompt: {
      bump: {
        options: {
          questions: [
            {
              config:  'bump.options.setVersion',
              type:    'list',
              message: 'Bump version from ' + '<%= pkg.version %>' + ' to:',
              choices: [
                {
                  value: semver.inc(currentVersion, 'patch'),
                  name:  'Patch:  ' + semver.inc(currentVersion, 'patch') + ' Backwards-compatible bug fixes.'
                },
                {
                  value: semver.inc(currentVersion, 'minor'),
                  name:  'Minor:  ' + semver.inc(currentVersion, 'minor') + ' Add functionality in a backwards-compatible manner.'
                },
                {
                  value: semver.inc(currentVersion, 'major'),
                  name:  'Major:  ' + semver.inc(currentVersion, 'major') + ' Incompatible API changes.'
                },
                {
                  value: 'custom',
                  name:  'Custom: ?.?.? Specify version...'
                }
              ]
            },
            {
              config:   'bump.options.setVersion',
              type:     'input',
              message:  'What specific version would you like',
              when:     function (answers) {
                return answers['bump.options.setVersion'] === 'custom';
              },
              validate: function (value) {
                var valid = semver.valid(value);
                return !!valid || 'Must be a valid semver, such as 1.2.3-rc1. See http://semver.org/ for more details.';
              }
            }
          ]
        }
      }
    },

    shell: {
      publish_npm: {
        command: 'npm publish'
      }
    }

  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-prompt');
  grunt.loadNpmTasks('grunt-bump');
  grunt.loadNpmTasks('grunt-shell');

  grunt.registerTask('build', 'Production Build', function() {
    grunt.task.run('prompt', 'bump', 'shell:publish_npm');
  });

};
<commit_msg>Updated the merge command, to keep develop and master in syn<commit_after>/*
 * grunt-translation-spreadsheet-sync
 * https://github.com/Andreas-Schoenefeldt/grunt-translation-spreadsheet-sync
 *
 * Copyright (c) 2019 Andreas Schönefeldt
 * Licensed under the MIT license.
 */

'use strict';

const semver = require('semver');

module.exports = function(grunt) {

  const pkg = grunt.file.readJSON('package.json');
  const currentVersion = pkg.version;

  // Project configuration.
  grunt.initConfig({
    pkg: pkg,

    bump: {
      options: {
        files: ['package.json'],
        commitFiles: ['-a'],
        pushTo: 'origin',
        globalReplace: true,
        // regExp: /(['|"]?version['|"]?[ ]*:[ ]*['|"]?|^framework:[\S\s]*?assets:[\s]*version:[ ]*)(\d+\.\d+\.\d+(-false\.\d+)?(-\d+)?)[\d||A-a|.|-]*(['|"]?)/gmi
      }
    },
    prompt: {
      bump: {
        options: {
          questions: [
            {
              config:  'bump.options.setVersion',
              type:    'list',
              message: 'Bump version from ' + '<%= pkg.version %>' + ' to:',
              choices: [
                {
                  value: semver.inc(currentVersion, 'patch'),
                  name:  'Patch:  ' + semver.inc(currentVersion, 'patch') + ' Backwards-compatible bug fixes.'
                },
                {
                  value: semver.inc(currentVersion, 'minor'),
                  name:  'Minor:  ' + semver.inc(currentVersion, 'minor') + ' Add functionality in a backwards-compatible manner.'
                },
                {
                  value: semver.inc(currentVersion, 'major'),
                  name:  'Major:  ' + semver.inc(currentVersion, 'major') + ' Incompatible API changes.'
                },
                {
                  value: 'custom',
                  name:  'Custom: ?.?.? Specify version...'
                }
              ]
            },
            {
              config:   'bump.options.setVersion',
              type:     'input',
              message:  'What specific version would you like',
              when:     function (answers) {
                return answers['bump.options.setVersion'] === 'custom';
              },
              validate: function (value) {
                var valid = semver.valid(value);
                return !!valid || 'Must be a valid semver, such as 1.2.3-rc1. See http://semver.org/ for more details.';
              }
            }
          ]
        }
      }
    },

    shell: {
      publish_npm: {
        command: 'npm publish'
      },
      merge: {
        command: [
          'git checkout develop',
          'git pull origin develop',
          'git merge master',
          'git push'
        ].join('&&')
      }
    }

  });

  // These plugins provide necessary tasks.
  grunt.loadNpmTasks('grunt-prompt');
  grunt.loadNpmTasks('grunt-bump');
  grunt.loadNpmTasks('grunt-shell');

  grunt.registerTask('build', 'Production Build', function() {
    grunt.task.run('prompt', 'bump', 'shell:publish_npm', 'shell:merge');
  });

};
<|endoftext|>


<commit_before>module.exports = function (grunt) {
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-contrib-uglify');
    grunt.loadNpmTasks('grunt-search');
    grunt.loadNpmTasks('grunt-preprocess');

    var packager = require('electron-packager');

    const BUILD_DIR = 'build/';
    const DIST_DIR = 'dist/';
    const APP_NAME = 'APP Name';
    const PLATFORM = 'all';
    const ARCH = 'all';
    const ELECTRON_VERSION = '0.34.0';
    const USE_ASAR = true;

    // Project configuration.
    grunt.initConfig(
        {
            pkg: grunt.file.readJSON('package.json'),
            uglify: {
                production: {
                    files: [
                        {
                            src : 'scripts/**/*.js',
                            dest : BUILD_DIR + '/scripts/app.angular.min.js'
                        },
                        {
                            expand: true,
                            src: BUILD_DIR + 'main.js'
                        }
                    ]
                }
            },
            copy: {
                electron_app: {
                    files: [
                        {
                            expand: true,
                            src: ['index.html', 'main.js', 'package.json'],
                            dest: BUILD_DIR
                        }
                    ]
                },
                angular_app_html: {
                    files: [
                        {
                            expand: true,
                            src: ['scripts/**/*.html'],
                            dest: BUILD_DIR
                        }
                    ]
                }
            },
            search: {
                node_modules_dependencies: {
                    files: {
                        src: ['index.html']
                    },
                    options: {
                        searchString: /="node_modules\/.*"/g,
                        logFormat: "custom",
                        onMatch: function (match) {
                            var filePath = match.match.substring(
                                2,
                                match.match.length - 1
                            );
                            grunt.file.copy(filePath, BUILD_DIR + filePath);
                            console.log('Found dependency: ' + filePath)
                        },
                        customLogFormatCallback: function (params) {
                        }
                    }
                }
            },
            preprocess: {
                production: {
                    options: {
                        context: {
                            NODE_ENV: 'production'
                        }
                    },
                    src : BUILD_DIR + 'index.html',
                    dest : BUILD_DIR + 'index.html'
                }
            }
        }
    );

    grunt.registerTask(
        'build',
        [
            'clean',
            'copy:electron_app',
            'copy:angular_app_html',
            'preprocess:production',
            'search:node_modules_dependencies',
            'uglify:production',
            'package',
            'fix_default_app'
        ]
    );

    // Clean the build directory
    grunt.registerTask(
        'clean',
        function () {
            if (grunt.file.isDir(BUILD_DIR)) {
                grunt.file.delete(BUILD_DIR, {force: true});
            }
            if (grunt.file.isDir(DIST_DIR)) {
                grunt.file.delete(DIST_DIR, {force: true});
            }
        }
    );

    grunt.registerTask(
        'package',
        function () {
            var done = this.async();
            packager(
                {
                    dir: BUILD_DIR,
                    out: DIST_DIR,
                    name: APP_NAME,
                    platform: PLATFORM,
                    arch: ARCH,
                    version: ELECTRON_VERSION,
                    asar: USE_ASAR
                },
                function (err) {
                    if (err) {
                        grunt.warn(err);
                        return;
                    }

                    done();
                }
            );
        }
    );

    // Used as a temporary fix for:
    // https://github.com/maxogden/electron-packager/issues/49
    grunt.registerTask(
        'fix_default_app',
        function () {

            var default_apps = grunt.file.expand(
                DIST_DIR + APP_NAME + '*/resources/default_app'
            );

            default_apps.forEach(
                function (folder) {
                    console.log('Removing ' + folder);
                    grunt.file.delete(folder);
                }
            );
        }
    );
};<commit_msg>deleted Grunt<commit_after><|endoftext|>


<commit_before>odoo.define('web_tour.Tip', function(require) {
"use strict";

var core = require('web.core');
var Widget = require('web.Widget');

return Widget.extend({
    template: "Tip",
    events: {
        mouseenter: "_to_info_mode",
        mouseleave: "_to_bubble_mode",
    },
    /**
     * @param {$anchor} [JQuery] the node on which the tip should be placed
     * @param {info} [Object] description of the tip, containing the following keys:
     *  - content [String] the html content of the tip
     *  - event_handlers [Object] description of optional event handlers to bind to the tip:
     *    - event [String] the event name
     *    - selector [String] the jQuery selector on which the event should be bound
     *    - handler [function] the handler
     *  - position [String] tip's position ('top', 'right', 'left' or 'bottom'), default 'right'
     *  - width [int] the width in px of the tip when opened, default 270
     *  - space [int] space in px between anchor and tip, default 10
     *  - overlay [Object] x and y values for the number of pixels the mouseout detection area
     *    overlaps the opened tip, default {x: 50, y: 50}
     */
    init: function(parent, $anchor, info) {
        this._super(parent);
        this.$anchor = $anchor;
        this.info = _.defaults(info, {
            position: "right",
            width: 270,
            space: 10,
            overlay: {
                x: 50,
                y: 50,
            },
        });
    },
    start: function() {
        this.$tooltip_overlay = this.$(".o_tooltip_overlay");
        this.$tooltip_content = this.$(".o_tooltip_content");
        this.init_width = this.$el.innerWidth();
        this.init_height = this.$el.innerHeight();
        this.border_width = this.$el.outerWidth() - this.init_width;
        this.content_width = this.$tooltip_content.outerWidth(true);
        this.content_height = this.$tooltip_content.outerHeight(true);
        this.$window = $(window);

        _.each(this.info.event_handlers, (function(data) {
            this.$tooltip_content.on(data.event, data.selector, data.handler);
        }).bind(this));
        this._bind_anchor_events();

        this._reposition();
        core.bus.on('scroll resize', this, function() {
            if (this.tip_opened) {
                this._to_bubble_mode(true);
            }
            this._reposition();
        });
        this.$tooltip_content.css({
            width: "100%",
            height: "100%",
        });

        return this._super.apply(this, arguments);
    },
    update: function($anchor) {
        if (!$anchor.is(this.$anchor)) {
            this.$anchor.off();
            this.$anchor = $anchor;
            this._bind_anchor_events();
        }
        this._reposition();
    },
    _reposition: function() {
        if (this.tip_opened) return;
        this.$el.removeClass("o_animated");

        this.$el.position({
            my: this._get_spaced_inverted_position(this.info.position),
            at: this.info.position,
            of: this.$anchor,
            collision: "none",
        });

        var offset = this.$el.offset();
        offset.left += this.border_width;
        offset.top += this.border_width;
        this.$tooltip_overlay.css({
            top: -Math.min((this.info.position === "bottom" ? this.info.space : this.info.overlay.y), offset.top),
            right: -Math.min((this.info.position === "left" ? this.info.space : this.info.overlay.x), this.$window.width() - (offset.left + this.init_width)),
            bottom: -Math.min((this.info.position === "top" ? this.info.space : this.info.overlay.y), this.$window.height() - (offset.top + this.init_height)),
            left: -Math.min((this.info.position === "right" ? this.info.space : this.info.overlay.x), offset.left),
        });

        this.$el.addClass("o_animated");
    },
    _bind_anchor_events: function () {
        var consume_event = this.$anchor.is('input,textarea') ? 'change' : 'mousedown';
        this.$anchor.one(consume_event, this.trigger.bind(this, 'tip_consumed'));
        this.$anchor.on('mouseenter', this._to_info_mode.bind(this));
        this.$anchor.on('mouseleave', this._to_bubble_mode.bind(this));
    },
    _get_spaced_inverted_position: function (position) {
        if (position === "right") return "left+" + this.info.space;
        if (position === "left") return "right-" + this.info.space;
        if (position === "bottom") return "top+" + this.info.space;
        return "bottom-" + this.info.space;
    },
    _to_info_mode: function (force) {
        if (this.timerOut !== undefined) {
            clearTimeout(this.timerOut);
            this.timerOut = undefined;
            return;
        }

        if (force === true) {
            this._build_info_mode();
        } else {
            this.timerIn = setTimeout(this._build_info_mode.bind(this), 100);
        }
    },
    _build_info_mode: function () {
        clearTimeout(this.timerIn);
        this.timerIn = undefined;

        this.tip_opened = true;

        var offset = this.$el.offset();
        var mbLeft = 0;
        var mbTop = 0;
        var overflow = false;
        var posVertical = (this.info.position === "top" || this.info.position === "bottom");
        if (posVertical) {
            overflow = (offset.left + this.content_width + 2 * this.border_width + this.info.overlay.x > this.$window.width());
        } else {
            overflow = (offset.top + this.content_height + 2 * this.border_width + this.info.overlay.y > this.$window.height());
        }
        if (posVertical && overflow || this.info.position === "left") {
            mbLeft -= (this.content_width - this.init_width);
        }
        if (!posVertical && overflow || this.info.position === "top") {
            mbTop -= (this.content_height - this.init_height);
        }

        this.$el.toggleClass("inverse", overflow);
        this.$el.removeClass("o_animated").addClass("active");
        this.$el.css({
            width: this.content_width,
            height: this.content_height,
            "margin-left": mbLeft,
            "margin-top": mbTop,
        });
    },
    _to_bubble_mode: function (force) {
        if (this.timerIn !== undefined) {
            clearTimeout(this.timerIn);
            this.timerIn = undefined;
            return;
        }

        if (force === true) {
            this._build_bubble_mode();
        } else {
            this.timerOut = setTimeout(this._build_bubble_mode.bind(this), 300);
        }
    },
    _build_bubble_mode: function () {
        clearTimeout(this.timerOut);
        this.timerOut = undefined;

        this.tip_opened = false;

        this.$el.removeClass("active").addClass("o_animated");
        this.$el.css({
            width: this.init_width,
            height: this.init_height,
            margin: 0,
        });
    },
});
});
<commit_msg>[FIX] web_tour: anchor events<commit_after>odoo.define('web_tour.Tip', function(require) {
"use strict";

var core = require('web.core');
var Widget = require('web.Widget');

return Widget.extend({
    template: "Tip",
    events: {
        mouseenter: "_to_info_mode",
        mouseleave: "_to_bubble_mode",
    },
    /**
     * @param {$anchor} [JQuery] the node on which the tip should be placed
     * @param {info} [Object] description of the tip, containing the following keys:
     *  - content [String] the html content of the tip
     *  - event_handlers [Object] description of optional event handlers to bind to the tip:
     *    - event [String] the event name
     *    - selector [String] the jQuery selector on which the event should be bound
     *    - handler [function] the handler
     *  - position [String] tip's position ('top', 'right', 'left' or 'bottom'), default 'right'
     *  - width [int] the width in px of the tip when opened, default 270
     *  - space [int] space in px between anchor and tip, default 10
     *  - overlay [Object] x and y values for the number of pixels the mouseout detection area
     *    overlaps the opened tip, default {x: 50, y: 50}
     */
    init: function(parent, $anchor, info) {
        this._super(parent);
        this.$anchor = $anchor;
        this.info = _.defaults(info, {
            position: "right",
            width: 270,
            space: 10,
            overlay: {
                x: 50,
                y: 50,
            },
        });
    },
    start: function() {
        this.$tooltip_overlay = this.$(".o_tooltip_overlay");
        this.$tooltip_content = this.$(".o_tooltip_content");
        this.init_width = this.$el.innerWidth();
        this.init_height = this.$el.innerHeight();
        this.border_width = this.$el.outerWidth() - this.init_width;
        this.content_width = this.$tooltip_content.outerWidth(true);
        this.content_height = this.$tooltip_content.outerHeight(true);
        this.$window = $(window);

        _.each(this.info.event_handlers, (function(data) {
            this.$tooltip_content.on(data.event, data.selector, data.handler);
        }).bind(this));
        this._bind_anchor_events();

        this._reposition();
        core.bus.on('scroll resize', this, function() {
            if (this.tip_opened) {
                this._to_bubble_mode(true);
            }
            this._reposition();
        });
        this.$tooltip_content.css({
            width: "100%",
            height: "100%",
        });

        return this._super.apply(this, arguments);
    },
    update: function($anchor) {
        if (!$anchor.is(this.$anchor)) {
            this._unbind_anchor_events();
            this.$anchor = $anchor;
            this._bind_anchor_events();
        }
        this._reposition();
    },
    _reposition: function() {
        if (this.tip_opened) return;
        this.$el.removeClass("o_animated");

        this.$el.position({
            my: this._get_spaced_inverted_position(this.info.position),
            at: this.info.position,
            of: this.$anchor,
            collision: "none",
        });

        var offset = this.$el.offset();
        offset.left += this.border_width;
        offset.top += this.border_width;
        this.$tooltip_overlay.css({
            top: -Math.min((this.info.position === "bottom" ? this.info.space : this.info.overlay.y), offset.top),
            right: -Math.min((this.info.position === "left" ? this.info.space : this.info.overlay.x), this.$window.width() - (offset.left + this.init_width)),
            bottom: -Math.min((this.info.position === "top" ? this.info.space : this.info.overlay.y), this.$window.height() - (offset.top + this.init_height)),
            left: -Math.min((this.info.position === "right" ? this.info.space : this.info.overlay.x), offset.left),
        });

        this.$el.addClass("o_animated");
    },
    _bind_anchor_events: function () {
        var consume_event = "mousedown";
        if (this.$anchor.is("textarea") || this.$anchor.filter("input").is(function () {
            return !!$(this).attr("type").match(/^(email|number|password|search|tel|text|url)$/);
        })) {
            consume_event = "input";
        }

        this.$anchor.on(consume_event + ".anchor", (function (e) {
            if (e.type !== "mousedown" || e.which === 1) { // only left click
                this.trigger("tip_consumed");
                this._unbind_anchor_events();
            }
        }).bind(this));
        this.$anchor.on('mouseenter.anchor', this._to_info_mode.bind(this));
        this.$anchor.on('mouseleave.anchor', this._to_bubble_mode.bind(this));
    },
    _unbind_anchor_events: function () {
        this.$anchor.off(".anchor");
    },
    _get_spaced_inverted_position: function (position) {
        if (position === "right") return "left+" + this.info.space;
        if (position === "left") return "right-" + this.info.space;
        if (position === "bottom") return "top+" + this.info.space;
        return "bottom-" + this.info.space;
    },
    _to_info_mode: function (force) {
        if (this.timerOut !== undefined) {
            clearTimeout(this.timerOut);
            this.timerOut = undefined;
            return;
        }

        if (force === true) {
            this._build_info_mode();
        } else {
            this.timerIn = setTimeout(this._build_info_mode.bind(this), 100);
        }
    },
    _build_info_mode: function () {
        clearTimeout(this.timerIn);
        this.timerIn = undefined;

        this.tip_opened = true;

        var offset = this.$el.offset();
        var mbLeft = 0;
        var mbTop = 0;
        var overflow = false;
        var posVertical = (this.info.position === "top" || this.info.position === "bottom");
        if (posVertical) {
            overflow = (offset.left + this.content_width + 2 * this.border_width + this.info.overlay.x > this.$window.width());
        } else {
            overflow = (offset.top + this.content_height + 2 * this.border_width + this.info.overlay.y > this.$window.height());
        }
        if (posVertical && overflow || this.info.position === "left") {
            mbLeft -= (this.content_width - this.init_width);
        }
        if (!posVertical && overflow || this.info.position === "top") {
            mbTop -= (this.content_height - this.init_height);
        }

        this.$el.toggleClass("inverse", overflow);
        this.$el.removeClass("o_animated").addClass("active");
        this.$el.css({
            width: this.content_width,
            height: this.content_height,
            "margin-left": mbLeft,
            "margin-top": mbTop,
        });
    },
    _to_bubble_mode: function (force) {
        if (this.timerIn !== undefined) {
            clearTimeout(this.timerIn);
            this.timerIn = undefined;
            return;
        }

        if (force === true) {
            this._build_bubble_mode();
        } else {
            this.timerOut = setTimeout(this._build_bubble_mode.bind(this), 300);
        }
    },
    _build_bubble_mode: function () {
        clearTimeout(this.timerOut);
        this.timerOut = undefined;

        this.tip_opened = false;

        this.$el.removeClass("active").addClass("o_animated");
        this.$el.css({
            width: this.init_width,
            height: this.init_height,
            margin: 0,
        });
    },
});
});
<|endoftext|>


<commit_before>'use strict';

const FIREFOX_EXTENSION_ID = '{799c0914-748b-41df-a25c-22d008f9e83f}';

const SRC_DIR = 'src';
const BUILD_DIR = 'build';

const DIST_FILE_CHROME = 'web-scrobbler-chrome.zip';
const DIST_FILE_FIREFOX = 'web-scrobbler-firefox.zip';
const MANIFEST_FILE = 'src/manifest.json';

const FILES_TO_PREPROCESS = [
	`${BUILD_DIR}/**/*.js`, `${BUILD_DIR}/**/*.css`, `${BUILD_DIR}/**/*.html`,
];

const FILES_TO_BUMP = [MANIFEST_FILE, 'package.json', 'package-lock.json'];

// Files to build zipball
const EXTENSION_SRC = [
	'**/*',
	// Skip SVG
	'!icons/*.svg',
];
const EXTENSION_DOCS = [
	'README.md', 'LICENSE.md',
];
const EXTENSION_EXTRA = [
	'package.json', 'package-lock.json',
];

// Files to lint
const JS_FILES = [
	'*.js',
	// Custom Grunt tasks
	'.grunt',
	// Connectors
	`${SRC_DIR}/connectors/**/*.js`,
	// Core files
	`${SRC_DIR}/core/**/*.js`, `${SRC_DIR}/ui/**/*.js`,
	// Shell Scripts
	'scripts/*.js',
	// Tests
	'tests/**/*.js',
];
const JSON_FILES = ['*.json', `${SRC_DIR}/**/*.json`];
const HTML_FILES = [`${SRC_DIR}/ui/**/*.html`];
const CSS_FILES = [`${SRC_DIR}/ui/**/*.css`];
const DOC_FILES = [
	'*.md', '.github/**/*.md',
];

const isCi = process.env.CI === 'true';

module.exports = (grunt) => {
	grunt.initConfig({
		manifest: grunt.file.readJSON(MANIFEST_FILE),

		/**
		 * Configs of build tasks.
		 */

		clean: {
			build: BUILD_DIR,
			dist: [DIST_FILE_CHROME, DIST_FILE_FIREFOX],
			chrome: [
				`${BUILD_DIR}/icons/icon_firefox_*.png`,
			],
			firefox: [
				`${BUILD_DIR}/icons/icon_chrome_*.png`,
			],
		},
		copy: {
			source_files: {
				expand: true,
				cwd: SRC_DIR,
				src: EXTENSION_SRC,
				dest: BUILD_DIR,
			},
			documentation: {
				expand: true,
				src: EXTENSION_DOCS,
				dest: BUILD_DIR,
			},
			extra_files: {
				expand: true,
				src: EXTENSION_EXTRA,
				dest: BUILD_DIR,
			},
		},
		compress: {
			chrome: {
				options: {
					archive: DIST_FILE_CHROME,
					pretty: true,
				},
				expand: true,
				cwd: BUILD_DIR,
				src: '**/*',
			},
			firefox: {
				options: {
					archive: DIST_FILE_FIREFOX,
					pretty: true,
				},
				expand: true,
				cwd: BUILD_DIR,
				src: '**/*',
			},
		},
		imagemin: {
			static: {
				files: [{
					expand: true,
					src: [
						`${BUILD_DIR}/icons/*.png`,
					],
				}],
			},
		},
		preprocess: {
			main: {
				src: FILES_TO_PREPROCESS,
				expand: true,
				options: {
					inline: true,
					context: { /* generated */ },
				},
			},
		},
		replace_json: {
			chrome: {
				src: `${BUILD_DIR}/manifest.json`,
				changes: {
					options_ui: undefined,
				},
			},
			firefox: {
				src: `${BUILD_DIR}/manifest.json`,
				changes: {
					applications: {
						gecko: {
							id: FIREFOX_EXTENSION_ID,
							strict_min_version: '53.0',
						},
					},
					icons: {
						16: '<%= manifest.icons.16 %>',
						48: 'icons/icon_firefox_48.png',
						128: 'icons/icon_firefox_128.png',
					},

					options_page: undefined,
				},
			},
		},

		/**
		 * Publish tasks.
		 */

		bump: {
			options: {
				files: FILES_TO_BUMP,
				updateConfigs: ['manifest'],
				commitFiles: FILES_TO_BUMP,
			},
		},

		/**
		 * Linter configs.
		 */

		eslint: {
			target: JS_FILES,
			options: {
				fix: !isCi,
			},
		},
		jsonlint: {
			src: JSON_FILES,
		},
		lintspaces: {
			src: [JS_FILES, JSON_FILES, CSS_FILES, HTML_FILES],
			options: {
				editorconfig: '.editorconfig',
				ignores: ['js-comments'],
			},
		},
		remark: {
			options: {
				quiet: true,
				frail: true,
			},
			src: DOC_FILES,
		},
		stylelint: {
			all: CSS_FILES,
		},

		/**
		 * Configs of other tasks.
		 */

		mochacli: {
			options: {
				require: ['tests/requirejs-config'],
				reporter: 'progress',
			},
			all: [
				'tests/background/*.js',
				'tests/content/*.js',
			],
		},
	});

	require('jit-grunt')(grunt, {
		mochacli: 'grunt-mocha-cli',
	});
	grunt.loadTasks('.grunt');

	/**
	 * Some tasks take browser name as an argument.
	 * We support only Chrome and Firefox, which can be specified
	 * as 'chrome' and 'firefox' respectively:
	 *
	 *   Create a zipball for Chrome browser
	 *   > grunt dist:chrome
	 *
	 *   Build the extension for Firefox browser
	 *   > grunt build:firefox
	 */

	/**
	 * Copy source filed to build directory, preprocess them and
	 * set the extension icon according to specified browser.
	 * @param {String} browser Browser name
	 * @param {String} [mode=debug] Development mode (debug or release)
	 */
	grunt.registerTask('build', (browser, mode = 'debug') => {
		assertBrowserIsSupported(browser);
		assertDevelopmentModeIsValid(mode);

		const flags = {
			chrome: 'CHROME', firefox: 'FIREFOX',
			debug: 'DEBUG', release: 'RELEASE',
		};

		const config = grunt.config.get('preprocess');
		config.main.options.context = {
			[flags[browser]]: true, [flags[mode]]: true,
		};
		grunt.config.set('preprocess', config);

		grunt.task.run([
			'copy',
			'preprocess',
			`replace_json:${browser}`,
		]);
	});

	/**
	 * Build the extension and pack source files in a zipball.
	 * @param {String} browser Browser name
	 * @param {String} [mode=debug] Development mode (debug or release)
	 */
	grunt.registerTask('dist', (browser, mode = 'debug') => {
		assertBrowserIsSupported(browser);
		assertDevelopmentModeIsValid(mode);

		grunt.task.run([
			'clean:build',
			`build:${browser}:${mode}`,
			`clean:${browser}`,
			'imagemin',
			`compress:${browser}`,
			'clean:build',
		]);
	});

	/**
	 * Release new version.
	 *
	 * For this project GitHub Actions are configured to publish the extension
	 * if new tag is pushed to the project repository.
	 *
	 * @param {String} versionType Release type supported by grunt-bump
	 */
	grunt.registerTask('release', (versionType) => {
		if (!versionType) {
			grunt.fail.fatal('You should specify release type!');
		}

		grunt.task.run(`bump:${versionType}`);
	});

	/**
	 * Run tests.
	 */
	grunt.registerTask('test', ['mochacli']);

	/**
	 * Lint source code using linters specified below.
	 */
	grunt.registerTask('lint', [
		'eslint', 'jsonlint', 'lintspaces',
		'stylelint', 'remark', 'unused_files',
	]);

	/**
	 * Throw an error if the extension doesn't support given browser.
	 * @param  {String}  browser Browser name
	 */
	function assertBrowserIsSupported(browser) {
		const supportedBrowsers = ['chrome', 'firefox'];
		const browsersLabel = `Currently supported browsers: ${supportedBrowsers.join(', ')}`;

		if (!browser) {
			grunt.fail.fatal(`You have not specified browser.\n${browsersLabel}.`);
		}

		if (!supportedBrowsers.includes(browser)) {
			grunt.fail.fatal(`Unknown browser: ${browser}.\n${browsersLabel}.`);
		}
	}

	/**
	 * Throw an error if the extension doesn't support given browser.
	 * @param  {String}  mode Mode
	 */
	function assertDevelopmentModeIsValid(mode) {
		const supportedModes = ['debug', 'release'];
		const modesLabel = `Currently supported modes: ${supportedModes.join(', ')}`;

		if (!mode) {
			grunt.fail.fatal(`You have not specified mode.\n${modesLabel}.`);
		}

		if (!supportedModes.includes(mode)) {
			grunt.fail.fatal(`Unknown mode: ${mode}.\n${modesLabel}.`);
		}
	}
};
<commit_msg>Allow stylelint to fix errors<commit_after>'use strict';

const FIREFOX_EXTENSION_ID = '{799c0914-748b-41df-a25c-22d008f9e83f}';

const SRC_DIR = 'src';
const BUILD_DIR = 'build';

const DIST_FILE_CHROME = 'web-scrobbler-chrome.zip';
const DIST_FILE_FIREFOX = 'web-scrobbler-firefox.zip';
const MANIFEST_FILE = 'src/manifest.json';

const FILES_TO_PREPROCESS = [
	`${BUILD_DIR}/**/*.js`, `${BUILD_DIR}/**/*.css`, `${BUILD_DIR}/**/*.html`,
];

const FILES_TO_BUMP = [MANIFEST_FILE, 'package.json', 'package-lock.json'];

// Files to build zipball
const EXTENSION_SRC = [
	'**/*',
	// Skip SVG
	'!icons/*.svg',
];
const EXTENSION_DOCS = [
	'README.md', 'LICENSE.md',
];
const EXTENSION_EXTRA = [
	'package.json', 'package-lock.json',
];

// Files to lint
const JS_FILES = [
	'*.js',
	// Custom Grunt tasks
	'.grunt',
	// Connectors
	`${SRC_DIR}/connectors/**/*.js`,
	// Core files
	`${SRC_DIR}/core/**/*.js`, `${SRC_DIR}/ui/**/*.js`,
	// Shell Scripts
	'scripts/*.js',
	// Tests
	'tests/**/*.js',
];
const JSON_FILES = ['*.json', `${SRC_DIR}/**/*.json`];
const HTML_FILES = [`${SRC_DIR}/ui/**/*.html`];
const CSS_FILES = [`${SRC_DIR}/ui/**/*.css`];
const DOC_FILES = [
	'*.md', '.github/**/*.md',
];

const isCi = process.env.CI === 'true';

module.exports = (grunt) => {
	grunt.initConfig({
		manifest: grunt.file.readJSON(MANIFEST_FILE),

		/**
		 * Configs of build tasks.
		 */

		clean: {
			build: BUILD_DIR,
			dist: [DIST_FILE_CHROME, DIST_FILE_FIREFOX],
			chrome: [
				`${BUILD_DIR}/icons/icon_firefox_*.png`,
			],
			firefox: [
				`${BUILD_DIR}/icons/icon_chrome_*.png`,
			],
		},
		copy: {
			source_files: {
				expand: true,
				cwd: SRC_DIR,
				src: EXTENSION_SRC,
				dest: BUILD_DIR,
			},
			documentation: {
				expand: true,
				src: EXTENSION_DOCS,
				dest: BUILD_DIR,
			},
			extra_files: {
				expand: true,
				src: EXTENSION_EXTRA,
				dest: BUILD_DIR,
			},
		},
		compress: {
			chrome: {
				options: {
					archive: DIST_FILE_CHROME,
					pretty: true,
				},
				expand: true,
				cwd: BUILD_DIR,
				src: '**/*',
			},
			firefox: {
				options: {
					archive: DIST_FILE_FIREFOX,
					pretty: true,
				},
				expand: true,
				cwd: BUILD_DIR,
				src: '**/*',
			},
		},
		imagemin: {
			static: {
				files: [{
					expand: true,
					src: [
						`${BUILD_DIR}/icons/*.png`,
					],
				}],
			},
		},
		preprocess: {
			main: {
				src: FILES_TO_PREPROCESS,
				expand: true,
				options: {
					inline: true,
					context: { /* generated */ },
				},
			},
		},
		replace_json: {
			chrome: {
				src: `${BUILD_DIR}/manifest.json`,
				changes: {
					options_ui: undefined,
				},
			},
			firefox: {
				src: `${BUILD_DIR}/manifest.json`,
				changes: {
					applications: {
						gecko: {
							id: FIREFOX_EXTENSION_ID,
							strict_min_version: '53.0',
						},
					},
					icons: {
						16: '<%= manifest.icons.16 %>',
						48: 'icons/icon_firefox_48.png',
						128: 'icons/icon_firefox_128.png',
					},

					options_page: undefined,
				},
			},
		},

		/**
		 * Publish tasks.
		 */

		bump: {
			options: {
				files: FILES_TO_BUMP,
				updateConfigs: ['manifest'],
				commitFiles: FILES_TO_BUMP,
			},
		},

		/**
		 * Linter configs.
		 */

		eslint: {
			target: JS_FILES,
			options: {
				fix: !isCi,
			},
		},
		jsonlint: {
			src: JSON_FILES,
		},
		lintspaces: {
			src: [JS_FILES, JSON_FILES, CSS_FILES, HTML_FILES],
			options: {
				editorconfig: '.editorconfig',
				ignores: ['js-comments'],
			},
		},
		remark: {
			options: {
				quiet: true,
				frail: true,
			},
			src: DOC_FILES,
		},
		stylelint: {
			options: {
				fix: !isCi,
			},
			all: CSS_FILES,
		},

		/**
		 * Configs of other tasks.
		 */

		mochacli: {
			options: {
				require: ['tests/requirejs-config'],
				reporter: 'progress',
			},
			all: [
				'tests/background/*.js',
				'tests/content/*.js',
			],
		},
	});

	require('jit-grunt')(grunt, {
		mochacli: 'grunt-mocha-cli',
	});
	grunt.loadTasks('.grunt');

	/**
	 * Some tasks take browser name as an argument.
	 * We support only Chrome and Firefox, which can be specified
	 * as 'chrome' and 'firefox' respectively:
	 *
	 *   Create a zipball for Chrome browser
	 *   > grunt dist:chrome
	 *
	 *   Build the extension for Firefox browser
	 *   > grunt build:firefox
	 */

	/**
	 * Copy source filed to build directory, preprocess them and
	 * set the extension icon according to specified browser.
	 * @param {String} browser Browser name
	 * @param {String} [mode=debug] Development mode (debug or release)
	 */
	grunt.registerTask('build', (browser, mode = 'debug') => {
		assertBrowserIsSupported(browser);
		assertDevelopmentModeIsValid(mode);

		const flags = {
			chrome: 'CHROME', firefox: 'FIREFOX',
			debug: 'DEBUG', release: 'RELEASE',
		};

		const config = grunt.config.get('preprocess');
		config.main.options.context = {
			[flags[browser]]: true, [flags[mode]]: true,
		};
		grunt.config.set('preprocess', config);

		grunt.task.run([
			'copy',
			'preprocess',
			`replace_json:${browser}`,
		]);
	});

	/**
	 * Build the extension and pack source files in a zipball.
	 * @param {String} browser Browser name
	 * @param {String} [mode=debug] Development mode (debug or release)
	 */
	grunt.registerTask('dist', (browser, mode = 'debug') => {
		assertBrowserIsSupported(browser);
		assertDevelopmentModeIsValid(mode);

		grunt.task.run([
			'clean:build',
			`build:${browser}:${mode}`,
			`clean:${browser}`,
			'imagemin',
			`compress:${browser}`,
			'clean:build',
		]);
	});

	/**
	 * Release new version.
	 *
	 * For this project GitHub Actions are configured to publish the extension
	 * if new tag is pushed to the project repository.
	 *
	 * @param {String} versionType Release type supported by grunt-bump
	 */
	grunt.registerTask('release', (versionType) => {
		if (!versionType) {
			grunt.fail.fatal('You should specify release type!');
		}

		grunt.task.run(`bump:${versionType}`);
	});

	/**
	 * Run tests.
	 */
	grunt.registerTask('test', ['mochacli']);

	/**
	 * Lint source code using linters specified below.
	 */
	grunt.registerTask('lint', [
		'eslint', 'jsonlint', 'lintspaces',
		'stylelint', 'remark', 'unused_files',
	]);

	/**
	 * Throw an error if the extension doesn't support given browser.
	 * @param  {String}  browser Browser name
	 */
	function assertBrowserIsSupported(browser) {
		const supportedBrowsers = ['chrome', 'firefox'];
		const browsersLabel = `Currently supported browsers: ${supportedBrowsers.join(', ')}`;

		if (!browser) {
			grunt.fail.fatal(`You have not specified browser.\n${browsersLabel}.`);
		}

		if (!supportedBrowsers.includes(browser)) {
			grunt.fail.fatal(`Unknown browser: ${browser}.\n${browsersLabel}.`);
		}
	}

	/**
	 * Throw an error if the extension doesn't support given browser.
	 * @param  {String}  mode Mode
	 */
	function assertDevelopmentModeIsValid(mode) {
		const supportedModes = ['debug', 'release'];
		const modesLabel = `Currently supported modes: ${supportedModes.join(', ')}`;

		if (!mode) {
			grunt.fail.fatal(`You have not specified mode.\n${modesLabel}.`);
		}

		if (!supportedModes.includes(mode)) {
			grunt.fail.fatal(`Unknown mode: ${mode}.\n${modesLabel}.`);
		}
	}
};
<|endoftext|>


<commit_before>/*
 * grunt-github-release-asset
 * https://github.com/bartinger/grunt-github-release-asset
 *
 * Copyright (c) 2014 Dominic Bartl
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		jshint: {
			all: [
				'Gruntfile.js',
				'tasks/*.js',
				'<%= nodeunit.tests %>'
			],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		// Before generating any new files, remove any previously-created files.
		clean: {
			tests: ['tmp']
		},

		// Configuration to be run (and then tested).
		githubAsset: {
			options: {
				credentials: grunt.file.readJSON('credentials.json'),
				repo: 'git@github.com:Bartinger/grunt-github-release-asset.git',
				file: 'test/test-file.zip',
				releaseName: 'Release {tag}'
			}
		},

		// Unit tests.
		nodeunit: {
			tests: ['test/*_test.js']
		}

	});

	// Actually load this plugin's task(s).
	grunt.loadTasks('tasks');

	// These plugins provide necessary tasks.
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-nodeunit');

	// Whenever the "test" task is run, first clean the "tmp" dir, then run this
	// plugin's task(s), then test the result.
	grunt.registerTask('test', ['clean', 'githubAsset'/*, 'nodeunit'*/]);

	// By default, lint and run all tests.
	grunt.registerTask('default', ['jshint', 'test']);

};
<commit_msg>Update config for multiple files<commit_after>/*
 * grunt-github-release-asset
 * https://github.com/bartinger/grunt-github-release-asset
 *
 * Copyright (c) 2014 Dominic Bartl
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

	// Project configuration.
	grunt.initConfig({
		jshint: {
			all: [
				'Gruntfile.js',
				'tasks/*.js',
				'<%= nodeunit.tests %>'
			],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		// Before generating any new files, remove any previously-created files.
		clean: {
			tests: ['tmp']
		},

		// Configuration to be run (and then tested).
		githubAsset: {
			options: {
				credentials: grunt.file.readJSON('credentials.json'),
				repo: 'git@github.com:Bartinger/grunt-github-release-asset.git',
				files: ['test/test-file.zip'],
				releaseName: 'Release {tag}'
			}
		},

		// Unit tests.
		nodeunit: {
			tests: ['test/*_test.js']
		}

	});

	// Actually load this plugin's task(s).
	grunt.loadTasks('tasks');

	// These plugins provide necessary tasks.
	grunt.loadNpmTasks('grunt-contrib-jshint');
	grunt.loadNpmTasks('grunt-contrib-clean');
	grunt.loadNpmTasks('grunt-contrib-nodeunit');

	// Whenever the "test" task is run, first clean the "tmp" dir, then run this
	// plugin's task(s), then test the result.
	grunt.registerTask('test', ['clean', 'githubAsset'/*, 'nodeunit'*/]);

	// By default, lint and run all tests.
	grunt.registerTask('default', ['jshint', 'test']);

};
<|endoftext|>