<commit_before>define([
		'goo/entities/systems/System',
		'goo/entities/SystemBus',
		'goo/addons/linerenderpack/LineRenderer',
		'goo/math/Vector3'
	],
	function (System,
			  SystemBus,
			  LineRenderer,
			  Vector3) {
		'use strict';

		/**
		 * Updates all of it's LineRenderers and exposes methods for drawing primitive line shapes.
		 * @param {World} world the world this system exists in.
		 */
		function LineRenderSystem(world) {
			System.call(this, 'LineRenderSystem', []);

			//an associative array for the LineRenderers
			this._lineRenderers = {};
			this._lineRendererKeys = [];

			this.world = world;
			this.camera = null;

			/**
			 *A managed array of all the LineRenderers render objects.
			 * @type {Object[]}
			 * */
			this.renderList = [];

			//add the camera
			SystemBus.addListener('goo.setCurrentCamera', function (newCam) {
				this.camera = newCam.camera;
			}.bind(this));
		}

		LineRenderSystem.prototype = Object.create(System.prototype);
		LineRenderSystem.prototype.constructor = LineRenderSystem;

		var tmpVec1 = new Vector3();
		var tmpVec2 = new Vector3();
		var tmpVec3 = new Vector3();

		//setup a preset of colors
		LineRenderSystem.prototype.WHITE = new Vector3(1, 1, 1);
		LineRenderSystem.prototype.RED = new Vector3(1, 0, 0);
		LineRenderSystem.prototype.GREEN = new Vector3(0, 1, 0);
		LineRenderSystem.prototype.BLUE = new Vector3(0, 0, 1);
		LineRenderSystem.prototype.AQUA = new Vector3(0, 1, 1);
		LineRenderSystem.prototype.MAGENTA = new Vector3(1, 0, 1);
		LineRenderSystem.prototype.YELLOW = new Vector3(1, 1, 0);
		LineRenderSystem.prototype.BLACK = new Vector3(0, 0, 0);

		/**
		 * Encodes a {@link Vector3} color to a number.
		 * Assumes that the color components are between 0-1.
		 * @param {Vector3} color
		 * @returns {number} The encoded color.
		 * @example
		 * var encodedColorRed = LineRenderSystem.encodeColor(lineRenderSystem.RED);
		 * console.log(encodedColorRed); // would output: 16777216
		 */
		LineRenderSystem.encodeColor = function (color) {
			var r = Math.floor(color.r * 255);
			var g = Math.floor(color.g * 255);
			var b = Math.floor(color.b * 255);

			return r * 65536 + g * 256 + b;
		};

		/**
		 * Draws a line between two {@link Vector3}'s with the specified color.
		 * @param {Vector3} start
		 * @param {Vector3} end
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @example
		 * var vector1 = new Vector3(0,0,0);
		 * var vector2 = new Vector3(13,3,7);
		 * var redColor = lineRenderSystem.RED;
		 * lineRenderSystem.drawLine(v1, v2, redColor);
		 */
		LineRenderSystem.prototype.drawLine = function (start, end, color) {

			var encodedColor = LineRenderSystem.encodeColor(color);

			var lineRenderer = this._lineRenderers[encodedColor];
			if (!lineRenderer) {
				lineRenderer = this._lineRenderers[encodedColor] = new LineRenderer(this.world, color);
				this._lineRendererKeys = Object.keys(this._lineRenderers);
			}
			lineRenderer._addLine(start, end);
		};

		/**
		 * Used internally to calculate the line segments in an axis aligned box, and render them.
		 * @param {Vector3} start
		 * @param {Vector3} startEndDelta
		 * @param {number} startDataIndex
		 * @param {number} endDataIndex
		 * @param {number} startPolarity
		 * @param {number} endPolarity
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} transformMatrix
		 */
		LineRenderSystem.prototype._drawAxisLine = function (start, startEndDelta, startDataIndex, endDataIndex, startPolarity, endPolarity, color, transformMatrix) {
			var lineStart = tmpVec2.setVector(start);
			lineStart.data[startDataIndex] += startEndDelta.data[startDataIndex] * startPolarity;

			var lineEnd = tmpVec3.setVector(lineStart);
			lineEnd.data[endDataIndex] += startEndDelta.data[endDataIndex] * endPolarity;

			if (transformMatrix !== undefined) {
				transformMatrix.applyPostPoint(lineStart);
				transformMatrix.applyPostPoint(lineEnd);
			}

			this.drawLine(lineStart, lineEnd, color);
		};

		/**
		 * Draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix.
		 * @param {Vector3} min
		 * @param {Vector3} max
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} [transformMatrix]
		 */
		LineRenderSystem.prototype.drawAABox = function (min, max, color, transformMatrix) {
			var diff = tmpVec1.setVector(max).subVector(min);

			for (var a = 0; a < 3; a++) {

				for (var b = 0; b < 3; b++) {
					if (b !== a) {
						this._drawAxisLine(min, diff, a, b, 1, 1, color, transformMatrix);
					}
				}

				this._drawAxisLine(max, diff, a, a, -1, 1, color, transformMatrix);
				this._drawAxisLine(min, diff, a, a, 1, -1, color, transformMatrix);
			}
		};

		/**
		 * Draws a cross at a position with the given color and size.
		 * @param {Vector3} position
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {number} [size=0.05]
		 */
		LineRenderSystem.prototype.drawCross = function (position, color, size) {

			size = size || 0.05;

			var start = tmpVec1.setVector(position).addDirect(-size, 0.0, -size);
			var end = tmpVec2.setVector(position).addDirect(size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(size, 0.0, -size);
			end = tmpVec2.setVector(position).addDirect(-size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(0, -size, 0.0);
			end = tmpVec2.setVector(position).addDirect(0.0, size, 0.0);
			this.drawLine(start, end, color);
		};

		LineRenderSystem.prototype.render = function (renderer) {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._updateVertexData();
				lineRenderer._manageRenderList(this.renderList);
				lineRenderer._clear();
			}

			renderer.checkResize(this.camera);

			if (this.camera) {
				renderer.render(this.renderList, this.camera, null, null, false);
			}
		};

		LineRenderSystem.prototype.clear = function () {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._remove();
			}
			delete this._lineRenderers;

			this.world.gooRunner.renderer.clearShaderCache();
		};

		return LineRenderSystem;
	});<commit_msg>rewrite the LineRenderSystem to not map LineRenderers<commit_after>define([
		'goo/entities/systems/System',
		'goo/entities/SystemBus',
		'goo/addons/linerenderpack/LineRenderer',
		'goo/math/Vector3'
	],
	function (System,
			  SystemBus,
			  LineRenderer,
			  Vector3) {
		'use strict';

		/**
		 * Updates all of it's LineRenderers and exposes methods for drawing primitive line shapes.
		 * @param {World} world the world this system exists in.
		 */
		function LineRenderSystem(world) {
			System.call(this, 'LineRenderSystem', []);

			this._lineRenderers = [];

			//adds a new LineRenderer to the list
			this._lineRenderers.push(new LineRenderer(this.world));

			this.world = world;
			this.camera = null;

			/**
			 *A managed array of all the LineRenderers render objects.
			 * @type {Object[]}
			 * */
			this.renderList = [];

			//add the camera
			SystemBus.addListener('goo.setCurrentCamera', function (newCam) {
				this.camera = newCam.camera;
			}.bind(this));
		}

		LineRenderSystem.prototype = Object.create(System.prototype);
		LineRenderSystem.prototype.constructor = LineRenderSystem;

		var tmpVec1 = new Vector3();
		var tmpVec2 = new Vector3();
		var tmpVec3 = new Vector3();

		//setup a preset of colors
		LineRenderSystem.prototype.WHITE = new Vector3(1, 1, 1);
		LineRenderSystem.prototype.RED = new Vector3(1, 0, 0);
		LineRenderSystem.prototype.GREEN = new Vector3(0, 1, 0);
		LineRenderSystem.prototype.BLUE = new Vector3(0, 0, 1);
		LineRenderSystem.prototype.AQUA = new Vector3(0, 1, 1);
		LineRenderSystem.prototype.MAGENTA = new Vector3(1, 0, 1);
		LineRenderSystem.prototype.YELLOW = new Vector3(1, 1, 0);
		LineRenderSystem.prototype.BLACK = new Vector3(0, 0, 0);

		/**
		 * Draws a line between two {@link Vector3}'s with the specified color.
		 * @param {Vector3} start
		 * @param {Vector3} end
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @example
		 * var vector1 = new Vector3(0,0,0);
		 * var vector2 = new Vector3(13,3,7);
		 * var redColor = lineRenderSystem.RED;
		 * lineRenderSystem.drawLine(v1, v2, redColor);
		 */
		LineRenderSystem.prototype.drawLine = function (start, end, color) {
			var lineRenderer = this._lineRenderers[0];

			lineRenderer._addLine(start, end, color);
		};

		/**
		 * Used internally to calculate the line segments in an axis aligned box, and render them.
		 * @param {Vector3} start
		 * @param {Vector3} startEndDelta
		 * @param {number} startDataIndex
		 * @param {number} endDataIndex
		 * @param {number} startPolarity
		 * @param {number} endPolarity
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} transformMatrix
		 */
		LineRenderSystem.prototype._drawAxisLine = function (start, startEndDelta, startDataIndex, endDataIndex, startPolarity, endPolarity, color, transformMatrix) {
			var lineStart = tmpVec2.setVector(start);
			lineStart.data[startDataIndex] += startEndDelta.data[startDataIndex] * startPolarity;

			var lineEnd = tmpVec3.setVector(lineStart);
			lineEnd.data[endDataIndex] += startEndDelta.data[endDataIndex] * endPolarity;

			if (transformMatrix !== undefined) {
				transformMatrix.applyPostPoint(lineStart);
				transformMatrix.applyPostPoint(lineEnd);
			}

			this.drawLine(lineStart, lineEnd, color);
		};

		/**
		 * Draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix.
		 * @param {Vector3} min
		 * @param {Vector3} max
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} [transformMatrix]
		 */
		LineRenderSystem.prototype.drawAABox = function (min, max, color, transformMatrix) {
			var diff = tmpVec1.setVector(max).subVector(min);

			for (var a = 0; a < 3; a++) {

				for (var b = 0; b < 3; b++) {
					if (b !== a) {
						this._drawAxisLine(min, diff, a, b, 1, 1, color, transformMatrix);
					}
				}

				this._drawAxisLine(max, diff, a, a, -1, 1, color, transformMatrix);
				this._drawAxisLine(min, diff, a, a, 1, -1, color, transformMatrix);
			}
		};

		/**
		 * Draws a cross at a position with the given color and size.
		 * @param {Vector3} position
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {number} [size=0.05]
		 */
		LineRenderSystem.prototype.drawCross = function (position, color, size) {

			size = size || 0.05;

			var start = tmpVec1.setVector(position).addDirect(-size, 0.0, -size);
			var end = tmpVec2.setVector(position).addDirect(size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(size, 0.0, -size);
			end = tmpVec2.setVector(position).addDirect(-size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(0, -size, 0.0);
			end = tmpVec2.setVector(position).addDirect(0.0, size, 0.0);
			this.drawLine(start, end, color);
		};

		LineRenderSystem.prototype.render = function (renderer) {
			for (var i = 0; i < this._lineRenderers.length; i++) {
				var lineRenderer = this._lineRenderers[i];
				lineRenderer._updateVertexData();
				lineRenderer._manageRenderList(this.renderList);
				lineRenderer._clear();
			}

			renderer.checkResize(this.camera);

			if (this.camera) {
				renderer.render(this.renderList, this.camera, null, null, false);
			}
		};

		LineRenderSystem.prototype.clear = function () {
			for (var i = 0; i < this._lineRenderers.length; i++) {
				var lineRenderer = this._lineRenderers[i];
				lineRenderer._remove();
			}
			delete this._lineRenderers;

			this.world.gooRunner.renderer.clearShaderCache();
		};

		return LineRenderSystem;
	});<|endoftext|>


<commit_before>var keystone 		= require('keystone'),
	Types 			= keystone.Field.Types,
	// Export to make it available using require.  The keystone.list import throws a ReferenceError when importing a list
	// that comes later when sorting alphabetically
	SiteVisitor		= require('./User_SiteVisitor'),
	SocialWorker	= require('./User_SocialWorker'),
	Family			= require('./User_Family'),
	Admin			= require('./User_Admin');

// Create model. Additional options allow menu name to be used to auto-generate the URL
var Donation = new keystone.List('Donation');

// Create fields
Donation.add({

	date: { type: Types.Date, label: 'date', format: 'MM/DD/YYYY', required: true, initial: true },
	amount: { type: Types.Money, format: '$0,0.00', label: 'amount', required: true, initial: true },

	isRegistered: { type: Types.Boolean, label: 'is a registered user', default: true, required: true, initial: true },
	userType: { type: Types.Select, label: 'user type', options: 'site visitor, social worker, family, admin', dependsOn: { isRegistered: true }, filters: { isActive: true }, initial: true },
	siteVisitor: { type: Types.Relationship, label: 'donation from', ref: 'Site Visitor', dependsOn: { isRegistered: true, userType: 'site visitor' }, filters: { isActive: true }, initial: true },
	socialWorker: { type: Types.Relationship, label: 'donation from', ref: 'Social Worker', dependsOn: { isRegistered: true, userType: 'social worker' }, filters: { isActive: true }, initial: true },
	family: { type: Types.Relationship, label: 'donation from', ref: 'Family', dependsOn: { isRegistered: true, userType: 'family' }, filters: { isActive: true }, initial: true },
	admin: { type: Types.Relationship, label: 'donation from', ref: 'Admin', dependsOn: { isRegistered: true, userType: 'admin' }, filters: { isActive: true }, initial: true },
	unregisteredUser: { type: Types.Text, label: 'donation from', dependsOn: { isRegistered: false }, initial: true },
	name: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }

});

// Pre Save
Donation.schema.pre('save', function(next) {
	'use strict';

	var targetUserType,
		targetId;

	if(this.isRegistered) {
		switch(this.userType) {
			case 'site visitor': targetUserType = SiteVisitor; targetId = this.siteVisitor; break;
			case 'social worker': targetUserType = SocialWorker; targetId = this.socialWorker; break;
			case 'family': targetUserType = Family; targetId = this.family; break;
			case 'admin': targetUserType = Admin; targetId = this.admin;
		}

		var model = this;

		targetUserType.model.findById(targetId)
				.exec()
				.then(function(user) {
					console.log('user:',typeof user);
					console.log('user.name:',user.name);
					// If the user has a name, they aren't a family.  Use this info to pull the correct name
					if(user.name) {
						model.name = user.name.full;
					} else {
						// TODO: This functionality is identical to that in event, pull both out and put them in the model as a virtual
						// if the targetGroup is families, we need to prettify the attendee name
						var contact2Exists = user.contact2.name.full.length > 0 ? true : false;
						var sameLastName = user.contact1.name.last === user.contact2.name.last ? true : false;

						if(contact2Exists && sameLastName) {
							model.name = user.contact1.name.first + ' and ' + user.contact2.name.full;
						} else if(contact2Exists && !sameLastName) {
							model.name = user.contact1.name.full + ' and ' + user.contact2.name.full;
						} else {
							model.name = user.contact1.name.full;
						}
					}

					next();

				}, function(err) {
					console.log(err);
					next();
				});
	} else {

		this.name = this.unregisteredUser;
	}
});

// Define default columns in the admin interface and register the model
Donation.defaultColumns = 'name, amount, date';
Donation.register();
<commit_msg>clean up and add comments to the donation model<commit_after>var keystone 		= require( 'keystone' ),
	Types 			= keystone.Field.Types,
	// the keystone.list import throws a ReferenceError when importing a list that comes later when sorting alphabetically
	SiteVisitor		= require( './User_SiteVisitor' ),
	SocialWorker	= require( './User_SocialWorker' ),
	Family			= require( './User_Family' ),
	Admin			= require( './User_Admin' );

// create model
var Donation = new keystone.List( 'Donation' );

// create fields
Donation.add({

	date: { type: Types.Date, label: 'date', format: 'MM/DD/YYYY', required: true, initial: true },
	amount: { type: Types.Money, format: '$0,0.00', label: 'amount', required: true, initial: true },

	isRegistered: { type: Types.Boolean, label: 'is a registered user', default: true, required: true, initial: true },
	userType: { type: Types.Select, label: 'user type', options: 'site visitor, social worker, family, admin', dependsOn: { isRegistered: true }, filters: { isActive: true }, initial: true },
	siteVisitor: { type: Types.Relationship, label: 'donation from', ref: 'Site Visitor', dependsOn: { isRegistered: true, userType: 'site visitor' }, filters: { isActive: true }, initial: true },
	socialWorker: { type: Types.Relationship, label: 'donation from', ref: 'Social Worker', dependsOn: { isRegistered: true, userType: 'social worker' }, filters: { isActive: true }, initial: true },
	family: { type: Types.Relationship, label: 'donation from', ref: 'Family', dependsOn: { isRegistered: true, userType: 'family' }, filters: { isActive: true }, initial: true },
	admin: { type: Types.Relationship, label: 'donation from', ref: 'Admin', dependsOn: { isRegistered: true, userType: 'admin' }, filters: { isActive: true }, initial: true },
	unregisteredUser: { type: Types.Text, label: 'donation from', dependsOn: { isRegistered: false }, initial: true },
	name: { type: Types.Text, label: 'name', hidden: true, noedit: true, initial: false }

});

// presave hook
Donation.schema.pre( 'save', function( next ) {
	'use strict';

	let targetUserType,
		targetId;
	// if the user is registered in the system
	if( this.isRegistered ) {
		// set variables to allow us to fetch the user
		switch( this.userType ) {
			case 'site visitor'	: targetUserType = SiteVisitor; 	targetId = this.siteVisitor; break;
			case 'social worker': targetUserType = SocialWorker; 	targetId = this.socialWorker; break;
			case 'family'		: targetUserType = Family; 			targetId = this.family; break;
			case 'admin'		: targetUserType = Admin; 			targetId = this.admin;
		}
		// attempt to fetch the user who made the donation by their _id
		targetUserType.model.findById( targetId )
				.exec()
				.then( user => {
					// if the user has a name, they're not a family
					if( user.name ) {
						// store the name of the user's name
						this.name = user.name.full;
					// otherwise, if they're a family
					} else {
						// TODO: This functionality is identical to that in event, pull both out and put them in the model as a virtual
						// check to see if a second contact has been filled out
						const contact2Exists = user.contact2.name.full.length > 0;
						// check to see if both contacts share a last name
						const sameLastName = user.contact1.name.last === user.contact2.name.last;

						// if there's a second contact and they both contacts share a last name
						if( contact2Exists && sameLastName ) {
							// set the name to both first names, then the last name: John Smith + Jane Smith = John and Jane Smith
							model.name = user.contact1.name.first + ' and ' + user.contact2.name.full;
						// if there's a second contact, but the contacts have different last names
						} else if( contact2Exists && !sameLastName ) {
							// set the name to the two names appended: John Smith + Jane Doe = John Smith and Jane Doe
							model.name = user.contact1.name.full + ' and ' + user.contact2.name.full;
						// if there's no second contact
						} else {
							// set the name to contact 1's full name
							model.name = user.contact1.name.full;
						}
					}
					// allow further processing beyond this middleware
					next();

				}, err => {
					// log the error for debugging purposes
					console.error( `an error occurred fetching the user model to set the donator name - ${ err }` );
					// allow further processing beyond this middleware
					next();
				});
	// if the user is not registered in the system
	} else {
		// set the name to whatever was filled out in the free text field
		this.name = this.unregisteredUser;
	}
});

// Define default columns in the admin interface and register the model
Donation.defaultColumns = 'name, amount, date';
Donation.register();
<|endoftext|>


<commit_before>define([
		'goo/entities/systems/System',
		'goo/entities/SystemBus',
		'goo/addons/linerenderpack/LineRenderer',
		'goo/math/Vector3'
	],
	function (System,
			  SystemBus,
			  LineRenderer,
			  Vector3) {
		'use strict';

		/**
		 * Updates all of it's LineRenderers and exposes methods for drawing primitive line shapes.
		 * @param {World} world the world this system exists in.
		 */
		function LineRenderSystem(world) {
			System.call(this, 'LineRenderSystem', []);

			//an associative array for the LineRenderers
			this._lineRenderers = {};
			this._lineRendererKeys = [];

			this.world = world;
			this.camera = null;

			/**
			 *A managed array of all the LineRenderers render objects.
			 * @type {Object[]}
			 * */
			this.renderList = [];

			var that = this;
			//add the camera
			SystemBus.addListener('goo.setCurrentCamera', function (newCam) {
				that.camera = newCam.camera;
			});
		}

		LineRenderSystem.prototype = Object.create(System.prototype);
		LineRenderSystem.prototype.constructor = LineRenderSystem;

		var tmpVec1 = new Vector3();
		var tmpVec2 = new Vector3();
		var tmpVec3 = new Vector3();

		//setup a preset of colors
		LineRenderSystem.prototype.WHITE = new Vector3(1, 1, 1);
		LineRenderSystem.prototype.RED = new Vector3(1, 0, 0);
		LineRenderSystem.prototype.GREEN = new Vector3(0, 1, 0);
		LineRenderSystem.prototype.BLUE = new Vector3(0, 0, 1);
		LineRenderSystem.prototype.AQUA = new Vector3(0, 0.5, 0.5);
		LineRenderSystem.prototype.MAGENTA = new Vector3(1, 0, 1);
		LineRenderSystem.prototype.YELLOW = new Vector3(1, 1, 0);
		LineRenderSystem.prototype.BLACK = new Vector3(0, 0, 0);

		/**
		 * Packs a {@link Vector3} color to a number.
		 * Assumes that the color components are between 0-1.
		 * @param {Vector3} color
		 * @returns {number} The packed color.
		 * @example
		 * var packedColorRed = lineRenderSystem.packColor(lineRenderSystem.RED);
		 * console.log(packedColorRed); // would output: 65025
		 */
		LineRenderSystem.prototype.packColor = function (color) {
			var r = Math.floor(color.x * 255);
			var g = Math.floor(color.y * 255);
			var b = Math.floor(color.z * 255);

			return r * 255 + g * 255 * 255 + b;
		};

		/**
		 * Draws a line between two {@link Vector3}'s with the specified color.
		 * @param {Vector3} start
		 * @param {Vector3} end
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @example
		 * var vector1 = new Vector3(0,0,0);
		 * var vector2 = new Vector3(13,3,7);
		 * var redColor = lineRenderSystem.RED;
		 * lineRenderSystem.drawLine(v1, v2, redColor);
		 */
		LineRenderSystem.prototype.drawLine = function (start, end, color) {

			var packedColor = this.packColor(color);

			var lineRenderer = this._lineRenderers[packedColor];
			if (!lineRenderer) {
				lineRenderer = this._lineRenderers[packedColor] = new LineRenderer(this.world, color);
				this._lineRendererKeys = Object.keys(this._lineRenderers);
			}
			lineRenderer._addLine(start, end);
		};

		/**
		 * Used internally to calculate the line segments in an axis aligned box, and render them.
		 * @param {Vector3} start
		 * @param {Vector3} startEndDelta
		 * @param {number} startDataIndex
		 * @param {number} endDataIndex
		 * @param {number} startPolarity
		 * @param {number} endPolarity
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} transformMatrix
		 */
		LineRenderSystem.prototype._drawAxisLine = function (start, startEndDelta, startDataIndex, endDataIndex, startPolarity, endPolarity, color, transformMatrix) {
			var lineStart = tmpVec2.setVector(start);
			lineStart.data[startDataIndex] += startEndDelta.data[startDataIndex] * startPolarity;

			var lineEnd = tmpVec3.setVector(lineStart);
			lineEnd.data[endDataIndex] += startEndDelta.data[endDataIndex] * endPolarity;

			if (transformMatrix !== undefined) {
				transformMatrix.applyPostPoint(lineStart);
				transformMatrix.applyPostPoint(lineEnd);
			}

			this.drawLine(lineStart, lineEnd, color);
		};

		/**
		 * Draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix.
		 * @param {Vector3} min
		 * @param {Vector3} max
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} [transformMatrix]
		 */
		LineRenderSystem.prototype.drawAABox = function (min, max, color, transformMatrix) {
			var diff = tmpVec1.setVector(max).subVector(min);

			for (var a = 0; a < 3; a++) {

				for (var b = 0; b < 3; b++) {
					if (b !== a) {
						this._drawAxisLine(min, diff, a, b, 1, 1, color, transformMatrix);
					}
				}

				this._drawAxisLine(max, diff, a, a, -1, 1, color, transformMatrix);
				this._drawAxisLine(min, diff, a, a, 1, -1, color, transformMatrix);
			}
		};

		/**
		 * Draws a cross at a position with the given color and size.
		 * @param {Vector3} position
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {number} [size=0.05]
		 */
		LineRenderSystem.prototype.drawCross = function (position, color, size) {

			size = size || 0.05;

			var start = tmpVec1.setVector(position).addDirect(-size, 0.0, -size);
			var end = tmpVec2.setVector(position).addDirect(size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(size, 0.0, -size);
			end = tmpVec2.setVector(position).addDirect(-size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(0, -size, 0.0);
			end = tmpVec2.setVector(position).addDirect(0.0, size, 0.0);
			this.drawLine(start, end, color);
		};

		LineRenderSystem.prototype.render = function (renderer) {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._updateVertexData();
				lineRenderer._manageRenderList(this.renderList);
				lineRenderer._clear();
			}

			renderer.checkResize(this.camera);

			if (this.camera) {
				renderer.render(this.renderList, this.camera, null, null, false);
			}
		};

		LineRenderSystem.prototype.clear = function () {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._remove();
			}
			delete this._lineRenderers;

			this.world.gooRunner.renderer.clearShaderCache();
		};

		return LineRenderSystem;
	});<commit_msg>rename packColor to encodeColor, fix the encodeColor<commit_after>define([
		'goo/entities/systems/System',
		'goo/entities/SystemBus',
		'goo/addons/linerenderpack/LineRenderer',
		'goo/math/Vector3'
	],
	function (System,
			  SystemBus,
			  LineRenderer,
			  Vector3) {
		'use strict';

		/**
		 * Updates all of it's LineRenderers and exposes methods for drawing primitive line shapes.
		 * @param {World} world the world this system exists in.
		 */
		function LineRenderSystem(world) {
			System.call(this, 'LineRenderSystem', []);

			//an associative array for the LineRenderers
			this._lineRenderers = {};
			this._lineRendererKeys = [];

			this.world = world;
			this.camera = null;

			/**
			 *A managed array of all the LineRenderers render objects.
			 * @type {Object[]}
			 * */
			this.renderList = [];

			var that = this;
			//add the camera
			SystemBus.addListener('goo.setCurrentCamera', function (newCam) {
				that.camera = newCam.camera;
			});
		}

		LineRenderSystem.prototype = Object.create(System.prototype);
		LineRenderSystem.prototype.constructor = LineRenderSystem;

		var tmpVec1 = new Vector3();
		var tmpVec2 = new Vector3();
		var tmpVec3 = new Vector3();

		//setup a preset of colors
		LineRenderSystem.prototype.WHITE = new Vector3(1, 1, 1);
		LineRenderSystem.prototype.RED = new Vector3(1, 0, 0);
		LineRenderSystem.prototype.GREEN = new Vector3(0, 1, 0);
		LineRenderSystem.prototype.BLUE = new Vector3(0, 0, 1);
		LineRenderSystem.prototype.AQUA = new Vector3(0, 0.5, 0.5);
		LineRenderSystem.prototype.MAGENTA = new Vector3(1, 0, 1);
		LineRenderSystem.prototype.YELLOW = new Vector3(1, 1, 0);
		LineRenderSystem.prototype.BLACK = new Vector3(0, 0, 0);

		/**
		 * Encodes a {@link Vector3} color to a number.
		 * Assumes that the color components are between 0-1.
		 * @param {Vector3} color
		 * @returns {number} The encoded color.
		 * @example
		 * var encodedColorRed = lineRenderSystem.encodeColor(lineRenderSystem.RED);
		 * console.log(encodedColorRed); // would output: 16777216
		 */
		LineRenderSystem.prototype.encodeColor = function (color) {
			var r = Math.floor(color.r * 255);
			var g = Math.floor(color.g * 255);
			var b = Math.floor(color.b * 255);

			return r * 65536 + g * 256 + b;
		};

		/**
		 * Draws a line between two {@link Vector3}'s with the specified color.
		 * @param {Vector3} start
		 * @param {Vector3} end
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @example
		 * var vector1 = new Vector3(0,0,0);
		 * var vector2 = new Vector3(13,3,7);
		 * var redColor = lineRenderSystem.RED;
		 * lineRenderSystem.drawLine(v1, v2, redColor);
		 */
		LineRenderSystem.prototype.drawLine = function (start, end, color) {

			var encodedColor = this.encodeColor(color);

			var lineRenderer = this._lineRenderers[encodedColor];
			if (!lineRenderer) {
				lineRenderer = this._lineRenderers[encodedColor] = new LineRenderer(this.world, color);
				this._lineRendererKeys = Object.keys(this._lineRenderers);
			}
			lineRenderer._addLine(start, end);
		};

		/**
		 * Used internally to calculate the line segments in an axis aligned box, and render them.
		 * @param {Vector3} start
		 * @param {Vector3} startEndDelta
		 * @param {number} startDataIndex
		 * @param {number} endDataIndex
		 * @param {number} startPolarity
		 * @param {number} endPolarity
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} transformMatrix
		 */
		LineRenderSystem.prototype._drawAxisLine = function (start, startEndDelta, startDataIndex, endDataIndex, startPolarity, endPolarity, color, transformMatrix) {
			var lineStart = tmpVec2.setVector(start);
			lineStart.data[startDataIndex] += startEndDelta.data[startDataIndex] * startPolarity;

			var lineEnd = tmpVec3.setVector(lineStart);
			lineEnd.data[endDataIndex] += startEndDelta.data[endDataIndex] * endPolarity;

			if (transformMatrix !== undefined) {
				transformMatrix.applyPostPoint(lineStart);
				transformMatrix.applyPostPoint(lineEnd);
			}

			this.drawLine(lineStart, lineEnd, color);
		};

		/**
		 * Draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix.
		 * @param {Vector3} min
		 * @param {Vector3} max
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {Matrix4x4} [transformMatrix]
		 */
		LineRenderSystem.prototype.drawAABox = function (min, max, color, transformMatrix) {
			var diff = tmpVec1.setVector(max).subVector(min);

			for (var a = 0; a < 3; a++) {

				for (var b = 0; b < 3; b++) {
					if (b !== a) {
						this._drawAxisLine(min, diff, a, b, 1, 1, color, transformMatrix);
					}
				}

				this._drawAxisLine(max, diff, a, a, -1, 1, color, transformMatrix);
				this._drawAxisLine(min, diff, a, a, 1, -1, color, transformMatrix);
			}
		};

		/**
		 * Draws a cross at a position with the given color and size.
		 * @param {Vector3} position
		 * @param {Vector3} color A vector with its components between 0-1.
		 * @param {number} [size=0.05]
		 */
		LineRenderSystem.prototype.drawCross = function (position, color, size) {

			size = size || 0.05;

			var start = tmpVec1.setVector(position).addDirect(-size, 0.0, -size);
			var end = tmpVec2.setVector(position).addDirect(size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(size, 0.0, -size);
			end = tmpVec2.setVector(position).addDirect(-size, 0.0, size);
			this.drawLine(start, end, color);

			start = tmpVec1.setVector(position).addDirect(0, -size, 0.0);
			end = tmpVec2.setVector(position).addDirect(0.0, size, 0.0);
			this.drawLine(start, end, color);
		};

		LineRenderSystem.prototype.render = function (renderer) {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._updateVertexData();
				lineRenderer._manageRenderList(this.renderList);
				lineRenderer._clear();
			}

			renderer.checkResize(this.camera);

			if (this.camera) {
				renderer.render(this.renderList, this.camera, null, null, false);
			}
		};

		LineRenderSystem.prototype.clear = function () {
			for (var i = 0; i < this._lineRendererKeys.length; i++) {
				var lineRenderer = this._lineRenderers[this._lineRendererKeys[i]];
				lineRenderer._remove();
			}
			delete this._lineRenderers;

			this.world.gooRunner.renderer.clearShaderCache();
		};

		return LineRenderSystem;
	});<|endoftext|>


<commit_before>define([
	'goo/entities/systems/System',
	'goo/addons/linerenderpack/LineRenderer',
	'goo/math/Vector3'
],
function (
		System,
        LineRenderer,
		Vector3) {
		'use strict';

    /**
     * updates all of its {LineRenderer}'s and exposes methods for drawing primitives
     * @param {World} world the world this system exists in
     */
    function LineRenderSystem(world){
        System.call(this, 'LineRenderSystem', []);

        this._renderers = [];
		this.world = world;
    }
    LineRenderSystem.prototype = Object.create(System.prototype);

	var tmpVec1 = new Vector3();
	var tmpVec2 = new Vector3();
	var tmpVec3 = new Vector3();

    //setup basic colors
    LineRenderSystem.prototype.WHITE = '[1,1,1]';
    LineRenderSystem.prototype.RED = '[1,0,0]';
    LineRenderSystem.prototype.GREEN = '[0,1,0]';
    LineRenderSystem.prototype.BLUE = '[0,0,1]';
    LineRenderSystem.prototype.AQUA = '[0,1,1]';
    LineRenderSystem.prototype.MAGENTA = '[1,0,1]';
    LineRenderSystem.prototype.YELLOW = '[1,1,0]';
    LineRenderSystem.prototype.BLACK = '[0,0,0]';

    /**
     * draws a line between two {@link Vector3}'s with the specified color
     * @param {Vector3} start
     * @param {Vector3} end
     * @param {String} colorStr following the format of '[red,green,blue]' where red,green,blue ranges between 0-1
     * @example
     * var v1 = new Vector3(0,0,0);
     * var v2 = new Vector3(13,3,7);
     * var color = "[1,0,0]";
     * LineRenderSystem.drawLine(v1, v2, color);
     */
    LineRenderSystem.prototype.drawLine = function(start, end, colorStr) {

        var lineRenderer = this._renderers[colorStr];
        if (!lineRenderer)
        {
            lineRenderer = this._renderers[this._renderers.length] = new LineRenderer(this, colorStr);

            //reference a string color index to the actual object
            this._renderers[colorStr] = lineRenderer;
        }
        lineRenderer.addLine(start, end);
    };

    /**
     * used internally to draw a line for an axis aligned box segment
     * @param {Vector3} startIn
     * @param {Vector3} diff
     * @param {int} startIndex
     * @param {int} endIndex
     * @param {float} startMul
     * @param {float} endMul
     * @param {String} colorStr
     * @param {Matrix4x4} transformMatrix
     */
    LineRenderSystem.prototype._drawAxisLine = function(startIn, diff, startIndex, endIndex, startMul, endMul, colorStr, transformMatrix) {
        var start = tmpVec2.setVector(startIn);
        start.data[startIndex] += diff.data[startIndex]*startMul;

        var end = tmpVec3.setVector(start);
        end.data[endIndex] += diff.data[endIndex]*endMul;

        if(transformMatrix !== undefined)
        {
            transformMatrix.applyPostPoint(start);
            transformMatrix.applyPostPoint(end);
        }

        this.drawLine(start, end, colorStr);
    };

    /**
     * draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix
     * @param {Vector3} min
     * @param {Vector3} max
     * @param {String} colorStr
     * @param {Matrix4x4} [transformMatrix]
     */
    LineRenderSystem.prototype.drawAABox = function(min, max, colorStr, transformMatrix) {
        for(var a=0; a<3; a++)
        {
            var diff = tmpVec1.setVector(max).subVector(min);
            for(var b=0; b<3; b++)
            {
                if(b !== a) {
                    this._drawAxisLine(min, diff, a, b, 1, 1, colorStr, transformMatrix);
                }
            }

            this._drawAxisLine(max, diff, a, a, -1, 1, colorStr, transformMatrix);
            this._drawAxisLine(min, diff, a, a, 1, -1, colorStr, transformMatrix);
        }
    };

    LineRenderSystem.prototype.process = function (){
        for(var i=0; i<this._renderers.length; i++) {
            this._renderers[i].update();
        }
    };

    LineRenderSystem.prototype.remove = function (){
        for(var i=0; i<this._renderers.length; i++)
        {
            if(this._renderers[i])
            {
                this._renderers[i].remove();
            }
        }
        this._renderers.length = 0;

        this.world.gooRunner.renderer.clearShaderCache();
    };

	return LineRenderSystem;
});<commit_msg>add drawCross method<commit_after>define([
	'goo/entities/systems/System',
	'goo/addons/linerenderpack/LineRenderer',
	'goo/math/Vector3'
],
function (
		System,
        LineRenderer,
		Vector3) {
		'use strict';

    /**
     * updates all of its {LineRenderer}'s and exposes methods for drawing primitives
     * @param {World} world the world this system exists in
     */
    function LineRenderSystem(world){
        System.call(this, 'LineRenderSystem', []);

        this._renderers = [];
		this.world = world;
    }
    LineRenderSystem.prototype = Object.create(System.prototype);

	var tmpVec1 = new Vector3();
	var tmpVec2 = new Vector3();
	var tmpVec3 = new Vector3();

    //setup basic colors
    LineRenderSystem.prototype.WHITE = '[1,1,1]';
    LineRenderSystem.prototype.RED = '[1,0,0]';
    LineRenderSystem.prototype.GREEN = '[0,1,0]';
    LineRenderSystem.prototype.BLUE = '[0,0,1]';
    LineRenderSystem.prototype.AQUA = '[0,1,1]';
    LineRenderSystem.prototype.MAGENTA = '[1,0,1]';
    LineRenderSystem.prototype.YELLOW = '[1,1,0]';
    LineRenderSystem.prototype.BLACK = '[0,0,0]';

    /**
     * draws a line between two {@link Vector3}'s with the specified color
     * @param {Vector3} start
     * @param {Vector3} end
     * @param {String} colorStr following the format of '[red,green,blue]' where red,green,blue ranges between 0-1
     * @example
     * var v1 = new Vector3(0,0,0);
     * var v2 = new Vector3(13,3,7);
     * var redColor = "[1,0,0]";
     * LineRenderSystem.drawLine(v1, v2, redColor);
     */
    LineRenderSystem.prototype.drawLine = function(start, end, colorStr) {

        var lineRenderer = this._renderers[colorStr];
        if (!lineRenderer)
        {
            lineRenderer = this._renderers[this._renderers.length] = new LineRenderer(this, colorStr);

            //reference a string color index to the actual object
            this._renderers[colorStr] = lineRenderer;
        }
        lineRenderer.addLine(start, end);
    };

    /**
     * used internally to draw a line for an axis aligned box segment
     * @param {Vector3} startIn
     * @param {Vector3} diff
     * @param {int} startIndex
     * @param {int} endIndex
     * @param {float} startMul
     * @param {float} endMul
     * @param {String} colorStr
     * @param {Matrix4x4} transformMatrix
     */
    LineRenderSystem.prototype._drawAxisLine = function(startIn, diff, startIndex, endIndex, startMul, endMul, colorStr, transformMatrix) {
        var start = tmpVec2.setVector(startIn);
        start.data[startIndex] += diff.data[startIndex]*startMul;

        var end = tmpVec3.setVector(start);
        end.data[endIndex] += diff.data[endIndex]*endMul;

        if(transformMatrix !== undefined)
        {
            transformMatrix.applyPostPoint(start);
            transformMatrix.applyPostPoint(end);
        }

        this.drawLine(start, end, colorStr);
    };

    /**
     * draws an axis aligned box between the min and max points, can be transformed to a specific space using the matrix
     * @param {Vector3} min
     * @param {Vector3} max
     * @param {String} colorStr
     * @param {Matrix4x4} [transformMatrix]
     */
    LineRenderSystem.prototype.drawAABox = function(min, max, colorStr, transformMatrix) {
        for(var a=0; a<3; a++)
        {
            var diff = tmpVec1.setVector(max).subVector(min);
            for(var b=0; b<3; b++)
            {
                if(b !== a) {
                    this._drawAxisLine(min, diff, a, b, 1, 1, colorStr, transformMatrix);
                }
            }

            this._drawAxisLine(max, diff, a, a, -1, 1, colorStr, transformMatrix);
            this._drawAxisLine(min, diff, a, a, 1, -1, colorStr, transformMatrix);
        }
    };

    /**
     * draws a cross at a position with the given color and size
     * @param {Vector3} position
     * @param {String} colorStr
     * @param {float} [size]
     */
    LineRenderSystem.prototype.drawCross = function(position, colorStr, size) {

        size = size || 0.05;

        var start = tmpVec1.setVector(position).addDirect(-size,0.0,-size);
        var end = tmpVec2.setVector(position).addDirect(size,0.0,size);
        this.drawLine(start, end, colorStr);

        start = tmpVec1.setVector(position).addDirect(size,0.0,-size);
        end = tmpVec2.setVector(position).addDirect(-size,0.0,size);
        this.drawLine(start, end, colorStr);

        start = tmpVec1.setVector(position).addDirect(0,-size,0.0);
        end = tmpVec2.setVector(position).addDirect(0.0,size,0.0);
        this.drawLine(start, end, colorStr);
    };

    LineRenderSystem.prototype.process = function (){
        for(var i=0; i<this._renderers.length; i++) {
            this._renderers[i].update();
        }
    };

    LineRenderSystem.prototype.remove = function (){
        for(var i=0; i<this._renderers.length; i++)
        {
            if(this._renderers[i])
            {
                this._renderers[i].remove();
            }
        }
        this._renderers.length = 0;

        this.world.gooRunner.renderer.clearShaderCache();
    };

	return LineRenderSystem;
});<|endoftext|>


<commit_before>var express = require('express');
var consolidate = require('consolidate');
var stats = require('./stats');
var manifest = require('./manifest');
var statics = require('./statics');
var brains = require('./brains');
var errors = require('./errors');
var graph = require('./graph');
var feed = require('./feed');

var app = express();

app.engine('html', consolidate.handlebars);
app.set('view engine', 'html');
app.set('views', __dirname + '/dist');

statics.init(app);

app.get('/:user/:repo/dev-info.json',  devInfo);
app.get('/:user/:repo/graph.json',     dependencyGraph);
app.get('/:user/:repo/dev-graph.json', devDependencyGraph);
app.get('/:user/:repo/rss.xml',        rssFeed);
app.get('/:user/:repo/dev-rss.xml',    devRssFeed);
app.get('/:user/:repo/status.png',     statusBadge);
app.get('/:user/:repo.png',            statusBadge);
app.get('/:user/:repo',                statusPage);
app.get('/dependency-counts.json',     dependencyCounts);
app.get('/stats',                      statsPage);
app.get('/',                           indexPage);

/**
 * Do a home page
 */
function indexPage(req, res) {
	res.render('index', {
		recentlyRetrievedManifests: stats.getRecentlyRetrievedManifests(),
		recentlyUpdatedPackages: stats.getRecentlyUpdatedPackages()
	});
}

/**
 * Show pretty graphs and gaudy baubles
 */
function statsPage(req, res) {

	res.render('stats', {
		recentlyUpdatedPackages: stats.getRecentlyUpdatedPackages(),
		recentlyRetrievedManifests: stats.getRecentlyRetrievedManifests(),
		recentlyUpdatedManifests: stats.getRecentlyUpdatedManifests()
	});
}

function dependencyCounts(req, res) {
	res.json(stats.getDependencyCounts());
}

/**
 * Send the status badge for this user and repository
 */
function statusPage(req, res) {

	withManifestAndInfo(req, res, function(manifest, info) {

		res.render('status', {
			user: req.params.user,
			repo: req.params.repo,
			manifest: manifest,
			info: info
		});

	});
}

/**
 * Send the status badge for this user and repository
 */
function statusBadge(req, res) {

	withManifestAndInfo(req, res, function(manifest, info) {

		res.setHeader('Cache-Control', 'no-cache');

		var totalDeps = info.deps.length;

		if(totalDeps && info.totals.unpinned.outOfDate) {

			if(info.totals.unpinned.outOfDate / totalDeps > 0.25) {
				res.sendfile('dist/img/outofdate.png');
			} else {
				res.sendfile('dist/img/notsouptodate.png');
			}

		} else {
			res.sendfile('dist/img/uptodate.png');
		}
	});
}

function dependencyGraph(req, res) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		graph.getProjectDependencyGraph(req.params.user + '/' + req.params.repo, manifest.version, manifest.dependencies || {}, function(err, graph) {

			if(errors.happened(err, req, res, 'Failed to get graph data')) {
				return;
			}

			res.json(graph);
		});
	});
}

