<commit_before>
/**
 * @module
 */

var util = require('./lib/util'),
	fs = require("fs"),
	path = require("path"),
	extend=require('./lib/other/jquery.extend'),
	asyncFlow=require('../client/lib/asyncFlow');

function testsMatch(t1, t2){
	return ((!t1.module && !t2.module) || (t1.module==t2.module))
			&& t1.fileName==t2.fileName
			&& t1.name==t2.name;
}
/**
 * TO-DO: move slave operations into a separate class and call methods on instances.
 */

//function getBrowserUpdateMsg(b){
////	console.dir(b)
//	var m={
//		id:'browserUpdate',
//		data:extend(true, {}, b)
//	};
////	console.log('m:')
////	console.dir(m.data)
//	delete m.data.socket;
//	for(var i=0; i<m.data.testsQueue.length; i++){
////		console.log('m.data.testsQueue['+i+']:')
////		console.dir(m.data.testsQueue[i])
//		delete m.data.testsQueue[i].contents;
//	}
//	return m;
//}

function TestManager(cfg){
	this.storage={
		info:{}
	};

	extend(true, this, {
		/**
		 * @property	{Array}	testFiles	Array of objects with details about available files with tests that can be executed.
		 */
		testFiles:[]
	}, cfg);

	if(!('clientManager' in this)){
		this.clientManager=this.server.clientManager;
		delete this.server;
	}

	if(typeof this.adaptor=='string'){
		this.adaptor=require(this.adaptor);
//		this.adaptor.initialize({});
	}

	this.clientManager.on('message', this.onClientMessage.scope(this));
//	this.clientManager.on('beforeSendCaptureMessage', function (mngr, client, requestMsg, responseMsg){
//		if(responseMsg.result=='captured')
//			responseMsg.testManagerInfo=this.storage.info;
//	}.scope(this));
	this.clientManager.on('beforeSendSlaveUpdateMessage', this.onBeforeSendSlaveUpdateMessage.scope(this));

	var appCfg=this.clientManager.server.appCfg,
		Connect=require('connect');
	this.storage.info.testsBaseDir=path.resolve(path.dirname(appCfg.configFileName), this.testsPath);
	this.storage.info.testsBaseUrl=this.testsUrl;
	this.storage.info.userLibsDir=path.resolve(path.dirname(appCfg.configFileName), this.userLibsPath);
	this.storage.info.userLibsUrl=this.userLibsUrl;
	this.clientManager.server.webServer
		.use(this.testsUrl, Connect['static'](this.storage.info.testsBaseDir))
		.use(this.userLibsUrl, Connect['static'](this.storage.info.userLibsDir));

	this.reloadTests();
	console.log('Go to '+appCfg.server.protocol+'://'+appCfg.server.host+':'+appCfg.server.port+'/manager/manager.html to manage and run tests');

	for(var b=0, slaves=appCfg.slaves; b<slaves.length; b++)
		this.clientManager.addSlave(extend({
			testsQueue:appCfg.autoRunTests.slice(0)
		}, slaves[b]));
}
require('util').inherits(TestManager, require('events').EventEmitter);
util.extend(TestManager.prototype, {
	onClientMessage:function (mngr, client, msg){
//		console.log('msg '+msg.id);
		switch(msg.id){
			case 'testManager.clientInitialized':
					var respMsg={
						id:'testManager.reset',
						testManagerInfo:this.storage.info
					};
					var queue=this.clientManager.slaves[client.name].testsQueue;
					if(queue.length)
						respMsg.tests=queue;
					client.socket.json.send(respMsg);
					break;
			case 'testManager.onTestDone':
	//					console.log('done test '+msg.name);
					for(var i=0, queue=this.clientManager.slaves[client.name].testsQueue; i<queue.length; i++){
						if(testsMatch(queue[i], msg)){
							queue.splice(i, 1);
	//							console.log('removed test '+msg.name);
							break;
						}
					}
					// relay this message to the managers
					this.clientManager.sendMessageToManagerClients(extend({
						slaveName:client.name
					}, msg));
					break;
			case 'testManager.onTestStart':
					for(var i=0, queue=this.clientManager.slaves[client.name].testsQueue; i<queue.length; i++){
						if(testsMatch(queue[i], msg)){
							this.clientManager.slaves[client.name].runningTest=queue[i];
	//							console.log('starting test '+msg.name);
							break;
						}
					}
	//					var m=extend({
	//						slaveName:client.name
	//					}, msg);
	//					for(var a in this.managerClients) // update manager clients
	//						this.managerClients[a].socket.json.send(m);
				// do not break; here and move on with the code in the next case:
			case 'testManager.onAssertion':
					// relay this message to the managers
					this.clientManager.sendMessageToManagerClients(extend({
						slaveName:client.name
					}, msg));
				break;
			case 'testManager.onAllTestsDone':
					var b=this.clientManager.slaves[client.name];
					delete b.runningTest;
					this.clientManager.sendSlaveUpdateMessage(client.name);
				break;
//			case 'getTestData':
//					for(var i=0; i<this.testFiles.length; i++){
//						var test=this.getTest(i);
//						if(test.relFileName==msg.fileName){
//							client.socket.json.send({
//								id:'testData',
//								test:test
//							});
//							break;
//						}
//					}
//				break;
			case 'getTestsList':
					this.getTestFiles(function (err, tests){
						client.socket.json.send({
							id:'testsList',
							data:tests
						});
					});
				break;
			case 'runTests':
					for(var i=0; i<msg.slaves.length; i++){
						var b=this.clientManager.slaves[msg.slaves[i]];
	//clientManager.slavestestsQueue=msg.tests.slice(0); // copy the queue for each slave
						this.runTests(b, msg.tests.slice(0)); // copy the queue for each slave
						this.clientManager.sendSlaveUpdateMessage(msg.slaves[i]);
//						this.sendMessageToManagerClients(getBrowserUpdateMsg(b));
	//						for(var a in this.managerClients) // update manager clients
	//							this.managerClients[a].socket.json.send(getBrowserUpdateMsg(b));
					}
				break;
			case 'reloadTests':
					this.reloadTests();
				break;
		}
	},
	onBeforeSendSlaveUpdateMessage:function (msg){
		msg.data.testsQueue=[];
		for(var i=0, queue=this.clientManager.slaves[msg.data.name]; i<queue.length; i++){
			var t={},
				td=queue[i];
			for(var p in td)
				if(p!='contents')
					t[p]=td[p];
			m.data.testsQueue.push(t);
		}
	},
	getFilesListFromDir:function (dir){
		var files=fs.readdirSync(dir);
		for(var i=0; i<files.length; i++){
			files[i]=path.resolve(dir, files[i]);
			var stat=fs.statSync(files[i]);
			if(stat.isFile()){
				if(path.extname(files[i]).toLowerCase()!='.js')
					files.splice(i--, 1);
			}else{ // is a folder (not sure if this assumption is correct
				var f=this.getFilesListFromDir(files[i]);
				files.splice.apply(files, [i, 1].concat(f));
				i+=f.length-1; // skip over these files
			}
		}
		return files;
	},
	/**
	 * @method	reloadTests
	 */
	reloadTests:function (){
		this.testFile=true;
		// tell all slaves to abort any running tests and reload the configuration
		for(var br in this.clientManager.slaves){
			var b=this.clientManager.slaves[br];
			delete b.runningTest;
			if(b.connected)
				b.socket.json.send({id:'reset'});
			b.testsQueue=[];
			this.clientManager.sendSlaveUpdateMessage(br);
//			this.sendMessageToManagerClients(getBrowserUpdateMsg(b));  // update manager clients
//			for(var a in this.managerClients)
//				this.managerClients[a].socket.json.send(getBrowserUpdateMsg(b));
		}

		var files=this.getFilesListFromDir(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.testsPath)),
			list=[];
//			flow=new asyncFlow.serial({
//				data:{
//					i:0
//				}
//			}),
//			mngr=this;
//		// process all files
//		flow.run(function (next){
//			if(this.data.i < files.length){
//				var file={
//					fileName:files[this.data.i],
//					relFileName:path.relative(path.resolve(path.dirname(mngr.clientManager.server.appCfg.configFileName), mngr.clientManager.server.appCfg.testsPath), files[this.data.i]),
//					tests:[]
//				};
//				mngr.adaptor.getTestsInfoList(files[this.data.i], function (err, tests){
//					file.tests=tests;
//					list.push(file);
//					flow.repeatCurrentFn();
//				});
//				++this.data.i;
//			}else
//				next();
//		}, function (next){
//			mngr.testFiles=list;
//			mngr.emit('testsLoaded', list);
////			mngr.clientManager.sendMessageToManagerClients({
////				id:'testsList',
////				data:list
////			});  // update manager clients
//		});

		this.adaptor.getTestsInfoList(files, function (err, tests){
			for(var i=0; i<tests.length; i++)
				list.push({
					fileName:tests[i].fileName,
					relFileName:path.relative(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.testsPath), tests[i].fileName),
					tests:tests[i].tests
				});
			this.testFiles=list;
			this.emit('testsLoaded', list);
		}.scope(this));

	},
	/**
	 * @method	getTestFiles
	 * Returns a list with all test files and details for the tests they contain.
	 * @return	{Array}
	 */
	getTestFiles:function (cb){
//		console.dir(this.testFiles)
//		console.log(require('util').isArray(this.testFiles))
		if(require('util').isArray(this.testFiles))
			process.nextTick(cb.createCallback(this, [null, this.testFiles]));
		else{
			if(!this.testFiles)
				this.reloadTests();
			this.once('testsLoaded', function (testFiles){
				cb(null, testFiles);
			});
		}
	},
