<commit_before>"use strict";
define([
	'knockout',
	'd3',
	'd3-tip',
	'lodash',
	'd3-selection',
	'services/MomentAPI',
	'services/AuthAPI',
	'appConfig',
	'extensions/d3-labeler',
], function (
	ko,
	d3,
	d3tip,
	_,
	d3Selection,
	momentApi,
	authApi,
	config
) {

	function canViewProfileDates() {
		return config.viewProfileDates && (!config.userAuthenticationEnabled || (config.userAuthenticationEnabled && authApi.isPermittedViewProfileDates()));
	}

	var margin = {
		get top() {
			return canViewProfileDates() ? 30 : 10;
		},
		right: 20,
		bottom: 30,
		left: 20
	};

	var vizHeight = 200;
	var width = 900 - margin.left - margin.right;

	var xScale = d3.scaleLinear();
	var x2Scale = d3.scaleTime();
	var yScale = d3.scaleBand();

	var tipText = d => {
		return d.conceptName;
	};

	var htmlTipText = d => {
		var tipText = '
Event: ' + d.conceptName + '

Start Day: ' + d.startDay + '
';
		if (authApi.isPermittedViewProfileDates() && d.startDate != null) {
			tipText += '
Start Date: ' + momentApi.formatDate(new Date(d.startDate)) + '
'
		}
		return tipText;
	};
	var pointClass = d => d.domain;
	var radius = d => 2;

	var highlightFunc = () => {};
	var zoomDimension = null;
	var xfObservable = null;

	var focusTip = d3tip()
		.attr('class', 'd3-tip')
		.offset(function (d) {
			return [-10, 0];
		})
		.html(function (d) {
			return htmlTipText(d);
		});

	ko.bindingHandlers.profileChart = {
		init: function (element, valueAccessor, allBindingsAccessor) {
			valueAccessor().highlightRecs.subscribe(xfObservable => {
				highlightFunc(xfObservable);
			});
		},
		update: function (element, valueAccessor, allBindingsAccessor) {
			var va = valueAccessor();

			vizHeight = 250 - margin.top - margin.bottom;
			va.aspectRatio((vizHeight + margin.top + margin.bottom) / width);

			if (va.xfObservable() === undefined)
				return;

			if (width < 100)
				return;

			var svg = categoryScatterPlot(element,
				va.xfObservable,
				ko.utils.unwrapObservable(va.verticalLines || []),
				ko.utils.unwrapObservable(va.shadedRegions || []),
				va.xfDimensions
			);

			// maintain highlights
			valueAccessor().highlightRecs.valueHasMutated();
		}
	};

	function categoryScatterPlot(element, xfo, verticalLines, shadedRegions, xfd) {

		function rectangle(datum) {
			var minBoxPix = 5;
			var g = d3.select(this);
			g.selectAll('rect.point.' + pointClass(datum))
				.data([datum])
				.enter()
				.append('rect')
				.classed('point', true)
				.classed(pointClass(datum), true);
			g.selectAll('rect.point.' + pointClass(datum))
				.attr('height', minBoxPix)
				.attr('width', function (d) {
					return calculateWidth(d);
				})
				.attr('x', function (d) {
					return -minBoxPix / 2;
				})
				.attr('y', -minBoxPix / 2)
		}

		function brushEnded() {
			var s = d3.event.selection;
			if (s === null) {
				xfd[0].filter(null);
			} else {
				xfd[0].filterFunction(function (d) {
					return xScale.invert(s[0]) <= d.startDay && d.startDay <= xScale.invert(s[1]) ||
						xScale.invert(s[0]) <= d.endDay && d.endDay <= xScale.invert(s[1]);
				}); // start day
			}
			xfObservable.valueHasMutated();
		}

		var points = xfo().allFiltered();

		// prevent filtering to no data and error in chart
		if (points.length == 0) {
			xfd[0].filter(null);
			points = xfo().allFiltered();
		}

		var fullDomain = d3.extent([].concat.apply([], points.map(d => [d.startDay, d.endDay])));
		xScale.domain(fullDomain).range([0, width]);

		var fullDateDomain = d3.extent([].concat.apply([], points.map(d => [d.startDate, d.endDate])));
		x2Scale.domain(fullDateDomain).range([0, width]);

		xfObservable = xfo;
		var categories = _.chain(points).map(d => d.domain).uniq().value();
		yScale.domain(categories.sort())
			.range([0, vizHeight]);

		$(element).empty();

		var svg = d3.select(element).append("svg")
			.attr("preserveAspectRatio", "xMinYMin meet")
			.attr("viewBox", `0 0 ${width + margin.left + margin.right} ${vizHeight + margin.top + margin.bottom}`)

		var profilePlot = svg.append("g")
			.attr("class", "profilePlot")
			.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

		var xAxis = d3.axisBottom().scale(xScale);
		var x2Axis = d3.axisTop().scale(x2Scale);
		svg.call(focusTip);

		var letterSpacingScale = d3.scaleLog()
			.domain([.8, 20])
			.range([-.05, 2]);

		var fontSizeScale = d3.scalePow(1 / 2)
			.domain([10, vizHeight])
			.range([15, 75]);

		var categoryContainer = profilePlot.append("g");

		categoryContainer.selectAll('rect.category')
			.data(categories)
			.enter()
			.append('rect')
			.attr('class', 'category')
			.attr('width', width)
			.attr('height', yScale.bandwidth())
			.attr('y', d => yScale(d));

		profilePlot.selectAll('text.category')
			.data(categories)
			.enter()
			.append('text')
			.attr('class', 'category')
			.attr('font-size', fontSizeScale(yScale.bandwidth()))
			.attr('y', d => yScale(d) + yScale.bandwidth() / 2 + fontSizeScale(yScale.bandwidth()) / 2)
			.attr('x', width / 2)
			.attr('text-anchor', 'middle')
			.style('letter-spacing', 0)
			.text(d => d + 's')
			.style('letter-spacing', function (d) {
				var ratio = width / this.getBBox().width;
				var ls = letterSpacingScale(ratio);
				return ls + 'em';
			});

		var regions = profilePlot.selectAll('rect.shaded-region')
			.data(shadedRegions)
			.enter()
			.append('rect')
			.attr('class', function (sr) {
				return sr.className;
			})
			.classed('shaded-region', true);

		profilePlot.selectAll('rect.shaded-region')
			.attr('x', d => xScale(d.x1))
			.attr('y', yScale.range()[0])
			.attr('width', d => xScale(d.x2) - xScale(d.x1))
			.attr('height', yScale.range()[1])

		var vLines = profilePlot.selectAll('line.vertical')
			.data(verticalLines);
		vLines.exit().remove();
		vLines.enter()
			.append('line')
			.attr('class', 'vertical');

		profilePlot.selectAll('line.vertical')
			.attr('x1', d => xScale(d.x))
			.attr('x2', d => xScale(d.x))
			.attr('y1', yScale.range()[0])
			.attr('y2', yScale.range()[1])
			.style('stroke', d => d.color);

		var brush = d3.brushX().extent([
				[0, 0],
				[width, yScale.bandwidth() * categories.length]
			])
			.on("end", brushEnded);

		categoryContainer.append("g")
			.attr("class", "brush")
			.call(brush);

		var pointGs = profilePlot.selectAll("g.point")
			.data(points)
			.enter()
			.append("g")
			.classed('point', true);

		profilePlot.selectAll("g.point")
			.attr("transform", function (d, i) {
				return "translate(" + xScale(d.startDay) + "," + (yScale(d.domain) + jitter(i).y) + ")";
			})
			.attr('class', function (d) {
				return rectangle(d);
			})
			.classed('point', true)
			.on('mouseover', (d) => {
				d3Selection.event = d3.event; // otherwise, d3Selection.event is null
				return focusTip.show(d);
			})
			.on('mouseout', focusTip.hide)
			.each(rectangle)

		if (points.length <= 50) {
			// labeler usage from https://github.com/tinker10/D3-Labeler demo
			var label_array = points.map((d, i) => {
				d.x = xScale(d.startDay) + jitter(i).x;
				d.y = yScale(d.domain) + jitter(i).y;
				d.r = 8;
				return {
					x: d.x,
					y: d.y,
					name: tipText(d),
					width: 0,
					height: 0,
					rec: d,
				};
			});
			var labels = profilePlot.selectAll('.labels')
				.data(label_array)
				.enter()
				.append('text')
				.attr('class', 'label')
				.attr('text-anchor', 'start')
				.text(d => d.name)
				.attr('x', d => d.x)
				.attr('y', d => d.y)
				.attr('fill', 'black');
			var index = 0;
			labels.each(function () {
				label_array[index].width = this.getBBox().width;
				label_array[index].height = this.getBBox().height;
				index += 1;
			});
			var links = profilePlot.selectAll('.link')
				.data(label_array)
				.enter()
				.append('line')
				.attr('class', 'link')
				.attr('x1', d => d.x)
				.attr('y1', d => d.y)
				.attr('x2', d => d.x)
				.attr('y2', d => d.y)
			var sim_ann = d3.labeler()
				.label(label_array)
				.anchor(points)
				.width(width)
				.height(vizHeight)
				.start();

			labels.attr('x', d => d.x)
				.attr('y', d => d.y);
			links.attr('x2', d => d.x)
				.attr('y2', d => d.y);
		}

		function addAxis(axis, top) {
			profilePlot.append("g")
				.attr("class", "x axis")
				.attr("transform", "translate(0," + top + ")")
				.call(axis);
		}

		addAxis(xAxis, vizHeight + 2);

		if (canViewProfileDates()) {
			addAxis(x2Axis, 0);
		}

		highlightFunc = function () {
			pointGs.selectAll('rect')
				.style('fill', function (d) {
					return d.highlight;
				})
				.style('stroke', function (d) {
					return d.stroke;
				});
		};
		return svg;
	}

	function calculateWidth(d) {
		var minBoxPix = 5;
		var startDayX = xScale(d.startDay);
		var endDayX = xScale(d.endDay);
		var daysX = Math.abs(startDayX - endDayX);
		return Math.max(minBoxPix, daysX);
	}

	var jitterOffsets = []; // keep them stable as points move around
	var jitterYScale = d3.scaleLinear().domain([-.5, .5]);

	function jitter(i, maxX = 6, maxY = 12) {
		jitterYScale.range([yScale.bandwidth() * .1, yScale.bandwidth() * .9]);
		jitterOffsets[i] = jitterOffsets[i] || [Math.random() - .5, Math.random() - .5];
		return {
			x: jitterOffsets[i][0] * maxX,
			y: jitterYScale(jitterOffsets[i][1])
		};
	}

	function makeFilter(ext) {
		var filter = function ([start, end] = []) {
			return (
				(start >= ext[0] && start <= ext[1]) ||
				(end >= ext[0] && end <= ext[1]) ||
				(start <= ext[0] && end >= ext[1])
			);
		};
		filter.ext = () => ext;
		return filter;
	}
});<commit_msg>Fixed Profiles strict mode (#1462)<commit_after>define([
	'knockout',
	'd3',
	'd3-tip',
	'lodash',
	'd3-selection',
	'services/MomentAPI',
	'services/AuthAPI',
	'appConfig',
	'extensions/d3-labeler',
], function (
	ko,
	d3,
	d3tip,
	_,
	d3Selection,
	momentApi,
	authApi,
	config
) {
	"use strict";

	function canViewProfileDates() {
		return config.viewProfileDates && (!config.userAuthenticationEnabled || (config.userAuthenticationEnabled && authApi.isPermittedViewProfileDates()));
	}

	var margin = {
		get top() {
			return canViewProfileDates() ? 30 : 10;
		},
		right: 20,
		bottom: 30,
		left: 20
	};

	var vizHeight = 200;
	var width = 900 - margin.left - margin.right;

	var xScale = d3.scaleLinear();
	var x2Scale = d3.scaleTime();
	var yScale = d3.scaleBand();

	var tipText = d => {
		return d.conceptName;
	};

	var htmlTipText = d => {
		var tipText = '
Event: ' + d.conceptName + '

Start Day: ' + d.startDay + '
';
		if (authApi.isPermittedViewProfileDates() && d.startDate != null) {
			tipText += '
Start Date: ' + momentApi.formatDate(new Date(d.startDate)) + '
'
		}
		return tipText;
	};
	var pointClass = d => d.domain;
	var radius = d => 2;

	var highlightFunc = () => {};
	var zoomDimension = null;
	var xfObservable = null;

	var focusTip = d3tip()
		.attr('class', 'd3-tip')
		.offset(function (d) {
			return [-10, 0];
		})
		.html(function (d) {
			return htmlTipText(d);
		});

	ko.bindingHandlers.profileChart = {
		init: function (element, valueAccessor, allBindingsAccessor) {
			valueAccessor().highlightRecs.subscribe(xfObservable => {
				highlightFunc(xfObservable);
			});
		},
		update: function (element, valueAccessor, allBindingsAccessor) {
			var va = valueAccessor();

			vizHeight = 250 - margin.top - margin.bottom;
			va.aspectRatio((vizHeight + margin.top + margin.bottom) / width);

			if (va.xfObservable() === undefined)
				return;

			if (width < 100)
				return;

			var svg = categoryScatterPlot(element,
				va.xfObservable,
				ko.utils.unwrapObservable(va.verticalLines || []),
				ko.utils.unwrapObservable(va.shadedRegions || []),
				va.xfDimensions
			);

			// maintain highlights
			valueAccessor().highlightRecs.valueHasMutated();
		}
	};

	function categoryScatterPlot(element, xfo, verticalLines, shadedRegions, xfd) {

		function rectangle(datum) {
			var minBoxPix = 5;
			var g = d3.select(this);
			g.selectAll('rect.point.' + pointClass(datum))
				.data([datum])
				.enter()
				.append('rect')
				.classed('point', true)
				.classed(pointClass(datum), true);
			g.selectAll('rect.point.' + pointClass(datum))
				.attr('height', minBoxPix)
				.attr('width', function (d) {
					return calculateWidth(d);
				})
				.attr('x', function (d) {
					return -minBoxPix / 2;
				})
				.attr('y', -minBoxPix / 2)
		}

		function brushEnded() {
			var s = d3.event.selection;
			if (s === null) {
				xfd[0].filter(null);
			} else {
				xfd[0].filterFunction(function (d) {
					return xScale.invert(s[0]) <= d.startDay && d.startDay <= xScale.invert(s[1]) ||
						xScale.invert(s[0]) <= d.endDay && d.endDay <= xScale.invert(s[1]);
				}); // start day
			}
			xfObservable.valueHasMutated();
		}

		var points = xfo().allFiltered();

		// prevent filtering to no data and error in chart
		if (points.length == 0) {
			xfd[0].filter(null);
			points = xfo().allFiltered();
		}

		var fullDomain = d3.extent([].concat.apply([], points.map(d => [d.startDay, d.endDay])));
		xScale.domain(fullDomain).range([0, width]);

		var fullDateDomain = d3.extent([].concat.apply([], points.map(d => [d.startDate, d.endDate])));
		x2Scale.domain(fullDateDomain).range([0, width]);

		xfObservable = xfo;
		var categories = _.chain(points).map(d => d.domain).uniq().value();
		yScale.domain(categories.sort())
			.range([0, vizHeight]);

		$(element).empty();

		var svg = d3.select(element).append("svg")
			.attr("preserveAspectRatio", "xMinYMin meet")
			.attr("viewBox", `0 0 ${width + margin.left + margin.right} ${vizHeight + margin.top + margin.bottom}`)

		var profilePlot = svg.append("g")
			.attr("class", "profilePlot")
			.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

		var xAxis = d3.axisBottom().scale(xScale);
		var x2Axis = d3.axisTop().scale(x2Scale);
		svg.call(focusTip);

		var letterSpacingScale = d3.scaleLog()
			.domain([.8, 20])
			.range([-.05, 2]);

		var fontSizeScale = d3.scalePow(1 / 2)
			.domain([10, vizHeight])
			.range([15, 75]);

		var categoryContainer = profilePlot.append("g");

		categoryContainer.selectAll('rect.category')
			.data(categories)
			.enter()
			.append('rect')
			.attr('class', 'category')
			.attr('width', width)
			.attr('height', yScale.bandwidth())
			.attr('y', d => yScale(d));

		profilePlot.selectAll('text.category')
			.data(categories)
			.enter()
			.append('text')
			.attr('class', 'category')
			.attr('font-size', fontSizeScale(yScale.bandwidth()))
			.attr('y', d => yScale(d) + yScale.bandwidth() / 2 + fontSizeScale(yScale.bandwidth()) / 2)
			.attr('x', width / 2)
			.attr('text-anchor', 'middle')
			.style('letter-spacing', 0)
			.text(d => d + 's')
			.style('letter-spacing', function (d) {
				var ratio = width / this.getBBox().width;
				var ls = letterSpacingScale(ratio);
				return ls + 'em';
			});

		var regions = profilePlot.selectAll('rect.shaded-region')
			.data(shadedRegions)
			.enter()
			.append('rect')
			.attr('class', function (sr) {
				return sr.className;
			})
			.classed('shaded-region', true);

		profilePlot.selectAll('rect.shaded-region')
			.attr('x', d => xScale(d.x1))
			.attr('y', yScale.range()[0])
			.attr('width', d => xScale(d.x2) - xScale(d.x1))
			.attr('height', yScale.range()[1])

		var vLines = profilePlot.selectAll('line.vertical')
			.data(verticalLines);
		vLines.exit().remove();
		vLines.enter()
			.append('line')
			.attr('class', 'vertical');

		profilePlot.selectAll('line.vertical')
			.attr('x1', d => xScale(d.x))
			.attr('x2', d => xScale(d.x))
			.attr('y1', yScale.range()[0])
			.attr('y2', yScale.range()[1])
			.style('stroke', d => d.color);

		var brush = d3.brushX().extent([
				[0, 0],
				[width, yScale.bandwidth() * categories.length]
			])
			.on("end", brushEnded);

		categoryContainer.append("g")
			.attr("class", "brush")
			.call(brush);

		var pointGs = profilePlot.selectAll("g.point")
			.data(points)
			.enter()
			.append("g")
			.classed('point', true);

		profilePlot.selectAll("g.point")
			.attr("transform", function (d, i) {
				return "translate(" + xScale(d.startDay) + "," + (yScale(d.domain) + jitter(i).y) + ")";
			})
			.attr('class', function (d) {
				return rectangle(d);
			})
			.classed('point', true)
			.on('mouseover', (d) => {
				d3Selection.event = d3.event; // otherwise, d3Selection.event is null
				return focusTip.show(d);
			})
			.on('mouseout', focusTip.hide)
			.each(rectangle)

		if (points.length <= 50) {
			// labeler usage from https://github.com/tinker10/D3-Labeler demo
			var label_array = points.map((d, i) => {
				d.x = xScale(d.startDay) + jitter(i).x;
				d.y = yScale(d.domain) + jitter(i).y;
				d.r = 8;
				return {
					x: d.x,
					y: d.y,
					name: tipText(d),
					width: 0,
					height: 0,
					rec: d,
				};
			});
			var labels = profilePlot.selectAll('.labels')
				.data(label_array)
				.enter()
				.append('text')
				.attr('class', 'label')
				.attr('text-anchor', 'start')
				.text(d => d.name)
				.attr('x', d => d.x)
				.attr('y', d => d.y)
				.attr('fill', 'black');
			var index = 0;
			labels.each(function () {
				label_array[index].width = this.getBBox().width;
				label_array[index].height = this.getBBox().height;
				index += 1;
			});
			var links = profilePlot.selectAll('.link')
				.data(label_array)
				.enter()
				.append('line')
				.attr('class', 'link')
				.attr('x1', d => d.x)
				.attr('y1', d => d.y)
				.attr('x2', d => d.x)
				.attr('y2', d => d.y)
			var sim_ann = d3.labeler()
				.label(label_array)
				.anchor(points)
				.width(width)
				.height(vizHeight)
				.start();

			labels.attr('x', d => d.x)
				.attr('y', d => d.y);
			links.attr('x2', d => d.x)
				.attr('y2', d => d.y);
		}

		function addAxis(axis, top) {
			profilePlot.append("g")
				.attr("class", "x axis")
				.attr("transform", "translate(0," + top + ")")
				.call(axis);
		}

		addAxis(xAxis, vizHeight + 2);

		if (canViewProfileDates()) {
			addAxis(x2Axis, 0);
		}

		highlightFunc = function () {
			pointGs.selectAll('rect')
				.style('fill', function (d) {
					return d.highlight;
				})
				.style('stroke', function (d) {
					return d.stroke;
				});
		};
		return svg;
	}

	function calculateWidth(d) {
		var minBoxPix = 5;
		var startDayX = xScale(d.startDay);
		var endDayX = xScale(d.endDay);
		var daysX = Math.abs(startDayX - endDayX);
		return Math.max(minBoxPix, daysX);
	}

	var jitterOffsets = []; // keep them stable as points move around
	var jitterYScale = d3.scaleLinear().domain([-.5, .5]);

	function jitter(i, maxX = 6, maxY = 12) {
		jitterYScale.range([yScale.bandwidth() * .1, yScale.bandwidth() * .9]);
		jitterOffsets[i] = jitterOffsets[i] || [Math.random() - .5, Math.random() - .5];
		return {
			x: jitterOffsets[i][0] * maxX,
			y: jitterYScale(jitterOffsets[i][1])
		};
	}

	function makeFilter(ext) {
		var filter = function ([start, end] = []) {
			return (
				(start >= ext[0] && start <= ext[1]) ||
				(end >= ext[0] && end <= ext[1]) ||
				(start <= ext[0] && end >= ext[1])
			);
		};
		filter.ext = () => ext;
		return filter;
	}
});<|endoftext|>


