<commit_before>"use strict";
/**
 * @fileOverview Gruntfile tasks. These tasks are intended to help you when modifying the template. If you are
 * just using the template, don't sweat this stuff. To use these tasks, you must install grunt, if you haven't already,
 * and install the dependencies. All of this requires node.js, of course.
 *
 * Install grunt:
 *
 *      npm install -g grunt-cli
 *
 * Then in the directory where you found this file:
 *
 *      npm install
 *
 * And you are all set. See the individual tasks for details.
 *
 * @module Gruntfile
 * @requires path
 * @requires lodash
 * @requires http
 * @requires async
 * @requires fs
 */
var path = require( "path" );
var _ = require( "lodash" );
var request = require('request');
var async = require( "async" );
var fs = require( "fs" );

// this rather odd arrangement of composing tasks like this to make sure this works on both
// windows and linux correctly. We can't depend on Grunt or Node to normalize
// paths for us because we shell out to make this work. So we gather up
// our relative paths here, normalize them later and then pass them into
// the shell to be run by JSDoc3.

/**
 * The definition to run the development test files. This runs the files in `fixtures` with the
 * project's `conf.json` file.
 * @private
 */
var jsdocTestPages = {
	dest      : "./testdocs",
	tutorials : "./fixtures/tutorials",
	template  : "./template",
	config    : "./fixtures/testdocs.conf.json",
	options   : " --lenient --verbose --recurse"
};
/**
 * The definition to run the sample files. This runs the files in `fixtures` with the
 * sample's `conf.json` file. No task directly exposes this configuration. The `fixtures` task
 * modifies this for each swatch it finds and then run the docs command against it.
 * @private
 */
var jsdocExamplePages = {
	src       : ["./fixtures/", "./README.md"],
	dest      : "./themes",
	tutorials : "./fixtures/tutorials",
	template  : "./template",
	config    : "./fixtures/example.conf.json",
	options   : " --lenient --verbose --recurse"
};

/**
 * This definition provides the project's main, published documentation.
 *  @private
 */
var projectDocs = {
	src       : ["./Gruntfile.js", "./README.md", "./template/publish.js"],
	dest      : "./dox",
	tutorials : "",
	template  : "./template",
	config    : "./template/jsdoc.conf.json",
	options   : " --lenient --verbose --recurse --private"
};

/**
 * Normalizes all paths from a JSDoc task definition and and returns an executable string that can be passed to the shell.
 * @param {object} jsdoc A JSDoc definition
 * @returns {string}
 */
function jsdocCommand( jsdoc ) {
	var cmd = [];
	cmd.unshift( jsdoc.options );
	if ( jsdoc.tutorials.length > 0 ) {
		cmd.push( "-u " + path.resolve( jsdoc.tutorials ) );
	}
	cmd.push( "-d " + path.resolve( jsdoc.dest ) );
	cmd.push( "-t " + path.resolve( jsdoc.template ) );
	cmd.push( "-c " + path.resolve( jsdoc.config ) );
	_.each( jsdoc.src, function ( src ) {
		cmd.push( path.resolve( src ) );
	} );
	cmd.unshift( path.resolve( "./node_modules/jsdoc/jsdoc" ) );
	cmd.unshift( "node" );

	return cmd.join( " " );
}

var tasks = {
	shell  : {
		options  : {
			stdout : true,
			stderr : true
		},
		/**
		 * TASK: Create the a documentation set for testing changes to the template
		 * @name shell:testdocs
		 * @memberOf module:Gruntfile
		 */
		testdocs : {
			command : jsdocCommand( jsdocTestPages )
		},
		/**
		 * TASK: Create project documentation
		 * @name shell:dox
		 * @memberOf module:Gruntfile
		 */
		dox      : {
			command : jsdocCommand( projectDocs )
		},
		release1 : {
			command : [
				"touch Gruntfile.js",
				"git add .",
				'git commit -m "ready for release"',
			].join( ";" )

		},
		release2 : {
			command : ["npm version patch",
				"git push",
				"git push --tags",
				"npm publish"
			].join( "&&" )
		}
	},
	jsdoc  : {
		testdocs : {
			src     : ['fixtures/**.js', "./README.md"],
			jsdoc   : "./node_modules/jsdoc/jsdoc.js",
			options : {
				destination : './testdocs',
				rescurse    : true,
				"private"   : true,
				"template"  : "./template",
				"configure" : "./template/jsdoc.conf.json"
			}
		}
	},
	/**
	 * TASK: The less task creates the themed css file from main.less. The file is written to the template styles
	 * directory as site.[name of theme].css. Later the .conf file will look for the theme to apply based
	 * on this naming convention.
	 * @name less
	 * @memberOf module:Gruntfile
	 */
	less   : {
		dev : {
			files : {
				"template/static/styles/site.<%= jsdocConf.templates.theme %>.css" : "styles/main.less"
			}
		}
	},
	copy   : {
		docs : {
			files : [
				{expand : true, cwd : "dox/", src : ['**'], dest : '../docstrap-dox/'},
				{expand : true, cwd : "themes/", src : ['**'], dest : '../docstrap-dox/themes'}
			]
		}
	},
	uglify : {
		template : {
			files : {
				'template/static/scripts/docstrap.lib.js' : [
					'bower_components/jquery/dist/jquery.min.js',
//					'bower_components/sunlight/src/sunlight.js',
//					'bower_components/sunlight/src/lang/sunlight.xml.js',
//					'bower_components/sunlight/src/**/*.js',
					'bower_components/prism/prism.js',

					'bower_components/jquery.scrollTo/jquery.scrollTo.min.js',
					'bower_components/jquery.localScroll/jquery.localScroll.min.js',
					'bower_components/bootstrap/dist/js/bootstrap.min.js'
				]
			}
		}
	}
};