//	/**
//	 * @method	getTest
//	 * Returns the test file details for the specified index.
//	 * @param	{Number} ind	The index of the test.
//	 * @return	{Object}
//	 */
//	getTest:function (ind, cb){
//		if(typeof this.testFiles[ind]=='string'){
//			this.testFiles[ind]={
//				fileName:this.testFiles[ind],
//				relFileName:path.relative(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.clientManager.server.appCfg.testsPath), this.testFiles[ind]),
//				contents:fs.readFileSync(this.testFiles[ind], 'utf8'),
//				tests:this.adaptor.getTestsInfoList(this.testFiles[ind])
//			};
//		}
//		return this.testFiles[ind];
//	},
	/**
	 * @method	runTests
	 * Run queued tests for the specified slave or for all slaves if not specified.
	 * @param	{Object}	(optional) slave
	 * @param	{Array}	(optional) testsList	The tests to run. If specified will replace what is in the testsQueue
	 */
	runTests:function (slave, testsList){
		if(slave){
			if(testsList)
				slave.testsQueue=testsList;
			if(slave.connected && slave.testsQueue.length && !slave.runningTest){
				slave.runningTest=true;
				slave.socket.json.send({
					id:'testManager.runTests',
					tests:slave.testsQueue
				});
			}
		}else
			for(var br in this.clientManager.slaves)
				this.runTests(this.clientManager.slaves[br]);
	}
});

exports.init=function (cfg){
	return new TestManager(cfg);
};
exports.TestManager=TestManager;<commit_msg>added clientBaseDir to the info object<commit_after>
/**
 * @module
 */

var util = require('./lib/util'),
	fs = require("fs"),
	path = require("path"),
	extend=require('./lib/other/jquery.extend'),
	asyncFlow=require('../client/lib/asyncFlow');

function testsMatch(t1, t2){
	return ((!t1.module && !t2.module) || (t1.module==t2.module))
			&& t1.fileName==t2.fileName
			&& t1.name==t2.name;
}
/**
 * TO-DO: move slave operations into a separate class and call methods on instances.
 */

//function getBrowserUpdateMsg(b){
////	console.dir(b)
//	var m={
//		id:'browserUpdate',
//		data:extend(true, {}, b)
//	};
////	console.log('m:')
////	console.dir(m.data)
//	delete m.data.socket;
//	for(var i=0; i<m.data.testsQueue.length; i++){
////		console.log('m.data.testsQueue['+i+']:')
////		console.dir(m.data.testsQueue[i])
//		delete m.data.testsQueue[i].contents;
//	}
//	return m;
//}