<commit_before>// Copyright 2002-2015, University of Colorado Boulder

/**
 * This grunt task generates a markdown form of sherpa/third-party-licenses.json.
 *
 * @author Aaron Davis
 */

// modules
var child_process = require( 'child_process' );
var assert = require( 'assert' );

// constants
var OUTPUT_FILE = 'info.md';
var SHERPA = '../sherpa';

/**
 * @param grunt the grunt instance
 */
module.exports = function( grunt ) {
  'use strict';

  var json = grunt.file.readJSON( SHERPA + '/third-party-licenses.json' );
  var i;

  var columnHeaders = [ 'Library', 'Website', 'License', 'License URL (if different than project website)', 'Text', 'How is it used in sims?' ];
  var headerDelimiters = [];
  for ( i = 0; i < columnHeaders.length; i++ ) {
    headerDelimiters.push( '------' );
  }
  var output = columnHeaders.join( '|' ) + '\n' + headerDelimiters.join( '|' );

  var rows = [];

  for ( var library in json ) {
    var text = json[ library ].text.join( '
' );
    var license = json[ library ].license;
    var projectURL = json[ library ].projectURL;
    var notes = json[ library ].notes;
    var licenseURL = json[ library ].licenseURL;
    rows.push( [ library, projectURL ? projectURL : '', license, licenseURL ? licenseURL : '', text, notes ] );
  }

  for ( i = 0; i < rows.length; i++ ) {
    var row = rows[ i ];
    output += '\n' + row.join( '|' );
  }

  grunt.log.writeln( 'writing file ' + OUTPUT_FILE );
  grunt.file.write( SHERPA + '/' + OUTPUT_FILE, output );

  var done = grunt.task.current.async();

  // exec a command in the sherpa directory
  var exec = function( command, callback ) {
    child_process.exec( command, { cwd: SHERPA }, function( err, stdout, stderr ) {
      grunt.log.writeln( stdout );
      grunt.log.writeln( stderr );
      assert( !err, 'assertion error running ' + command );
      callback();
    } );
  };

  exec( 'git add ' + OUTPUT_FILE, function() {
    exec( 'git commit --message "update info.md"', function() {
      exec( 'git push', function() {
        done();
      } );
    } );
  } );

};
<commit_msg>Converted from table output to entry-by-entry, see https://github.com/phetsims/sherpa/issues/22<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 * This grunt task generates a markdown form of sherpa/third-party-licenses.json.
 *
 * @author Aaron Davis
 */

// constants
var SHERPA = '../sherpa';

/**
 * @param grunt the grunt instance
 */
module.exports = function( grunt ) {
  'use strict';

  var json = grunt.file.readJSON( SHERPA + '/third-party-licenses.json' );

  var entries = [];

  for ( var library in json ) {
    var lines = [
      '**' + library + '**',
      '*' + json[ library ].text.join( '
' ) + '*',
      json[ library ].projectURL,
      '- ' + json[ library ].license + '  ' + json[ library ].licenseURL,
      '- ' + json[ library ].notes
    ];

    entries.push( lines.join( '\n' ) );
    //output += '*' + library + '*';
    //var text = json[ library ].text.join( '
' );
    //var license = json[ library ].license;
    //var projectURL = json[ library ].projectURL;
    //var notes = json[ library ].notes;
    //var licenseURL = json[ library ].licenseURL;
    //rows.push( [ library, projectURL ? projectURL : '', license, licenseURL ? licenseURL : '', text, notes ] );
  }

  var output = entries.join( '\n\n' );
  //for ( i = 0; i < entr.length; i++ ) {
  //  var row = rows[ i ];
  //  output += '\n' + row.join( '|' );
  //}
  console.log( '!!!!!!' );
  console.log( output );
  console.log( '!!!!!!' );

  //grunt.log.writeln( 'writing file ' + OUTPUT_FILE );
  //grunt.file.write( SHERPA + '/' + OUTPUT_FILE, output );
  //
  //var done = grunt.task.current.async();
  //
  //// exec a command in the sherpa directory
  //var exec = function( command, callback ) {
  //  child_process.exec( command, { cwd: SHERPA }, function( err, stdout, stderr ) {
  //    grunt.log.writeln( stdout );
  //    grunt.log.writeln( stderr );
  //    assert( !err, 'assertion error running ' + command );
  //    callback();
  //  } );
  //};
  //
  //exec( 'git add ' + OUTPUT_FILE, function() {
  //  exec( 'git commit --message "update info.md"', function() {
  //    exec( 'git push', function() {
  //      done();
  //    } );
  //  } );
  //} );

};
<|endoftext|>


<commit_before>/**
 * Services for the Metrics Manager.
 * Those factories provide adapters for the RESTful API of the Metrics Manager.
 * They are built on top of AngularJS' Resource module.
 */

// As the API does not allow to not-paginate, we simply put in a large number
// as page_size.
var LARGE_NUMBER = 100000;

angular.module('pcApp.metrics.services.metric', [
    'ngResource', 'pcApp.config'
])

/**
 * Factory for the Resource for metrics
 */
    .factory('MetricService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.METRICS_MANAGER_URL + "/metrics/:id";
            var Metric = $resource(url, {
                id: "@id"
            }, {
                // Add support for update
                'update': {method: 'PUT'},
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Metric;
        }
    ])

/**
 * Factory for getting an Indicator, which connects to the Indicator endpoint
 * FIX ME: Should I use the Service from the indicator app?
 */
    .factory('IndicatorService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.INDICATOR_SERVICE_URL + "/indicators/:id";
            var Indicator = $resource(url, {
                id: "@id",
                page_size: LARGE_NUMBER
            }, {
                'update': {method: 'PUT'},
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Indicator;
        }
    ])

/**
 * Factory to get Normalizers
 *
 */
    .factory('NormalizerService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.NORMALIZERS_URL;
            var Normalizer = $resource(url, {
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Normalizer;
        }
    ])

/**
 * Factory to get create formula
 *
 */
    .factory('FormulaHelper', ['$http', 'API_CONF', function ($http, API_CONF) {
        var helper = {
            formula: "",
            variableIndex: 1,
            variables: {},
            cursorPosition: undefined,
        };

        helper.reset = function(formula, variables) {
            this.formula = formula || "";
            this.variables = variables || {};
            this.variableIndex = variables ? Object.keys(variables).length + 1 : 1;
            this.cursorPosition = undefined;
        };

        helper.updateCursor = function (event) {
            var oField = event.target;
            var iCaretPos = 0;

            // IE Support
            if (document.selection) {
                oField.focus();
                var oSel = document.selection.createRange();
                oSel.moveStart('character', -oField.value.length);
                iCaretPos = oSel.text.length;
            }

            else if (oField.selectionStart || oField.selectionStart == '0') {
                iCaretPos = oField.selectionStart;
            }
            this.cursorPosition = iCaretPos;
        };

        helper.addIndicator = function (indicator) {
            var i = "__" + this.variableIndex + "__";
            var cursorPosition = this.cursorPosition;
            if (angular.isUndefined(cursorPosition)) {
                this.formula = this.formula + i;
            } else {
                this.formula = [
                    this.formula.slice(0, cursorPosition),
                    i,
                    this.formula.slice(cursorPosition)
                ].join('');
            }
            this.variableIndex += 1;
            this.variables[i] = {
                "type": "indicator",
                "id": indicator.id,
            };
        };

        helper.validate = function() {
            var url = API_CONF.FORMULA_VALIDATION_URL;
            return $http({
                url: url,
                method: 'get',
                params: {
                    formula: this.formula,
                    variables: this.variables
                }
            });
        }

        return helper;
    }])

/**
 * Factory to create Metric using a wizard
 */
    .factory('MetricsControllerHelper', [
        'IndicatorService', 'NormalizerService', 'FormulaHelper',
        function (IndicatorService, NormalizerService, FormulaHelper) {

            var helper = {
                metricsdata: {
                    title: "",
                    formula: "",
                    description: "",
                    keywords: "",
                    variableIndex: 1,
                    variables: {}
                }
            };

            helper.clear = function () {
                helper.metricsdata = {
                    title: "",
                    formula: "",
                    description: "",
                    keywords: "",
                    variableIndex: 1,
                    variables: {}
                };
            }

            helper.init = function () {
                if (!helper.metricsdata) {
                    helper.clear();
                }

                var indicators = IndicatorService.query(function () {
                    helper.indicators = _.map(indicators.results, function (indicator) {
                        return {
                            name: indicator.name,
                            unit_category: indicator.unit_category,
                            id: indicator.id,
                            date: indicator.modified
                        };
                    });
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });

                helper.normalizers = NormalizerService.query(function () {
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });
            }

            helper.getFormulaHelper = function() {
                var formulaHelper = FormulaHelper;
                formulaHelper.reset(this.metricsdata.formula, this.metricsdata.variables);
                return formulaHelper;
            }

            return helper;
        }
    ])

/**
 * Factory to operationalize Metric using a wizard
 */
    .factory('ApplyMetricHelper', [
        'MetricService', 'IndicatorService', function (MetricService, IndicatorService) {

            var datasets = {};
            var _metric_id;

            datasets.clear = function () {
                datasets.data = {
                    title: "",
                    unit_id: "",
                    datasets: []
                };
            }

            datasets.getDatasets = function (metric_id) {
                datasets.metric = MetricService.get({id: metric_id}, function (metric) {
                    var variablesJson = datasets.metric.variables;
                    _.each(variablesJson, function (value, key) {
                        datasets.data.datasets.push({
                            variable: key.trim(),
                            dataset: -1,
                            indicator: value.id
                        });
                    });
                    IndicatorService.get({id: metric.indicator_id}, function (indicator) {
                        datasets.unit_category_id = indicator.unit_category;
                    });
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });
            }

            datasets.init = function (metric_id) {

                if (_metric_id !== metric_id) {
                    _metric_id = metric_id;

                    datasets.clear();
                    datasets.getDatasets(metric_id);
                }
            };
            return datasets;
        }
    ]);
<commit_msg>Ensure formula is never undefined<commit_after>/**
 * Services for the Metrics Manager.
 * Those factories provide adapters for the RESTful API of the Metrics Manager.
 * They are built on top of AngularJS' Resource module.
 */

// As the API does not allow to not-paginate, we simply put in a large number
// as page_size.
var LARGE_NUMBER = 100000;

angular.module('pcApp.metrics.services.metric', [
    'ngResource', 'pcApp.config'
])

/**
 * Factory for the Resource for metrics
 */
    .factory('MetricService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.METRICS_MANAGER_URL + "/metrics/:id";
            var Metric = $resource(url, {
                id: "@id"
            }, {
                // Add support for update
                'update': {method: 'PUT'},
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Metric;
        }
    ])

/**
 * Factory for getting an Indicator, which connects to the Indicator endpoint
 * FIX ME: Should I use the Service from the indicator app?
 */
    .factory('IndicatorService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.INDICATOR_SERVICE_URL + "/indicators/:id";
            var Indicator = $resource(url, {
                id: "@id",
                page_size: LARGE_NUMBER
            }, {
                'update': {method: 'PUT'},
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Indicator;
        }
    ])

/**
 * Factory to get Normalizers
 *
 */
    .factory('NormalizerService', [
        '$resource', 'API_CONF', function ($resource, API_CONF) {
            // Get the base URL from the configuration
            var url = API_CONF.NORMALIZERS_URL;
            var Normalizer = $resource(url, {
                'query': {
                    method: 'GET',
                    isArray: false
                }
            });
            return Normalizer;
        }
    ])

/**
 * Factory to get create formula
 *
 */
    .factory('FormulaHelper', ['$http', 'API_CONF', function ($http, API_CONF) {
        var helper = {
            formula: "",
            variableIndex: 1,
            variables: {},
            cursorPosition: undefined,
        };

        helper.reset = function(formula, variables) {
            this.formula = formula || "";
            this.variables = variables || {};
            this.variableIndex = variables ? Object.keys(variables).length + 1 : 1;
            this.cursorPosition = undefined;
        };

        helper.updateCursor = function (event) {
            var oField = event.target;
            var iCaretPos = 0;

            // IE Support
            if (document.selection) {
                oField.focus();
                var oSel = document.selection.createRange();
                oSel.moveStart('character', -oField.value.length);
                iCaretPos = oSel.text.length;
            }

            else if (oField.selectionStart || oField.selectionStart == '0') {
                iCaretPos = oField.selectionStart;
            }
            this.cursorPosition = iCaretPos;
        };

        helper.addIndicator = function (indicator) {
            var i = "__" + this.variableIndex + "__";
            var cursorPosition = this.cursorPosition;

            if (angular.isUndefined(this.formula)) {
                this.formula = '';
            }

            if (angular.isUndefined(cursorPosition)) {
                this.formula = this.formula + i;
            } else {
                this.formula = [
                    this.formula.slice(0, cursorPosition),
                    i,
                    this.formula.slice(cursorPosition)
                ].join('');
            }
            this.variableIndex += 1;
            this.variables[i] = {
                "type": "indicator",
                "id": indicator.id,
            };
        };

        helper.validate = function() {
            var url = API_CONF.FORMULA_VALIDATION_URL;
            return $http({
                url: url,
                method: 'get',
                params: {
                    formula: this.formula,
                    variables: this.variables
                }
            });
        }

        return helper;
    }])

/**
 * Factory to create Metric using a wizard
 */
    .factory('MetricsControllerHelper', [
        'IndicatorService', 'NormalizerService', 'FormulaHelper',
        function (IndicatorService, NormalizerService, FormulaHelper) {

            var helper = {
                metricsdata: {
                    title: "",
                    formula: "",
                    description: "",
                    keywords: "",
                    variableIndex: 1,
                    variables: {}
                }
            };

            helper.clear = function () {
                helper.metricsdata = {
                    title: "",
                    formula: "",
                    description: "",
                    keywords: "",
                    variableIndex: 1,
                    variables: {}
                };
            }

            helper.init = function () {
                if (!helper.metricsdata) {
                    helper.clear();
                }

                var indicators = IndicatorService.query(function () {
                    helper.indicators = _.map(indicators.results, function (indicator) {
                        return {
                            name: indicator.name,
                            unit_category: indicator.unit_category,
                            id: indicator.id,
                            date: indicator.modified
                        };
                    });
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });

                helper.normalizers = NormalizerService.query(function () {
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });
            }

            helper.getFormulaHelper = function() {
                var formulaHelper = FormulaHelper;
                formulaHelper.reset(this.metricsdata.formula, this.metricsdata.variables);
                return formulaHelper;
            }

            return helper;
        }
    ])

/**
 * Factory to operationalize Metric using a wizard
 */
    .factory('ApplyMetricHelper', [
        'MetricService', 'IndicatorService', function (MetricService, IndicatorService) {

            var datasets = {};
            var _metric_id;

            datasets.clear = function () {
                datasets.data = {
                    title: "",
                    unit_id: "",
                    datasets: []
                };
            }

            datasets.getDatasets = function (metric_id) {
                datasets.metric = MetricService.get({id: metric_id}, function (metric) {
                    var variablesJson = datasets.metric.variables;
                    _.each(variablesJson, function (value, key) {
                        datasets.data.datasets.push({
                            variable: key.trim(),
                            dataset: -1,
                            indicator: value.id
                        });
                    });
                    IndicatorService.get({id: metric.indicator_id}, function (indicator) {
                        datasets.unit_category_id = indicator.unit_category;
                    });
                }, function (err) {
                    throw {message: JSON.stringify(err.data)};
                });
            }

            datasets.init = function (metric_id) {

                if (_metric_id !== metric_id) {
                    _metric_id = metric_id;

                    datasets.clear();
                    datasets.getDatasets(metric_id);
                }
            };
            return datasets;
        }
    ]);
<|endoftext|>


<commit_before>// Copyright 2002-2015, University of Colorado Boulder

/**
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var MonsterNode = require( 'MRCHOMPY/mrchompy/view/MonsterNode' );
  var HouseNode = require( 'MRCHOMPY/mrchompy/view/HouseNode' );
  var PersonNode = require( 'MRCHOMPY/mrchompy/view/PersonNode' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {MrchompyModel} mrchompyModel
   * @constructor
   */
  function MrchompyScreenView( mrchompyModel ) {

    ScreenView.call( this );

    var worldNode = new Node();
    this.addChild( worldNode );
    var ground = new Rectangle( -1000, 600, 20000, 1000, { fill: '#092e0d' } );
    worldNode.addChild( ground );

    var floorY = 400;
    var monsterModel = {
      x: 200,
      jumping: false,
      vy: 0,
      gravity: 5000,
      y: floorY,
      jawsClosing: false,
      jawsOpening: false,
      mouthOpenAmount: 1
    };

    var addedSpears = false;
    var zoomingOut = false;

    worldNode.addChild( new HouseNode( { x: 800, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 1600, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 2400, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 3200, bottom: ground.top } ) );

    var peopleLayer = new Node();
    worldNode.addChild( peopleLayer );
    var monsterNode = new MonsterNode( monsterModel );
    worldNode.addChild( monsterNode );

    var newPerson = function( x, spear ) {
      return {
        x: x,
        y: 450,
        dead: false,
        vx: -180,
        scared: false,
        angle: 0,
        falling: false,
        finishedFalling: false,
        spear: spear
      };
    };

    var worldScale = 1;
    var people = [];
    for ( var i = 0; i < 4; i++ ) {
      people.push( newPerson( i * 800 + 1500, false ) );
    }

    this.step = function( dt ) {

      if ( pressedKeys[ 39 ] ) {

        // right
        monsterModel.x += 400 * dt;
      }
      if ( pressedKeys[ 37 ] ) {
        monsterModel.x -= 400 * dt;
      }
      if ( pressedKeys[ 38 ] && !monsterModel.jumping ) {
        monsterModel.jumping = true;
        monsterModel.vy = -2000;
      }
      if ( pressedKeys[ 32 ] && !monsterModel.jawsClosing && !monsterModel.jawsOpening ) {
        monsterModel.jawsClosing = true;
      }
      if ( monsterModel.jawsClosing && monsterModel.mouthOpenAmount <= 0 ) {
        monsterModel.mouthOpenAmount = 0;
        monsterModel.jawsClosing = false;
        monsterModel.jawsOpening = true;
        people.forEach( function( p ) {
          if ( Math.abs( p.x - monsterModel.x ) < 250 ) {
            p.dead = true;
          }
        } );
      }
      if ( monsterModel.jawsOpening && monsterModel.mouthOpenAmount >= 1 ) {
        monsterModel.mouthOpenAmount = 1;
        monsterModel.jawsOpening = false;
      }
      if ( monsterModel.jawsClosing ) {
        monsterModel.mouthOpenAmount -= 0.2;
      }
      if ( monsterModel.jawsOpening ) {
        monsterModel.mouthOpenAmount += 0.1;
      }

      people.forEach( function( person ) {
        if ( !person.dead ) {
          person.x += person.vx * dt;
        }
        if ( person.x <= monsterModel.x + 500 && !person.scared ) {
          person.vx = Math.abs( person.vx );
          person.scared = true;
          person.vx = 320;
        }
        if ( person.x >= monsterModel.x + 1000 && person.scared ) {
          person.scared = false;
          person.vx = 0;
        }
        if ( person.dead && !person.finishedFalling ) {
          person.angle = person.angle + Math.PI * 2 * dt;
          if ( person.angle > Math.PI / 2 ) {
            person.angle = Math.PI / 2;
            person.falling = false;
            person.finishedFalling = true;
          }
        }
      } );
      var deadCount = 0;
      for ( var i = 0; i < people.length; i++ ) {
        var person = people[ i ];
        if ( person.dead ) {
          deadCount++;
        }
      }
      if ( deadCount === 4 && !addedSpears ) {
        addedSpears = true;
        zoomingOut = true;
        people.push( newPerson( monsterModel.x + 3000, true ) );
        people.push( newPerson( monsterModel.x + 3400, true ) );
        people.push( newPerson( monsterModel.x + 3600, true ) );
        people.push( newPerson( monsterModel.x + 3800, true ) );
      }
      if ( zoomingOut ) {
        worldScale = worldScale - 1.2 * dt;
        if ( worldScale <= 0.5 ) {
          zoomingOut = false;
          worldScale = 0.5;
        }
        worldNode.setScaleMagnitude( worldScale );
      }

      monsterModel.vy = monsterModel.vy + monsterModel.gravity * dt;
      monsterModel.y = monsterModel.y + monsterModel.vy * dt;
      if ( monsterModel.y >= floorY ) {
        monsterModel.y = floorY;
        monsterModel.jumping = false;
      }

      worldNode.removeChild( monsterNode );

      monsterNode = new MonsterNode( monsterModel );
      monsterNode.x = monsterModel.x;
      monsterNode.y = monsterModel.y;
      worldNode.addChild( monsterNode );

      peopleLayer.removeAllChildren();
      for ( var i = 0; i < people.length; i++ ) {
        var personNode = new PersonNode( people[ i ], {
          scale: {
            x: people[ i ].scared ? -1 : 1,
            y: 1
          },
          centerX: people[ i ].x,
          bottom: ground.top,
          rotation: people[ i ].angle
        } );
        peopleLayer.addChild( personNode );
      }

      if ( monsterModel.x >= 400 ) {
        worldNode.x = (-monsterModel.x + 400) * worldScale;
        worldNode.y = Util.linear( 1, 0.5, 0, 400, worldScale );
      }
    };

    // Key listeners
    // http://stackoverflow.com/questions/16089421/simplest-way-to-detect-keypresses-in-javascript
    function addEvent( element, eventName, callback ) {
      if ( element.addEventListener ) {
        element.addEventListener( eventName, callback, false );
      }
      else if ( element.attachEvent ) {
        element.attachEvent( "on" + eventName, callback );
      }
      else {
        element[ "on" + eventName ] = callback;
      }
    }

    var pressedKeys = {};
    addEvent( document, "keydown", function( e ) {
      var e = e || window.event;
      // use e.keyCode
      pressedKeys[ e.keyCode ] = true;
    } );

    addEvent( document, "keyup", function( e ) {
      var e = e || window.event;
      // use e.keyCode
      pressedKeys[ e.keyCode ] = false;
    } );

  }

  return inherit( ScreenView, MrchompyScreenView );
} );<commit_msg>fixed groun<commit_after>// Copyright 2002-2015, University of Colorado Boulder