module.exports = function ( grunt ) {
	tasks.jsdocConf = grunt.file.readJSON( 'template/jsdoc.conf.json' );

	grunt.initConfig( tasks );

	grunt.loadNpmTasks( 'grunt-contrib-less' );
	grunt.loadNpmTasks( 'grunt-shell' );
	grunt.loadNpmTasks( 'grunt-contrib-copy' );
	grunt.loadNpmTasks( 'grunt-contrib-uglify' );

	grunt.registerTask( "default", ["docs"] );

	/**
	 * Builds the project's documentation
	 * @name docs
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "docs", "Create the project documentation", ["shell:dox"] );
	/**
	 * Compile the CSS and create the project documentation
	 * @name dev
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "dev", "Compile the CSS and create the project documentation", ["less", "shell:dox"] );
	/**
	 * TASK: Builds the main less file and then generates the test documents
	 * @name testdocs
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "testdocs", "Builds the main less file and then generates the test documents", ["less:dev", "shell:testdocs"] );
	/**
	 * TASK: Builds the whole shebang. Which means creating testdocs, the bootswatch fixtures and then resetting the
	 * styles directory.
	 * @name build
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "build", "Builds the whole shebang. Which means creating testdocs, the bootswatch samples and then resetting the styles directory", ["uglify:template", "testdocs", "shell:dox", "bootswatch", "examples", "apply", "copy"] );
	/**
	 * TASK: Applies the theme in the conf file and applies it to the styles directory.
	 * @name apply
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "apply", "Applies the theme in the conf file and applies it to the styles directory", function () {
		var def = {
			less          : "http://bootswatch.com/" + tasks.jsdocConf.templates.theme + "/bootswatch.less",
			lessVariables : "http://bootswatch.com/" + tasks.jsdocConf.templates.theme + "/variables.less"
		};
		grunt.registerTask( "swatch-apply", _.partial( applyTheme, grunt, def ) );
		grunt.task.run( ["swatch-apply"] );
	} );
	/**
	 * TASK: Grab all Bootswatch themes and create css from each one based on the main.less in the styles directory. NOTE that this will
	 * leave the last swatch downloaded in the styles directory, you will want to call "apply" afterwards
	 * @name bootswatch
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "bootswatch", "Grab all Bootswatch themes and create css from each one based on the main.less in the styles directory", function () {
		var toRun = [];

		var done = this.async();
		getBootSwatchList( function ( err, list ) {
			if ( err ) {return done( err );}

			_.each( list.themes, function ( entry ) {

				toRun.push( "swatch" + entry.name );
				grunt.registerTask( "swatch" + entry.name, _.partial( applyTheme, grunt, entry ) );

				var key = "template/static/styles/site." + entry.name.toLowerCase() + ".css";
				var def = {};
				def[key] = "styles/main.less";
				tasks.less["swatch" + entry.name] = {
					files : def
				};
				toRun.push( "less:swatch" + entry.name );
			} );
			grunt.task.run( toRun );
			done();
		} );

	} );
	/**
	 * TASK:Create fixtures from the themes. The files must have been built first from the bootswatch task.
	 * @name examples
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "examples", "Create samples from the themes", function () {
		var toRun = [];
		var done = this.async();
		getBootSwatchList( function ( err, list ) {
			if ( err ) {return done( err );}

			_.each( list.themes, function ( entry ) {
				var conf = grunt.file.readJSON( './fixtures/example.conf.json' );
				conf.templates.theme = entry.name.toLowerCase();
				grunt.file.write( "tmp/example.conf." + conf.templates.theme + ".json", JSON.stringify( conf, null, 4 ) );

				var jsdenv = _.cloneDeep( jsdocExamplePages );
				jsdenv.config = "./tmp/example.conf." + conf.templates.theme + ".json";
				jsdenv.dest = "./themes/" + conf.templates.theme;
				tasks.shell["example" + conf.templates.theme] = {
					command : jsdocCommand( jsdenv )
				};
				toRun.push( "shell:example" + conf.templates.theme );
			} );

			grunt.registerTask( "cleanup", "", function () {
				grunt.file["delete"]( "tmp/" );
			} );
			toRun.push( "cleanup" );
			grunt.task.run( toRun );
			done();
		} );

	} );

	grunt.registerTask( "release", "Create the project documentation", ["shell:release1", "shell:release2"] );
};

/**
 * Applies one of the Bootswatch themes to the working `styles` directory. When you want to modify a particular theme, this where you
 * get the basis for it. The files are written to `./styles/variables.less` and `./styles/bootswatch.less`. The `./styles/main.less`
 * file includes them directly, so after you apply the theme, modify `main.less` to your heart's content and then run the `less` task
 * as in
 *
 *      grunt less
 *
 * @param {object} grunt The grunt object reference
 * @param {object} definition The swatch definition files
 * @param {string} definition.less The url to the `bootswatch.less` file
 * @param {string} definition.lessVariables The url to the `variables.less` file
 * @private
 */
function applyTheme( grunt, definition ) {
	//noinspection JSHint

	var webProtocol = tasks.jsdocConf.templates.protocol || "//";
	var done = this.async();
	async.waterfall( [
		function ( cb ) {
			getBootSwatchComponent( definition.less, function ( err, swatch ) {
				if ( err ) {return cb( err );}
				var fullPath = path.join( __dirname, "styles/bootswatch.less" );
				fs.writeFile( fullPath, swatch.replace( "http://", webProtocol ), cb );
			} );
		},
		function ( cb ) {
			getBootSwatchComponent( definition.lessVariables, function ( err, swatch ) {
				if ( err ) {return cb( err );}
				var fullPath = path.join( __dirname, "styles/variables.less" );
				fs.writeFile( fullPath, swatch.replace( "http://", webProtocol ), cb );
			} );
		}
	], done );
}

/**
 * Gets the list of available Bootswatches from, well, Bootswatch.
 *
 * @see http://news.bootswatch.com/post/22193315172/bootswatch-api
 * @param {function(err, responseBody)} done The callback when complete
 * @param {?object} done.err If an error occurred, you will find it here.
 * @param {object} done.responseBody This is a parsed edition of the bootswatch server's response. It's format it defined
 * by the return message from [here](http://api.bootswatch.com/)
 * @private
 */
function getBootSwatchList( done ) {
	request('http://api.bootswatch.com/3/', function(error, response, body) {
		if (error) {
			return done(error);
		}
		done(null, JSON.parse(body));
	});
}

/**
 * This method will get one of the components from Bootswatch, which is generally a `less` file or a `lessVariables` file.
 *
 * @see http://news.bootswatch.com/post/22193315172/bootswatch-api
 * @param {string} url The url to retreive from
 * @param {function(err, responseText)} done The callback when complete
 * @param {?object} done.err If an error occurred, you will find it here.
 * @param {string} done.responseText The body of whatever was returned
 * @private
 */
function getBootSwatchComponent( url, done ) {
	var body = "";
	var req = request(url, function ( error, response, body ) {
		if (error) {
			return done(error);
		}
		done(null, body);
	});
}
<commit_msg>Removed references to SunlightJS<commit_after>"use strict";
/**
 * @fileOverview Gruntfile tasks. These tasks are intended to help you when modifying the template. If you are
 * just using the template, don't sweat this stuff. To use these tasks, you must install grunt, if you haven't already,
 * and install the dependencies. All of this requires node.js, of course.
 *
 * Install grunt:
 *
 *      npm install -g grunt-cli
 *
 * Then in the directory where you found this file:
 *
 *      npm install
 *
 * And you are all set. See the individual tasks for details.
 *
 * @module Gruntfile
 * @requires path
 * @requires lodash
 * @requires http
 * @requires async
 * @requires fs
 */
var path = require( "path" );
var _ = require( "lodash" );
var request = require('request');
var async = require( "async" );
var fs = require( "fs" );

// this rather odd arrangement of composing tasks like this to make sure this works on both
// windows and linux correctly. We can't depend on Grunt or Node to normalize
// paths for us because we shell out to make this work. So we gather up
// our relative paths here, normalize them later and then pass them into
// the shell to be run by JSDoc3.

/**
 * The definition to run the development test files. This runs the files in `fixtures` with the
 * project's `conf.json` file.
 * @private
 */
var jsdocTestPages = {
	dest      : "./testdocs",
	tutorials : "./fixtures/tutorials",
	template  : "./template",
	config    : "./fixtures/testdocs.conf.json",
	options   : " --lenient --verbose --recurse"
};
/**
 * The definition to run the sample files. This runs the files in `fixtures` with the
 * sample's `conf.json` file. No task directly exposes this configuration. The `fixtures` task
 * modifies this for each swatch it finds and then run the docs command against it.
 * @private
 */
var jsdocExamplePages = {
	src       : ["./fixtures/", "./README.md"],
	dest      : "./themes",
	tutorials : "./fixtures/tutorials",
	template  : "./template",
	config    : "./fixtures/example.conf.json",
	options   : " --lenient --verbose --recurse"
};

/**
 * This definition provides the project's main, published documentation.
 *  @private
 */
var projectDocs = {
	src       : ["./Gruntfile.js", "./README.md", "./template/publish.js"],
	dest      : "./dox",
	tutorials : "",
	template  : "./template",
	config    : "./template/jsdoc.conf.json",
	options   : " --lenient --verbose --recurse --private"
};

/**
 * Normalizes all paths from a JSDoc task definition and and returns an executable string that can be passed to the shell.
 * @param {object} jsdoc A JSDoc definition
 * @returns {string}
 */
function jsdocCommand( jsdoc ) {
	var cmd = [];
	cmd.unshift( jsdoc.options );
	if ( jsdoc.tutorials.length > 0 ) {
		cmd.push( "-u " + path.resolve( jsdoc.tutorials ) );
	}
	cmd.push( "-d " + path.resolve( jsdoc.dest ) );
	cmd.push( "-t " + path.resolve( jsdoc.template ) );
	cmd.push( "-c " + path.resolve( jsdoc.config ) );
	_.each( jsdoc.src, function ( src ) {
		cmd.push( path.resolve( src ) );
	} );
	cmd.unshift( path.resolve( "./node_modules/jsdoc/jsdoc" ) );
	cmd.unshift( "node" );

	return cmd.join( " " );
}

var tasks = {
	shell  : {
		options  : {
			stdout : true,
			stderr : true
		},
		/**
		 * TASK: Create the a documentation set for testing changes to the template
		 * @name shell:testdocs
		 * @memberOf module:Gruntfile
		 */
		testdocs : {
			command : jsdocCommand( jsdocTestPages )
		},
		/**
		 * TASK: Create project documentation
		 * @name shell:dox
		 * @memberOf module:Gruntfile
		 */
		dox      : {
			command : jsdocCommand( projectDocs )
		},
		release1 : {
			command : [
				"touch Gruntfile.js",
				"git add .",
				'git commit -m "ready for release"',
			].join( ";" )

		},
		release2 : {
			command : ["npm version patch",
				"git push",
				"git push --tags",
				"npm publish"
			].join( "&&" )
		}
	},
	jsdoc  : {
		testdocs : {
			src     : ['fixtures/**.js', "./README.md"],
			jsdoc   : "./node_modules/jsdoc/jsdoc.js",
			options : {
				destination : './testdocs',
				rescurse    : true,
				"private"   : true,
				"template"  : "./template",
				"configure" : "./template/jsdoc.conf.json"
			}
		}
	},
	/**
	 * TASK: The less task creates the themed css file from main.less. The file is written to the template styles
	 * directory as site.[name of theme].css. Later the .conf file will look for the theme to apply based
	 * on this naming convention.
	 * @name less
	 * @memberOf module:Gruntfile
	 */
	less   : {
		dev : {
			files : {
				"template/static/styles/site.<%= jsdocConf.templates.theme %>.css" : "styles/main.less"
			}
		}
	},
	copy   : {
		docs : {
			files : [
				{expand : true, cwd : "dox/", src : ['**'], dest : '../docstrap-dox/'},
				{expand : true, cwd : "themes/", src : ['**'], dest : '../docstrap-dox/themes'}
			]
		}
	},
	uglify : {
		template : {
			files : {
				'template/static/scripts/docstrap.lib.js' : [
					'bower_components/jquery/dist/jquery.min.js',
					'bower_components/prism/prism.js',

					'bower_components/jquery.scrollTo/jquery.scrollTo.min.js',
					'bower_components/jquery.localScroll/jquery.localScroll.min.js',
					'bower_components/bootstrap/dist/js/bootstrap.min.js'
				]
			}
		}
	}
};

module.exports = function ( grunt ) {
	tasks.jsdocConf = grunt.file.readJSON( 'template/jsdoc.conf.json' );

	grunt.initConfig( tasks );

	grunt.loadNpmTasks( 'grunt-contrib-less' );
	grunt.loadNpmTasks( 'grunt-shell' );
	grunt.loadNpmTasks( 'grunt-contrib-copy' );
	grunt.loadNpmTasks( 'grunt-contrib-uglify' );

	grunt.registerTask( "default", ["docs"] );

	/**
	 * Builds the project's documentation
	 * @name docs
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "docs", "Create the project documentation", ["shell:dox"] );
	/**
	 * Compile the CSS and create the project documentation
	 * @name dev
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "dev", "Compile the CSS and create the project documentation", ["less", "shell:dox"] );
	/**
	 * TASK: Builds the main less file and then generates the test documents
	 * @name testdocs
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "testdocs", "Builds the main less file and then generates the test documents", ["less:dev", "shell:testdocs"] );
	/**
	 * TASK: Builds the whole shebang. Which means creating testdocs, the bootswatch fixtures and then resetting the
	 * styles directory.
	 * @name build
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "build", "Builds the whole shebang. Which means creating testdocs, the bootswatch samples and then resetting the styles directory", ["uglify:template", "testdocs", "shell:dox", "bootswatch", "examples", "apply", "copy"] );
	/**
	 * TASK: Applies the theme in the conf file and applies it to the styles directory.
	 * @name apply
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "apply", "Applies the theme in the conf file and applies it to the styles directory", function () {
		var def = {
			less          : "http://bootswatch.com/" + tasks.jsdocConf.templates.theme + "/bootswatch.less",
			lessVariables : "http://bootswatch.com/" + tasks.jsdocConf.templates.theme + "/variables.less"
		};
		grunt.registerTask( "swatch-apply", _.partial( applyTheme, grunt, def ) );
		grunt.task.run( ["swatch-apply"] );
	} );
	/**
	 * TASK: Grab all Bootswatch themes and create css from each one based on the main.less in the styles directory. NOTE that this will
	 * leave the last swatch downloaded in the styles directory, you will want to call "apply" afterwards
	 * @name bootswatch
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "bootswatch", "Grab all Bootswatch themes and create css from each one based on the main.less in the styles directory", function () {
		var toRun = [];

		var done = this.async();
		getBootSwatchList( function ( err, list ) {
			if ( err ) {return done( err );}

			_.each( list.themes, function ( entry ) {

				toRun.push( "swatch" + entry.name );
				grunt.registerTask( "swatch" + entry.name, _.partial( applyTheme, grunt, entry ) );

				var key = "template/static/styles/site." + entry.name.toLowerCase() + ".css";
				var def = {};
				def[key] = "styles/main.less";
				tasks.less["swatch" + entry.name] = {
					files : def
				};
				toRun.push( "less:swatch" + entry.name );
			} );
			grunt.task.run( toRun );
			done();
		} );

	} );
	/**
	 * TASK:Create fixtures from the themes. The files must have been built first from the bootswatch task.
	 * @name examples
	 * @memberof module:Gruntfile
	 */
	grunt.registerTask( "examples", "Create samples from the themes", function () {
		var toRun = [];
		var done = this.async();
		getBootSwatchList( function ( err, list ) {
			if ( err ) {return done( err );}

			_.each( list.themes, function ( entry ) {
				var conf = grunt.file.readJSON( './fixtures/example.conf.json' );
				conf.templates.theme = entry.name.toLowerCase();
				grunt.file.write( "tmp/example.conf." + conf.templates.theme + ".json", JSON.stringify( conf, null, 4 ) );

				var jsdenv = _.cloneDeep( jsdocExamplePages );
				jsdenv.config = "./tmp/example.conf." + conf.templates.theme + ".json";
				jsdenv.dest = "./themes/" + conf.templates.theme;
				tasks.shell["example" + conf.templates.theme] = {
					command : jsdocCommand( jsdenv )
				};
				toRun.push( "shell:example" + conf.templates.theme );
			} );

			grunt.registerTask( "cleanup", "", function () {
				grunt.file["delete"]( "tmp/" );
			} );
			toRun.push( "cleanup" );
			grunt.task.run( toRun );
			done();
		} );

	} );

	grunt.registerTask( "release", "Create the project documentation", ["shell:release1", "shell:release2"] );
};

/**
 * Applies one of the Bootswatch themes to the working `styles` directory. When you want to modify a particular theme, this where you
 * get the basis for it. The files are written to `./styles/variables.less` and `./styles/bootswatch.less`. The `./styles/main.less`
 * file includes them directly, so after you apply the theme, modify `main.less` to your heart's content and then run the `less` task
 * as in
 *
 *      grunt less
 *
 * @param {object} grunt The grunt object reference
 * @param {object} definition The swatch definition files
 * @param {string} definition.less The url to the `bootswatch.less` file
 * @param {string} definition.lessVariables The url to the `variables.less` file
 * @private
 */
function applyTheme( grunt, definition ) {
	//noinspection JSHint

	var webProtocol = tasks.jsdocConf.templates.protocol || "//";
	var done = this.async();
	async.waterfall( [
		function ( cb ) {
			getBootSwatchComponent( definition.less, function ( err, swatch ) {
				if ( err ) {return cb( err );}
				var fullPath = path.join( __dirname, "styles/bootswatch.less" );
				fs.writeFile( fullPath, swatch.replace( "http://", webProtocol ), cb );
			} );
		},
		function ( cb ) {
			getBootSwatchComponent( definition.lessVariables, function ( err, swatch ) {
				if ( err ) {return cb( err );}
				var fullPath = path.join( __dirname, "styles/variables.less" );
				fs.writeFile( fullPath, swatch.replace( "http://", webProtocol ), cb );
			} );
		}
	], done );
}

/**
 * Gets the list of available Bootswatches from, well, Bootswatch.
 *
 * @see http://news.bootswatch.com/post/22193315172/bootswatch-api
 * @param {function(err, responseBody)} done The callback when complete
 * @param {?object} done.err If an error occurred, you will find it here.
 * @param {object} done.responseBody This is a parsed edition of the bootswatch server's response. It's format it defined
 * by the return message from [here](http://api.bootswatch.com/)
 * @private
 */
function getBootSwatchList( done ) {
	request('http://api.bootswatch.com/3/', function(error, response, body) {
		if (error) {
			return done(error);
		}
		done(null, JSON.parse(body));
	});
}

/**
 * This method will get one of the components from Bootswatch, which is generally a `less` file or a `lessVariables` file.
 *
 * @see http://news.bootswatch.com/post/22193315172/bootswatch-api
 * @param {string} url The url to retreive from
 * @param {function(err, responseText)} done The callback when complete
 * @param {?object} done.err If an error occurred, you will find it here.
 * @param {string} done.responseText The body of whatever was returned
 * @private
 */
function getBootSwatchComponent( url, done ) {
	var body = "";
	var req = request(url, function ( error, response, body ) {
		if (error) {
			return done(error);
		}
		done(null, body);
	});
}
<|endoftext|>


<commit_before>var assert = require('should');
var sinon = require('sinon');
var Chord = require('../../js/chord/chord');
var ChordNode = require('../../js/chord/node');
var DataChannel = require('../adapter-mock').DataChannel;
var Sha1 = require('../../js/third_party/sha1');
var BigInteger = require('../../js/third_party/BigInteger');
var Peer = require('../../js/peer');

function mock_dcs() {
    var dc_in = {
        send: function(msg) {
            console.log(dc_out);
            dc_out.onmessage({
                data: msg
            });
        }
    },
        dc_out = {
            send: function(msg) {
                dc_in.onmessage({
                    data: msg
                });
            }
        };
    return [dc_in, dc_out];
}

function mockHash() {
    return {
        update: function(str) {
            this.str = str;
            this.number = BigInt(0);
        },
        digest: function() {
            return [this.str];
        },
        bigInteger: function() {
            return this.number;
        }
    };

}

describe('Chord', function() {
    var c, cm, dcStub;

    beforeEach(function() {
        cm = {
            connect: function() {}
        };
        dcStub = sinon.createStubInstance(DataChannel);
        c = new Chord(new BigInteger(42), dcStub, cm);
    });

    describe('constructor', function() {
        it('should return an instance', function() {
            c.should.be.an.instanceof(Chord);
            c.should.have.property('_connectionManager', cm);
            c.should.have.property('_localNode');
            c._localNode.should.be.an.instanceof(ChordNode);

            assert(c.id.equals(new BigInteger(5))); // how does this work??
        });
        it('should start with successor set to myself and predecessor set to null', function() {
            c._localNode._successor.should.equal(c._localNode);
            assert.equal(c._localNode._predecessor, null);
            assert.equal(c._localNode._peer._dataChannel, dcStub);
        });
        it('should initialize finger table', function() {
            var hash = mockHash(),
                i;
            assert.equal(Object.keys(c._fingerTable).length, 160);
            for (i = 1; i <= 160; i++) {
                assert.equal(c._fingerTable[i].start().toString(), (BigInteger(42).plus(BigInteger(2).pow(BigInteger(i - 1)).toString())));
                assert.equal(c._fingerTable[i].node, c._localNode);
            }
        });
    });
    describe('#id', function() {
        it('should return correct ID', function() {
            assert.ok(c.id.equals(new BigInteger(42)));
        });
        it('should be immutable', function() {
            assert.ok(c.id.equals(new BigInteger(42)));
            c.id = 'something else';
            assert.ok(c.id.equals(new BigInteger(42)));
        });
    });
    describe('#join', function() {
        it('should not allow to be called twice', function(done) {
            c.join(new BigInteger(1), function() {
                throw new Error("Success callback called");
            });
            c.join(new BigInteger(1), function(err) {
                if (err) {
                    done();
                }
            });
        });
        it('should try to connect to bootstrap peer', function() {
            sinon.spy(cm, "connect");
            c.join(new BigInteger(1));
            assert.ok(cm.connect.calledOnce);
            assert.ok(cm.connect.args[0][0].equals(new BigInteger(1)));
            cm.connect.restore();
        });
    });
    describe('#responsible', function() {
        it('should return true for my id', function() {
            c._localNode.responsible(c._localNode.id()).should.be.ok;
        });
        it('should handle (preId, myId] when predecessor is set', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c._localNode.responsible(c._localNode.id()).should.be.ok;
            c._localNode.responsible(c._localNode.id().plus(1)).should.not.be.ok;
            c._localNode.responsible(c._localNode.predecessor_id()).should.not.be.ok;
            c._localNode.responsible(c._localNode.predecessor_id().plus(1)).should.be.ok;
        });
        it('should handle wrap around', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().plus(2), null, dcStub), c, false);
            c._localNode.responsible(c._localNode.id()).should.be.ok;
            c._localNode.responsible(c._localNode.id().plus(1)).should.not.be.ok;
            c._localNode.responsible(c._localNode.id().plus(2)).should.not.be.ok;
            c._localNode.responsible(c._localNode.id().plus(3)).should.be.ok;
        });
    });
    describe('#localFindOperations', function() {
        it('should locally find correct successor', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().minus(10), null, dcStub), c, false);
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.successor_id());
            });
            c.find_successor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.successor_id());
            });
            c.find_successor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
        });
        it('should locally find correct predecessor', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().minus(10), null, dcStub), c, false);
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_predecessor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.predecessor_id());
            });
            c.find_predecessor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.predecessor_id());
            });
        });
        it('should handle edge case: predecessor unset', function() {
            c._localNode._predecessor = null;
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.predecessor_id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
        });
        it('should handle edge case: i am my successor, predecessor unset', function() {
            c._localNode._predecessor = null;
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id(), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
        });
    });
});
/*

    describe('joining', function() {
        it('should call success callback', function(done) {
            var s0 = {}, s1 = {};
            sinon.stub(s0, "connect");
            var c0 = new Chord(new BigInteger(0), s0);
            var c1 = new Chord(new BigInteger(10), s1);
            c0.join(c1.id(), function() {
                done();
            });
        });
    });
});
/*
                it('should fill complete finger table', function(done) {
                    var c1 = new Chord({}, new Sha1(), 5);
                    var c2 = new Chord({}, new Sha1(), 5);
                    c1.join(c2._localNode, function() {
                        / / TODO(max): check individual entries
assert.equal(Object.keys(c._fingerTable).length, 5);
done();
});
});
});
});

describe('Node', function() {
    describe('message handling', function() {
        it('should return successor', function(done) {
            var dcs = mock_dcs();
            var n_in = new ChordNode(0, null, null, dcs[0], null);
            var n_out = new ChordNode(1, null, null, dcs[1], null);
            n_in.find_successor(2, function(succ) {
                if (succ === null) {
                    done();
                }
            });
        });
        it('should handle unexpected requests gracefully', function() {
            var n = new ChordNode(0, null, null, {}, null);

            function msg(obj) {
                return {
                    data: JSON.stringify(obj)
                };
            }
            n._onmessage({
                data: "justastring"
            });
            n._onmessage(msg({}));
            n._onmessage(msg({
                type: 'hello'
            }));
            n._onmessage(msg({
                type: n.message_types.SUCCESSOR
            }));
            n._onmessage(msg({
                type: n.message_types.FIND_SUCCESSOR
            }));
        });
    });
    describe('get_node_id', function() {
        it('should return and set the correct ID', function(done) {
            var dcs = mock_dcs();
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInteger(1), null, null, dcs[1], null);
            n1.get_node_id(function(id) {
                assert.ok(id.equals(BigInteger(1)));
                assert.equal(n1._id, id);
                done();
            });

        });
        it('should return the same ID upon subsequent calls', function(done) {
            var dcs = mock_dcs();
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInt(1), null, null, dcs[1], null);
            var id1;
            n1.get_node_id(function(id) {
                id1 = id;
            });
            n1.get_node_id(function(id) {
                assert.equal(id, id1);
                done();
            });

        });
        it('should cache the ID', function() {
            var dcs = mock_dcs();
            sinon.spy(dcs[0], 'send');
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInt(1), null, null, dcs[1], null);
            n1.get_node_id(function() {});
            n1.get_node_id(function() {});
            assert.ok(dcs[0].send.calledOnce);
        });
    });
    describe('find_successor', function() {
        it('should send the correct message', function() {
            var dc = new DataChannel();
            var dcStub = sinon.stub(dc, 'send');
            var n = new ChordNode(0, null, null, dc, null);
            n.find_successor(1);
            sinon.assert.calledWith(dcStub, JSON.stringify({
                type: n.message_types.FIND_SUCCESSOR,
                id: "1",
                seqnr: 0
            }));
        });
        it('should call the correct callback upon arrival of the ID', function(done) {
            var dc = {};
            dc.send = function(msg) {
                var dec = JSON.parse(msg);
                if (dec.id === "2") {
                    setTimeout(function() {
                        dc.onmessage({
                            data: JSON.stringify({
                                type: Node.prototype.message_types.SUCCESSOR,
                                successor: 3,
                                seqnr: dec.seqnr
                            })
                        });
                    }, 10);
                } else if (dec.id === "1") {
                    setTimeout(function() {
                        dc.onmessage({
                            data: JSON.stringify({
                                type: Node.prototype.message_types.SUCCESSOR,
                                successor: 2,
                                seqnr: dec.seqnr
                            })
                        });
                    }, 20);
                }
            };
            var n = new ChordNode(0, null, null, dc, null);
            var oks = 0;

            function find_successor(id, expected) {
                n.find_successor(id, function(id) {
                    if (id === expected) {
                        if (oks === 1 && Object.keys(n._pending).length === 0) {
                            done();
                        } else {
                            oks += 1;
                        }
                    }
                });
            }
            find_successor(2, 3);
            find_successor(1, 2);
        });
    });
}); * /
*/
<commit_msg>Fixed Chord tests<commit_after>var assert = require('should');
var sinon = require('sinon');
var Chord = require('../../js/chord/chord');
var ChordNode = require('../../js/chord/node');
var DataChannel = require('../adapter-mock').DataChannel;
var Sha1 = require('../../js/third_party/sha1');
var BigInteger = require('../../js/third_party/BigInteger');
var Peer = require('../../js/peer');