function TestManager(cfg){
	this.storage={
		info:{}
	};

	extend(true, this, {
		/**
		 * @property	{Array}	testFiles	Array of objects with details about available files with tests that can be executed.
		 */
		testFiles:[]
	}, cfg);

	if(!('clientManager' in this)){
		this.clientManager=this.server.clientManager;
		delete this.server;
	}

	if(typeof this.adaptor=='string'){
		this.adaptor=require(this.adaptor);
//		this.adaptor.initialize({});
	}

	this.clientManager.on('message', this.onClientMessage.scope(this));
//	this.clientManager.on('beforeSendCaptureMessage', function (mngr, client, requestMsg, responseMsg){
//		if(responseMsg.result=='captured')
//			responseMsg.testManagerInfo=this.storage.info;
//	}.scope(this));
	this.clientManager.on('beforeSendSlaveUpdateMessage', this.onBeforeSendSlaveUpdateMessage.scope(this));

	var appCfg=this.clientManager.server.appCfg,
		Connect=require('connect');
	this.storage.info.testsBaseDir=path.resolve(path.dirname(appCfg.configFileName), this.testsPath);
	this.storage.info.testsBaseUrl=this.testsUrl;
	this.storage.info.userLibsDir=path.resolve(path.dirname(appCfg.configFileName), this.userLibsPath);
	this.storage.info.userLibsUrl=this.userLibsUrl;
	this.storage.info.clientBaseDir=this.clientManager.server.processParamString('%CLIENT_ROOT%');
	this.clientManager.server.webServer
		.use(this.testsUrl, Connect['static'](this.storage.info.testsBaseDir))
		.use(this.userLibsUrl, Connect['static'](this.storage.info.userLibsDir));

	this.reloadTests();
	console.log('Go to '+appCfg.server.protocol+'://'+appCfg.server.host+':'+appCfg.server.port+'/manager/manager.html to manage and run tests');

	for(var b=0, slaves=appCfg.slaves; b<slaves.length; b++)
		this.clientManager.addSlave(extend({
			testsQueue:appCfg.autoRunTests.slice(0)
		}, slaves[b]));
}
require('util').inherits(TestManager, require('events').EventEmitter);
util.extend(TestManager.prototype, {
	onClientMessage:function (mngr, client, msg){
//		console.log('msg '+msg.id);
		switch(msg.id){
			case 'testManager.clientInitialized':
					var respMsg={
						id:'testManager.reset',
						testManagerInfo:this.storage.info
					};
					var queue=this.clientManager.slaves[client.name].testsQueue;
					if(queue.length)
						respMsg.tests=queue;
					client.socket.json.send(respMsg);
					break;
			case 'testManager.onTestDone':
	//					console.log('done test '+msg.name);
					for(var i=0, queue=this.clientManager.slaves[client.name].testsQueue; i<queue.length; i++){
						if(testsMatch(queue[i], msg)){
							queue.splice(i, 1);
	//							console.log('removed test '+msg.name);
							break;
						}
					}
					// relay this message to the managers
					this.clientManager.sendMessageToManagerClients(extend({
						slaveName:client.name
					}, msg));
					break;
			case 'testManager.onTestStart':
					for(var i=0, queue=this.clientManager.slaves[client.name].testsQueue; i<queue.length; i++){
						if(testsMatch(queue[i], msg)){
							this.clientManager.slaves[client.name].runningTest=queue[i];
	//							console.log('starting test '+msg.name);
							break;
						}
					}
	//					var m=extend({
	//						slaveName:client.name
	//					}, msg);
	//					for(var a in this.managerClients) // update manager clients
	//						this.managerClients[a].socket.json.send(m);
				// do not break; here and move on with the code in the next case:
			case 'testManager.onAssertion':
					// relay this message to the managers
					this.clientManager.sendMessageToManagerClients(extend({
						slaveName:client.name
					}, msg));
				break;
			case 'testManager.onAllTestsDone':
					var b=this.clientManager.slaves[client.name];
					delete b.runningTest;
					this.clientManager.sendSlaveUpdateMessage(client.name);
				break;
//			case 'getTestData':
//					for(var i=0; i<this.testFiles.length; i++){
//						var test=this.getTest(i);
//						if(test.relFileName==msg.fileName){
//							client.socket.json.send({
//								id:'testData',
//								test:test
//							});
//							break;
//						}
//					}
//				break;
			case 'getTestsList':
					this.getTestFiles(function (err, tests){
						client.socket.json.send({
							id:'testsList',
							data:tests
						});
					});
				break;
			case 'runTests':
					for(var i=0; i<msg.slaves.length; i++){
						var b=this.clientManager.slaves[msg.slaves[i]];
	//clientManager.slavestestsQueue=msg.tests.slice(0); // copy the queue for each slave
						this.runTests(b, msg.tests.slice(0)); // copy the queue for each slave
						this.clientManager.sendSlaveUpdateMessage(msg.slaves[i]);
//						this.sendMessageToManagerClients(getBrowserUpdateMsg(b));
	//						for(var a in this.managerClients) // update manager clients
	//							this.managerClients[a].socket.json.send(getBrowserUpdateMsg(b));
					}
				break;
			case 'reloadTests':
					this.reloadTests();
				break;
		}
	},
	onBeforeSendSlaveUpdateMessage:function (msg){
		msg.data.testsQueue=[];
		for(var i=0, queue=this.clientManager.slaves[msg.data.name]; i<queue.length; i++){
			var t={},
				td=queue[i];
			for(var p in td)
				if(p!='contents')
					t[p]=td[p];
			m.data.testsQueue.push(t);
		}
	},
	getFilesListFromDir:function (dir){
		var files=fs.readdirSync(dir);
		for(var i=0; i<files.length; i++){
			files[i]=path.resolve(dir, files[i]);
			var stat=fs.statSync(files[i]);
			if(stat.isFile()){
				if(path.extname(files[i]).toLowerCase()!='.js')
					files.splice(i--, 1);
			}else{ // is a folder (not sure if this assumption is correct
				var f=this.getFilesListFromDir(files[i]);
				files.splice.apply(files, [i, 1].concat(f));
				i+=f.length-1; // skip over these files
			}
		}
		return files;
	},
	/**
	 * @method	reloadTests
	 */
	reloadTests:function (){
		this.testFile=true;
		// tell all slaves to abort any running tests and reload the configuration
		for(var br in this.clientManager.slaves){
			var b=this.clientManager.slaves[br];
			delete b.runningTest;
			if(b.connected)
				b.socket.json.send({id:'reset'});
			b.testsQueue=[];
			this.clientManager.sendSlaveUpdateMessage(br);
//			this.sendMessageToManagerClients(getBrowserUpdateMsg(b));  // update manager clients
//			for(var a in this.managerClients)
//				this.managerClients[a].socket.json.send(getBrowserUpdateMsg(b));
		}

		var files=this.getFilesListFromDir(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.testsPath)),
			list=[];
//			flow=new asyncFlow.serial({
//				data:{
//					i:0
//				}
//			}),
//			mngr=this;
//		// process all files
//		flow.run(function (next){
//			if(this.data.i < files.length){
//				var file={
//					fileName:files[this.data.i],
//					relFileName:path.relative(path.resolve(path.dirname(mngr.clientManager.server.appCfg.configFileName), mngr.clientManager.server.appCfg.testsPath), files[this.data.i]),
//					tests:[]
//				};
//				mngr.adaptor.getTestsInfoList(files[this.data.i], function (err, tests){
//					file.tests=tests;
//					list.push(file);
//					flow.repeatCurrentFn();
//				});
//				++this.data.i;
//			}else
//				next();
//		}, function (next){
//			mngr.testFiles=list;
//			mngr.emit('testsLoaded', list);
////			mngr.clientManager.sendMessageToManagerClients({
////				id:'testsList',
////				data:list
////			});  // update manager clients
//		});

		this.adaptor.getTestsInfoList(files, function (err, tests){
			for(var i=0; i<tests.length; i++)
				list.push({
					fileName:tests[i].fileName,
					relFileName:path.relative(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.testsPath), tests[i].fileName),
					tests:tests[i].tests
				});
			this.testFiles=list;
			this.emit('testsLoaded', list);
		}.scope(this));

	},
	/**
	 * @method	getTestFiles
	 * Returns a list with all test files and details for the tests they contain.
	 * @return	{Array}
	 */
	getTestFiles:function (cb){
//		console.dir(this.testFiles)
//		console.log(require('util').isArray(this.testFiles))
		if(require('util').isArray(this.testFiles))
			process.nextTick(cb.createCallback(this, [null, this.testFiles]));
		else{
			if(!this.testFiles)
				this.reloadTests();
			this.once('testsLoaded', function (testFiles){
				cb(null, testFiles);
			});
		}
	},
//	/**
//	 * @method	getTest
//	 * Returns the test file details for the specified index.
//	 * @param	{Number} ind	The index of the test.
//	 * @return	{Object}
//	 */
//	getTest:function (ind, cb){
//		if(typeof this.testFiles[ind]=='string'){
//			this.testFiles[ind]={
//				fileName:this.testFiles[ind],
//				relFileName:path.relative(path.resolve(path.dirname(this.clientManager.server.appCfg.configFileName), this.clientManager.server.appCfg.testsPath), this.testFiles[ind]),
//				contents:fs.readFileSync(this.testFiles[ind], 'utf8'),
//				tests:this.adaptor.getTestsInfoList(this.testFiles[ind])
//			};
//		}
//		return this.testFiles[ind];
//	},
	/**
	 * @method	runTests
	 * Run queued tests for the specified slave or for all slaves if not specified.
	 * @param	{Object}	(optional) slave
	 * @param	{Array}	(optional) testsList	The tests to run. If specified will replace what is in the testsQueue
	 */
	runTests:function (slave, testsList){
		if(slave){
			if(testsList)
				slave.testsQueue=testsList;
			if(slave.connected && slave.testsQueue.length && !slave.runningTest){
				slave.runningTest=true;
				slave.socket.json.send({
					id:'testManager.runTests',
					tests:slave.testsQueue
				});
			}
		}else
			for(var br in this.clientManager.slaves)
				this.runTests(this.clientManager.slaves[br]);
	}
});

exports.init=function (cfg){
	return new TestManager(cfg);
};
exports.TestManager=TestManager;<|endoftext|>