function devDependencyGraph(req, res) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		graph.getProjectDependencyGraph(req.params.user + '/' + req.params.repo + '#dev', manifest.version, manifest.devDependencies || {}, function(err, graph) {

			if(errors.happened(err, req, res, 'Failed to get graph data')) {
				return;
			}

			res.json(graph);
		});
	});
}

function buildRssFeed(req, res, dev) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		feed.get(manifest, {dev: dev}, function(err, xml) {

			if(errors.happened(err, req, res, 'Failed to build RSS XML')) {
				return;
			}

			res.contentType('application/rss+xml');
			res.send(xml, 200);
		});
	});
}

function rssFeed(req, res) {
	buildRssFeed(req, res, false);
}

function devRssFeed(req, res) {
	buildRssFeed(req, res, true);
}

function devInfo(req, res) {
	withManifestAndInfo(req, res, {dev: true}, function(manifest, info) {
		res.json(info);
	});
}

/**
 * Common callback boilerplate of getting a manifest and info for the status page and badge
 */
function withManifestAndInfo(req, res, options, callback) {

	// Allow callback to be passed as third parameter
	if(!callback) {
		callback = options;
		options = {};
	} else {
		options = options || {};
	}

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		brains.getInfo(manifest, options, function(err, info) {

			if(errors.happened(err, req, res, 'Failed to get dependency info')) {
				return;
			}

			callback(manifest, info);
		});
	});
}