function mock_dcs() {
    var dc_in = {
        send: function(msg) {
            console.log(dc_out);
            dc_out.onmessage({
                data: msg
            });
        }
    },
        dc_out = {
            send: function(msg) {
                dc_in.onmessage({
                    data: msg
                });
            }
        };
    return [dc_in, dc_out];
}

function mockHash() {
    return {
        update: function(str) {
            this.str = str;
            this.number = BigInt(0);
        },
        digest: function() {
            return [this.str];
        },
        bigInteger: function() {
            return this.number;
        }
    };

}

describe('Chord', function() {
    var c, cm, dcStub;

    beforeEach(function() {
        cm = {
            connect: function() {}
        };
        dcStub = sinon.createStubInstance(DataChannel);
        c = new Chord(new BigInteger(42), dcStub, cm);
    });

    describe('constructor', function() {
        it('should return an instance', function() {
            c.should.be.an.instanceof(Chord);
            c.should.have.property('_connectionManager', cm);
            c.should.have.property('_localNode');
            c._localNode.should.be.an.instanceof(ChordNode);

            assert(c.id.equals(new BigInteger(5))); // how does this work??
        });
        it('should start with successor set to myself and predecessor set to null', function() {
            c._localNode._successor.should.equal(c._localNode);
            assert.equal(c._localNode._predecessor, null);
            assert.equal(c._localNode._peer._dataChannel, dcStub);
        });
        it('should initialize finger table', function() {
            var hash = mockHash(),
                i;
            assert.equal(Object.keys(c._fingerTable).length, 160);
            for (i = 1; i <= 160; i++) {
                assert.equal(c._fingerTable[i].start().toString(), (BigInteger(42).plus(BigInteger(2).pow(BigInteger(i - 1)).toString())));
                assert.equal(c._fingerTable[i].node, c._localNode);
            }
        });
    });
    describe('#id', function() {
        it('should return correct ID', function() {
            assert.ok(c.id.equals(new BigInteger(42)));
        });
        it('should be immutable', function() {
            assert.ok(c.id.equals(new BigInteger(42)));
            c.id = 'something else';
            assert.ok(c.id.equals(new BigInteger(42)));
        });
    });
    describe('#join', function() {
        it('should not allow to be called twice', function(done) {
            c.join(new Peer(new BigInteger(1), null, dcStub), function() {
                throw new Error("Success callback called");
            });
            c.join(new Peer(new BigInteger(1), null, dcStub), function(err) {
                if (err) {
                    done();
                }
            });
        });
    });
    describe('#responsible', function() {
        it('should return true for my id', function() {
            c._localNode.responsible(c._localNode.id()).should.be.ok;
        });
        it('should handle (preId, myId] when predecessor is set', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c._localNode.responsible(c._localNode.id()).should.be.ok;
            c._localNode.responsible(c._localNode.id().plus(1)).should.not.be.ok;
            c._localNode.responsible(c._localNode.predecessor_id()).should.not.be.ok;
            c._localNode.responsible(c._localNode.predecessor_id().plus(1)).should.be.ok;
        });
        it('should handle wrap around', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().plus(2), null, dcStub), c, false);
            c._localNode.responsible(c._localNode.id()).should.be.ok;
            c._localNode.responsible(c._localNode.id().plus(1)).should.not.be.ok;
            c._localNode.responsible(c._localNode.id().plus(2)).should.not.be.ok;
            c._localNode.responsible(c._localNode.id().plus(3)).should.be.ok;
        });
    });
    describe('#localFindOperations', function() {
        it('should locally find correct successor', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().minus(10), null, dcStub), c, false);
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.successor_id());
            });
            c.find_successor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.successor_id());
            });
            c.find_successor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
        });
        it('should locally find correct predecessor', function() {
            c._localNode._predecessor = new ChordNode(new Peer(c._localNode.id().minus(10), null, dcStub), c, false);
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_predecessor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.predecessor_id());
            });
            c.find_predecessor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.predecessor_id());
            });
        });
        it('should handle edge case: predecessor unset', function() {
            c._localNode._predecessor = null;
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id().plus(10), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.predecessor_id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.successor_id(), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
        });
        it('should handle edge case: i am my successor, predecessor unset', function() {
            c._localNode._predecessor = null;
            c._localNode._successor = new ChordNode(new Peer(c._localNode.id(), null, dcStub), c, false);
            c.find_successor(c._localNode.id(), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_successor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.successor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().plus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
            c.find_predecessor(c._localNode.id().minus(3), function(err, res) {
                assert.equal(err, null);
                res.predecessor.should.equal(c._localNode.id());
            });
        });
    });
});
/*

    describe('joining', function() {
        it('should call success callback', function(done) {
            var s0 = {}, s1 = {};
            sinon.stub(s0, "connect");
            var c0 = new Chord(new BigInteger(0), s0);
            var c1 = new Chord(new BigInteger(10), s1);
            c0.join(c1.id(), function() {
                done();
            });
        });
    });
});
/*
                it('should fill complete finger table', function(done) {
                    var c1 = new Chord({}, new Sha1(), 5);
                    var c2 = new Chord({}, new Sha1(), 5);
                    c1.join(c2._localNode, function() {
                        / / TODO(max): check individual entries
assert.equal(Object.keys(c._fingerTable).length, 5);
done();
});
});
});
});

describe('Node', function() {
    describe('message handling', function() {
        it('should return successor', function(done) {
            var dcs = mock_dcs();
            var n_in = new ChordNode(0, null, null, dcs[0], null);
            var n_out = new ChordNode(1, null, null, dcs[1], null);
            n_in.find_successor(2, function(succ) {
                if (succ === null) {
                    done();
                }
            });
        });
        it('should handle unexpected requests gracefully', function() {
            var n = new ChordNode(0, null, null, {}, null);

            function msg(obj) {
                return {
                    data: JSON.stringify(obj)
                };
            }
            n._onmessage({
                data: "justastring"
            });
            n._onmessage(msg({}));
            n._onmessage(msg({
                type: 'hello'
            }));
            n._onmessage(msg({
                type: n.message_types.SUCCESSOR
            }));
            n._onmessage(msg({
                type: n.message_types.FIND_SUCCESSOR
            }));
        });
    });
    describe('get_node_id', function() {
        it('should return and set the correct ID', function(done) {
            var dcs = mock_dcs();
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInteger(1), null, null, dcs[1], null);
            n1.get_node_id(function(id) {
                assert.ok(id.equals(BigInteger(1)));
                assert.equal(n1._id, id);
                done();
            });

        });
        it('should return the same ID upon subsequent calls', function(done) {
            var dcs = mock_dcs();
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInt(1), null, null, dcs[1], null);
            var id1;
            n1.get_node_id(function(id) {
                id1 = id;
            });
            n1.get_node_id(function(id) {
                assert.equal(id, id1);
                done();
            });

        });
        it('should cache the ID', function() {
            var dcs = mock_dcs();
            sinon.spy(dcs[0], 'send');
            var n1 = new ChordNode(null, null, null, dcs[0], null);
            var n2 = new ChordNode(BigInt(1), null, null, dcs[1], null);
            n1.get_node_id(function() {});
            n1.get_node_id(function() {});
            assert.ok(dcs[0].send.calledOnce);
        });
    });
    describe('find_successor', function() {
        it('should send the correct message', function() {
            var dc = new DataChannel();
            var dcStub = sinon.stub(dc, 'send');
            var n = new ChordNode(0, null, null, dc, null);
            n.find_successor(1);
            sinon.assert.calledWith(dcStub, JSON.stringify({
                type: n.message_types.FIND_SUCCESSOR,
                id: "1",
                seqnr: 0
            }));
        });
        it('should call the correct callback upon arrival of the ID', function(done) {
            var dc = {};
            dc.send = function(msg) {
                var dec = JSON.parse(msg);
                if (dec.id === "2") {
                    setTimeout(function() {
                        dc.onmessage({
                            data: JSON.stringify({
                                type: Node.prototype.message_types.SUCCESSOR,
                                successor: 3,
                                seqnr: dec.seqnr
                            })
                        });
                    }, 10);
                } else if (dec.id === "1") {
                    setTimeout(function() {
                        dc.onmessage({
                            data: JSON.stringify({
                                type: Node.prototype.message_types.SUCCESSOR,
                                successor: 2,
                                seqnr: dec.seqnr
                            })
                        });
                    }, 20);
                }
            };
            var n = new ChordNode(0, null, null, dc, null);
            var oks = 0;

            function find_successor(id, expected) {
                n.find_successor(id, function(id) {
                    if (id === expected) {
                        if (oks === 1 && Object.keys(n._pending).length === 0) {
                            done();
                        } else {
                            oks += 1;
                        }
                    }
                });
            }
            find_successor(2, 3);
            find_successor(1, 2);
        });
    });
}); * /
*/
<|endoftext|>