/**
 *
 * @author Sam Reid
 */
define( function( require ) {
  'use strict';

  // modules
  var inherit = require( 'PHET_CORE/inherit' );
  var ScreenView = require( 'JOIST/ScreenView' );
  var ResetAllButton = require( 'SCENERY_PHET/buttons/ResetAllButton' );
  var Rectangle = require( 'SCENERY/nodes/Rectangle' );
  var MonsterNode = require( 'MRCHOMPY/mrchompy/view/MonsterNode' );
  var HouseNode = require( 'MRCHOMPY/mrchompy/view/HouseNode' );
  var PersonNode = require( 'MRCHOMPY/mrchompy/view/PersonNode' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Util = require( 'DOT/Util' );
  var Line = require( 'SCENERY/nodes/Line' );

  /**
   * @param {MrchompyModel} mrchompyModel
   * @constructor
   */
  function MrchompyScreenView( mrchompyModel ) {

    ScreenView.call( this );

    var worldNode = new Node();
    this.addChild( worldNode );
    var ground = new Rectangle( -1000, 600, 20000, 1000, { fill: '#092e0d' } );
    worldNode.addChild( ground );

    var floorY = 400;
    var monsterModel = {
      x: 200,
      jumping: false,
      vy: 0,
      gravity: 5000,
      y: floorY,
      jawsClosing: false,
      jawsOpening: false,
      mouthOpenAmount: 1
    };

    var addedSpears = false;
    var zoomingOut = false;

    worldNode.addChild( new HouseNode( { x: 800, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 1600, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 2400, bottom: ground.top } ) );
    worldNode.addChild( new HouseNode( { x: 3200, bottom: ground.top } ) );

    var peopleLayer = new Node();
    worldNode.addChild( peopleLayer );
    var monsterNode = new MonsterNode( monsterModel );
    worldNode.addChild( monsterNode );

    var newPerson = function( x, spear ) {
      return {
        x: x,
        y: 450,
        dead: false,
        vx: -180,
        scared: false,
        angle: 0,
        falling: false,
        finishedFalling: false,
        spear: spear
      };
    };

    var worldScale = 1;
    var people = [];
    for ( var i = 0; i < 4; i++ ) {
      people.push( newPerson( i * 800 + 1500, false ) );
    }

    this.step = function( dt ) {

      if ( pressedKeys[ 39 ] ) {

        // right
        monsterModel.x += 400 * dt;
      }
      if ( pressedKeys[ 37 ] ) {
        monsterModel.x -= 400 * dt;
      }
      if ( pressedKeys[ 38 ] && !monsterModel.jumping ) {
        monsterModel.jumping = true;
        monsterModel.vy = -2000;
      }
      if ( pressedKeys[ 32 ] && !monsterModel.jawsClosing && !monsterModel.jawsOpening ) {
        monsterModel.jawsClosing = true;
      }
      if ( monsterModel.jawsClosing && monsterModel.mouthOpenAmount <= 0 ) {
        monsterModel.mouthOpenAmount = 0;
        monsterModel.jawsClosing = false;
        monsterModel.jawsOpening = true;
        people.forEach( function( p ) {
          if ( Math.abs( p.x - monsterModel.x ) < 250 ) {
            p.dead = true;
          }
        } );
      }
      if ( monsterModel.jawsOpening && monsterModel.mouthOpenAmount >= 1 ) {
        monsterModel.mouthOpenAmount = 1;
        monsterModel.jawsOpening = false;
      }
      if ( monsterModel.jawsClosing ) {
        monsterModel.mouthOpenAmount -= 0.2;
      }
      if ( monsterModel.jawsOpening ) {
        monsterModel.mouthOpenAmount += 0.1;
      }

      people.forEach( function( person ) {
        if ( !person.dead ) {
          person.x += person.vx * dt;
        }
        if ( !person.spear ) {
          if ( person.x <= monsterModel.x + 500 && !person.scared ) {
            person.vx = Math.abs( person.vx );
            person.scared = true;
            person.vx = 320;
          }
          if ( person.x >= monsterModel.x + 1000 && person.scared ) {
            person.scared = false;
            person.vx = 0;
          }
          if ( person.dead && !person.finishedFalling ) {
            person.angle = person.angle + Math.PI * 2 * dt;
            if ( person.angle > Math.PI / 2 ) {
              person.angle = Math.PI / 2;
              person.falling = false;
              person.finishedFalling = true;
            }
          }
        }
        if ( person.spear ) {}
      } );
      var deadCount = 0;
      for ( var i = 0; i < people.length; i++ ) {
        var person = people[ i ];
        if ( person.dead ) {
          deadCount++;
        }
      }
      if ( deadCount === 4 && !addedSpears ) {
        addedSpears = true;
        zoomingOut = true;
        people.push( newPerson( monsterModel.x + 3000, true ) );
        people.push( newPerson( monsterModel.x + 3400, true ) );
        people.push( newPerson( monsterModel.x + 3600, true ) );
        people.push( newPerson( monsterModel.x + 3800, true ) );
      }
      if ( zoomingOut ) {
        worldScale = worldScale - 1.2 * dt;
        if ( worldScale <= 0.5 ) {
          zoomingOut = false;
          worldScale = 0.5;
        }
        worldNode.setScaleMagnitude( worldScale );
      }

      monsterModel.vy = monsterModel.vy + monsterModel.gravity * dt;
      monsterModel.y = monsterModel.y + monsterModel.vy * dt;
      if ( monsterModel.y >= floorY ) {
        monsterModel.y = floorY;
        monsterModel.jumping = false;
      }

      worldNode.removeChild( monsterNode );

      monsterNode = new MonsterNode( monsterModel );
      monsterNode.x = monsterModel.x;
      monsterNode.y = monsterModel.y;
      worldNode.addChild( monsterNode );

      peopleLayer.removeAllChildren();
      for ( var i = 0; i < people.length; i++ ) {
        var personNode = new PersonNode( people[ i ], {
          scale: {
            x: people[ i ].scared ? -1 : 1,
            y: 1
          },
          centerX: people[ i ].x,
          bottom: ground.top,
          rotation: people[ i ].angle
        } );
        peopleLayer.addChild( personNode );

        if ( people[ i ].spear ) {
          var spear = new Line( 0, 0, 0, 120, { lineWidth: 10, stroke: '#937b33' } );
          peopleLayer.addChild( spear );
          spear.left = personNode.right + 10;
          spear.bottom = personNode.bottom;
        }
      }

      if ( monsterModel.x >= 400 ) {
        worldNode.x = (-monsterModel.x + 400) * worldScale;
        worldNode.y = Util.linear( 1, 0.5, 0, 250, worldScale );
      }
    };

    // Key listeners
    // http://stackoverflow.com/questions/16089421/simplest-way-to-detect-keypresses-in-javascript
    function addEvent( element, eventName, callback ) {
      if ( element.addEventListener ) {
        element.addEventListener( eventName, callback, false );
      }
      else if ( element.attachEvent ) {
        element.attachEvent( "on" + eventName, callback );
      }
      else {
        element[ "on" + eventName ] = callback;
      }
    }

    var pressedKeys = {};
    addEvent( document, "keydown", function( e ) {
      var e = e || window.event;
      // use e.keyCode
      pressedKeys[ e.keyCode ] = true;
    } );

    addEvent( document, "keyup", function( e ) {
      var e = e || window.event;
      // use e.keyCode
      pressedKeys[ e.keyCode ] = false;
    } );

  }

  return inherit( ScreenView, MrchompyScreenView );
} );<|endoftext|>


<commit_before>/*
* mvcActionResultApi
* author: ronglin
* create date: 2014.7.3
*/

'use strict';

var utils = require('./utilities'),
    actionResult = require('./mvcActionResult');

var mvcActionResultApi = function(set) {
    utils.extend(this, set);
};

var emit = function(result) {
    if (this.sync) {
        return result;
    }
    if (utils.isFunction(this.callback)) {
        this.callback(result);
    }
};

mvcActionResultApi.prototype = {

    httpContext: null, sync: false, callback: null,

    constructor: mvcActionResultApi, className: 'mvcActionResultApi',

    empty: function() {
        return emit.call(this, new actionResult.emptyResult());
    },

    json: function(data, contentType) {
        return emit.call(this, new actionResult.jsonResult({ data: data, contentType: contentType}));
    },

    jsonp: function(data, callbackName) {
        return emit.call(this, new actionResult.jsonpResult({ data: data, callbackName: callbackName }));
    },

    partialView: function(viewName) {
        return emit.call(this, new actionResult.partialViewResult({ viewName: viewName }));
    },

    view: function(viewName, model) {
        return emit.call(this, new actionResult.viewResult({ viewName: viewName, model: model }));
    },

    file: function(filePath, fileDownloadName) {
        return emit.call(this, new actionResult.fileResult({ filePath: filePath, fileDownloadName: fileDownloadName }));
    },

    content: function(content, contentType) {
        return emit.call(this, new actionResult.contentResult({ content: content, contentType: contentType }));
    },

    httpNotFound: function(statusText) {
        return emit.call(this, new actionResult.httpNotFoundResult({ statusText: statusText }));
    },

    redirect: function(url, permanent) {
        return emit.call(this, new actionResult.redirectResult({ url: url, permanent: permanent }));
    },

    redirectToAction: function(actionName, controllerName, routeValues) {
        return this.redirectToRoute(mvcHelper.mergeRouteValues(actionName, controllerName, this.httpContext.routeData, routeValues, true));
    },

    redirectToActionPermanent: function(actionName, controllerName, routeValues) {
        return this.redirectToRoutePermanent(mvcHelper.mergeRouteValues(actionName, controllerName, this.httpContext.routeData, routeValues, true));
    },

    redirectToRoute: function(routeValues) {
        return emit.call(this, new actionResult.redirectToRouteResult({ routeValues: routeValues, permanent: false }));
    },

    redirectToRoutePermanent: function(routeValues) {
        return emit.call(this, new actionResult.redirectToRouteResult({ routeValues: routeValues, permanent: true }));
    }
};

module.exports = mvcActionResultApi;
<commit_msg>update<commit_after>/*
* mvcActionResultApi
* author: ronglin
* create date: 2014.7.3
*/

'use strict';

var utils = require('./utilities'),
    actionResult = require('./mvcActionResult');

var mvcActionResultApi = function(set) {
    utils.extend(this, set);
};

var emit = function(result) {
    if (this.sync) {
        return result;
    }
    if (utils.isFunction(this.callback)) {
        this.callback(result);
    }
};

mvcActionResultApi.prototype = {

    httpContext: null, sync: false, callback: null,

    constructor: mvcActionResultApi, className: 'mvcActionResultApi',

    with: function(result) {
        return emit.call(this, result);
    },

    empty: function() {
        return emit.call(this, new actionResult.emptyResult());
    },

    json: function(data, contentType) {
        return emit.call(this, new actionResult.jsonResult({ data: data, contentType: contentType}));
    },

    jsonp: function(data, callbackName) {
        return emit.call(this, new actionResult.jsonpResult({ data: data, callbackName: callbackName }));
    },

    partialView: function(viewName) {
        return emit.call(this, new actionResult.partialViewResult({ viewName: viewName }));
    },

    view: function(viewName, model) {
        return emit.call(this, new actionResult.viewResult({ viewName: viewName, model: model }));
    },

    file: function(filePath, fileDownloadName) {
        return emit.call(this, new actionResult.fileResult({ filePath: filePath, fileDownloadName: fileDownloadName }));
    },

    content: function(content, contentType) {
        return emit.call(this, new actionResult.contentResult({ content: content, contentType: contentType }));
    },

    httpNotFound: function(statusText) {
        return emit.call(this, new actionResult.httpNotFoundResult({ statusText: statusText }));
    },

    redirect: function(url, permanent) {
        return emit.call(this, new actionResult.redirectResult({ url: url, permanent: permanent }));
    },

    redirectToAction: function(actionName, controllerName, routeValues) {
        return this.redirectToRoute(mvcHelper.mergeRouteValues(actionName, controllerName, this.httpContext.routeData, routeValues, true));
    },

    redirectToActionPermanent: function(actionName, controllerName, routeValues) {
        return this.redirectToRoutePermanent(mvcHelper.mergeRouteValues(actionName, controllerName, this.httpContext.routeData, routeValues, true));
    },

    redirectToRoute: function(routeValues) {
        return emit.call(this, new actionResult.redirectToRouteResult({ routeValues: routeValues, permanent: false }));
    },

    redirectToRoutePermanent: function(routeValues) {
        return emit.call(this, new actionResult.redirectToRouteResult({ routeValues: routeValues, permanent: true }));
    }
};

module.exports = mvcActionResultApi;
<|endoftext|>


<commit_before>'use strict';

/* App Module */

var <%= angularAppName %> = angular.module('<%= angularAppName %>', ['http-auth-interceptor', 'tmh.dynamicLocale',
    'ngResource', 'ngRoute', 'ngCookies', 'pascalprecht.translate']);

<%= angularAppName %>
    .config(['$routeProvider', '$httpProvider', '$translateProvider',  'tmhDynamicLocaleProvider', 'USER_ROLES',
        function ($routeProvider, $httpProvider, $translateProvider, tmhDynamicLocaleProvider, USER_ROLES) {
            $routeProvider
                .when('/login', {
                    templateUrl: 'views/login.html',
                    controller: 'LoginController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/error', {
                    templateUrl: 'views/error.html',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/settings', {
                    templateUrl: 'views/settings.html',
                    controller: 'SettingsController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/password', {
                    templateUrl: 'views/password.html',
                    controller: 'PasswordController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/sessions', {
                    templateUrl: 'views/sessions.html',
                    controller: 'SessionsController',
                    resolve:{
                        resolvedSessions:['Sessions', function (Sessions) {
                            return Sessions.get();
                        }]
                    },
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
<% if (websocket == 'atmosphere') { %>                .when('/tracker', {
                    templateUrl: 'views/tracker.html',
                    controller: 'TrackerController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
<% } %>                .when('/metrics', {
                    templateUrl: 'views/metrics.html',
                    controller: 'MetricsController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/logs', {
                    templateUrl: 'views/logs.html',
                    controller: 'LogsController',
                    resolve:{
                        resolvedLogs:['LogsService', function (LogsService) {
                            return LogsService.findAll();
                        }]
                    },
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/audits', {
                    templateUrl: 'views/audits.html',
                    controller: 'AuditsController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/logout', {
                    templateUrl: 'views/main.html',
                    controller: 'LogoutController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/docs', {
                    templateUrl: 'views/docs.html',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .otherwise({
                    templateUrl: 'views/main.html',
                    controller: 'MainController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                });

            // Initialize angular-translate
            $translateProvider.useStaticFilesLoader({
                prefix: 'i18n/',
                suffix: '.json'
            });

            $translateProvider.preferredLanguage('en');

            $translateProvider.useCookieStorage();

            tmhDynamicLocaleProvider.localeLocationPattern('bower_components/angular-i18n/angular-locale_{{locale}}.js')
            tmhDynamicLocaleProvider.useCookieStorage('NG_TRANSLATE_LANG_KEY');
        }])
        .run(['$rootScope', '$location', '$http', 'AuthenticationSharedService', 'Session', 'USER_ROLES',
            function($rootScope, $location, $http, AuthenticationSharedService, Session, USER_ROLES) {
                $rootScope.$on('$routeChangeStart', function (event, next) {
                    $rootScope.authenticated = AuthenticationSharedService.isAuthenticated();
                    $rootScope.isAuthorized = AuthenticationSharedService.isAuthorized;
                    $rootScope.userRoles = USER_ROLES;
                    $rootScope.account = Session;

                    var authorizedRoles = next.access.authorizedRoles;
                    if (!AuthenticationSharedService.isAuthorized(authorizedRoles)) {
                        event.preventDefault();
                        if (AuthenticationSharedService.isAuthenticated()) {
                            // user is not allowed
                            $rootScope.$broadcast("event:auth-notAuthorized");
                        } else {
                            // user is not logged in
                            $rootScope.$broadcast("event:auth-loginRequired");
                        }
                    } else {
                        // Check if the customer is still authenticated on the server
                        // Try to load a protected 1 pixel image.
                        $http({method: 'GET', url: '/protected/transparent.gif'}).
                            error(function(response) {
                            // Not authorized
                                if (response.status === 401) {
                                    $rootScope.$broadcast("event:auth-notAuthorized");
                                }
                            })
                    }
                });

                // Call when the the client is confirmed
                $rootScope.$on('event:auth-loginConfirmed', function(data) {
                    if ($location.path() === "/login") {
                        $location.path('/').replace();
                    }
                });

                // Call when the 401 response is returned by the server
                $rootScope.$on('event:auth-loginRequired', function(rejection) {
                    Session.destroy();
                    if ($location.path() !== "/" && $location.path() !== "") {
                        $location.path('/login').replace();
                    }
                });

                // Call when the 403 response is returned by the server
                $rootScope.$on('event:auth-notAuthorized', function(rejection) {
                    $rootScope.errorMessage = 'errors.403';
                    $location.path('/error').replace();
                });

                // Call when the user logs out
                $rootScope.$on('event:auth-loginCancelled', function() {
                    $location.path('');
                });
        }])<% if (websocket == 'atmosphere') { %>
        .run(['$rootScope', '$route',
            function($rootScope, $route) {
                // This uses the Atmoshpere framework to do a Websocket connection with the server, in order to send
                // user activities each time a route changes.
                // The user activities can then be monitored by an administrator, see the views/tracker.html Angular view.

                $rootScope.websocketSocket = atmosphere;
                $rootScope.websocketSubSocket;
                $rootScope.websocketTransport = 'websocket';

                $rootScope.websocketRequest = { url: 'websocket/activity',
                    contentType : "application/json",
                    transport : $rootScope.websocketTransport ,
                    trackMessageLength : true,
                    reconnectInterval : 5000,
                    enableXDR: true,
                    timeout : 60000 };

                $rootScope.websocketRequest.onOpen = function(response) {
                    $rootScope.websocketTransport = response.transport;
                    $rootScope.websocketRequest.sendMessage();
                };

                $rootScope.websocketRequest.onClientTimeout = function(r) {
                    $rootScope.websocketRequest.sendMessage();
                    setTimeout(function (){
                        $rootScope.websocketSubSocket = $rootScope.websocketSocket.subscribe($rootScope.websocketRequest);
                    }, $rootScope.websocketRequest.reconnectInterval);
                };

                $rootScope.websocketRequest.onClose = function(response) {
                    if ($rootScope.websocketSubSocket) {
                        $rootScope.websocketRequest.sendMessage();
                    }
                };

                $rootScope.websocketRequest.sendMessage = function() {
                    if ($rootScope.websocketSubSocket.request.isOpen) {
                        $rootScope.websocketSubSocket.push(atmosphere.util.stringifyJSON({
                                userLogin: $rootScope.login,
                                page: $route.current.templateUrl}
                        ));
                    }
                };

                $rootScope.websocketSubSocket = $rootScope.websocketSocket.subscribe($rootScope.websocketRequest);

                $rootScope.$on("$routeChangeSuccess", function(event, next, current) {
                    $rootScope.websocketRequest.sendMessage();
                });
            }
        ])<% } %>;
<commit_msg>Bug fix 224<commit_after>'use strict';

/* App Module */

var <%= angularAppName %> = angular.module('<%= angularAppName %>', ['http-auth-interceptor', 'tmh.dynamicLocale',
    'ngResource', 'ngRoute', 'ngCookies', 'pascalprecht.translate']);

<%= angularAppName %>
    .config(['$routeProvider', '$httpProvider', '$translateProvider',  'tmhDynamicLocaleProvider', 'USER_ROLES',
        function ($routeProvider, $httpProvider, $translateProvider, tmhDynamicLocaleProvider, USER_ROLES) {
            $routeProvider
                .when('/login', {
                    templateUrl: 'views/login.html',
                    controller: 'LoginController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/error', {
                    templateUrl: 'views/error.html',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/settings', {
                    templateUrl: 'views/settings.html',
                    controller: 'SettingsController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/password', {
                    templateUrl: 'views/password.html',
                    controller: 'PasswordController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/sessions', {
                    templateUrl: 'views/sessions.html',
                    controller: 'SessionsController',
                    resolve:{
                        resolvedSessions:['Sessions', function (Sessions) {
                            return Sessions.get();
                        }]
                    },
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
<% if (websocket == 'atmosphere') { %>                .when('/tracker', {
                    templateUrl: 'views/tracker.html',
                    controller: 'TrackerController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
<% } %>                .when('/metrics', {
                    templateUrl: 'views/metrics.html',
                    controller: 'MetricsController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/logs', {
                    templateUrl: 'views/logs.html',
                    controller: 'LogsController',
                    resolve:{
                        resolvedLogs:['LogsService', function (LogsService) {
                            return LogsService.findAll();
                        }]
                    },
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/audits', {
                    templateUrl: 'views/audits.html',
                    controller: 'AuditsController',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .when('/logout', {
                    templateUrl: 'views/main.html',
                    controller: 'LogoutController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                })
                .when('/docs', {
                    templateUrl: 'views/docs.html',
                    access: {
                        authorizedRoles: [USER_ROLES.admin]
                    }
                })
                .otherwise({
                    templateUrl: 'views/main.html',
                    controller: 'MainController',
                    access: {
                        authorizedRoles: [USER_ROLES.all]
                    }
                });

            // Initialize angular-translate
            $translateProvider.useStaticFilesLoader({
                prefix: 'i18n/',
                suffix: '.json'
            });

            $translateProvider.preferredLanguage('en');

            $translateProvider.useCookieStorage();

            tmhDynamicLocaleProvider.localeLocationPattern('bower_components/angular-i18n/angular-locale_{{locale}}.js')
            tmhDynamicLocaleProvider.useCookieStorage('NG_TRANSLATE_LANG_KEY');
        }])
        .run(['$rootScope', '$location', '$http', 'AuthenticationSharedService', 'Session', 'USER_ROLES',
            function($rootScope, $location, $http, AuthenticationSharedService, Session, USER_ROLES) {
                $rootScope.$on('$routeChangeStart', function (event, next) {
                    $rootScope.authenticated = AuthenticationSharedService.isAuthenticated();
                    $rootScope.isAuthorized = AuthenticationSharedService.isAuthorized;
                    $rootScope.userRoles = USER_ROLES;
                    $rootScope.account = Session;

                    var authorizedRoles = next.access.authorizedRoles;
                    if (!AuthenticationSharedService.isAuthorized(authorizedRoles)) {
                        event.preventDefault();
                        if (AuthenticationSharedService.isAuthenticated()) {
                            // user is not allowed
                            $rootScope.$broadcast("event:auth-notAuthorized");
                        } else {
                            // user is not logged in
                            $rootScope.$broadcast("event:auth-loginRequired");
                        }
                    } else {
                        // Check if the customer is still authenticated on the server
                        // Try to load a protected 1 pixel image.
                        $http({method: 'GET', url: '/protected/transparent.gif'});
                    }
                });

                // Call when the the client is confirmed
                $rootScope.$on('event:auth-loginConfirmed', function(data) {
                    if ($location.path() === "/login") {
                        $location.path('/').replace();
                    }
                });

                // Call when the 401 response is returned by the server
                $rootScope.$on('event:auth-loginRequired', function(rejection) {
                    Session.destroy();
                    $rootScope.authenticated = false;
                    if ($location.path() !== "/" && $location.path() !== "") {
                        $location.path('/login').replace();
                    }
                });

                // Call when the 403 response is returned by the server
                $rootScope.$on('event:auth-notAuthorized', function(rejection) {
                    $rootScope.errorMessage = 'errors.403';
                    $location.path('/error').replace();
                });

                // Call when the user logs out
                $rootScope.$on('event:auth-loginCancelled', function() {
                    $location.path('');
                });
        }])<% if (websocket == 'atmosphere') { %>
        .run(['$rootScope', '$route',
            function($rootScope, $route) {
                // This uses the Atmoshpere framework to do a Websocket connection with the server, in order to send
                // user activities each time a route changes.
                // The user activities can then be monitored by an administrator, see the views/tracker.html Angular view.

                $rootScope.websocketSocket = atmosphere;
                $rootScope.websocketSubSocket;
                $rootScope.websocketTransport = 'websocket';

                $rootScope.websocketRequest = { url: 'websocket/activity',
                    contentType : "application/json",
                    transport : $rootScope.websocketTransport ,
                    trackMessageLength : true,
                    reconnectInterval : 5000,
                    enableXDR: true,
                    timeout : 60000 };

                $rootScope.websocketRequest.onOpen = function(response) {
                    $rootScope.websocketTransport = response.transport;
                    $rootScope.websocketRequest.sendMessage();
                };

                $rootScope.websocketRequest.onClientTimeout = function(r) {
                    $rootScope.websocketRequest.sendMessage();
                    setTimeout(function (){
                        $rootScope.websocketSubSocket = $rootScope.websocketSocket.subscribe($rootScope.websocketRequest);
                    }, $rootScope.websocketRequest.reconnectInterval);
                };

                $rootScope.websocketRequest.onClose = function(response) {
                    if ($rootScope.websocketSubSocket) {
                        $rootScope.websocketRequest.sendMessage();
                    }
                };

                $rootScope.websocketRequest.sendMessage = function() {
                    if ($rootScope.websocketSubSocket.request.isOpen) {
                        $rootScope.websocketSubSocket.push(atmosphere.util.stringifyJSON({
                                userLogin: $rootScope.login,
                                page: $route.current.templateUrl}
                        ));
                    }
                };

                $rootScope.websocketSubSocket = $rootScope.websocketSocket.subscribe($rootScope.websocketRequest);

                $rootScope.$on("$routeChangeSuccess", function(event, next, current) {
                    $rootScope.websocketRequest.sendMessage();
                });
            }
        ])<% } %>;
<|endoftext|>


<commit_before>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var noNuts = function(pizza){
        return pizza.containsNuts === false;
      };

      var noMushroom = function(pizza) {
        return _(pizza.ingredients)
          .all( function(ingredient) {return ingredient !== "mushrooms"} );
      };

      productsICanEat = _(products).filter(noNuts).filter(noMushroom);

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    /* try chaining range() and reduce() */
    var sum = _.range(1000)
              .reduce(function (sum, x) {
                return (x % 3 === 0 || x % 5 === 0) ? sum + x : sum;
              });

    expect(233168).toBe(sum);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    var test = _(products).chain()
      .map( function(item){ return item.ingredients; } )
      .flatten()
      // TODO try to reduce instead as suggested
      .each(function (ingredient) {
                ingredientCount[ingredient] = (ingredientCount[ingredient] || 0) + 1;
              })
      .value();

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {

    var factors = function(compositeNumber){
      var results = [];
      var i;
      var max = compositeNumber / 2;
      for(i = 2; i <= max ; i++) {
        if (compositeNumber % i === 0) {
          results.push(i);
        }
      }
      return results;
    };

    var isPrime = function(n) {
      return factors(n).length === 0;
    }

    var largestPrime = function(n) {
      return factors(n).filter(isPrime).pop();
    }

    expect(largestPrime(21)).toBe(7);
  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {
    // A alindrome is a word, or a number, that can be read both from head to end and from end to head
    var isPalindrome = function(number) {
      var toTest = number.toString();
      for (var i = 0; i < Math.floor(toTest.length / 2); i++)
        if (toTest[i] !== toTest[toTest.length - 1 - i]) {
          return false;
        }
      return true;
    }

    expect(isPalindrome(111 * 222)).toBe(true);
  });
  /*
  it("should find the smallest number divisible by each of the numbers 1 to 20", function () {

  });

  it("should find the difference between the sum of the squares and the square of the sums", function () {

  });

  it("should find the 10001st prime", function () {

  });
  */
});
<commit_msg>Extra Credit: find the difference between the sum of the squares and the square of the sums<commit_after>var _; //globals

describe("About Applying What We Have Learnt", function() {

  var products;

  beforeEach(function () {
    products = [
       { name: "Sonoma", ingredients: ["artichoke", "sundried tomatoes", "mushrooms"], containsNuts: false },
       { name: "Pizza Primavera", ingredients: ["roma", "sundried tomatoes", "goats cheese", "rosemary"], containsNuts: false },
       { name: "South Of The Border", ingredients: ["black beans", "jalapenos", "mushrooms"], containsNuts: false },
       { name: "Blue Moon", ingredients: ["blue cheese", "garlic", "walnuts"], containsNuts: true },
       { name: "Taste Of Athens", ingredients: ["spinach", "kalamata olives", "sesame seeds"], containsNuts: true }
    ];
  });

  /*********************************************************************************/

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (imperative)", function () {

    var i,j,hasMushrooms, productsICanEat = [];

    for (i = 0; i < products.length; i+=1) {
        if (products[i].containsNuts === false) {
            hasMushrooms = false;
            for (j = 0; j < products[i].ingredients.length; j+=1) {
               if (products[i].ingredients[j] === "mushrooms") {
                  hasMushrooms = true;
               }
            }
            if (!hasMushrooms) productsICanEat.push(products[i]);
        }
    }

    expect(productsICanEat.length).toBe(1);
  });

  it("given I'm allergic to nuts and hate mushrooms, it should find a pizza I can eat (functional)", function () {

      var productsICanEat = [];

      /* solve using filter() & all() / any() */
      var noNuts = function(pizza){
        return pizza.containsNuts === false;
      };

      var noMushroom = function(pizza) {
        return _(pizza.ingredients)
          .all( function(ingredient) {return ingredient !== "mushrooms"} );
      };

      productsICanEat = _(products).filter(noNuts).filter(noMushroom);

      expect(productsICanEat.length).toBe(1);
  });

  /*********************************************************************************/

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (imperative)", function () {

    var sum = 0;
    for(var i=1; i<1000; i+=1) {
      if (i % 3 === 0 || i % 5 === 0) {
        sum += i;
      }
    }

    expect(sum).toBe(233168);
  });

  it("should add all the natural numbers below 1000 that are multiples of 3 or 5 (functional)", function () {

    /* try chaining range() and reduce() */
    var sum = _.range(1000)
              .reduce(function (sum, x) {
                return (x % 3 === 0 || x % 5 === 0) ? sum + x : sum;
              });

    expect(233168).toBe(sum);
  });

  /*********************************************************************************/
   it("should count the ingredient occurrence (imperative)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    for (i = 0; i < products.length; i+=1) {
        for (j = 0; j < products[i].ingredients.length; j+=1) {
            ingredientCount[products[i].ingredients[j]] = (ingredientCount[products[i].ingredients[j]] || 0) + 1;
        }
    }

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  it("should count the ingredient occurrence (functional)", function () {
    var ingredientCount = { "{ingredient name}": 0 };

    /* chain() together map(), flatten() and reduce() */
    var test = _(products).chain()
      .map( function(item){ return item.ingredients; } )
      .flatten()
      // TODO try to reduce instead as suggested
      .each(function (ingredient) {
                ingredientCount[ingredient] = (ingredientCount[ingredient] || 0) + 1;
              })
      .value();

    expect(ingredientCount['mushrooms']).toBe(2);
  });

  /*********************************************************************************/
  /* UNCOMMENT FOR EXTRA CREDIT */

  it("should find the largest prime factor of a composite number", function () {

    var factors = function(compositeNumber){
      var results = [];
      var i;
      var max = compositeNumber / 2;
      for(i = 2; i <= max ; i++) {
        if (compositeNumber % i === 0) {
          results.push(i);
        }
      }
      return results;
    };

    var isPrime = function(n) {
      return factors(n).length === 0;
    }

    var largestPrime = function(n) {
      return factors(n).filter(isPrime).pop();
    }

    expect(largestPrime(21)).toBe(7);
  });

  it("should find the largest palindrome made from the product of two 3 digit numbers", function () {
    // A alindrome is a word, or a number, that can be read both from head to end and from end to head
    var isPalindrome = function(number) {
      var toTest = number.toString();
      for (var i = 0; i < Math.floor(toTest.length / 2); i++)
        if (toTest[i] !== toTest[toTest.length - 1 - i]) {
          return false;
        }
      return true;
    }

    expect(isPalindrome(111 * 222)).toBe(true);
  });

  // it("should find the smallest number divisible by each of the numbers 1 to 20", function () {
  //   var isDivisible = function(number) {
  //     for (var i  = 1; i <= 20; i++) {
  //       if (number % i !== 0 )
  //         return false;
  //     }
  //     return true;
  //   };

  //   expect(false).toBe(true);
  // });

  it("should find the difference between the sum of the squares and the square of the sums", function () {
    var sum = function(a,b) {
      return a + b;
    };

    var square = function(a) {
      return a * a;
    }

    var difference = function(numbers){
      var sumOfSquares = _(numbers)
        .map( function(num){return num*num} )
        .reduce(sum);

      var squareOfSums = square(_(numbers).reduce(sum));

      return squareOfSums - sumOfSquares;
    };

    expect(difference([2,3,4])).toBe(52);
  });
  /*
  it("should find the 10001st prime", function () {

  });
  */
});
<|endoftext|>