app.use(function(req, res, next){
	res.status(404);

	// respond with html page
	if (req.accepts('html')) {
		res.render('404');
		return;
	}

	// respond with json
	if (req.accepts('json')) {
		res.send({err: 'Not found'});
		return;
	}

	// default to plain-text. send()
	res.type('txt').send('Not found');
});

if(!process.argv[2]) {
	console.log('No port specified');
	return;
}

app.listen(process.argv[2]);

console.log('David listening on port', process.argv[2]);<commit_msg>Closes #34 - David now uses process.title to name the process<commit_after>var express = require('express');
var consolidate = require('consolidate');
var stats = require('./stats');
var manifest = require('./manifest');
var statics = require('./statics');
var brains = require('./brains');
var errors = require('./errors');
var graph = require('./graph');
var feed = require('./feed');

var app = express();

app.engine('html', consolidate.handlebars);
app.set('view engine', 'html');
app.set('views', __dirname + '/dist');

statics.init(app);

app.get('/:user/:repo/dev-info.json',  devInfo);
app.get('/:user/:repo/graph.json',     dependencyGraph);
app.get('/:user/:repo/dev-graph.json', devDependencyGraph);
app.get('/:user/:repo/rss.xml',        rssFeed);
app.get('/:user/:repo/dev-rss.xml',    devRssFeed);
app.get('/:user/:repo/status.png',     statusBadge);
app.get('/:user/:repo.png',            statusBadge);
app.get('/:user/:repo',                statusPage);
app.get('/dependency-counts.json',     dependencyCounts);
app.get('/stats',                      statsPage);
app.get('/',                           indexPage);