<commit_before>var LOCAL_CONFIG = {
  appName: 'local',
  appVersion: '1',
  hardCodeStripe: true,
  stripePublicKey: '',
  stripePrivateKey: '',
  productionPaypal: false,
};

var DEV_CONFIG = {
  appName: 'lessig-trust-test',
  hardCodeStripe: true,
  stripePublicKey: '',
  stripePrivateKey: '',
  appVersion: '1',
  productionPaypal: false,
};

var STAGING_CONFIG = {
  appName: 'lessig-trust',
  appVersion: 'staging',
  productionPaypal: true,
};

var LESSIG_CONFIG = {
  appName: 'lessig-trust',
  appVersion: '1',
  productionPaypal: true,
};

var preprocessAppYaml = function(config) {
  return {
    src : [ 'build/app.yaml' ],
    options: { inline : true, context : config }
  };
};

var createConfigFile = function(config) {
  return {
    "build/config.json": function(fs, fd, done) {
      fs.writeSync(fd, JSON.stringify(config));
      done();
    }
  };
};

module.exports = function(grunt) {
  // configure the tasks
  grunt.initConfig({
    clean: {
      main: {
        src: [ 'build' ],
      },
    },

    copy: {
      main: {
        files: [
          {cwd: 'backend/', src: '**', dest: 'build/', expand: true },
          {cwd: 'lib/', src: '**', dest: 'build/', expand: true },
          {cwd: 'assets/', src: '**', dest: 'build/static/', expand: true },
          {cwd: 'jinja_templates', src: '**', dest: 'build/templates/', expand: true },
        ],
      },
    },

    preprocess: {
      local : preprocessAppYaml(LOCAL_CONFIG),
      dev: preprocessAppYaml(DEV_CONFIG),
      staging: preprocessAppYaml(STAGING_CONFIG),
      lessig: preprocessAppYaml(LESSIG_CONFIG),

    },

    jade: {
      compile: {
        options: {
          data: {
            debug: false
          }
        },
        files: [
          {cwd: 'markup/', src: '*.jade.j2', dest: 'build/templates/',
           expand: true, ext: '.html'},
          {cwd: 'markup/', src: '*.jade', dest: 'build/static/', expand: true,
           ext: '.html'},
        ]
      }
    },

    autoprefixer: {
      build: {
        expand: true,
        cwd: 'build/static/css/',
        src: [ '*.css' ],
        dest: 'build/static/css/'
      }
    },

    shell: {
      devserver: {
        command: 'dev_appserver.py --skip_sdk_update_check --host 0.0.0.0 --admin_host 0.0.0.0 build/',
        options: {
          async: true,
        },
      },
    },

    "file-creator": {
      local: createConfigFile(LOCAL_CONFIG),
      dev: createConfigFile(DEV_CONFIG),
      staging: createConfigFile(STAGING_CONFIG),
      lessig:createConfigFile(LESSIG_CONFIG)
    },

    watch: {
      markup: {
        files: 'markup/**',
        tasks: [ 'jade' ]
      },
      copy: {
        files: [ '{js/src,resources,assets,templates,backend}/**' ],
        tasks: [ 'copy', 'preprocess:local' ]
      }
    },
  });

  // load the tasks
  grunt.loadNpmTasks('grunt-autoprefixer');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-file-creator');
  grunt.loadNpmTasks('grunt-preprocess');
  grunt.loadNpmTasks('grunt-shell-spawn');

  // define the tasks
  grunt.registerTask(
    'build',
    'Compiles all of the assets and copies the files to the build directory.',
    [ 'clean', 'copy', 'jade']
  );
  grunt.registerTask(
    'local',
    'Builds, runs the local dev server, and watches for updates.',
    [ 'build', 'preprocess:local', 'file-creator:local',
      'shell:devserver', 'watch']
  );
  grunt.registerTask('dev', 'Builds for the DEV appengine environment.',
                     [ 'build', 'preprocess:dev', 'file-creator:dev' ]);
  grunt.registerTask('staging', 'Builds for the STAGING appengine environment.',
                     [ 'build', 'preprocess:staging', 'file-creator:staging' ]);
  grunt.registerTask('lessig', 'Builds the live lessig app.',
                     [ 'build', 'preprocess:lessig', 'file-creator:lessig' ]);

};
<commit_msg>stripe test key goes off datastore, take off gruntfile hardcode option<commit_after>var LOCAL_CONFIG = {
  appName: 'local',
  appVersion: '1',
  hardCodeStripe: true,
  stripePublicKey: '',
  stripePrivateKey: '',
  productionPaypal: false,
};