<commit_before>// Generated on 2017-03-16 using generator-angular 0.16.0
'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) {

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

  // Automatically load required Grunt tasks
  require('jit-grunt')(grunt, {
    useminPrepare: 'grunt-usemin',
    ngtemplates: 'grunt-angular-templates',
    cdnify: 'grunt-google-cdn'
  });

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist'
  };

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

    // Project settings
    yeoman: appConfig,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all', 'newer:jscs:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'newer:jscs:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/views/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'postcss:server']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/views/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          open: true,
          middleware: function (connect) {
            return [
              serveStatic('.tmp'),
              connect().use(
                '/bower_components',
                serveStatic('./bower_components')
              ),
              connect().use(
                '/app/views',
                serveStatic('./app/views')
              ),
              serveStatic(appConfig.app)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9001,
          middleware: function (connect) {
            return [
              serveStatic('.tmp'),
              serveStatic('test'),
              connect().use(
                '/bower_components',
                serveStatic('./bower_components')
              ),
              serveStatic(appConfig.app)
            ];
          }
        }
      },
      dist: {
        options: {
          open: true,
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Make sure code styles are up to par
    jscs: {
      options: {
        config: '.jscsrc',
        verbose: true
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        src: ['test/spec/{,*/}*.js']
      }
    },

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

    // Add vendor prefixed styles
    postcss: {
      options: {
        processors: [
          require('autoprefixer')({browsers: ['last 1 version']})
        ]
      },
      server: {
        options: {
          map: true
        },
        files: [{
          expand: true,
          cwd: '.tmp/views/',
          src: '{,*/}*.css',
          dest: '.tmp/views/'
        }]
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/views/',
          src: '{,*/}*.css',
          dest: '.tmp/views/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      },
      test: {
        devDependencies: true,
        src: '<%= karma.unit.configFile %>',
        ignorePath:  /\.\.\//,
        fileTypes:{
          js: {
            block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
              detect: {
                js: /'(.*\.js)'/gi
              },
              replace: {
                js: '\'{{filePath}}\','
              }
            }
          }
      },
      sass: {
        src: ['<%= yeoman.app %>/views/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/views',
        cssDir: '.tmp/views',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/views/fonts',
        importPath: './bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/views/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          sourcemap: true
        }
      }
    },

    // Renames files for browser caching purposes
    filerev: {
      dist: {
        src: [
          '<%= yeoman.dist %>/scripts/{,*/}*.js',
          '<%= yeoman.dist %>/views/{,*/}*.css',
          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
          '!<%= yeoman.dist %>/images/flags/*',
          '<%= yeoman.dist %>/views/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 %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/views/{,*/}*.css'],
      js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'],
      options: {
        assetsDirs: [
          '<%= yeoman.dist %>',
          '<%= yeoman.dist %>/images',
          '<%= yeoman.dist %>/views'
        ],
        patterns: {
          js: [[/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']]
        }
      }
    },

    // The following *-min tasks will produce minified files in the dist folder
    // 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 %>/views/main.css': [
    //         '.tmp/views/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/scripts/scripts.js': [
    //         '<%= yeoman.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg,gif,ico}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

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

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

    ngtemplates: {
      dist: {
        options: {
          module: 'serinaApp',
          htmlmin: '<%= htmlmin.dist.options %>',
          usemin: 'scripts/scripts.js'
        },
        cwd: '<%= yeoman.app %>',
        src: 'views/{,*/}*.html',
        dest: '.tmp/templateCache.js'
      }
    },

    // ng-annotate tries to make the code safe for minification automatically
    // by using the Angular long form for dependency injection.
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: '*.js',
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // 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}',
            '*.html',
            'images/{,*/}*.{webp}',
            'icons/icon-x64.ico',
            'views/fonts/{,*/}*.*',
            'main.js',
            'package.json'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: 'app/app/',
          dest: '<%= yeoman.dist %>',
          src: '**'
        }, {
          expand: true,
          cwd: 'api/dist',
          dest: '<%= yeoman.dist %>',
          src: 'api.js'
        }, {
          expand: true,
          cwd: 'node_modules/',
          dest: '<%= yeoman.dist %>/node_modules',
          src: [
            'accepts/**',
            'array-flatten/**',
            'body-parser/**',
            'bytes/**',
            'content-disposition/**',
            'content-type/**',
            'cookie-signature/**',
            'debug/**',
            'depd/**',
            'destroy/**',
            'ee-first/**',
            'encodeurl/**',
            'escape-html/**',
            'express/**',
            'finalhandler/**',
            'forwarded/**',
            'iconv-lite/**',
            'inherits/**',
            'ipaddr.js/**',
            'jsonfile/**',
            'media-typer/**',
            'merge-descriptors/**',
            'methods/**',
            'mime/**',
            'mime-db/**',
            'mime-types/**',
            'ms/**',
            'negotiator/**',
            'on-finished/**',
            'parseurl/**',
            'path-to-regexp/**',
            'proxy-addr/**',
            'qs/**',
            'range-parser/**',
            'raw-body/**',
            'send/**',
            'serve-static/**',
            'setprototypeof/**',
            'statuses/**',
            'type-is/**',
            'unpipe/**',
            'utils-merge/**',
            'vary/**'
          ]
        }, {
          expand: true,
          cwd: 'bower_components/material-design-icons/iconfont',
          dest: '<%= yeoman.dist %>/styles',
          src: [
            'MaterialIcons-Regular.ttf',
            'MaterialIcons-Regular.woff',
            'MaterialIcons-Regular.woff2'
          ]
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/views',
        dest: '.tmp/views/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Build app electron
    electron: {
      buildWin32: {
        options: {
          name: 'serina',
          dir: 'dist',
          out: 'packages',
          platform: 'win32',
          arch: 'x64',
          overwrite: true,
          prune: false,
          icon: 'icons/icon-x64.ico'
        }
      },
      buildLinux: {
        options: {
          name: 'serina',
          dir: 'dist',
          out: 'packages',
          platform: 'linux',
          arch: 'x64',
          overwrite: true,
          prune: false,
          icon: 'icons/icon-x64.ico'
        }
      }
    },

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

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'postcss:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:' + target]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'wiredep',
    'concurrent:test',
    'postcss',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'clean:package',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'postcss',
    'ngtemplates',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('package', 'Package electron app', function (target) {
    switch (target) {
      case 'linux':
        grunt.task.run([
          'build',
          'electron:buildLinux'
        ]);
        break;
      case 'win32':
        grunt.task.run([
          'build',
          'electron:buildWin32'
        ]);
        break;
      default:
      grunt.task.run([
        'build',
        'electron:buildLinux',
        'electron:buildWin32'
      ]);
    }
  });

  grunt.registerTask('default', [
    'newer:jshint',
    'newer:jscs',
    'test',
    'build'
  ]);
};
<commit_msg>Add node_modules need for electron app<commit_after>// Generated on 2017-03-16 using generator-angular 0.16.0
'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) {

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

  // Automatically load required Grunt tasks
  require('jit-grunt')(grunt, {
    useminPrepare: 'grunt-usemin',
    ngtemplates: 'grunt-angular-templates',
    cdnify: 'grunt-google-cdn'
  });

  // Configurable paths for the application
  var appConfig = {
    app: require('./bower.json').appPath || 'app',
    dist: 'dist'
  };

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

    // Project settings
    yeoman: appConfig,

    // Watches files for changes and runs tasks based on the changed files
    watch: {
      bower: {
        files: ['bower.json'],
        tasks: ['wiredep']
      },
      js: {
        files: ['<%= yeoman.app %>/scripts/{,*/}*.js'],
        tasks: ['newer:jshint:all', 'newer:jscs:all'],
        options: {
          livereload: '<%= connect.options.livereload %>'
        }
      },
      jsTest: {
        files: ['test/spec/{,*/}*.js'],
        tasks: ['newer:jshint:test', 'newer:jscs:test', 'karma']
      },
      compass: {
        files: ['<%= yeoman.app %>/views/{,*/}*.{scss,sass}'],
        tasks: ['compass:server', 'postcss:server']
      },
      gruntfile: {
        files: ['Gruntfile.js']
      },
      livereload: {
        options: {
          livereload: '<%= connect.options.livereload %>'
        },
        files: [
          '<%= yeoman.app %>/{,*/}*.html',
          '.tmp/views/{,*/}*.css',
          '<%= yeoman.app %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
        ]
      }
    },

    // The actual grunt server settings
    connect: {
      options: {
        port: 9000,
        // Change this to '0.0.0.0' to access the server from outside.
        hostname: 'localhost',
        livereload: 35729
      },
      livereload: {
        options: {
          open: true,
          middleware: function (connect) {
            return [
              serveStatic('.tmp'),
              connect().use(
                '/bower_components',
                serveStatic('./bower_components')
              ),
              connect().use(
                '/app/views',
                serveStatic('./app/views')
              ),
              serveStatic(appConfig.app)
            ];
          }
        }
      },
      test: {
        options: {
          port: 9001,
          middleware: function (connect) {
            return [
              serveStatic('.tmp'),
              serveStatic('test'),
              connect().use(
                '/bower_components',
                serveStatic('./bower_components')
              ),
              serveStatic(appConfig.app)
            ];
          }
        }
      },
      dist: {
        options: {
          open: true,
          base: '<%= yeoman.dist %>'
        }
      }
    },

    // Make sure there are no obvious mistakes
    jshint: {
      options: {
        jshintrc: '.jshintrc',
        reporter: require('jshint-stylish')
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        options: {
          jshintrc: 'test/.jshintrc'
        },
        src: ['test/spec/{,*/}*.js']
      }
    },

    // Make sure code styles are up to par
    jscs: {
      options: {
        config: '.jscsrc',
        verbose: true
      },
      all: {
        src: [
          'Gruntfile.js',
          '<%= yeoman.app %>/scripts/{,*/}*.js'
        ]
      },
      test: {
        src: ['test/spec/{,*/}*.js']
      }
    },

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

    // Add vendor prefixed styles
    postcss: {
      options: {
        processors: [
          require('autoprefixer')({browsers: ['last 1 version']})
        ]
      },
      server: {
        options: {
          map: true
        },
        files: [{
          expand: true,
          cwd: '.tmp/views/',
          src: '{,*/}*.css',
          dest: '.tmp/views/'
        }]
      },
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/views/',
          src: '{,*/}*.css',
          dest: '.tmp/views/'
        }]
      }
    },

    // Automatically inject Bower components into the app
    wiredep: {
      app: {
        src: ['<%= yeoman.app %>/index.html'],
        ignorePath:  /\.\.\//
      },
      test: {
        devDependencies: true,
        src: '<%= karma.unit.configFile %>',
        ignorePath:  /\.\.\//,
        fileTypes:{
          js: {
            block: /(([\s\t]*)\/{2}\s*?bower:\s*?(\S*))(\n|\r|.)*?(\/{2}\s*endbower)/gi,
              detect: {
                js: /'(.*\.js)'/gi
              },
              replace: {
                js: '\'{{filePath}}\','
              }
            }
          }
      },
      sass: {
        src: ['<%= yeoman.app %>/views/{,*/}*.{scss,sass}'],
        ignorePath: /(\.\.\/){1,2}bower_components\//
      }
    },

    // Compiles Sass to CSS and generates necessary files if requested
    compass: {
      options: {
        sassDir: '<%= yeoman.app %>/views',
        cssDir: '.tmp/views',
        generatedImagesDir: '.tmp/images/generated',
        imagesDir: '<%= yeoman.app %>/images',
        javascriptsDir: '<%= yeoman.app %>/scripts',
        fontsDir: '<%= yeoman.app %>/views/fonts',
        importPath: './bower_components',
        httpImagesPath: '/images',
        httpGeneratedImagesPath: '/images/generated',
        httpFontsPath: '/views/fonts',
        relativeAssets: false,
        assetCacheBuster: false,
        raw: 'Sass::Script::Number.precision = 10\n'
      },
      dist: {
        options: {
          generatedImagesDir: '<%= yeoman.dist %>/images/generated'
        }
      },
      server: {
        options: {
          sourcemap: true
        }
      }
    },

    // Renames files for browser caching purposes
    filerev: {
      dist: {
        src: [
          '<%= yeoman.dist %>/scripts/{,*/}*.js',
          '<%= yeoman.dist %>/views/{,*/}*.css',
          '<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
          '!<%= yeoman.dist %>/images/flags/*',
          '<%= yeoman.dist %>/views/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 %>/index.html',
      options: {
        dest: '<%= yeoman.dist %>',
        flow: {
          html: {
            steps: {
              js: ['concat', 'uglifyjs'],
              css: ['cssmin']
            },
            post: {}
          }
        }
      }
    },

    // Performs rewrites based on filerev and the useminPrepare configuration
    usemin: {
      html: ['<%= yeoman.dist %>/{,*/}*.html'],
      css: ['<%= yeoman.dist %>/views/{,*/}*.css'],
      js: ['<%= yeoman.dist %>/scripts/{,*/}*.js'],
      options: {
        assetsDirs: [
          '<%= yeoman.dist %>',
          '<%= yeoman.dist %>/images',
          '<%= yeoman.dist %>/views'
        ],
        patterns: {
          js: [[/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']]
        }
      }
    },

    // The following *-min tasks will produce minified files in the dist folder
    // 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 %>/views/main.css': [
    //         '.tmp/views/{,*/}*.css'
    //       ]
    //     }
    //   }
    // },
    // uglify: {
    //   dist: {
    //     files: {
    //       '<%= yeoman.dist %>/scripts/scripts.js': [
    //         '<%= yeoman.dist %>/scripts/scripts.js'
    //       ]
    //     }
    //   }
    // },
    // concat: {
    //   dist: {}
    // },

    imagemin: {
      dist: {
        files: [{
          expand: true,
          cwd: '<%= yeoman.app %>/images',
          src: '{,*/}*.{png,jpg,jpeg,gif,ico}',
          dest: '<%= yeoman.dist %>/images'
        }]
      }
    },

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

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

    ngtemplates: {
      dist: {
        options: {
          module: 'serinaApp',
          htmlmin: '<%= htmlmin.dist.options %>',
          usemin: 'scripts/scripts.js'
        },
        cwd: '<%= yeoman.app %>',
        src: 'views/{,*/}*.html',
        dest: '.tmp/templateCache.js'
      }
    },

    // ng-annotate tries to make the code safe for minification automatically
    // by using the Angular long form for dependency injection.
    ngAnnotate: {
      dist: {
        files: [{
          expand: true,
          cwd: '.tmp/concat/scripts',
          src: '*.js',
          dest: '.tmp/concat/scripts'
        }]
      }
    },

    // Replace Google CDN references
    cdnify: {
      dist: {
        html: ['<%= yeoman.dist %>/*.html']
      }
    },

    // 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}',
            '*.html',
            'images/{,*/}*.{webp}',
            'icons/icon-x64.ico',
            'views/fonts/{,*/}*.*',
            'main.js',
            'package.json'
          ]
        }, {
          expand: true,
          cwd: '.tmp/images',
          dest: '<%= yeoman.dist %>/images',
          src: ['generated/*']
        }, {
          expand: true,
          cwd: 'app/app/',
          dest: '<%= yeoman.dist %>',
          src: '**'
        }, {
          expand: true,
          cwd: 'api/dist',
          dest: '<%= yeoman.dist %>',
          src: 'api.js'
        }, {
          expand: true,
          cwd: 'node_modules/',
          dest: '<%= yeoman.dist %>/node_modules',
          src: [
            'accepts/**',
            'array-flatten/**',
            'body-parser/**',
            'bytes/**',
            'content-disposition/**',
            'content-type/**',
            'cookie-signature/**',
            'debug/**',
            'depd/**',
            'destroy/**',
            'ee-first/**',
            'encodeurl/**',
            'escape-html/**',
            'express/**',
            'finalhandler/**',
            'forwarded/**',
            'iconv-lite/**',
            'inherits/**',
            'ipaddr.js/**',
            'jsonfile/**',
            'http-errors/**',
            'etag/**',
            'fresh/**',
            'cookie/**',
            'media-typer/**',
            'merge-descriptors/**',
            'methods/**',
            'mime/**',
            'mime-db/**',
            'mime-types/**',
            'ms/**',
            'negotiator/**',
            'on-finished/**',
            'parseurl/**',
            'path-to-regexp/**',
            'proxy-addr/**',
            'qs/**',
            'range-parser/**',
            'raw-body/**',
            'send/**',
            'serve-static/**',
            'setprototypeof/**',
            'statuses/**',
            'type-is/**',
            'unpipe/**',
            'utils-merge/**',
            'vary/**'
          ]
        }, {
          expand: true,
          cwd: 'bower_components/material-design-icons/iconfont',
          dest: '<%= yeoman.dist %>/styles',
          src: [
            'MaterialIcons-Regular.ttf',
            'MaterialIcons-Regular.woff',
            'MaterialIcons-Regular.woff2'
          ]
        }]
      },
      styles: {
        expand: true,
        cwd: '<%= yeoman.app %>/views',
        dest: '.tmp/views/',
        src: '{,*/}*.css'
      }
    },

    // Run some tasks in parallel to speed up the build process
    concurrent: {
      server: [
        'compass:server'
      ],
      test: [
        'compass'
      ],
      dist: [
        'compass:dist',
        'imagemin',
        'svgmin'
      ]
    },

    // Build app electron
    electron: {
      buildWin32: {
        options: {
          name: 'serina',
          dir: 'dist',
          out: 'packages',
          platform: 'win32',
          arch: 'x64',
          overwrite: true,
          prune: false,
          icon: 'icons/icon-x64.ico'
        }
      },
      buildLinux: {
        options: {
          name: 'serina',
          dir: 'dist',
          out: 'packages',
          platform: 'linux',
          arch: 'x64',
          overwrite: true,
          prune: false,
          icon: 'icons/icon-x64.ico'
        }
      }
    },

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

  grunt.registerTask('serve', 'Compile then start a connect web server', function (target) {
    if (target === 'dist') {
      return grunt.task.run(['build', 'connect:dist:keepalive']);
    }

    grunt.task.run([
      'clean:server',
      'wiredep',
      'concurrent:server',
      'postcss:server',
      'connect:livereload',
      'watch'
    ]);
  });

  grunt.registerTask('server', 'DEPRECATED TASK. Use the "serve" task instead', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:' + target]);
  });

  grunt.registerTask('test', [
    'clean:server',
    'wiredep',
    'concurrent:test',
    'postcss',
    'connect:test',
    'karma'
  ]);

  grunt.registerTask('build', [
    'clean:dist',
    'clean:package',
    'wiredep',
    'useminPrepare',
    'concurrent:dist',
    'postcss',
    'ngtemplates',
    'concat',
    'ngAnnotate',
    'copy:dist',
    'cdnify',
    'cssmin',
    'uglify',
    'filerev',
    'usemin',
    'htmlmin'
  ]);

  grunt.registerTask('package', 'Package electron app', function (target) {
    switch (target) {
      case 'linux':
        grunt.task.run([
          'build',
          'electron:buildLinux'
        ]);
        break;
      case 'win32':
        grunt.task.run([
          'build',
          'electron:buildWin32'
        ]);
        break;
      default:
      grunt.task.run([
        'build',
        'electron:buildLinux',
        'electron:buildWin32'
      ]);
    }
  });

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


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

	grunt.initConfig({
		sass: {
			compile: {
				options: {
					style: 'compressed'
				},
				files: {
					'styles/screen.css': 'styles/screen.scss'
				}
			}
		},
		autoprefixer: {
			prefix: {
				src: 'styles/screen.css'
			}
		},
		jekyll: {
			build: {}
		},
		htmlmin: {
			site: {
				options: {
					removeComments: true,
					collapseWhitespace: true
				},
				expand: true,
				cwd: '_site/',
				src: '**/*.html',
				dest: '_site/'
			}
		},
		imagemin: {
			site: {
				expand: true,
				cwd: '_site/',
				src: '**/*.{png,jpg,gif}',
				dest: '_site/'
			}
		},
		watch: {
			styles: {
				files: 'styles/*.scss',
				tasks: ['sass', 'autoprefixer', 'copy']
			},
			jekyll: {
				files: [
					'**',
					'!_site/**',
					'!node_modules/**',
					'!.sass-cache/**',
					'!styles/*',
					'!Gruntfile.js',
					'!README.md',
					'!package.json',
					'!.git/**'
				],
				tasks: ['jekyll', 'htmlmin']
			}
		},
		copy: {
			css: {
				files: {
					'_site/styles/screen.css' : 'styles/screen.css'
				}
			}
		},
		rsync: {
			options: {
				args: ['--delete', '-rtz', '-O'],
				exclude: ['.DS_Store'],
				recursive: true
			},
			deploy: {
				options: {
					src: '_site/',
					dest: '/var/www/html/',
					host: '54.213.240.91'
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-autoprefixer');
	grunt.loadNpmTasks('grunt-jekyll');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-htmlmin');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-rsync');

	grunt.registerTask('default', [
		'sass',
		'autoprefixer',
		'jekyll',
		'htmlmin',
		'imagemin'
	]);

	grunt.registerTask('deploy', ['rsync']);

};<commit_msg>Updated rsync flags, now with extra verbosity<commit_after>module.exports = function(grunt) {

	grunt.initConfig({
		sass: {
			compile: {
				options: {
					style: 'compressed'
				},
				files: {
					'styles/screen.css': 'styles/screen.scss'
				}
			}
		},
		autoprefixer: {
			prefix: {
				src: 'styles/screen.css'
			}
		},
		jekyll: {
			build: {}
		},
		htmlmin: {
			site: {
				options: {
					removeComments: true,
					collapseWhitespace: true
				},
				expand: true,
				cwd: '_site/',
				src: '**/*.html',
				dest: '_site/'
			}
		},
		imagemin: {
			site: {
				expand: true,
				cwd: '_site/',
				src: '**/*.{png,jpg,gif}',
				dest: '_site/'
			}
		},
		watch: {
			styles: {
				files: 'styles/*.scss',
				tasks: ['sass', 'autoprefixer', 'copy']
			},
			jekyll: {
				files: [
					'**',
					'!_site/**',
					'!node_modules/**',
					'!.sass-cache/**',
					'!styles/*',
					'!Gruntfile.js',
					'!README.md',
					'!package.json',
					'!.git/**'
				],
				tasks: ['jekyll', 'htmlmin']
			}
		},
		copy: {
			css: {
				files: {
					'_site/styles/screen.css' : 'styles/screen.css'
				}
			}
		},
		rsync: {
			options: {
				args: ['--delete', '-rtzv', '-O'],
				exclude: ['.DS_Store'],
				recursive: true
			},
			deploy: {
				options: {
					src: '_site/',
					dest: '/var/www/html/',
					host: '54.213.240.91'
				}
			}
		}
	});

	grunt.loadNpmTasks('grunt-contrib-sass');
	grunt.loadNpmTasks('grunt-autoprefixer');
	grunt.loadNpmTasks('grunt-jekyll');
	grunt.loadNpmTasks('grunt-contrib-watch');
	grunt.loadNpmTasks('grunt-contrib-htmlmin');
	grunt.loadNpmTasks('grunt-contrib-imagemin');
	grunt.loadNpmTasks('grunt-contrib-copy');
	grunt.loadNpmTasks('grunt-rsync');

	grunt.registerTask('default', [
		'sass',
		'autoprefixer',
		'jekyll',
		'htmlmin',
		'imagemin'
	]);

	grunt.registerTask('deploy', ['rsync']);

};<|endoftext|>


<commit_before>module.exports = function(grunt) {
    // Project config
    grunt.initConfig({
        shell: {
            jison: {
                command: [
                    'mkdir -p build',
                    'jison src/grammar.jison --module-type js --outfile build/grammar.js',
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
            merge: {
                command: [
                    'rm -f build/tablequery.js',
                    'touch build/tablequery.js',
                    'cat bower_components/moment/moment.js >> build/tablequery.js',
                    'cat bower_components/moment-range/lib/moment-range.js >> build/tablequery.js',
                    'cat build/lodash.custom.js >> build/tablequery.js',
                    'cat src/vendor/backbone.events.js >> build/tablequery.js',
                    'cat build/grammar.js >> build/tablequery.js',
                    'cat src/tablequery-core.js >> build/tablequery.js',
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
            minify: {
                command: '',
                options: {
                    stdout: true
                }
            },
            casperjs: {
                command: [
                    "casperjs test --direct --log-level=debug test/tablequery-core/test_simple_eq.js",
                    "casperjs test --direct --log-level=debug test/tablequery-core/test_simple_or.js"
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
        },
        qunit: {
            files: ['test/grammar/tests.html']
        },
        casperjs: {
            files: [
                'test/git-commit-token/*.js',
                'test/dependency-leakage/*.js',
                'test/tablequery-core/test*.js',
                'test/tablequery-core-robustness/test*.js',
                'test/events/*.js',
            ],
            options: {
                direct: true,
                logLevel: "debug"
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-shell');
    grunt.loadNpmTasks('grunt-casperjs');
    grunt.registerTask('test', ['build',
                                'qunit',
                                'casperjs']);
    grunt.registerTask('build', ['shell:jison',
                                 'shell:merge',
                                 'shell:minify']);
};
<commit_msg>Gruntfile - add minify step to build task<commit_after>module.exports = function(grunt) {
    // Project config
    grunt.initConfig({
        shell: {
            jison: {
                command: [
                    'mkdir -p build',
                    'jison src/grammar.jison --module-type js --outfile build/grammar.js',
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
            merge: {
                command: [
                    'rm -f build/tablequery.js',
                    'touch build/tablequery.js',
                    'cat bower_components/moment/moment.js >> build/tablequery.js',
                    'cat bower_components/moment-range/lib/moment-range.js >> build/tablequery.js',
                    'cat build/lodash.custom.js >> build/tablequery.js',
                    'cat src/vendor/backbone.events.js >> build/tablequery.js',
                    'cat build/grammar.js >> build/tablequery.js',
                    'cat src/tablequery-core.js >> build/tablequery.js',
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
            minify: {
                command: 'ccjs build/tablequery.js > build/tablequery.min.js',
                options: {
                    stdout: true
                }
            },
            casperjs: {
                command: [
                    "casperjs test --direct --log-level=debug test/tablequery-core/test_simple_eq.js",
                    "casperjs test --direct --log-level=debug test/tablequery-core/test_simple_or.js"
                ].join('&& '),
                options: {
                    stdout: true
                }
            },
        },
        qunit: {
            files: ['test/grammar/tests.html']
        },
        casperjs: {
            files: [
                'test/git-commit-token/*.js',
                'test/dependency-leakage/*.js',
                'test/tablequery-core/test*.js',
                'test/tablequery-core-robustness/test*.js',
                'test/events/*.js',
            ],
            options: {
                direct: true,
                logLevel: "debug"
            }
        }
    });

    grunt.loadNpmTasks('grunt-contrib-qunit');
    grunt.loadNpmTasks('grunt-shell');
    grunt.loadNpmTasks('grunt-casperjs');
    grunt.registerTask('test', ['build',
                                'qunit',
                                'casperjs']);
    grunt.registerTask('build', ['shell:jison',
                                 'shell:merge',
                                 'shell:minify']);
};
<|endoftext|>


<commit_before>/*global module,require*/
var connect = require('connect'),
    connectLivereload = require('connect-livereload'),
    serveStatic = require('serve-static'),
    http = require('http'),
    open = require('open'),
    _ = require('lodash'),
    packageJson = require('./package.json');

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  grunt.loadNpmTasks('grunt-sync');

  var config = {
    site: '_site',
    build: '_build',
    source: 'source',
    defaultTarget: 'staging',
    baseurl: '/' + (grunt.option('baseurl') || 'patternfly-org')
  };

  grunt.initConfig({
    clean: {
      build: '<%= config.build %>',
      site: '<%= config.site %>'
    },
    config: config,
    run: {
      options: {
      },
      submodulesUpdate: {
        cmd: 'git',
        args: [
          'submodule',
          'update',
          '--init',
          '--remote'
        ]
      }
    },
    sync: {
      source: {
        files: [
          {
            expand: true,
            cwd: '<%= config.source %>',
            src: ['**', '!<%= config.build %>/assets/css'],
            dest: '<%= config.build %>'
          }
        ],
        verbose: true
      },
      design: {
        files: [
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/design/**', '!**/documents/**'],
            dest: '<%= config.build %>/_includes/pattern-library'
          },
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/design/**', '!**/documents/**', '!**/*.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('/design', '');
            }
          },
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/site.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('site.md', 'index.md');
            }
          }
        ]
      },
      examples: {
        files: [
          // Copy resources from git submodules
          {
            expand: true,
            cwd: 'submodules/patternfly-core/tests/pages/_includes/widgets',
            src: ['**'],
            dest: '<%= config.build %>/_includes/widgets'
          },
          {
            expand: true,
            cwd: 'submodules/angular-patternfly/dist/docs/partials',
            src: ['**'],
            dest: '<%= config.build %>/_includes/angular-partials'
          }
        ]
      }
    },
    copy: {
      components: {
        files: [
          {
            expand: true,
            cwd: 'node_modules',
            src: [
              '**/*'
            ],
            filter: function(filepath) { // this filter is 5x faster as the corresponding glob
              if (! grunt.file.isFile(filepath)) {
                return false;
              }
              var fileparts = filepath.split('/');
              if (fileparts[2] == 'node_modules') {
                return false;
              }
              var packages = _.keys(packageJson.dependencies);
              if (packages.indexOf(fileparts[1]) < 0) {
                return false;
              }
              var extensions = ['html','txt','js','coffee','css','scss','less','otf','eot','svg','ttf','woff','woff2','png','jpg','gif','ico','xml','yml','yaml','map','json','md'];
              var extparts = fileparts[fileparts.length - 1].split('.');
              return extensions.indexOf(extparts[extparts.length-1]) >= 0;
            },
            dest: '<%= config.build %>/components'
          },
        ]
      }
    },
    csscount: {
      source: {
        src: [
          '<%= config.build %>/assets/css/patternfly*.min.css'
        ],
        options: {
          maxSelectors: 4096
        }
      }
    },
    cssmin: {
      source: {
        files: [{
          expand: true,
          cwd: '<%= config.build %>/assets/css',
          src: ['patternfly*.css', '!*.min.css'],
          dest: '<%= config.build %>/assets/css',
          ext: '.min.css',
        }],
        options: {
          sourceMap: true
        }
      }
    },
    jekyll: {
      options: {
        dest: '<%= config.site %>',
        config: '<%= config.source %>/_config.yml',
        src: '<%= config.build %>',
        bundleExec: 'true',
        incremental: 'true'
      },
      production: {
        incremental: 'false'
      },
      staging: {
        options: {
          raw: `baseurl: '${config.baseurl}'`
        }
      }
    },
    less: {
      patternflySite: {
        files: {
          '<%= config.build %>/assets/css/patternfly-site.css': '<%= config.source %>/_less/patternfly-site.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-site.css.map',
          sourceMapURL: 'patternfly-site.css.map'
        }
      },
      patternflySiteAdjusted: {
        files: {
          '<%= config.build %>/assets/css/patternfly-adjusted.css': '<%= config.source %>/_less/patternfly-adjusted.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-adjusted.css.map',
          sourceMapURL: 'patternfly-adjusted.css.map'
        }
      }
    },
    uglify: {
      options: {
        mangle: false
      },
      production: {
        files: {
          '<%= config.build %>/assets/js/patternfly-site.min.js': ['<%= config.source %>/assets/js/patternfly-site.js']
        }
      }
    },
    watch: {
      source: {
        files: ['<%= config.source %>/**/*', '!<%= config.source %>/_less/**/*', '!<%= config.source %>/assets/js/**/*'],
        tasks: ['sync:source']
      },
      less: {
        files: ['<%= config.source %>/_less/*.less'],
        tasks: ['less', 'cssmin']
      },
      js: {
        files: ['<%= config.source %>/assets/js/*.js'],
        tasks: ['uglify']
      },
      jekyll: {
        files: ['<%= config.build %>/**/*', '!<%= config.source %>/_less/**/*'],
        tasks: ['jekyll']
      },
      design: {
        files: ['submodules/patternfly-design/**/*'],
        tasks: ['sync:design']
      },
      examples: {
        files: ['submodules/patternfly-core/tests/pages/_includes/widgets',
                'submodules/angular-patternfly/dist/docs/partials'],
        tasks: ['sync:examples']
      },
      livereload: {
        files: ['<%= config.site %>/**/*'],
        options: {
          livereload: 35731
        }
      }
    }
  });

  grunt.registerTask('jenkins', [
    'less',
    'cssmin',
    'uglify'
  ]);

  grunt.registerTask('cname', function (target) {
    if (target === 'production') {
      grunt.log.writeln(`Writing CNAME file to ${config.build}/CNAME`);
      grunt.file.write(`${config.build}/CNAME`, 'www.patternfly.org\n');
    }
  });

  grunt.registerTask('serve', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'build:' + target,
      'connect:' + target,
      'watch'
    ]);
  });

  grunt.registerTask('build', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'clean',
      'run:submodulesUpdate',
      'copy:components',
      'cname:' + target,
      'sync:source',
      'sync:design',
      'sync:examples',
      'less',
      'cssmin',
      //'csscount',
      'uglify',
      'jekyll:' + target
    ]);
  });

  grunt.registerTask('connect', function(target) {
    // Load the jekyll config
    var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
    if (target === 'staging') {
      jekyllConfig.baseurl = config.baseurl;
    }

    var host = '0.0.0.0';
    var port = 9002;
    grunt.log.writeln(`Starting static web server for folder ${config.site} on host ${host}:${port}.`);
    var url = `http://localhost:${port}${config.baseurl}/`;
    grunt.log.writeln(url);
    var app = connect();
    app.use(connectLivereload({
      port: 35731
    }));
    app.use(config.baseurl, serveStatic(config.site));
    http.createServer(app).listen(port, host);
    open(url);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:'+target]);
  });

  grunt.registerTask('default', ['build']);
};
<commit_msg>Split the build step in two, to allow external scripts to modify the _build folder prior to the jekyll build<commit_after>/*global module,require*/
var connect = require('connect'),
    connectLivereload = require('connect-livereload'),
    serveStatic = require('serve-static'),
    http = require('http'),
    open = require('open'),
    _ = require('lodash'),
    packageJson = require('./package.json');

module.exports = function (grunt) {
  // load all grunt tasks
  require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
  grunt.loadNpmTasks('grunt-sync');

  var config = {
    site: '_site',
    build: '_build',
    source: 'source',
    defaultTarget: 'staging',
    baseurl: '/' + (grunt.option('baseurl') || 'patternfly-org')
  };

  grunt.initConfig({
    clean: {
      build: '<%= config.build %>',
      site: '<%= config.site %>'
    },
    config: config,
    run: {
      options: {
      },
      submodulesUpdate: {
        cmd: 'git',
        args: [
          'submodule',
          'update',
          '--init',
          '--remote'
        ]
      }
    },
    sync: {
      source: {
        files: [
          {
            expand: true,
            cwd: '<%= config.source %>',
            src: ['**', '!<%= config.build %>/assets/css'],
            dest: '<%= config.build %>'
          }
        ],
        verbose: true
      },
      design: {
        files: [
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/design/**', '!**/documents/**'],
            dest: '<%= config.build %>/_includes/pattern-library'
          },
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/design/**', '!**/documents/**', '!**/*.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('/design', '');
            }
          },
          {
            expand: true,
            cwd: 'submodules/patternfly-design/pattern-library',
            src: ['**/site.md'],
            dest: '<%= config.build %>/pattern-library',
            rename: function(dest, src) {
              return dest + '/' + src.replace('site.md', 'index.md');
            }
          }
        ]
      },
      examples: {
        files: [
          // Copy resources from git submodules
          {
            expand: true,
            cwd: 'submodules/patternfly-core/tests/pages/_includes/widgets',
            src: ['**'],
            dest: '<%= config.build %>/_includes/widgets'
          },
          {
            expand: true,
            cwd: 'submodules/angular-patternfly/dist/docs/partials',
            src: ['**'],
            dest: '<%= config.build %>/_includes/angular-partials'
          }
        ]
      }
    },
    copy: {
      components: {
        files: [
          {
            expand: true,
            cwd: 'node_modules',
            src: [
              '**/*'
            ],
            filter: function(filepath) { // this filter is 5x faster as the corresponding glob
              if (! grunt.file.isFile(filepath)) {
                return false;
              }
              var fileparts = filepath.split('/');
              if (fileparts[2] == 'node_modules') {
                return false;
              }
              var packages = _.keys(packageJson.dependencies);
              if (packages.indexOf(fileparts[1]) < 0) {
                return false;
              }
              var extensions = ['html','txt','js','coffee','css','scss','less','otf','eot','svg','ttf','woff','woff2','png','jpg','gif','ico','xml','yml','yaml','map','json','md'];
              var extparts = fileparts[fileparts.length - 1].split('.');
              return extensions.indexOf(extparts[extparts.length-1]) >= 0;
            },
            dest: '<%= config.build %>/components'
          },
        ]
      }
    },
    csscount: {
      source: {
        src: [
          '<%= config.build %>/assets/css/patternfly*.min.css'
        ],
        options: {
          maxSelectors: 4096
        }
      }
    },
    cssmin: {
      source: {
        files: [{
          expand: true,
          cwd: '<%= config.build %>/assets/css',
          src: ['patternfly*.css', '!*.min.css'],
          dest: '<%= config.build %>/assets/css',
          ext: '.min.css',
        }],
        options: {
          sourceMap: true
        }
      }
    },
    jekyll: {
      options: {
        dest: '<%= config.site %>',
        config: '<%= config.source %>/_config.yml',
        src: '<%= config.build %>',
        bundleExec: 'true',
        incremental: 'true'
      },
      production: {
        incremental: 'false'
      },
      staging: {
        options: {
          raw: `baseurl: '${config.baseurl}'`
        }
      }
    },
    less: {
      patternflySite: {
        files: {
          '<%= config.build %>/assets/css/patternfly-site.css': '<%= config.source %>/_less/patternfly-site.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-site.css.map',
          sourceMapURL: 'patternfly-site.css.map'
        }
      },
      patternflySiteAdjusted: {
        files: {
          '<%= config.build %>/assets/css/patternfly-adjusted.css': '<%= config.source %>/_less/patternfly-adjusted.less'
        },
        options: {
          paths: [
            'less/',
            'node_modules/'
          ],
          sourceMap: true,
          outputSourceFiles: true,
          sourceMapFilename: '<%= config.build %>/assets/css/patternfly-adjusted.css.map',
          sourceMapURL: 'patternfly-adjusted.css.map'
        }
      }
    },
    uglify: {
      options: {
        mangle: false
      },
      production: {
        files: {
          '<%= config.build %>/assets/js/patternfly-site.min.js': ['<%= config.source %>/assets/js/patternfly-site.js']
        }
      }
    },
    watch: {
      source: {
        files: ['<%= config.source %>/**/*', '!<%= config.source %>/_less/**/*', '!<%= config.source %>/assets/js/**/*'],
        tasks: ['sync:source']
      },
      less: {
        files: ['<%= config.source %>/_less/*.less'],
        tasks: ['less', 'cssmin']
      },
      js: {
        files: ['<%= config.source %>/assets/js/*.js'],
        tasks: ['uglify']
      },
      jekyll: {
        files: ['<%= config.build %>/**/*', '!<%= config.source %>/_less/**/*'],
        tasks: ['jekyll']
      },
      design: {
        files: ['submodules/patternfly-design/**/*'],
        tasks: ['sync:design']
      },
      examples: {
        files: ['submodules/patternfly-core/tests/pages/_includes/widgets',
                'submodules/angular-patternfly/dist/docs/partials'],
        tasks: ['sync:examples']
      },
      livereload: {
        files: ['<%= config.site %>/**/*'],
        options: {
          livereload: 35731
        }
      }
    }
  });

  grunt.registerTask('jenkins', [
    'less',
    'cssmin',
    'uglify'
  ]);

  grunt.registerTask('cname', function (target) {
    if (target === 'production') {
      grunt.log.writeln(`Writing CNAME file to ${config.build}/CNAME`);
      grunt.file.write(`${config.build}/CNAME`, 'www.patternfly.org\n');
    }
  });

  grunt.registerTask('serve', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'build:' + target,
      'connect:' + target,
      'watch'
    ]);
  });

  grunt.registerTask('prebuild', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'clean',
      'run:submodulesUpdate',
      'copy:components',
      'cname:' + target,
      'sync:source',
      'sync:design',
      'sync:examples',
      'less',
      'cssmin',
      //'csscount',
      'uglify',
    ]);
  });

  grunt.registerTask('build', function (target) {
    target = target || config.defaultTarget;
    grunt.task.run([
      'prebuild:' + target,
      'jekyll:' + target
    ]);
  });

  grunt.registerTask('connect', function(target) {
    // Load the jekyll config
    var jekyllConfig = grunt.file.readYAML(`${config.source}/_config.yml`);
    if (target === 'staging') {
      jekyllConfig.baseurl = config.baseurl;
    }

    var host = '0.0.0.0';
    var port = 9002;
    grunt.log.writeln(`Starting static web server for folder ${config.site} on host ${host}:${port}.`);
    var url = `http://localhost:${port}${config.baseurl}/`;
    grunt.log.writeln(url);
    var app = connect();
    app.use(connectLivereload({
      port: 35731
    }));
    app.use(config.baseurl, serveStatic(config.site));
    http.createServer(app).listen(port, host);
    open(url);
  });

  grunt.registerTask('server', function (target) {
    grunt.log.warn('The `server` task has been deprecated. Use `grunt serve` to start a server.');
    grunt.task.run(['serve:'+target]);
  });

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