/**
 * Do a home page
 */
function indexPage(req, res) {
	res.render('index', {
		recentlyRetrievedManifests: stats.getRecentlyRetrievedManifests(),
		recentlyUpdatedPackages: stats.getRecentlyUpdatedPackages()
	});
}

/**
 * Show pretty graphs and gaudy baubles
 */
function statsPage(req, res) {

	res.render('stats', {
		recentlyUpdatedPackages: stats.getRecentlyUpdatedPackages(),
		recentlyRetrievedManifests: stats.getRecentlyRetrievedManifests(),
		recentlyUpdatedManifests: stats.getRecentlyUpdatedManifests()
	});
}

function dependencyCounts(req, res) {
	res.json(stats.getDependencyCounts());
}

/**
 * Send the status badge for this user and repository
 */
function statusPage(req, res) {

	withManifestAndInfo(req, res, function(manifest, info) {

		res.render('status', {
			user: req.params.user,
			repo: req.params.repo,
			manifest: manifest,
			info: info
		});

	});
}

/**
 * Send the status badge for this user and repository
 */
function statusBadge(req, res) {

	withManifestAndInfo(req, res, function(manifest, info) {

		res.setHeader('Cache-Control', 'no-cache');

		var totalDeps = info.deps.length;

		if(totalDeps && info.totals.unpinned.outOfDate) {

			if(info.totals.unpinned.outOfDate / totalDeps > 0.25) {
				res.sendfile('dist/img/outofdate.png');
			} else {
				res.sendfile('dist/img/notsouptodate.png');
			}

		} else {
			res.sendfile('dist/img/uptodate.png');
		}
	});
}