var DEV_CONFIG = {
  appName: 'lessig-trust-test',
  hardCodeStripe: false,
  stripePublicKey: '',
  stripePrivateKey: '',
  appVersion: '1',
  productionPaypal: false,
};

var STAGING_CONFIG = {
  appName: 'lessig-trust',
  appVersion: 'staging',
  productionPaypal: true,
};

var LESSIG_CONFIG = {
  appName: 'lessig-trust',
  appVersion: '1',
  productionPaypal: true,
};

var preprocessAppYaml = function(config) {
  return {
    src : [ 'build/app.yaml' ],
    options: { inline : true, context : config }
  };
};

var createConfigFile = function(config) {
  return {
    "build/config.json": function(fs, fd, done) {
      fs.writeSync(fd, JSON.stringify(config));
      done();
    }
  };
};

module.exports = function(grunt) {
  // configure the tasks
  grunt.initConfig({
    clean: {
      main: {
        src: [ 'build' ],
      },
    },

    copy: {
      main: {
        files: [
          {cwd: 'backend/', src: '**', dest: 'build/', expand: true },
          {cwd: 'lib/', src: '**', dest: 'build/', expand: true },
          {cwd: 'assets/', src: '**', dest: 'build/static/', expand: true },
          {cwd: 'jinja_templates', src: '**', dest: 'build/templates/', expand: true },
        ],
      },
    },

    preprocess: {
      local : preprocessAppYaml(LOCAL_CONFIG),
      dev: preprocessAppYaml(DEV_CONFIG),
      staging: preprocessAppYaml(STAGING_CONFIG),
      lessig: preprocessAppYaml(LESSIG_CONFIG),

    },

    jade: {
      compile: {
        options: {
          data: {
            debug: false
          }
        },
        files: [
          {cwd: 'markup/', src: '*.jade.j2', dest: 'build/templates/',
           expand: true, ext: '.html'},
          {cwd: 'markup/', src: '*.jade', dest: 'build/static/', expand: true,
           ext: '.html'},
        ]
      }
    },

    autoprefixer: {
      build: {
        expand: true,
        cwd: 'build/static/css/',
        src: [ '*.css' ],
        dest: 'build/static/css/'
      }
    },

    shell: {
      devserver: {
        command: 'dev_appserver.py --skip_sdk_update_check --host 0.0.0.0 --admin_host 0.0.0.0 build/',
        options: {
          async: true,
        },
      },
    },

    "file-creator": {
      local: createConfigFile(LOCAL_CONFIG),
      dev: createConfigFile(DEV_CONFIG),
      staging: createConfigFile(STAGING_CONFIG),
      lessig:createConfigFile(LESSIG_CONFIG)
    },

    watch: {
      markup: {
        files: 'markup/**',
        tasks: [ 'jade' ]
      },
      copy: {
        files: [ '{js/src,resources,assets,templates,backend}/**' ],
        tasks: [ 'copy', 'preprocess:local' ]
      }
    },
  });

  // load the tasks
  grunt.loadNpmTasks('grunt-autoprefixer');
  grunt.loadNpmTasks('grunt-contrib-clean');
  grunt.loadNpmTasks('grunt-contrib-copy');
  grunt.loadNpmTasks('grunt-contrib-jade');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-file-creator');
  grunt.loadNpmTasks('grunt-preprocess');
  grunt.loadNpmTasks('grunt-shell-spawn');

  // define the tasks
  grunt.registerTask(
    'build',
    'Compiles all of the assets and copies the files to the build directory.',
    [ 'clean', 'copy', 'jade']
  );
  grunt.registerTask(
    'local',
    'Builds, runs the local dev server, and watches for updates.',
    [ 'build', 'preprocess:local', 'file-creator:local',
      'shell:devserver', 'watch']
  );
  grunt.registerTask('dev', 'Builds for the DEV appengine environment.',
                     [ 'build', 'preprocess:dev', 'file-creator:dev' ]);
  grunt.registerTask('staging', 'Builds for the STAGING appengine environment.',
                     [ 'build', 'preprocess:staging', 'file-creator:staging' ]);
  grunt.registerTask('lessig', 'Builds the live lessig app.',
                     [ 'build', 'preprocess:lessig', 'file-creator:lessig' ]);

};
<|endoftext|>


<commit_before>/*
 * grunt-jira
 * https://github.com/shift/grunt-jira
 *
 * Copyright (c) 2013 Vincent Palmer
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    mochaTest: {
      test: {
        options: {
          reporter: 'spec',
          require: 'coverage/blanket',
          ui: 'bdd',
        },
        src: ['test/**/*.js']
      },
    },
    jshint: {
      all: [
        'Gruntfile.js',
        'tasks/*.js',
      ],
      options: {
        jshintrc: '.jshintrc',
      }
    },

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

    // Configuration to be run (and then tested).
    jira: {
      default_options: {
        options: {
        },
        files: {
          'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123'],
        },
      },
      custom_options: {
        options: {
          separator: ': ',
          punctuation: ' !!!',
        },
        files: {
          'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123'],
        },
      },
    },

    // 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-mocha-test');

  // 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', 'mochaTest']);

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

};
<commit_msg>Brought Gruntfile.js inline with previous changes.<commit_after>/*
 * grunt-jira
 * https://github.com/shift/grunt-jira
 *
 * Copyright (c) 2013 Vincent Palmer
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    mochaTest: {
      test: {
        options: {
          reporter: 'spec',
          ui: 'bdd',
        },
        src: ['test/**/*.js']
      },
    },
    jshint: {
      all: [
        'Gruntfile.js',
        'tasks/*.js',
      ],
      options: {
        jshintrc: '.jshintrc',
      }
    },

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

    // Configuration to be run (and then tested).
    jira: {
      default_options: {
        options: {
        },
        files: {
          'tmp/default_options': ['test/fixtures/testing', 'test/fixtures/123'],
        },
      },
      custom_options: {
        options: {
          separator: ': ',
          punctuation: ' !!!',
        },
        files: {
          'tmp/custom_options': ['test/fixtures/testing', 'test/fixtures/123'],
        },
      },
    },

    // 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-mocha-test');

  // 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', 'mochaTest']);

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

};
<|endoftext|>


<commit_before>/*!
 *
 * Grunt Task configuration for MY BIG project
 * David Gowrie <david@webmodia.com>
 * http://www.webmodia.com
 * Gruntfile.js
 *
 * Assumptions:
 * - Using Sass
 * - Enabled CSS source maps in Chrome
 */

'use strict';

/**
 * Livereload, Grunnt Connect, and server port variables
 *
 * Livereload default port: 35729
 * Custom ports allowed for multiple instances of Livereload on different ports
 * 'livereload' key:value option (incl those in watch task) should all reference the 'LIVERELOAD_PORT' var as the value
 *
 * Connect default server port: 9000
 * Custom port for multiple instances of connect server (be sure to configure custom livereload port as well)
 *
 */