function dependencyGraph(req, res) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		graph.getProjectDependencyGraph(req.params.user + '/' + req.params.repo, manifest.version, manifest.dependencies || {}, function(err, graph) {

			if(errors.happened(err, req, res, 'Failed to get graph data')) {
				return;
			}

			res.json(graph);
		});
	});
}

function devDependencyGraph(req, res) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		graph.getProjectDependencyGraph(req.params.user + '/' + req.params.repo + '#dev', manifest.version, manifest.devDependencies || {}, function(err, graph) {

			if(errors.happened(err, req, res, 'Failed to get graph data')) {
				return;
			}

			res.json(graph);
		});
	});
}

function buildRssFeed(req, res, dev) {

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		feed.get(manifest, {dev: dev}, function(err, xml) {

			if(errors.happened(err, req, res, 'Failed to build RSS XML')) {
				return;
			}

			res.contentType('application/rss+xml');
			res.send(xml, 200);
		});
	});
}

function rssFeed(req, res) {
	buildRssFeed(req, res, false);
}

function devRssFeed(req, res) {
	buildRssFeed(req, res, true);
}

function devInfo(req, res) {
	withManifestAndInfo(req, res, {dev: true}, function(manifest, info) {
		res.json(info);
	});
}

/**
 * Common callback boilerplate of getting a manifest and info for the status page and badge
 */
function withManifestAndInfo(req, res, options, callback) {

	// Allow callback to be passed as third parameter
	if(!callback) {
		callback = options;
		options = {};
	} else {
		options = options || {};
	}

	var url = manifest.getGithubManifestUrl(req.params.user, req.params.repo);

	manifest.getManifest(url, function(err, manifest) {

		if(errors.happened(err, req, res, 'Failed to get package.json')) {
			return;
		}

		brains.getInfo(manifest, options, function(err, info) {

			if(errors.happened(err, req, res, 'Failed to get dependency info')) {
				return;
			}

			callback(manifest, info);
		});
	});
}

app.use(function(req, res, next){
	res.status(404);

	// respond with html page
	if (req.accepts('html')) {
		res.render('404');
		return;
	}

	// respond with json
	if (req.accepts('json')) {
		res.send({err: 'Not found'});
		return;
	}

	// default to plain-text. send()
	res.type('txt').send('Not found');
});

if(!process.argv[2]) {
	console.log('No port specified');
	return;
}

app.listen(process.argv[2]);

process.title = 'david:' + process.argv[2];

console.log('David listening on port', process.argv[2]);<|endoftext|>


<commit_before>var urlKeyPrefix = "url_";
var clicksKeyPrefix = "clicks_";

var createResponseObject = function(key, url, clicks) {
  return {
    key: key,
    url: url,
    clicks: clicks
  };
};

var redisResponseToObject = function(key, a, b) {
  resultUrl = a[1];
  resultClicks = b[1];
  if (resultUrl && resultClicks)
    return createResponseObject(key, resultUrl, resultClicks);
  else
    return false;
};

var baseKey = function(key, prefix) {
  return key.substring(prefix.length);
};

module.exports = function(redis) {
  var Redirect = {};

  Redirect.get = function(key, callback) {
    key = key.toLowerCase();
    redis.multi({ pipeline: false });
    redis.get(urlKeyPrefix+key);
    redis.get(clicksKeyPrefix+key);
    redis.incr(clicksKeyPrefix+key);
    redis.exec(function(err, result) {
      if (err)
        return callback(err);
      callback(false, redisResponseToObject(key, result[0], result[1]));
    });
  };

  Redirect.create = function(key, url, callback) {
    key = key.toLowerCase();
    redis.multi({ pipeline: false });
    redis.set(urlKeyPrefix+key, url);
    redis.set(clicksKeyPrefix+key, 0);
    redis.exec(function(err, result) {
      if (err) {
        callback(err);
        return;
      }
      callback(false, createResponseObject(key, url, 0));
    });
  };

  Redirect.delete = function(key, callback) {
    key = key.toLowerCase();
    redis.del(urlKeyPrefix+key, clicksKeyPrefix+key, function(err, result) {
      if (err) {
        callback(err);
        return;
      }
      callback(!!err);
    });
  };

  Redirect.getAll = function(callback) {
    redis.keys(urlKeyPrefix+"*", function(keysError, keys) {
      if (keysError)
        return callback(keysError);
      redis.multi({ pipeline: false });
      keys.forEach(function(element) {
        var key = baseKey(element, urlKeyPrefix);
        redis.get(urlKeyPrefix+key);
        redis.get(clicksKeyPrefix+key);
      });
      redis.exec(function(err, results) {
        if (err) {
          callback(err);
          return;
        }
        var resultArray = [];
        for (var i = 0; i < keys.length; i++) {
          var key = baseKey(keys[i], urlKeyPrefix);
          resultArray.push(redisResponseToObject(key, results[2*i], results[2*i+1]));
        }
        resultArray.sort(function(a,b){
          return a.key.localeCompare(b.key);
        });
        callback(false, resultArray);
      });
    });
  };

  return Redirect;
};
<commit_msg>Format links<commit_after>var urlKeyPrefix = "url_";
var clicksKeyPrefix = "clicks_";

var createResponseObject = function(key, url, clicks) {
  return {
    key: key,
    url: url,
    clicks: clicks
  };
};

var redisResponseToObject = function(key, a, b) {
  resultUrl = a[1];
  resultClicks = b[1];
  if (resultUrl && resultClicks)
    return createResponseObject(key, resultUrl, resultClicks);
  else
    return false;
};

var baseKey = function(key, prefix) {
  return key.substring(prefix.length);
};

module.exports = function(redis) {
  var Redirect = {};

  Redirect.get = function(key, callback) {
    key = decodeURIComponent(key.toLowerCase()).replace(/[^a-z0-9]/g,'-');
    redis.multi({ pipeline: false });
    redis.get(urlKeyPrefix+key);
    redis.get(clicksKeyPrefix+key);
    redis.incr(clicksKeyPrefix+key);
    redis.exec(function(err, result) {
      if (err)
        return callback(err);
      callback(false, redisResponseToObject(key, result[0], result[1]));
    });
  };

  Redirect.create = function(key, url, callback) {
    key = decodeURIComponent(key.toLowerCase()).replace(/[^a-z0-9]/g,'-');
    redis.multi({ pipeline: false });
    redis.set(urlKeyPrefix+key, url);
    redis.set(clicksKeyPrefix+key, 0);
    redis.exec(function(err, result) {
      if (err) {
        callback(err);
        return;
      }
      callback(false, createResponseObject(key, url, 0));
    });
  };

  Redirect.delete = function(key, callback) {
    key = decodeURIComponent(key.toLowerCase()).replace(/[^a-z0-9]/g,'-');
    redis.del(urlKeyPrefix+key, clicksKeyPrefix+key, function(err, result) {
      if (err) {
        callback(err);
        return;
      }
      callback(!!err);
    });
  };

  Redirect.getAll = function(callback) {
    redis.keys(urlKeyPrefix+"*", function(keysError, keys) {
      if (keysError)
        return callback(keysError);
      redis.multi({ pipeline: false });
      keys.forEach(function(element) {
        var key = baseKey(element, urlKeyPrefix);
        redis.get(urlKeyPrefix+key);
        redis.get(clicksKeyPrefix+key);
      });
      redis.exec(function(err, results) {
        if (err) {
          callback(err);
          return;
        }
        var resultArray = [];
        for (var i = 0; i < keys.length; i++) {
          var key = baseKey(keys[i], urlKeyPrefix);
          resultArray.push(redisResponseToObject(key, results[2*i], results[2*i+1]));
        }
        resultArray.sort(function(a,b){
          return a.key.localeCompare(b.key);
        });
        callback(false, resultArray);
      });
    });
  };

  return Redirect;
};
<|endoftext|>


<commit_before>'use strict';
const path = require('path');
const fs = require('fs');
const i18n = require('i18n');
const electron = require('electron');
const ipc = electron.ipcMain;
const Tray = electron.Tray;
const dialog = electron.dialog;

// Module to control application life.
const app = electron.app;

if (require('electron-squirrel-startup')) {
    app.quit();
}

// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const Menu = electron.Menu;
const debug = /--debug/.test(process.argv[2]);

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow = null;
let tray = null;
const config = path.resolve(app.getPath('userData'), 'config.json');
const localeArray = ['en-US', 'zh-CN', 'zh-TW'];

function initialize() {
    const shouldQuit = makeSingleInstance();
    if (shouldQuit) {
        return app.exit(0);
    }

    i18n.configure({
        locales: localeArray,
        directory: `${__dirname}/locales`,
        objectNotation: true
    });

    function createWindow() {
        const windowOptions = {
            width: 1080,
            minWidth: 680,
            height: 840,
            icon: path.join(__dirname, `${process.platform === 'win32' ? '/public/image/hostsdock.ico' : '/public/image/hostsdock.png'}`),
            show: false
        };

        // Create the browser window.
        mainWindow = new BrowserWindow(windowOptions);

        // and load the index.html of the app.
        mainWindow.loadURL(path.join('file://', __dirname, '/index.html'));

        if (debug) {
            mainWindow.webContents.openDevTools();
            mainWindow.maximize();
        }

        mainWindow.once('ready-to-show', () => {
            mainWindow.show();
        });

        mainWindow.on('close', event => {
            event.preventDefault();
            mainWindow.hide();
        });

        // Emitted when the window is closed.
        mainWindow.on('closed', () => {
            // Dereference the window object, usually you would store windows
            // in an array if your app supports multi windows, this is the time
            // when you should delete the corresponding element.
            mainWindow = null;
        });
    }

    /**
     * get current locale
     * @returns {*}
     */
    function getLocale() {
        // get locale from config if exists
        let locale;
        try {
            let data = fs.readFileSync(config, 'utf8');
            data = JSON.parse(data);
            locale = data.locale;
        } catch (e) {

        }

        // then try get current env locale
        if (!locale) {
            locale = app.getLocale();
        }

        // if not in the 3 locales, return en-US
        if (localeArray.indexOf(locale) === -1) {
            locale = 'en-US';
        }
        return locale;
    }

    /**
     * set locale
     * @param locale
     */
    function setLocale(locale) {
        try {
            let data = fs.readFileSync(config, 'utf8');
            data = JSON.parse(data);
            data.locale = locale;
            fs.writeFileSync(config, JSON.stringify(data, null, 4), 'utf8');
        } catch (e) {

        }
    }

    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    app.on('ready', () => {
        createWindow();
        const locale = getLocale();
        i18n.setLocale(locale);

        ipc.on('save-dialog', (event, data) => {
            const options = {
                title: i18n.__('renderer.export_title'),
                defaultPath: 'hosts',
                buttonLabel: i18n.__('renderer.btnExport')
            };
            dialog.showSaveDialog(options, fileName => {
                event.sender.send('save-file', {
                    fileName,
                    id: data.id,
                    url: data.url
                });
            });
        });

        // Tray
        tray = new Tray(path.join(__dirname, `${process.platform === 'win32' ? '/public/image/hostsdock.ico' : '/public/image/hostsdock.png'}`));
        tray.on('double-click', () => {
            mainWindow.show();
        });
        tray.setToolTip('HostsDock');

        ipc.on('tray', (event, data) => {
            const appliedId = data.appliedId;

            // list local schema
            const list = [{
                label: i18n.__('renderer.local'),
                enabled: false
            }];
            data.localHosts.forEach(item => {
                list.push({
                    label: item.name,
                    type: 'checkbox',
                    checked: item.id === appliedId,
                    click() {
                        mainWindow.webContents.send('apply', {
                            id: item.id,
                            name: item.name
                        });
                    }
                });
            });

            // list remote schema
            list.push({
                label: i18n.__('renderer.remote'),
                enabled: false
            });
            data.remoteHosts.forEach(item => {
                list.push({
                    label: item.name,
                    type: 'checkbox',
                    checked: item.id === appliedId,
                    click() {
                        mainWindow.webContents.send('apply', {
                            id: item.id,
                            name: item.name,
                            url: item.url
                        });
                    }
                });
            });

            list.push({
                type: 'separator'
            }, {
                label: i18n.__('tray_menu.win'),
                click() {
                    mainWindow.show();
                }
            }, {
                label: i18n.__('main_menu.exit'),
                click() {
                    app.exit(0);
                }
            });
            const contextMenu = Menu.buildFromTemplate(list);
            tray.setContextMenu(contextMenu);
        });

        // Menus
        const template = [{
            label: i18n.__('main_menu.file'),
            submenu: [{
                label: i18n.__('main_menu.new'),
                accelerator: 'CmdOrCtrl+N',
                click(item, focusedWindow) {
                    // send to renderer
                    focusedWindow.webContents.send('new', true);
                }
            }, {
                label: i18n.__('renderer.btnExport'),
                accelerator: 'CmdOrCtrl+E',
                click(item, focusedWindow) {
                    // send to renderer
                    focusedWindow.webContents.send('export', true);
                }
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.reload'),
                accelerator: 'CmdOrCtrl+R',
                click(item, focusedWindow) {
                    if (focusedWindow) {
                        app.relaunch();
                        app.exit(0);
                    }
                }
            }, {
                label: i18n.__('main_menu.exit'),
                accelerator: 'CmdOrCtrl+W',
                click() {
                    app.exit(0);
                }
            }]
        }, {
            label: i18n.__('main_menu.edit'),
            submenu: [{
                label: i18n.__('main_menu.copy'),
                accelerator: 'CmdOrCtrl+C',
                role: 'copy'
            }, {
                label: i18n.__('main_menu.cut'),
                accelerator: 'CmdOrCtrl+X',
                role: 'cut'
            }, {
                label: i18n.__('main_menu.paste'),
                accelerator: 'CmdOrCtrl+V',
                role: 'paste'
            }, {
                label: i18n.__('main_menu.select_all'),
                accelerator: 'CmdOrCtrl+A',
                role: 'selectall'
            }]
        }, {
            label: 'Language',
            submenu: [{
                label: 'English',
                type: 'checkbox',
                checked: locale === 'en-US',
                click() {
                    setLocale('en-US');
                    app.relaunch();
                    app.exit(0);
                }
            }, {
                label: '简体中文',
                type: 'checkbox',
                checked: locale === 'zh-CN',
                click() {
                    setLocale('zh-CN');
                    app.relaunch();
                    app.exit(0);
                }
            }, {
                label: '繁體中文',
                type: 'checkbox',
                checked: locale === 'zh-TW',
                click() {
                    setLocale('zh-TW');
                    app.relaunch();
                    app.exit(0);
                }
            }]
        }, {
            label: i18n.__('main_menu.window'),
            submenu: [{
                label: i18n.__('main_menu.min'),
                role: 'minimize'
            }, {
                label: i18n.__('main_menu.full_screen'),
                accelerator: (function () {
                    if (process.platform === 'darwin') {
                        return 'CmdOrCtrl+F';
                    }
                    return 'F11';
                }()),
                click(item, focusedWindow) {
                    if (focusedWindow) {
                        focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
                    }
                }
            }]
        }, {
            label: i18n.__('main_menu.help'),
            submenu: [{
                label: `${i18n.__('main_menu.version')} ${app.getVersion()}`,
                enabled: false
            }, {
                label: i18n.__('main_menu.homepage'),
                click() {
                    electron.shell.openExternal('https://github.com/eshengsky/HostsDock');
                }
            }, {
                label: i18n.__('main_menu.issue'),
                click() {
                    electron.shell.openExternal('https://github.com/eshengsky/HostsDock/issues');
                }
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.devtool'),
                accelerator: (function () {
                    if (process.platform === 'darwin') {
                        return 'CmdOrCtrl+T';
                    }
                    return 'F12';
                }()),
                role: 'toggledevtools'
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.about'),
                click() {
                    electron.shell.openExternal('http://www.skysun.name/about');
                }
            }]
        }];
        const menu = Menu.buildFromTemplate(template);
        Menu.setApplicationMenu(menu);
    });

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
        // On OS X it is common for applications and their menu bar
        // to stay active until the user quits explicitly with Cmd + Q
        if (process.platform !== 'darwin') {
            app.quit();
        }
    });

    app.on('activate', () => {
        if (mainWindow === null) {
            createWindow();
        } else {
            mainWindow.show();
        }
    });

    app.on('before-quit', () => {
        app.isQuiting = true;
    });
}