var LIVERELOAD_PORT = 35729,
	lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}),
	mountFolder = function(connect, dir) {
		return connect.static(require('path').resolve(dir));
	};
var SERVER_PORT = 9000;

/**
 * Grunt module
 */
module.exports = function(grunt) {

	/**
	 * Dynamically load npm tasks
	 */
	require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

	/**
	 * Grunt config
	 */
	grunt.initConfig({

		//
		// Meta
		//

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

		/**
		 * Set project info
		 */
		project: {
			src: 			'src/',
			build: 			'build/',
			dist: 			'dist/',

			srcDirData:		'<%= project.src %>data/',
			srcDirFonts:	'<%= project.src %>fonts/',
			srcDirHtml: 	'<%= project.src %>html/',
			srcDirImgs:		'<%= project.src %>images/',
			srcDirJs: 		'<%= project.src %>javascript/',
			srcDirSass: 	'<%= project.src %>sass/',
			srcDirVdr:		'<%= project.src %>vendor/',
			srcScss: 		'<%= project.srcDirSass %>style.scss',

			buildAssets: 	'<%= project.build %>assets/',
			buildDirCss: 	'<%= project.buildAssets %>css/',
			buildDirData: 	'<%= project.buildAssets %>data/',
			buildDirFonts: 	'<%= project.buildAssets %>fonts/',
			buildDirImgs: 	'<%= project.buildAssets %>images/',
			buildDirJs: 	'<%= project.buildAssets %>js/',
			buildDirJsVdr: 	'<%= project.buildDirJs %>vendor/',

			distAssets: 	'<%= project.dist %>assets/',
			distDirCss: 	'<%= project.distAssets %>css/',
			distDirData: 	'<%= project.distAssets %>data/',
			distDirFonts: 	'<%= project.distAssets %>fonts/',
			distDirImgs: 	'<%= project.distAssets %>images/',
			distDirJs: 		'<%= project.distAssets %>js/',
			distDirJsVdr:	'<%= project.distDirJs %>vendor/'
		},

		/**
		 * Project banner
		 * Dynamically appended to styles/JS files
		 * Inherits text from package.json
		 */
		banner: '/*!\n' +
		' * <%= pkg.name %>\n' +
		' * <%= pkg.title %>\n' +
		' * <%= pkg.url %>\n' +
		' * @author <%= pkg.author %>\n' +
		' * @version <%= pkg.version %>\n' +
		' * Copyright (c) <%= grunt.template.today("yyyy") %>\n' +
		' */\n',

		//
		// Server Related Tasks
		//

		/**
		 * Connect port/livereload
		 * https://github.com/gruntjs/grunt-contrib-connect
		 * Starts a local webserver and injects
		 * Works in conjunction with livereload snippet
		 */
		connect: {
			options: {
				port: SERVER_PORT,
				hostname: '*'
			},
			livereload: {
				options: {
					middleware: function(connect) {
						return [
							lrSnippet,
							mountFolder(connect, 'build')
						];
					}
				}
			}
		},

		/**
		 * Opens the web server in the browser
		 * https://github.com/jsoverson/grunt-open
		 */
		open: {
			server: {
				path: 'http://localhost:<%= connect.options.port %>',
				app: 'Google Chrome'
			}
		},

		//
		// JS Tasks
		//

		/**
		 * JSHint
		 * https://github.com/gruntjs/grunt-contrib-jshint
		 * Manage the options inside .jshintrc file
		 */
		jshint: {
			files: ['<%= project.srcDirJs %>{,*/}*.js', 'Gruntfile.js'],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		/**
		 * Concatenate JavaScript files
		 * https://github.com/gruntjs/grunt-contrib-concat
		 * Imports and combines all JavaScript files into one
		 */
		concat: {
			dev: {
				files: {
					'<%= project.buildDirJs %>scripts.min.js': [ // appended with .min, but not minified for dev build
						'<%= project.srcDirJs %>{,*/}*.js'
						// more files added to array as needed
					]
				}
			},
			options: {
				stripBanners: true,
				nonull: true,
			}
		},

		/**
		 * Uglify (minify) JavaScript files
		 * https://github.com/gruntjs/grunt-contrib-uglify
		 * Compresses / minifies JavaScript build file, copies to dist JS dir and appends project banner
		 */
		uglify: {
			options: {
				preserveComments: false,
				banner: '<%= banner %>'
			},
			deploy: {
				files: {
				'<%= project.distDirJs %>scripts.min.js': '<%= project.buildDirJs %>scripts.min.js'
				}
			}
		},

		//
		// CSS Tasks
		//

		/**
		 * Compile Sass/SCSS files
		 * https://github.com/gruntjs/grunt-contrib-sass
		 * Compiles all Sass/SCSS files and appends project banner
		 */
		sass: {
			dev: {
				options: {
					style: 'expanded',
					lineNumbers: true,
					sourcemap: true
				},
				files: {
					'<%= project.buildDirCss %>style.unprefixed.css': '<%= project.srcScss %>'
				}
			}
		},

		/**
		 * Autoprefixer
		 * Adds vendor prefixes automatically
		 * https://github.com/nDmitry/grunt-autoprefixer
		 */
		autoprefixer: {
			options: {
				browsers: ['last 2 version', 'safari 6', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'],
				map: true
			},
			dev: {
				files: {
					'<%= project.buildDirCss %>style.css': ['<%= project.buildDirCss %>style.unprefixed.css']
				}
			}
		},

		/**
		 * CSSMin
		 * Minification of CSS build file, copies to dist CSS dir and appends project banner
		 * https://github.com/gruntjs/grunt-contrib-cssmin
		 */
		cssmin: {
			deploy: {
				options: {
					banner: '<%= banner %>'
				},
				files: {
					'<%= project.distDirCss %>style.css': ['<%= project.buildDirCss %>style.css']
				}
			}
		},

		//
		// Housekeeping
		//

		/**
		 * Copies files to the build & dist dirs
		 * Handles non-CSS and non-app.JS assets - e.g. HTML, images, vendor libs (optional), data (optonal)
		 * https://github.com/gruntjs/grunt-contrib-copy
		 */
		copy: {
			// From src dir to build dir
			toBuild: {
				files: [
					// data
					{
						cwd: '<%= project.srcDirData %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirData %>'
					},
					// fonts
					{
						cwd: '<%= project.srcDirFonts %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirFonts %>'
					},
					// html
					{
						cwd: '<%= project.srcDirHtml %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.build %>'
					},
					// images
					{
						cwd: '<%= project.srcDirImgs %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirImgs %>'
					},
					// vendor JS (libs)
					{
						cwd: '<%= project.srcDirVdr %>',
						expand: true,
						src: '{,*/}*.js',
						dest: '<%= project.buildDirJs %>vendor'
					}
				]
			},

			// From build dir to dist dir
			toDist: {
				files: [
					// data
					{
						cwd: '<%= project.buildDirImgs %>',
						expand: true,
						src: [
							'**/*'
							// more files added to array as needed
							],
						dest: '<%= project.distDirImgs %>'
					},
					// fonts
					{
						cwd: '<%= project.buildDirFonts %>',
						expand: true,
						src: [
							'**/*'
						],
						dest: '<%= project.distDirFonts %>'
					},
					// html
					{
						cwd: '<%= project.build %>',
						expand: true,
						src: [
							'{,*/}*.html'
						],
						dest: '<%= project.dist %>'
					},
					// images
					{
						cwd: '<%= project.buildDirImgs %>',
						expand: true,
						src: [
							'**/*'
							// more files added to array as needed
							],
						dest: '<%= project.distDirImgs %>'
					},
					// vendor JS (libs)
					{
						cwd: '<%= project.buildDirJsVdr %>',
						expand: true,
						src: '{,*/}*.js',
						dest: '<%= project.distDirJsVdr %>'
					}
				]
			}

		},

		/**
		 * Clean files and folders
		 * https://github.com/gruntjs/grunt-contrib-clean
		 * Remove generated files for clean deploy
		 */
		clean: {
			//build: ['<%= project.cssDir %>style.unprefixed.css', '<%= project.cssDir %>style.prefixed.css']
		},

		/**
		 * Runs tasks against changed watched files
		 * https://github.com/gruntjs/grunt-contrib-watch
		 * Watching development files and assets, run concat/compile and build tasks
		 * Livereload the browser once complete
		 */
		watch: {
			data: {
				files: ['<%= project.srcDirData %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			html: {
				files: ['<%= project.srcDirHtml %>{,*/}*.html'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			fonts: {
				files: ['<%= project.srcDirFonts %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			js: {
				files: ['<%= project.srcDirJs %>{,*/}*.js'],
				tasks: ['jshint', 'concat:dev'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			sass: {
				files: ['<%= project.srcDirSass %>{,*/}*.{scss,sass}'],
				tasks: ['sass:dev', 'autoprefixer:dev'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			vendor: {
				files: ['<%= project.srcDirVdr %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			livereload: {
				files: [
					'<%= project.build %>{,*/}*.html',
					'<%= project.buildAssets %>{,*/}*.{css, js}',
					'<%= project.buildAssets %>{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= project.buildDirData %>**/*'
				],
				options: {
					livereload: LIVERELOAD_PORT
				}
			}
		}
	});

	//
	// Tasks Registry
	//

	/**
	 * Default task
	 * Run `grunt` on the command line
	 */
	grunt.registerTask('default', ['copy:toBuild', 'sass:dev', 'autoprefixer:dev', 'jshint', 'concat:dev', 'connect:livereload', 'open', 'watch']);

	/**
	 * Deploy task
	 * Run `grunt deploy` on the command line
	 * Then compress all JS/CSS files
	 */
	grunt.registerTask('deploy', ['sass:dev', 'autoprefixer:dev', 'cssmin', 'jshint', 'concat:dev', 'uglify', 'copy:toDist']);
};
<commit_msg>Correcting data dir var for build process<commit_after>/*!
 *
 * Grunt Task configuration for MY BIG project
 * David Gowrie <david@webmodia.com>
 * http://www.webmodia.com
 * Gruntfile.js
 *
 * Assumptions:
 * - Using Sass
 * - Enabled CSS source maps in Chrome
 */

'use strict';

/**
 * Livereload, Grunnt Connect, and server port variables
 *
 * Livereload default port: 35729
 * Custom ports allowed for multiple instances of Livereload on different ports
 * 'livereload' key:value option (incl those in watch task) should all reference the 'LIVERELOAD_PORT' var as the value
 *
 * Connect default server port: 9000
 * Custom port for multiple instances of connect server (be sure to configure custom livereload port as well)
 *
 */
var LIVERELOAD_PORT = 35729,
	lrSnippet = require('connect-livereload')({port: LIVERELOAD_PORT}),
	mountFolder = function(connect, dir) {
		return connect.static(require('path').resolve(dir));
	};
var SERVER_PORT = 9000;

/**
 * Grunt module
 */
module.exports = function(grunt) {

	/**
	 * Dynamically load npm tasks
	 */
	require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);

	/**
	 * Grunt config
	 */
	grunt.initConfig({

		//
		// Meta
		//

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

		/**
		 * Set project info
		 */
		project: {
			src: 			'src/',
			build: 			'build/',
			dist: 			'dist/',

			srcDirData:		'<%= project.src %>data/',
			srcDirFonts:	'<%= project.src %>fonts/',
			srcDirHtml: 	'<%= project.src %>html/',
			srcDirImgs:		'<%= project.src %>images/',
			srcDirJs: 		'<%= project.src %>javascript/',
			srcDirSass: 	'<%= project.src %>sass/',
			srcDirVdr:		'<%= project.src %>vendor/',
			srcScss: 		'<%= project.srcDirSass %>style.scss',

			buildAssets: 	'<%= project.build %>assets/',
			buildDirCss: 	'<%= project.buildAssets %>css/',
			buildDirData: 	'<%= project.build %>data/',
			buildDirFonts: 	'<%= project.buildAssets %>fonts/',
			buildDirImgs: 	'<%= project.buildAssets %>images/',
			buildDirJs: 	'<%= project.buildAssets %>js/',
			buildDirJsVdr: 	'<%= project.buildDirJs %>vendor/',

			distAssets: 	'<%= project.dist %>assets/',
			distDirCss: 	'<%= project.distAssets %>css/',
			distDirData: 	'<%= project.dist %>data/',
			distDirFonts: 	'<%= project.distAssets %>fonts/',
			distDirImgs: 	'<%= project.distAssets %>images/',
			distDirJs: 		'<%= project.distAssets %>js/',
			distDirJsVdr:	'<%= project.distDirJs %>vendor/'
		},

		/**
		 * Project banner
		 * Dynamically appended to styles/JS files
		 * Inherits text from package.json
		 */
		banner: '/*!\n' +
		' * <%= pkg.name %>\n' +
		' * <%= pkg.title %>\n' +
		' * <%= pkg.url %>\n' +
		' * @author <%= pkg.author %>\n' +
		' * @version <%= pkg.version %>\n' +
		' * Copyright (c) <%= grunt.template.today("yyyy") %>\n' +
		' */\n',

		//
		// Server Related Tasks
		//

		/**
		 * Connect port/livereload
		 * https://github.com/gruntjs/grunt-contrib-connect
		 * Starts a local webserver and injects
		 * Works in conjunction with livereload snippet
		 */
		connect: {
			options: {
				port: SERVER_PORT,
				hostname: '*'
			},
			livereload: {
				options: {
					middleware: function(connect) {
						return [
							lrSnippet,
							mountFolder(connect, 'build')
						];
					}
				}
			}
		},

		/**
		 * Opens the web server in the browser
		 * https://github.com/jsoverson/grunt-open
		 */
		open: {
			server: {
				path: 'http://localhost:<%= connect.options.port %>',
				app: 'Google Chrome'
			}
		},

		//
		// JS Tasks
		//

		/**
		 * JSHint
		 * https://github.com/gruntjs/grunt-contrib-jshint
		 * Manage the options inside .jshintrc file
		 */
		jshint: {
			files: ['<%= project.srcDirJs %>{,*/}*.js', 'Gruntfile.js'],
			options: {
				jshintrc: '.jshintrc'
			}
		},

		/**
		 * Concatenate JavaScript files
		 * https://github.com/gruntjs/grunt-contrib-concat
		 * Imports and combines all JavaScript files into one
		 */
		concat: {
			dev: {
				files: {
					'<%= project.buildDirJs %>scripts.min.js': [ // appended with .min, but not minified for dev build
						'<%= project.srcDirJs %>{,*/}*.js'
						// more files added to array as needed
					]
				}
			},
			options: {
				stripBanners: true,
				nonull: true,
			}
		},

		/**
		 * Uglify (minify) JavaScript files
		 * https://github.com/gruntjs/grunt-contrib-uglify
		 * Compresses / minifies JavaScript build file, copies to dist JS dir and appends project banner
		 */
		uglify: {
			options: {
				preserveComments: false,
				banner: '<%= banner %>'
			},
			deploy: {
				files: {
				'<%= project.distDirJs %>scripts.min.js': '<%= project.buildDirJs %>scripts.min.js'
				}
			}
		},

		//
		// CSS Tasks
		//

		/**
		 * Compile Sass/SCSS files
		 * https://github.com/gruntjs/grunt-contrib-sass
		 * Compiles all Sass/SCSS files and appends project banner
		 */
		sass: {
			dev: {
				options: {
					style: 'expanded',
					lineNumbers: true,
					sourcemap: true
				},
				files: {
					'<%= project.buildDirCss %>style.unprefixed.css': '<%= project.srcScss %>'
				}
			}
		},

		/**
		 * Autoprefixer
		 * Adds vendor prefixes automatically
		 * https://github.com/nDmitry/grunt-autoprefixer
		 */
		autoprefixer: {
			options: {
				browsers: ['last 2 version', 'safari 6', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'],
				map: true
			},
			dev: {
				files: {
					'<%= project.buildDirCss %>style.css': ['<%= project.buildDirCss %>style.unprefixed.css']
				}
			}
		},

		/**
		 * CSSMin
		 * Minification of CSS build file, copies to dist CSS dir and appends project banner
		 * https://github.com/gruntjs/grunt-contrib-cssmin
		 */
		cssmin: {
			deploy: {
				options: {
					banner: '<%= banner %>'
				},
				files: {
					'<%= project.distDirCss %>style.css': ['<%= project.buildDirCss %>style.css']
				}
			}
		},

		//
		// Housekeeping
		//

		/**
		 * Copies files to the build & dist dirs
		 * Handles non-CSS and non-app.JS assets - e.g. HTML, images, vendor libs (optional), data (optonal)
		 * https://github.com/gruntjs/grunt-contrib-copy
		 */
		copy: {
			// From src dir to build dir
			toBuild: {
				files: [
					// data
					{
						cwd: '<%= project.srcDirData %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirData %>'
					},
					// fonts
					{
						cwd: '<%= project.srcDirFonts %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirFonts %>'
					},
					// html
					{
						cwd: '<%= project.srcDirHtml %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.build %>'
					},
					// images
					{
						cwd: '<%= project.srcDirImgs %>',
						expand: true,
						src: '**/*',
						dest: '<%= project.buildDirImgs %>'
					},
					// vendor JS (libs)
					{
						cwd: '<%= project.srcDirVdr %>',
						expand: true,
						src: '{,*/}*.js',
						dest: '<%= project.buildDirJs %>vendor'
					}
				]
			},

			// From build dir to dist dir
			toDist: {
				files: [
					// data
					{
						cwd: '<%= project.buildDirImgs %>',
						expand: true,
						src: [
							'**/*'
							// more files added to array as needed
							],
						dest: '<%= project.distDirImgs %>'
					},
					// fonts
					{
						cwd: '<%= project.buildDirFonts %>',
						expand: true,
						src: [
							'**/*'
						],
						dest: '<%= project.distDirFonts %>'
					},
					// html
					{
						cwd: '<%= project.build %>',
						expand: true,
						src: [
							'{,*/}*.html'
						],
						dest: '<%= project.dist %>'
					},
					// images
					{
						cwd: '<%= project.buildDirImgs %>',
						expand: true,
						src: [
							'**/*'
							// more files added to array as needed
							],
						dest: '<%= project.distDirImgs %>'
					},
					// vendor JS (libs)
					{
						cwd: '<%= project.buildDirJsVdr %>',
						expand: true,
						src: '{,*/}*.js',
						dest: '<%= project.distDirJsVdr %>'
					}
				]
			}

		},

		/**
		 * Clean files and folders
		 * https://github.com/gruntjs/grunt-contrib-clean
		 * Remove generated files for clean deploy
		 */
		clean: {
			//build: ['<%= project.cssDir %>style.unprefixed.css', '<%= project.cssDir %>style.prefixed.css']
		},

		/**
		 * Runs tasks against changed watched files
		 * https://github.com/gruntjs/grunt-contrib-watch
		 * Watching development files and assets, run concat/compile and build tasks
		 * Livereload the browser once complete
		 */
		watch: {
			data: {
				files: ['<%= project.srcDirData %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			html: {
				files: ['<%= project.srcDirHtml %>{,*/}*.html'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			fonts: {
				files: ['<%= project.srcDirFonts %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			js: {
				files: ['<%= project.srcDirJs %>{,*/}*.js'],
				tasks: ['jshint', 'concat:dev'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			sass: {
				files: ['<%= project.srcDirSass %>{,*/}*.{scss,sass}'],
				tasks: ['sass:dev', 'autoprefixer:dev'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			vendor: {
				files: ['<%= project.srcDirVdr %>**/*'],
				tasks: ['copy:toBuild'],
				options: {
					spawn: false,
					livereload: LIVERELOAD_PORT
				}
			},
			livereload: {
				files: [
					'<%= project.build %>{,*/}*.html',
					'<%= project.buildAssets %>{,*/}*.{css, js}',
					'<%= project.buildAssets %>{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
					'<%= project.buildDirData %>**/*'
				],
				options: {
					livereload: LIVERELOAD_PORT
				}
			}
		}
	});

	//
	// Tasks Registry
	//

	/**
	 * Default task
	 * Run `grunt` on the command line
	 */
	grunt.registerTask('default', ['copy:toBuild', 'sass:dev', 'autoprefixer:dev', 'jshint', 'concat:dev', 'connect:livereload', 'open', 'watch']);

	/**
	 * Deploy task
	 * Run `grunt deploy` on the command line
	 * Then compress all JS/CSS files
	 */
	grunt.registerTask('deploy', ['sass:dev', 'autoprefixer:dev', 'cssmin', 'jshint', 'concat:dev', 'uglify', 'copy:toDist']);
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import JSONClientSingleton from '../util/JSONClientSingleton'

import './SwitchRGBW.css';
import './SwitchOnOff.css';

class SwitchBlinds extends Component {

  constructor(props) {
    super(props);
    this.state = {
      color: ''
    }
    this.json = new JSONClientSingleton();
  }

  toggle = () => {
    if (this.props.readOnly) {
      return
    }
    let message = {
      type: 'command',
      param: 'switchlight',
      switchcmd: 'Toggle',
      idx: this.props.idx
    }
    this.json.get(message);
  }

  changeColor = (event) => {
    if (this.props.readOnly) {
      return
    }
    this.setState({color: event.target.value});
    let message = {
      type: 'command',
      param: 'setcolbrightnessvalue',
      idx: this.props.idx,
      hex: event.target.value.replace('#',''),
      brightness: 100,
      iswhite: false
    };
    this.json.get(message);
  }

  render() {
    const value = this.props.value === 0 ? 'Off' : 'On';
    return (

?

        <button onClick={this.toggle} className={'switch ' + value}>{this.props.label}</button>
        <input type="color" value={this.state.color ? this.state.color : '#000000'} onChange={this.changeColor}/>

    );
  }

}

export default SwitchBlinds
<commit_msg>Update SwitchRGBW.js<commit_after>import React, { Component } from 'react';
import JSONClientSingleton from '../util/JSONClientSingleton'

import './SwitchRGBW.css';
import './SwitchOnOff.css';

class SwitchRGBW extends Component {

  constructor(props) {
    super(props);
    this.state = {
      color: ''
    }
    this.json = new JSONClientSingleton();
  }

  toggle = () => {
    if (this.props.readOnly) {
      return
    }
    let message = {
      type: 'command',
      param: 'switchlight',
      switchcmd: 'Toggle',
      idx: this.props.idx
    }
    this.json.get(message);
  }

  changeColor = (event) => {
    if (this.props.readOnly) {
      return
    }
    this.setState({color: event.target.value});
    let message = {
      type: 'command',
      param: 'setcolbrightnessvalue',
      idx: this.props.idx,
      hex: event.target.value.replace('#',''),
      brightness: 100,
      iswhite: false
    };
    this.json.get(message);
  }

  render() {
    const value = this.props.value === 0 ? 'Off' : 'On';
    return (

?

        <button onClick={this.toggle} className={'switch ' + value}>{this.props.label}</button>
        <input type="color" value={this.state.color ? this.state.color : '#000000'} onChange={this.changeColor}/>

    );
  }

}

export default SwitchRGBW
<|endoftext|>


<commit_before>module.exports = function (grunt) {
	// load all grunt tasks matching the `grunt-*` pattern
	require('load-grunt-tasks')(grunt);

	grunt.initConfig({

		// Generates a POT file for translators.
		makepot: {
			target: {
				options: {
					type: 'wp-plugin',
					domainPath: 'languages',
					exclude: ['node_modules/.*']
				}
			}
		},

		// Creates an MD version of the README file
		wp_readme_to_markdown: {
			your_target: {
				files: {
					'README.md': 'README.txt'
				}
			}
		},

		// Deploys a new version to the svn WordPress.org repo.
		wp_deploy: {
			deploy: {
				options: {
					plugin_slug: 'comment-popularity',
					svn_user: 'pauldewouters',
					build_dir: 'build',
					assets_dir: 'wp-assets'
				}
			}
		}
	});

};<commit_msg>Add build tasks<commit_after>/* jshint node:true */

module.exports = function (grunt) {
	// load all grunt tasks matching the `grunt-*` pattern
	require('load-grunt-tasks')(grunt);

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

		jshint: {
			options: grunt.file.readJSON( '.jshintrc' ),
			grunt: {
				src: [
					'Gruntfile.js'
				]
			},
			plugin: {
				src: [
					'assets/js/voting.js'
				]
			}
		},

		uglify: {
			options: {
				preserveComments: 'some'
			},
			modules: {
				files: {
					'assets/js/modules/growl/javascripts/jquery.growl.min.js': ['assets/js/modules/growl/javascripts/jquery.growl.js']
				}
			},
			plugin: {
				files: {
					'assets/js/voting.min.js': ['assets/js/voting.js']
				}
			}
		},

		// Generates a POT file for translators.
		makepot: {
			target: {
				options: {
					type: 'wp-plugin',
					domainPath: 'languages',
					exclude: ['node_modules/.*'],
					processPot: function( pot, options ) {
						pot.headers['report-msgid-bugs-to'] = 'support@humanmade.co.uk';
						pot.headers['last-translator'] = 'Human Made Limited';
						pot.headers['language-team'] = 'Human Made Limited';
						return pot;
					}
				}
			}
		},

		// Creates an MD version of the README file
		wp_readme_to_markdown: {
			your_target: {
				files: {
					'README.md': 'README.txt'
				}
			}
		},

		shell: {
			commit: {
				command: 'git add . --all && git commit -m "Version <%= pkg.version %>"'
			},
			tag: {
				command: 'git tag -a <%= pkg.version %> -m "Version <%= pkg.version %>"'
			}
		},

		copy: {
			build: {
				files: [
					{
						expand: true,
						cwd: '.',
						src: [
							'**/*',
							'!**/.{svn,git,bowerrc,jshintrc,travis.yml,gitignore}/**',
							'!**/.DS_Store/**',
							'!**composer{.json,.lock}**',
							'!**package.json**',
							'!**Gruntfile.js**',
							'!**README.md**',
							'!**phpunit**',
							'!**/node_modules/**',
							'!**/wp-assets/**',
							'!**/tests/**',
							'!**/build/**',
							'!**/inc/lib/twig/twig/{test,doc}/**'
						],
						dest: 'build'
					}
				]
			}
		},

		clean:{
			build: {
				src: [ 'build' ]
			}
		},

		replace: {
			pluginsVersion: {
				src: [
					'comment-popularity.php'
				],
				overwrite: true,
				replacements: [ {
					from: /^Version: .*$/m,
					to: 'Version: <%= pkg.version %>'
				} ]
			},
			readmeVersion: {
				src: [
					'README.txt'
				],
				overwrite: true,
				replacements: [ {
					from: /^Stable tag: .*$/m,
					to: 'Stable tag: <%= pkg.version %>'
				} ]
			}
		},

		bump: {
			options: {
				files: [ 'package.json' ],
				updateConfigs: [ 'pkg' ],
				commit: false
			}
		},

		other: {
			changelog: 'changelog.md'
		},

		// Deploys a new version to the svn WordPress.org repo.
		wp_deploy: {
			deploy: {
				options: {
					plugin_slug: 'comment-popularity',
					svn_user: 'pauldewouters',
					build_dir: 'build',
					assets_dir: 'wp-assets'
				}
			}
		}

	});
	grunt.registerTask('minify', ['newer:uglify:modules','newer:uglify:plugin']);
	grunt.registerTask('lint', ['newer:jshint:grunt','newer:jshint:plugin']);

	// Top level function to build a new release
	grunt.registerTask( 'release', function( releaseType ) {
		if ( 'minor' !== releaseType && 'major' !== releaseType && 'patch' !== releaseType ) {
			grunt.fail.fatal( 'Please specify the release type (e.g., "grunt release:patch")' );
		} else {
			// Check to make sure the log exists
			grunt.task.run( 'log:' + releaseType );

			// Bump the version numbers
			grunt.task.run( 'bumpto:' + releaseType );

			// Create the .pot file
			grunt.task.run( 'makepot' );

			// Build the SASS and scripts
			grunt.task.run( 'default' );

			// Zip it up
			grunt.task.run( 'package' );

			// Commit and tag version update
			//grunt.task.run( 'shell:commit' );
			//grunt.task.run( 'shell:tag' );
		}
	} );

	// Default task(s).
	grunt.registerTask( 'default', [ 'minify', 'uglify' ] );

	// Bump the version to the specified value; e.g., "grunt bumpto:patch"
	grunt.registerTask( 'bumpto', function( releaseType ) {
		if ( 'minor' !== releaseType && 'major' !== releaseType && 'patch' !== releaseType ) {
			grunt.fail.fatal( 'Please specify the bump type (e.g., "grunt bumpto:patch")' );
		} else {
			grunt.task.run( 'bump-only:' + releaseType );

			// Update the version numbers
			grunt.task.run( 'replace' );
		}
	} );

	// Prompt for the changelog
	grunt.registerTask( 'log', function( releaseType ) {
		var semver = require( 'semver' ),
			changelog,
			newVersion = semver.inc( grunt.config.get( 'pkg' ).version, releaseType),
			regex = new RegExp( '^## ' + newVersion, 'gm' ); // Match the version number (e.g., "# 1.2.3")

		if ( 'minor' !== releaseType && 'major' !== releaseType && 'patch' !== releaseType ) {
			grunt.log.writeln().fail( 'Please choose a valid version type (minor, major, or patch)' );
		} else {
			// Get the new version
			changelog = grunt.file.read( grunt.config.get( 'other' ).changelog );

			if ( changelog.match( regex ) ) {
				grunt.log.ok( 'v' + newVersion + ' changlelog entry found' );
			} else {
				grunt.fail.fatal( 'Please enter a changelog entry for v' + newVersion );
			}
		}
	} );

	// Package a new release
	grunt.registerTask( 'package', [
		'copy:build',
		'compress:build',
		'clean:build'
	] );
};<|endoftext|>


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

  grunt.initConfig({

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

    concat: {
      options: {
        separator: "\n\n"
      },
      dist: {
        src: [
          'src/_intro.js',
          'src/main.js',
          'src/create.js',
          'src/layout.js',
          'src/loader.js',
          'src/getters-setters.js',
          'src/renderer.js',
          'src/_outro.js'
        ],
        dest: 'dist/<%= pkg.name.replace(".js", "") %>.js'
      }
    },

    uglify: {
      options: {
        banner: '/*! <%= pkg.name.replace(".js", "") %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      dist: {
        files: {
          'dist/<%= pkg.name.replace(".js", "") %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },

    qunit: {
      files: ['test/*.html']
    },

    jshint: {
      files: ['dist/threesixty.js'],
      options: {
        globals: {
          console: true,
          module: true,
          document: true
        },
        jshintrc: '.jshintrc'
      }
    },

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

  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('test', ['jshint', 'qunit']);
  grunt.registerTask('default', ['concat', 'qunit', 'uglify']);
  //grunt.registerTask('default', ['concat', 'jshint', 'qunit', 'uglify']);

};
<commit_msg>add ie9 requestAnimationFrame<commit_after>module.exports = function(grunt) {

  grunt.initConfig({

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

    concat: {
      options: {
        separator: "\n\n"
      },
      dist: {
        src: [
          'src/requestanimationframe.js',
          'src/_intro.js',
          'src/main.js',
          'src/create.js',
          'src/layout.js',
          'src/loader.js',
          'src/getters-setters.js',
          'src/renderer.js',
          'src/_outro.js'
        ],
        dest: 'dist/<%= pkg.name.replace(".js", "") %>.js'
      }
    },

    uglify: {
      options: {
        banner: '/*! <%= pkg.name.replace(".js", "") %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
      },
      dist: {
        files: {
          'dist/<%= pkg.name.replace(".js", "") %>.min.js': ['<%= concat.dist.dest %>']
        }
      }
    },

    qunit: {
      files: ['test/*.html']
    },

    jshint: {
      files: ['dist/threesixty.js'],
      options: {
        globals: {
          console: true,
          module: true,
          document: true
        },
        jshintrc: '.jshintrc'
      }
    },

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

  });

  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-qunit');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-concat');

  grunt.registerTask('test', ['jshint', 'qunit']);
  grunt.registerTask('default', ['concat', 'qunit', 'uglify']);
  //grunt.registerTask('default', ['concat', 'jshint', 'qunit', 'uglify']);

};
<|endoftext|>