function makeSingleInstance() {
    return app.makeSingleInstance(() => {
        if (mainWindow) {
            if (mainWindow.isMinimized()) mainWindow.restore();
            mainWindow.focus();
        }
    });
}

initialize();
<commit_msg>commit<commit_after>'use strict';
const path = require('path');
const fs = require('fs');
const i18n = require('i18n');
const electron = require('electron');
const ipc = electron.ipcMain;
const Tray = electron.Tray;
const dialog = electron.dialog;

// Module to control application life.
const app = electron.app;

// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow;
const Menu = electron.Menu;
const debug = /--debug/.test(process.argv[2]);

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow = null;
let tray = null;
const config = path.resolve(app.getPath('userData'), 'config.json');
const localeArray = ['en-US', 'zh-CN', 'zh-TW'];

function initialize() {
    const shouldQuit = makeSingleInstance();
    if (shouldQuit) {
        return app.exit(0);
    }

    i18n.configure({
        locales: localeArray,
        directory: `${__dirname}/locales`,
        objectNotation: true
    });

    function createWindow() {
        const windowOptions = {
            width: 1080,
            minWidth: 680,
            height: 840,
            icon: path.join(__dirname, `${process.platform === 'win32' ? '/public/image/hostsdock.ico' : '/public/image/hostsdock.png'}`),
            show: false
        };

        // Create the browser window.
        mainWindow = new BrowserWindow(windowOptions);

        // and load the index.html of the app.
        mainWindow.loadURL(path.join('file://', __dirname, '/index.html'));

        if (debug) {
            mainWindow.webContents.openDevTools();
            mainWindow.maximize();
        }

        mainWindow.once('ready-to-show', () => {
            mainWindow.show();
        });

        mainWindow.on('close', event => {
            event.preventDefault();
            mainWindow.hide();
        });

        // Emitted when the window is closed.
        mainWindow.on('closed', () => {
            // Dereference the window object, usually you would store windows
            // in an array if your app supports multi windows, this is the time
            // when you should delete the corresponding element.
            mainWindow = null;
        });
    }

    /**
     * get current locale
     * @returns {*}
     */
    function getLocale() {
        // get locale from config if exists
        let locale;
        try {
            let data = fs.readFileSync(config, 'utf8');
            data = JSON.parse(data);
            locale = data.locale;
        } catch (e) {

        }

        // then try get current env locale
        if (!locale) {
            locale = app.getLocale();
        }

        // if not in the 3 locales, return en-US
        if (localeArray.indexOf(locale) === -1) {
            locale = 'en-US';
        }
        return locale;
    }

    /**
     * set locale
     * @param locale
     */
    function setLocale(locale) {
        try {
            let data = fs.readFileSync(config, 'utf8');
            data = JSON.parse(data);
            data.locale = locale;
            fs.writeFileSync(config, JSON.stringify(data, null, 4), 'utf8');
        } catch (e) {

        }
    }

    // This method will be called when Electron has finished
    // initialization and is ready to create browser windows.
    app.on('ready', () => {
        createWindow();
        const locale = getLocale();
        i18n.setLocale(locale);

        ipc.on('save-dialog', (event, data) => {
            const options = {
                title: i18n.__('renderer.export_title'),
                defaultPath: 'hosts',
                buttonLabel: i18n.__('renderer.btnExport')
            };
            dialog.showSaveDialog(options, fileName => {
                event.sender.send('save-file', {
                    fileName,
                    id: data.id,
                    url: data.url
                });
            });
        });

        // Tray
        tray = new Tray(path.join(__dirname, `${process.platform === 'win32' ? '/public/image/hostsdock.ico' : '/public/image/hostsdock.png'}`));
        tray.on('double-click', () => {
            mainWindow.show();
        });
        tray.setToolTip('HostsDock');

        ipc.on('tray', (event, data) => {
            const appliedId = data.appliedId;

            // list local schema
            const list = [{
                label: i18n.__('renderer.local'),
                enabled: false
            }];
            data.localHosts.forEach(item => {
                list.push({
                    label: item.name,
                    type: 'checkbox',
                    checked: item.id === appliedId,
                    click() {
                        mainWindow.webContents.send('apply', {
                            id: item.id,
                            name: item.name
                        });
                    }
                });
            });

            // list remote schema
            list.push({
                label: i18n.__('renderer.remote'),
                enabled: false
            });
            data.remoteHosts.forEach(item => {
                list.push({
                    label: item.name,
                    type: 'checkbox',
                    checked: item.id === appliedId,
                    click() {
                        mainWindow.webContents.send('apply', {
                            id: item.id,
                            name: item.name,
                            url: item.url
                        });
                    }
                });
            });

            list.push({
                type: 'separator'
            }, {
                label: i18n.__('tray_menu.win'),
                click() {
                    mainWindow.show();
                }
            }, {
                label: i18n.__('main_menu.exit'),
                click() {
                    app.exit(0);
                }
            });
            const contextMenu = Menu.buildFromTemplate(list);
            tray.setContextMenu(contextMenu);
        });

        // Menus
        const template = [{
            label: i18n.__('main_menu.file'),
            submenu: [{
                label: i18n.__('main_menu.new'),
                accelerator: 'CmdOrCtrl+N',
                click(item, focusedWindow) {
                    // send to renderer
                    focusedWindow.webContents.send('new', true);
                }
            }, {
                label: i18n.__('renderer.btnExport'),
                accelerator: 'CmdOrCtrl+E',
                click(item, focusedWindow) {
                    // send to renderer
                    focusedWindow.webContents.send('export', true);
                }
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.reload'),
                accelerator: 'CmdOrCtrl+R',
                click(item, focusedWindow) {
                    if (focusedWindow) {
                        app.relaunch();
                        app.exit(0);
                    }
                }
            }, {
                label: i18n.__('main_menu.exit'),
                accelerator: 'CmdOrCtrl+W',
                click() {
                    app.exit(0);
                }
            }]
        }, {
            label: i18n.__('main_menu.edit'),
            submenu: [{
                label: i18n.__('main_menu.copy'),
                accelerator: 'CmdOrCtrl+C',
                role: 'copy'
            }, {
                label: i18n.__('main_menu.cut'),
                accelerator: 'CmdOrCtrl+X',
                role: 'cut'
            }, {
                label: i18n.__('main_menu.paste'),
                accelerator: 'CmdOrCtrl+V',
                role: 'paste'
            }, {
                label: i18n.__('main_menu.select_all'),
                accelerator: 'CmdOrCtrl+A',
                role: 'selectall'
            }]
        }, {
            label: 'Language',
            submenu: [{
                label: 'English',
                type: 'checkbox',
                checked: locale === 'en-US',
                click() {
                    setLocale('en-US');
                    app.relaunch();
                    app.exit(0);
                }
            }, {
                label: '简体中文',
                type: 'checkbox',
                checked: locale === 'zh-CN',
                click() {
                    setLocale('zh-CN');
                    app.relaunch();
                    app.exit(0);
                }
            }, {
                label: '繁體中文',
                type: 'checkbox',
                checked: locale === 'zh-TW',
                click() {
                    setLocale('zh-TW');
                    app.relaunch();
                    app.exit(0);
                }
            }]
        }, {
            label: i18n.__('main_menu.window'),
            submenu: [{
                label: i18n.__('main_menu.min'),
                role: 'minimize'
            }, {
                label: i18n.__('main_menu.full_screen'),
                accelerator: (function () {
                    if (process.platform === 'darwin') {
                        return 'CmdOrCtrl+F';
                    }
                    return 'F11';
                }()),
                click(item, focusedWindow) {
                    if (focusedWindow) {
                        focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
                    }
                }
            }]
        }, {
            label: i18n.__('main_menu.help'),
            submenu: [{
                label: `${i18n.__('main_menu.version')} ${app.getVersion()}`,
                enabled: false
            }, {
                label: i18n.__('main_menu.homepage'),
                click() {
                    electron.shell.openExternal('https://github.com/eshengsky/HostsDock');
                }
            }, {
                label: i18n.__('main_menu.issue'),
                click() {
                    electron.shell.openExternal('https://github.com/eshengsky/HostsDock/issues');
                }
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.devtool'),
                accelerator: (function () {
                    if (process.platform === 'darwin') {
                        return 'CmdOrCtrl+T';
                    }
                    return 'F12';
                }()),
                role: 'toggledevtools'
            }, {
                type: 'separator'
            }, {
                label: i18n.__('main_menu.about'),
                click() {
                    electron.shell.openExternal('http://www.skysun.name/about');
                }
            }]
        }];
        const menu = Menu.buildFromTemplate(template);
        Menu.setApplicationMenu(menu);
    });

    // Quit when all windows are closed.
    app.on('window-all-closed', () => {
        // On OS X it is common for applications and their menu bar
        // to stay active until the user quits explicitly with Cmd + Q
        if (process.platform !== 'darwin') {
            app.quit();
        }
    });

    app.on('activate', () => {
        if (mainWindow === null) {
            createWindow();
        } else {
            mainWindow.show();
        }
    });

    app.on('before-quit', () => {
        app.isQuiting = true;
    });
}

function makeSingleInstance() {
    return app.makeSingleInstance(() => {
        if (mainWindow) {
            if (mainWindow.isMinimized()) mainWindow.restore();
            mainWindow.focus();
        }
    });
}

initialize();
<|endoftext|>


<commit_before>const electron = require('electron');
const app = electron.app;
const Menu = electron.Menu;
const Tray = electron.Tray;
const spawn = require('child_process').spawn;

const capture = function() {
  const unixtimestamp = parseInt((new Date) / 1000);
  const filePath = `${unixtimestamp}.png`;
  spawn('screencapture', ['-i', filePath]);
};

var appIcon = null;

app.on('ready', function(){
  appIcon = new Tray('./images/camera.png');
  var contextMenu = Menu.buildFromTemplate([
    { label: 'Capture', click: function() { capture(); } },
    { type: 'separator' },
    { label: 'Quit', accelerator: 'Command+Q', click: function() { app.quit(); } }
  ]);
  appIcon.setToolTip('Cammy');
  appIcon.setContextMenu(contextMenu);
});
<commit_msg>Use HOME env<commit_after>const electron = require('electron');
const app = electron.app;
const Menu = electron.Menu;
const Tray = electron.Tray;
const spawn = require('child_process').spawn;

const capture = function() {
  const unixtimestamp = parseInt((new Date) / 1000);
  const dir = `${process.env["HOME"]}/Desktop/`;
  const filePath = `${dir}${unixtimestamp}.png`;
  spawn('screencapture', ['-i', filePath]);
};

var appIcon = null;

app.on('ready', function(){
  appIcon = new Tray('./images/camera.png');
  var contextMenu = Menu.buildFromTemplate([
    { label: 'Capture', click: function() { capture(); } },
    { type: 'separator' },
    { label: 'Quit', accelerator: 'Command+Q', click: function() { app.quit(); } }
  ]);
  appIcon.setToolTip('Cammy');
  appIcon.setContextMenu(contextMenu);
});
<|endoftext|>


<commit_before>// JavaScript Document

// Scripts written by __gulp_init_author_name__ @ __gulp_init_author_company__

module.exports = {
    html(gulp, plugins, ran_tasks, on_error) {
        // task-specific plugins
        const TEMPLATE = require("gulp-template");

        // copy binaries
        const COPY_BINARIES = (html_directory, source = [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`]) => {
            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // check if a file is a binary
                .pipe(plugins.is_binary())
                // skip file if it's not a binary
                .pipe(plugins.through.obj((file, enc, next) => {
                    if (!file.isBinary()) {
                        next();
                        return;
                    }

                    // go to next file
                    next(null, file);
                }))
                // output to compiled directory
                .pipe(gulp.dest(html_directory));
        };

        // copy composer
        const COPY_COMPOSER = (html_directory, source = [`${global.settings.paths.vendor}/**/*`]) => {
            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // output to compiled directory
                .pipe(gulp.dest(`${html_directory}/functions`));
        };

        // process HTML
        const PROCESS_HTML = (html_directory, source = [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`]) => {
            // read data from package.json
            const JSON_DATA = plugins.json.readFileSync("package.json");

            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // check if file is a binary
                .pipe(plugins.is_binary())
                // skip file if it's a binary
                .pipe(plugins.through.obj((file, enc, next) => {
                    if (file.isBinary()) {
                        next();
                        return;
                    }

                    // go to next file
                    next(null, file);
                }))
                // replace variables
                .pipe(TEMPLATE({
                    name: JSON_DATA.name,
                    pwa_name: JSON_DATA.progressiveWebApp.name + (!plugins.argv.dist ? " - DEV" : ""),
                    pwa_short_name: JSON_DATA.progressiveWebApp.short_name,
                    pwa_theme_color: JSON_DATA.progressiveWebApp.theme_color,
                    description: JSON_DATA.description,
                    version: JSON_DATA.version,
                    repository: JSON_DATA.repository.url,
                    license: JSON_DATA.license,
                }))
                // output to compiled directory
                .pipe(gulp.dest(html_directory));
        };

        // html task, copies binaries, converts includes & variables in HTML
        return new Promise ((resolve) => {
            // set HTML directory
            const HTML_DIRECTORY = plugins.argv.dist ? global.settings.paths.dist : global.settings.paths.dev;

            // process all non-asset files
            const BINARIES = COPY_BINARIES(HTML_DIRECTORY, [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`, `!${global.settings.paths.src}/**/*.{jpg,png,svg}`]);
            const COMPOSER = COPY_COMPOSER(HTML_DIRECTORY, [`${global.settings.paths.vendor}/**/*`]);
            const HTML     = PROCESS_HTML(HTML_DIRECTORY, [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`, `!${global.settings.paths.src}/**/*.{jpg,png,svg}`]);

            // merge both steams back in to one
            plugins.merge(BINARIES, COMPOSER, HTML)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // notify that task is complete, if not part of default or watch
                .pipe(plugins.gulpif(gulp.seq.indexOf("html") > gulp.seq.indexOf("default"), plugins.notify({
                    title:   "Success!",
                    message: "HTML task complete!",
                    onLast:  true,
                })))
                // push task to ran_tasks array
                .on("data", () => {
                    if (ran_tasks.indexOf("html") < 0) {
                        ran_tasks.push("html");
                    }
                })
                .on("end", () => {
                    resolve();
                });
        });
    }
};
<commit_msg>Simplify HTML source; Close #182<commit_after>// JavaScript Document

// Scripts written by __gulp_init_author_name__ @ __gulp_init_author_company__

module.exports = {
    html(gulp, plugins, ran_tasks, on_error) {
        // task-specific plugins
        const TEMPLATE = require("gulp-template");

        // copy binaries
        const COPY_BINARIES = (html_directory, source = [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`]) => {
            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // check if a file is a binary
                .pipe(plugins.is_binary())
                // skip file if it's not a binary
                .pipe(plugins.through.obj((file, enc, next) => {
                    if (!file.isBinary()) {
                        next();
                        return;
                    }

                    // go to next file
                    next(null, file);
                }))
                // output to compiled directory
                .pipe(gulp.dest(html_directory));
        };

        // copy composer
        const COPY_COMPOSER = (html_directory, source = [`${global.settings.paths.vendor}/**/*`]) => {
            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // output to compiled directory
                .pipe(gulp.dest(`${html_directory}/functions`));
        };

        // process HTML
        const PROCESS_HTML = (html_directory, source = [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}/assets`]) => {
            // read data from package.json
            const JSON_DATA = plugins.json.readFileSync("package.json");

            return gulp.src(source)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // check if source is newer than destination
                .pipe(plugins.gulpif(!plugins.argv.dist, plugins.newer(html_directory)))
                // check if file is a binary
                .pipe(plugins.is_binary())
                // skip file if it's a binary
                .pipe(plugins.through.obj((file, enc, next) => {
                    if (file.isBinary()) {
                        next();
                        return;
                    }

                    // go to next file
                    next(null, file);
                }))
                // replace variables
                .pipe(TEMPLATE({
                    name: JSON_DATA.name,
                    pwa_name: JSON_DATA.progressiveWebApp.name + (!plugins.argv.dist ? " - DEV" : ""),
                    pwa_short_name: JSON_DATA.progressiveWebApp.short_name,
                    pwa_theme_color: JSON_DATA.progressiveWebApp.theme_color,
                    description: JSON_DATA.description,
                    version: JSON_DATA.version,
                    repository: JSON_DATA.repository.url,
                    license: JSON_DATA.license,
                }))
                // output to compiled directory
                .pipe(gulp.dest(html_directory));
        };

        // html task, copies binaries, converts includes & variables in HTML
        return new Promise ((resolve) => {
            // set HTML directory
            const HTML_DIRECTORY = plugins.argv.dist ? global.settings.paths.dist : global.settings.paths.dev;

            // process all non-asset files
            const BINARIES = COPY_BINARIES(HTML_DIRECTORY, [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`, `!${global.settings.paths.src}/**/*.{jpg,png,svg}`]);
            const COMPOSER = COPY_COMPOSER(HTML_DIRECTORY, [`${global.settings.paths.vendor}/**/*`]);
            const HTML     = PROCESS_HTML(HTML_DIRECTORY, [`${global.settings.paths.src}/**/*`, `!${global.settings.paths.src}{/assets,/assets/**}`, `!${global.settings.paths.src}/**/*.{jpg,png,svg}`]);

            // merge both steams back in to one
            plugins.merge(BINARIES, COMPOSER, HTML)
                // prevent breaking on error
                .pipe(plugins.plumber({ errorHandler: on_error }))
                // notify that task is complete, if not part of default or watch
                .pipe(plugins.gulpif(gulp.seq.indexOf("html") > gulp.seq.indexOf("default"), plugins.notify({
                    title:   "Success!",
                    message: "HTML task complete!",
                    onLast:  true,
                })))
                // push task to ran_tasks array
                .on("data", () => {
                    if (ran_tasks.indexOf("html") < 0) {
                        ran_tasks.push("html");
                    }
                })
                .on("end", () => {
                    resolve();
                });
        });
    }
};
<|endoftext|>