<commit_before>/**
 * tilelayer.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 slider.js
 *
 * @todo redo all public interfaces to use physical coordinates instead of pixel coordinates
 */

/**
 * Get the part of the tile name that consists of dimensions z, t, ...
 * For a 3D stack this will return "z/", for a 4D stack "t/z/", etc.
 *
 * @param pixelPos pixel position of the stack [x, y, z, t, ...]
 */
function getTileBaseName( pixelPos )
{
	var n = pixelPos.length;
	var dir = ""
	for ( var i = n - 1; i > 1; --i )
	{
		dir += pixelPos[ i ] + "/";
	}
	return dir;
}

/**
 *
 */
function TileLayer(
		stack,						//!< reference to the parent stack
		baseURL,					//!< base URL for image tiles
		tileWidth,
		tileHeight,
		fileExtension
		)
{
	/**
	 * initialise the tiles array
	 */
	var initTiles = function( rows, cols )
	{
		while ( tilesContainer.firstChild )
			tilesContainer.removeChild( tilesContainer.firstChild );

		delete tiles;
		tiles = new Array();

		for ( var i = 0; i < rows; ++i )
		{
			tiles[ i ] = new Array();
			for ( var j = 0; j < cols; ++j )
			{
				tiles[ i ][ j ] = document.createElement( "img" );
				tiles[ i ][ j ].alt = "empty";
				tiles[ i ][ j ].src = "widgets/empty256.gif";

				tilesContainer.appendChild( tiles[ i ][ j ] );
			}
		}
		return;
	}

	/**
	 * align and update the tiles to be ( x, y ) in the image center
	 */
	this.redraw = function()
	{
		var pixelPos = [ stack.x, stack.y, stack.z ];
		var tileBaseName = getTileBaseName( pixelPos );

		var zoom = stack.s;
		var mag = 1.0;
		var artificialZoom = false;
		/* If the zoom is negative we zoom in digitally. For this
		 * we take the zero zoom level and adjust the tile properties.
		 * This way we let the browser do the zooming work.
		 */
		if (zoom < 0) {
			artificialZoom = true;
			mag = -( zoom - 1 );
			zoom = 0;
		}

		effectiveTileWidth = tileWidth * mag;
		effectiveTileHeight = tileHeight * mag;

		var fr = Math.floor( stack.yc / effectiveTileHeight );
		var fc = Math.floor( stack.xc / effectiveTileWidth );

		var xd = 0;
		var yd = 0;

		if ( stack.z == stack.old_z && stack.s == stack.old_s )
		{
			var old_fr = Math.floor( stack.old_yc / effectiveTileHeight );
			var old_fc = Math.floor( stack.old_xc / effectiveTileWidth );

			xd = fc - old_fc;
			yd = fr - old_fr;

			// re-order the tiles array on demand
			if ( xd < 0 )
			{
				for ( var i = 0; i < tiles.length; ++i )
				{
					tilesContainer.removeChild( tiles[ i ].pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					tiles[ i ].unshift( img );
				}
			}
			else if ( xd > 0 )
			{
				for ( var i = 0; i < tiles.length; ++i )
				{
					tilesContainer.removeChild( tiles[ i ].shift() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					tiles[ i ].push( img );
				}
			}
			else if ( yd < 0 )
			{
				var old_row = tiles.pop();
				var new_row = new Array();
				for ( var i = 0; i < tiles[ 0 ].length; ++i )
				{
					tilesContainer.removeChild( old_row.pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					new_row.push( img );
				}
				tiles.unshift( new_row );
			}
			else if ( yd > 0 )
			{
				var old_row = tiles.shift();
				var new_row = new Array();
				for ( var i = 0; i < tiles[ 0 ].length; ++i )
				{
					tilesContainer.removeChild( old_row.pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					new_row.push( img );
				}
				tiles.push( new_row );
			}
		}

		if ( stack.s != stack.old_s)
		{
			if (artificialZoom)
			{
				LAST_XT = Math.floor( ( stack.dimension.x - 1 ) / tileWidth );
				LAST_YT = Math.floor( ( stack.dimension.y - 1 ) / tileHeight );
			}
			else
			{
				LAST_XT = Math.floor( ( stack.dimension.x * stack.scale - 1 ) / tileWidth );
				LAST_YT = Math.floor( ( stack.dimension.y * stack.scale - 1 ) / tileHeight );
			}
		}

		var top;
		var left;

		if ( stack.yc >= 0 )
			top  = -( stack.yc % effectiveTileHeight );
		else
			top  = -( ( stack.yc + 1 ) % effectiveTileHeight ) - effectiveTileHeight + 1;
		if ( stack.xc >= 0 )
			left = -( stack.xc % effectiveTileWidth );
		else
			left = -( ( stack.xc + 1 ) % effectiveTileWidth ) - effectiveTileWidth + 1;

		var t = top;
		var l = left;

		// update the images sources
		for ( var i = 0; i < tiles.length; ++i )
		{
			var r = fr + i;
			for ( var j = 0; j < tiles[ 0 ].length; ++j )
			{
				var c = fc + j;

				/**
				 * TODO Test if updating the URLs always was required to
				 * guarantee homogeneous update speed for modulo-changing steps
				 * and non-modulo changing steps.  Write more comments in
				 * general.
				 */
				if ( r < 0 || c < 0 || r > LAST_YT || c > LAST_XT )
				{
					tiles[ i ][ j ].alt = "";
					tiles[ i ][ j ].src = "widgets/black.gif";
				}
				else
				{
					// TODO: use this for the new tile naming scheme:
					// tiles[ i ][ j ].alt = tileBaseName + stack.s + "/" + ( fr + i ) + "/" + ( fc + j );
					tiles[ i ][ j ].alt = tileBaseName + r + "_" + c + "_" + zoom;
					tiles[ i ][ j ].src = self.getTileURL( tiles[ i ][ j ].alt );
				}
				tiles[ i ][ j ].style.top = t + "px";
				tiles[ i ][ j ].style.left = l + "px";
				tiles[ i ][ j ].style.visibility = "visible";

				tiles[ i ][ j ].style.width = effectiveTileWidth + "px";
				tiles[ i ][ j ].style.height = effectiveTileHeight + "px";

				l += effectiveTileWidth;

				//alert( l + ", " + t );

			}
			l = left;
			t += effectiveTileHeight;
		}

		return 2;
	}

	/**
	 * Creates the URL for a tile.
	 */
	this.getTileURL = function(tileId) {
		return baseURL + tileId + "." + fileExtension;
	}

	this.resize = function( width, height )
	{
//		alert( "resize tileLayer of stack" + stack.getId() );

		/* TODO 2 more?  Should be 1---not?! */
		var rows = Math.floor( height / tileHeight ) + 2;
		var cols = Math.floor( width / tileWidth ) + 2;
		initTiles( rows, cols );
		self.redraw();
		return;
	}

	/**
	 * Get the width of an image tile.
	 */
	this.getTileWidth = function(){ return tileWidth; }

	/**
	 * Get the height of an image tile.
	 */
	this.getTileHeight = function(){ return tileHeight; }

	/**
	 * Get the number of tile columns.
	 */
	this.numTileColumns = function()
	{
		if ( tiles.length == 0 )
			return 0;
		else
			return tiles[ 0 ].length;
	}

	/**
	 * Get the number of tile rows.
	 */
	this.numTileColumns = function(){ return tiles.length; }

	/**
	 * Get the stack.
	 */
	this.getStack = function(){ return stack; }

	var OverviewLayer = function()
	{
		this.redraw = function()
		{
			img.src = baseURL + stack.z + "/small." + fileExtension;
			return;
		}

		this.unregister = function()
		{
			if ( img.parentNode )
				img.parentNode.removeChild( img );
		}

		var self = this;

		var img = document.createElement( "img" );
		img.className = "smallMapMap";
		img.src = "map/small." + fileExtension;

		stack.overview.getView().appendChild( img );
		stack.overview.addLayer( "tilelayer", this );
	}

	this.setOpacity = function( val )
	{
		tilesContainer.style.opacity = val+"";
		opacity = val;
	}

	this.getOpacity = function()
	{
		return opacity;
	}

	// initialise
	var self = this;

	// internal opacity variable
	var opacity = 100;

	/* Contains all tiles in a 2d-array */
	var tiles = new Array();

	var tilesContainer = document.createElement( "div" );
	tilesContainer.className = "sliceTiles";
	stack.getView().appendChild( tilesContainer );

	var overviewLayer = new OverviewLayer();

	var LAST_XT = Math.floor( ( stack.dimension.x * stack.scale - 1 ) / tileWidth );
	var LAST_YT = Math.floor( ( stack.dimension.y * stack.scale - 1 ) / tileHeight );

	self.baseURL = baseURL;
}
<commit_msg>Correct the calculation of magnification with artificial zoom<commit_after>/**
 * tilelayer.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 slider.js
 *
 * @todo redo all public interfaces to use physical coordinates instead of pixel coordinates
 */

/**
 * Get the part of the tile name that consists of dimensions z, t, ...
 * For a 3D stack this will return "z/", for a 4D stack "t/z/", etc.
 *
 * @param pixelPos pixel position of the stack [x, y, z, t, ...]
 */
function getTileBaseName( pixelPos )
{
	var n = pixelPos.length;
	var dir = ""
	for ( var i = n - 1; i > 1; --i )
	{
		dir += pixelPos[ i ] + "/";
	}
	return dir;
}

/**
 *
 */
function TileLayer(
		stack,						//!< reference to the parent stack
		baseURL,					//!< base URL for image tiles
		tileWidth,
		tileHeight,
		fileExtension
		)
{
	/**
	 * initialise the tiles array
	 */
	var initTiles = function( rows, cols )
	{
		while ( tilesContainer.firstChild )
			tilesContainer.removeChild( tilesContainer.firstChild );

		delete tiles;
		tiles = new Array();

		for ( var i = 0; i < rows; ++i )
		{
			tiles[ i ] = new Array();
			for ( var j = 0; j < cols; ++j )
			{
				tiles[ i ][ j ] = document.createElement( "img" );
				tiles[ i ][ j ].alt = "empty";
				tiles[ i ][ j ].src = "widgets/empty256.gif";

				tilesContainer.appendChild( tiles[ i ][ j ] );
			}
		}
		return;
	}

	/**
	 * align and update the tiles to be ( x, y ) in the image center
	 */
	this.redraw = function()
	{
		var pixelPos = [ stack.x, stack.y, stack.z ];
		var tileBaseName = getTileBaseName( pixelPos );

		var zoom = stack.s;
		var mag = 1.0;
		var artificialZoom = false;
		/* If the zoom is negative we zoom in digitally. For this
		 * we take the zero zoom level and adjust the tile properties.
		 * This way we let the browser do the zooming work.
		 */
		if (zoom < 0) {
			artificialZoom = true;
			mag = Math.pow(2, -zoom);
			zoom = 0;
		}

		effectiveTileWidth = tileWidth * mag;
		effectiveTileHeight = tileHeight * mag;

		var fr = Math.floor( stack.yc / effectiveTileHeight );
		var fc = Math.floor( stack.xc / effectiveTileWidth );

		var xd = 0;
		var yd = 0;

		if ( stack.z == stack.old_z && stack.s == stack.old_s )
		{
			var old_fr = Math.floor( stack.old_yc / effectiveTileHeight );
			var old_fc = Math.floor( stack.old_xc / effectiveTileWidth );

			xd = fc - old_fc;
			yd = fr - old_fr;

			// re-order the tiles array on demand
			if ( xd < 0 )
			{
				for ( var i = 0; i < tiles.length; ++i )
				{
					tilesContainer.removeChild( tiles[ i ].pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					tiles[ i ].unshift( img );
				}
			}
			else if ( xd > 0 )
			{
				for ( var i = 0; i < tiles.length; ++i )
				{
					tilesContainer.removeChild( tiles[ i ].shift() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					tiles[ i ].push( img );
				}
			}
			else if ( yd < 0 )
			{
				var old_row = tiles.pop();
				var new_row = new Array();
				for ( var i = 0; i < tiles[ 0 ].length; ++i )
				{
					tilesContainer.removeChild( old_row.pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					new_row.push( img );
				}
				tiles.unshift( new_row );
			}
			else if ( yd > 0 )
			{
				var old_row = tiles.shift();
				var new_row = new Array();
				for ( var i = 0; i < tiles[ 0 ].length; ++i )
				{
					tilesContainer.removeChild( old_row.pop() );
					var img = document.createElement( "img" );
					img.alt = "empty";
					img.src = "widgets/empty256.gif";
					img.style.visibility = "hidden";
					tilesContainer.appendChild( img );
					new_row.push( img );
				}
				tiles.push( new_row );
			}
		}

		if ( stack.s != stack.old_s)
		{
			if (artificialZoom)
			{
				LAST_XT = Math.floor( ( stack.dimension.x - 1 ) / tileWidth );
				LAST_YT = Math.floor( ( stack.dimension.y - 1 ) / tileHeight );
			}
			else
			{
				LAST_XT = Math.floor( ( stack.dimension.x * stack.scale - 1 ) / tileWidth );
				LAST_YT = Math.floor( ( stack.dimension.y * stack.scale - 1 ) / tileHeight );
			}
		}

		var top;
		var left;

		if ( stack.yc >= 0 )
			top  = -( stack.yc % effectiveTileHeight );
		else
			top  = -( ( stack.yc + 1 ) % effectiveTileHeight ) - effectiveTileHeight + 1;
		if ( stack.xc >= 0 )
			left = -( stack.xc % effectiveTileWidth );
		else
			left = -( ( stack.xc + 1 ) % effectiveTileWidth ) - effectiveTileWidth + 1;

		var t = top;
		var l = left;

		// update the images sources
		for ( var i = 0; i < tiles.length; ++i )
		{
			var r = fr + i;
			for ( var j = 0; j < tiles[ 0 ].length; ++j )
			{
				var c = fc + j;

				/**
				 * TODO Test if updating the URLs always was required to
				 * guarantee homogeneous update speed for modulo-changing steps
				 * and non-modulo changing steps.  Write more comments in
				 * general.
				 */
				if ( r < 0 || c < 0 || r > LAST_YT || c > LAST_XT )
				{
					tiles[ i ][ j ].alt = "";
					tiles[ i ][ j ].src = "widgets/black.gif";
				}
				else
				{
					// TODO: use this for the new tile naming scheme:
					// tiles[ i ][ j ].alt = tileBaseName + stack.s + "/" + ( fr + i ) + "/" + ( fc + j );
					tiles[ i ][ j ].alt = tileBaseName + r + "_" + c + "_" + zoom;
					tiles[ i ][ j ].src = self.getTileURL( tiles[ i ][ j ].alt );
				}
				tiles[ i ][ j ].style.top = t + "px";
				tiles[ i ][ j ].style.left = l + "px";
				tiles[ i ][ j ].style.visibility = "visible";

				tiles[ i ][ j ].style.width = effectiveTileWidth + "px";
				tiles[ i ][ j ].style.height = effectiveTileHeight + "px";

				l += effectiveTileWidth;

				//alert( l + ", " + t );

			}
			l = left;
			t += effectiveTileHeight;
		}

		return 2;
	}

	/**
	 * Creates the URL for a tile.
	 */
	this.getTileURL = function(tileId) {
		return baseURL + tileId + "." + fileExtension;
	}

	this.resize = function( width, height )
	{
//		alert( "resize tileLayer of stack" + stack.getId() );

		/* TODO 2 more?  Should be 1---not?! */
		var rows = Math.floor( height / tileHeight ) + 2;
		var cols = Math.floor( width / tileWidth ) + 2;
		initTiles( rows, cols );
		self.redraw();
		return;
	}

	/**
	 * Get the width of an image tile.
	 */
	this.getTileWidth = function(){ return tileWidth; }

	/**
	 * Get the height of an image tile.
	 */
	this.getTileHeight = function(){ return tileHeight; }

	/**
	 * Get the number of tile columns.
	 */
	this.numTileColumns = function()
	{
		if ( tiles.length == 0 )
			return 0;
		else
			return tiles[ 0 ].length;
	}

	/**
	 * Get the number of tile rows.
	 */
	this.numTileColumns = function(){ return tiles.length; }

	/**
	 * Get the stack.
	 */
	this.getStack = function(){ return stack; }

	var OverviewLayer = function()
	{
		this.redraw = function()
		{
			img.src = baseURL + stack.z + "/small." + fileExtension;
			return;
		}

		this.unregister = function()
		{
			if ( img.parentNode )
				img.parentNode.removeChild( img );
		}

		var self = this;

		var img = document.createElement( "img" );
		img.className = "smallMapMap";
		img.src = "map/small." + fileExtension;

		stack.overview.getView().appendChild( img );
		stack.overview.addLayer( "tilelayer", this );
	}

	this.setOpacity = function( val )
	{
		tilesContainer.style.opacity = val+"";
		opacity = val;
	}

	this.getOpacity = function()
	{
		return opacity;
	}

	// initialise
	var self = this;

	// internal opacity variable
	var opacity = 100;

	/* Contains all tiles in a 2d-array */
	var tiles = new Array();

	var tilesContainer = document.createElement( "div" );
	tilesContainer.className = "sliceTiles";
	stack.getView().appendChild( tilesContainer );

	var overviewLayer = new OverviewLayer();

	var LAST_XT = Math.floor( ( stack.dimension.x * stack.scale - 1 ) / tileWidth );
	var LAST_YT = Math.floor( ( stack.dimension.y * stack.scale - 1 ) / tileHeight );

	self.baseURL = baseURL;
}
<|endoftext|>


<commit_before>define([
	'goo/entities/components/Component'
],
/** @lends */
function (
	Component
	) {
	'use strict';

	/**
	 * @class A generic container of data (transform, geometry, material and so on) wrapped in Components
	 *
	 * @param {World} world The {@link World} this entity will be part of when calling .addToWorld
	 * @param {String} [name] Entity name
	 * @param {number} [id] Entity id
	 */
	function Entity(world, name, id) {
		this._world = world;
		this._components = [];
		this.id = id !== undefined ? id : Entity.entityCount;
		this._index = Entity.entityCount;

		//! AT: not sure if this tags/attributes abstraction is really needed or if they are just glorified properties
		this._tags = {};
		this._attributes = {};

		/*Object.defineProperty(this, 'id', {
			value : Entity.entityCount++,
			writable : false
		});*/
		this.name = name !== undefined ? name : 'Entity_' + this.id;

		/** Set to true to skip rendering (move to meshrenderercomponent)
		 * @type {boolean}
		 * @default false
		 */
		this.skip = false;

		this.hidden = false;
		this.static = false;
		Entity.entityCount++;
	}

	//! AT: not sure if 'add' is a better name - need to search for something short and compatible with the other 'set' methods
	/**
	 * Sets components on the entity or tries to create and set components out of the supplied parameters
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.set = function() {
		for (var i = 0; i < arguments.length; i++) {
			var argument = arguments[i];
			if (argument instanceof Component) {
				this.setComponent(argument);
			} else {
				// ask all components if they are compatible with the given data
				var components = this._world._components;
				for (var j = 0; j < components.length; j++) {
					var component = components[j];
					var applied = component.applyOnEntity(argument, this);
					if (applied) {
						break;
					}
				}
			}
		}

		// allow chaining
		return this;
	};

	/**
	 * Add the entity to the world, making it active and processed by systems and managers.
	 * @param {boolean} [recursive=true] Add children recursively
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.addToWorld = function (recursive) {
		this._world.addEntity(this, recursive);
		return this;
	};

	/**
	 * Remove entity from the world.
	 * @param {boolean} [recursive=true] Remove children recursively
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.removeFromWorld = function (recursive) {
		this._world.removeEntity(this, recursive);
		return this;
	};

	/**
	 * lower cases the first character of the type parameter.
	 * @param {string} type name
	 * @returns {string} lower cased type name
	 * @private
	 */
	function getTypeAttributeName(type) {
		return type.charAt(0).toLowerCase() + type.substr(1);
	}

	/**
	 * Set component of a certain type on entity. The operation has no effect if the entity already contains a component of the same type.
	 *
	 * @param {Component} component Component to set on the entity
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setComponent = function (component) {
		if (this.hasComponent(component.type)) {
			return this;
		} else {
			this._components.push(component);
		}
		this[getTypeAttributeName(component.type)] = component;

		// inform the component it's being attached to an entity
		if (component.attached) {
			component.attached(this);
		}

		component.applyAPI(this);

		if (this._world.entityManager.containsEntity(this)) {
			this._world.changedEntity(this, component, 'addedComponent');
		}

		return this;
	};

	/**
	 * Checks if a component of a specific type is present or not
	 *
	 * @param {string} type Type of component to check for (eg. 'meshDataComponent')
	 * @returns {boolean}
	 */
	Entity.prototype.hasComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		var component = this[typeAttributeName];
		return !!component && this._components.indexOf(component) > -1;
	};

	/**
	 * Retrieve a component of a specific type
	 *
	 * @param {string} type Type of component to retrieve (eg. 'transformComponent')
	 * @returns {Component} component with requested type or undefined if not present
	 */
	Entity.prototype.getComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		if (this.hasComponent(type)) {
			return this[typeAttributeName];
		}
	};

	/**
	 * Remove a component of a specific type from entity
	 *
	 * @param {string} type Type of component to remove (eg. 'meshDataComponent')
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		var component = this[typeAttributeName];

		if (!!component && this._components.indexOf(component) > -1) {
			// inform the component it's being detached from the entity
			if (component.detached) {
				component.detached(this);
			}

			// removing API
			component.removeAPI(this);

			// removing from dense array
			var index = this._components.indexOf(component);
			this._components.splice(index, 1);

			// removing from entity
			delete this[typeAttributeName];

			// notifying the world of the change
			if (this._world.entityManager.containsEntity(this)) {
				this._world.changedEntity(this, component, 'removedComponent');
			}
		}

		return this;
	};

	/**
	 * Adds a tag to the entity
	 * @param tag
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setTag = function (tag) {
		this._tags[tag] = true;
		return this;
	};

	/**
	 * Checks whether an entity has a tag or not
	 * @param tag
	 * @returns {boolean}
	 */
	Entity.prototype.hasTag = function (tag) {
		return !!this._tags[tag];
	};

	/**
	 * Clears a tag on an entity
	 * @param tag
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearTag = function (tag) {
		delete this._tags[tag];
		return this;
	};

	/**
	 * Sets an attribute and its value on the entity
	 * @param attribute
	 * @param value
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setAttribute = function (attribute, value) {
		this._attributes[attribute] = value;
		return this;
	};

	/**
	 * Checks whether an entity has an attribute or not
	 * @param tag
	 * @returns {boolean}
	 */
	Entity.prototype.hasAttribute = function (attribute) {
		return typeof this._attributes[attribute] !== 'undefined';
	};

	/**
	 * Gets the value of the specified attribute
	 * @param attribute
	 * @returns {*}
	 */
	Entity.prototype.getAttribute = function (attribute) {
		return this._attributes[attribute];
	};

	/**
	 * Clears an attribute of the entity
	 * @param attribute
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearAttribute = function (attribute) {
		delete this._attributes[attribute];
		return this;
	};

	/**
	 * @returns {string} Name of entity
	 */
	Entity.prototype.toString = function () {
		//! AT: should also return a list of its components or something more descriptive than just the name
		return this.name;
	};

	Entity.entityCount = 0;

	return Entity;
});
<commit_msg>Rephrased the jsdocs to Entity.js based on team feedback.<commit_after>define([
	'goo/entities/components/Component'
],
/** @lends */
function (
	Component
	) {
	'use strict';

	/**
	 * @class The Goo Engine is using an Entity-Component-System API which is a software design pattern that favors composition over inheritance.
	 * With this approach a developer can create powerful objects in the {@link World} by combining [Components]{@link Component} in an entity.
	 * Components usually provide a single feature like the position and orientation of an entity in the world or the textures to be used.
	 * For example one can make a light move around a scene by setting a {@link TransformComponent}, a {@link LightComponent} and a {@link ScriptComponent} on an entity.
	 * Setting standard components can be a lot to type so there is a convenience function in the World class called [createEntity]{@link World#createEntity}.
	 * This is the function that should be used most of the time to create a new entity.
	 * Refer to this document to see what can be done with an entity.
	 * Due to the power of JavaScript there is a feature that allows Components to inject their functions directly into entities.
	 * Most notably this is done by the {@link TransformComponent}. Some examples include [setTranslation]{@link TransformComponent#setTranslation}, [setRotation]{@link TransformComponent#setRotation} and [lookAt]{@link TransformComponent#lookAt}.
	 * @param {World} world The {@link World} this entity will be part of when calling .addToWorld
	 * @param {String} [name] Entity name
	 * @param {number} [id] Entity id
	 */
	function Entity(world, name, id) {
		this._world = world;
		this._components = [];
		this.id = id !== undefined ? id : Entity.entityCount;
		this._index = Entity.entityCount;

		//! AT: not sure if this tags/attributes abstraction is really needed or if they are just glorified properties
		this._tags = {};
		this._attributes = {};

		/*Object.defineProperty(this, 'id', {
			value : Entity.entityCount++,
			writable : false
		});*/
		this.name = name !== undefined ? name : 'Entity_' + this.id;

		/** Set to true to skip rendering (move to meshrenderercomponent)
		 * @type {boolean}
		 * @default false
		 */
		this.skip = false;

		this.hidden = false;
		this.static = false;
		Entity.entityCount++;
	}

	//! AT: not sure if 'add' is a better name - need to search for something short and compatible with the other 'set' methods
	/**
	 * Sets components on the entity or tries to create and set components out of the supplied parameters
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.set = function() {
		for (var i = 0; i < arguments.length; i++) {
			var argument = arguments[i];
			if (argument instanceof Component) {
				this.setComponent(argument);
			} else {
				// ask all components if they are compatible with the given data
				var components = this._world._components;
				for (var j = 0; j < components.length; j++) {
					var component = components[j];
					var applied = component.applyOnEntity(argument, this);
					if (applied) {
						break;
					}
				}
			}
		}

		// allow chaining
		return this;
	};

	/**
	 * Add the entity to the world, making it active and processed by systems and managers.
	 * @param {boolean} [recursive=true] Add children recursively
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.addToWorld = function (recursive) {
		this._world.addEntity(this, recursive);
		return this;
	};

	/**
	 * Remove entity from the world.
	 * @param {boolean} [recursive=true] Remove children recursively
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.removeFromWorld = function (recursive) {
		this._world.removeEntity(this, recursive);
		return this;
	};

	/**
	 * lower cases the first character of the type parameter.
	 * @param {string} type name
	 * @returns {string} lower cased type name
	 * @private
	 */
	function getTypeAttributeName(type) {
		return type.charAt(0).toLowerCase() + type.substr(1);
	}

	/**
	 * Set component of a certain type on entity. The operation has no effect if the entity already contains a component of the same type.
	 *
	 * @param {Component} component Component to set on the entity
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setComponent = function (component) {
		if (this.hasComponent(component.type)) {
			return this;
		} else {
			this._components.push(component);
		}
		this[getTypeAttributeName(component.type)] = component;

		// inform the component it's being attached to an entity
		if (component.attached) {
			component.attached(this);
		}

		component.applyAPI(this);

		if (this._world.entityManager.containsEntity(this)) {
			this._world.changedEntity(this, component, 'addedComponent');
		}

		return this;
	};

	/**
	 * Checks if a component of a specific type is present or not
	 *
	 * @param {string} type Type of component to check for (eg. 'meshDataComponent')
	 * @returns {boolean}
	 */
	Entity.prototype.hasComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		var component = this[typeAttributeName];
		return !!component && this._components.indexOf(component) > -1;
	};

	/**
	 * Retrieve a component of a specific type
	 *
	 * @param {string} type Type of component to retrieve (eg. 'transformComponent')
	 * @returns {Component} component with requested type or undefined if not present
	 */
	Entity.prototype.getComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		if (this.hasComponent(type)) {
			return this[typeAttributeName];
		}
	};

	/**
	 * Remove a component of a specific type from entity
	 *
	 * @param {string} type Type of component to remove (eg. 'meshDataComponent')
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearComponent = function (type) {
		var typeAttributeName = getTypeAttributeName(type);
		var component = this[typeAttributeName];

		if (!!component && this._components.indexOf(component) > -1) {
			// inform the component it's being detached from the entity
			if (component.detached) {
				component.detached(this);
			}

			// removing API
			component.removeAPI(this);

			// removing from dense array
			var index = this._components.indexOf(component);
			this._components.splice(index, 1);

			// removing from entity
			delete this[typeAttributeName];

			// notifying the world of the change
			if (this._world.entityManager.containsEntity(this)) {
				this._world.changedEntity(this, component, 'removedComponent');
			}
		}

		return this;
	};

	/**
	 * Adds a tag to the entity
	 * @param tag
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setTag = function (tag) {
		this._tags[tag] = true;
		return this;
	};

	/**
	 * Checks whether an entity has a tag or not
	 * @param tag
	 * @returns {boolean}
	 */
	Entity.prototype.hasTag = function (tag) {
		return !!this._tags[tag];
	};

	/**
	 * Clears a tag on an entity
	 * @param tag
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearTag = function (tag) {
		delete this._tags[tag];
		return this;
	};

	/**
	 * Sets an attribute and its value on the entity
	 * @param attribute
	 * @param value
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.setAttribute = function (attribute, value) {
		this._attributes[attribute] = value;
		return this;
	};

	/**
	 * Checks whether an entity has an attribute or not
	 * @param tag
	 * @returns {boolean}
	 */
	Entity.prototype.hasAttribute = function (attribute) {
		return typeof this._attributes[attribute] !== 'undefined';
	};

	/**
	 * Gets the value of the specified attribute
	 * @param attribute
	 * @returns {*}
	 */
	Entity.prototype.getAttribute = function (attribute) {
		return this._attributes[attribute];
	};

	/**
	 * Clears an attribute of the entity
	 * @param attribute
	 * @returns {Entity} Returns self to allow chaining
	 */
	Entity.prototype.clearAttribute = function (attribute) {
		delete this._attributes[attribute];
		return this;
	};

	/**
	 * @returns {string} Name of entity
	 */
	Entity.prototype.toString = function () {
		//! AT: should also return a list of its components or something more descriptive than just the name
		return this.name;
	};

	Entity.entityCount = 0;

	return Entity;
});
<|endoftext|>


<commit_before>let moment = require("moment");
let sprintf = require("sprintf-js").sprintf;
let chalk = require("chalk");
let emoji = require("node-emoji");
let winston = require("winston");
let util = require("./utility.js");
let cli = require("./cli.js");
let twitter = require("twitter");

const exec = require("child_process").exec;

let getLogger = (path) => {
  let settings = {
    transports: [
      new winston.transports.File({ filename: path, json: true})
    ],
    exceptionHandlers: [
      new winston.transports.File({ filename: path, json: true})
    ]
  };

  return new (winston.Logger)(settings);
};

let core = {};

core.display = (data)  => {
  if (util.users[data.user]) {
    name = chalk[util.users[data.user].color](util.users[data.user].name);
  } else {
    if (typeof data.user == "string") {
      name = chalk.white(data.user);
    } else {
      name = chalk.white("-");
    }
  }

  if (util.channels[data.channel]) {
    channel = "#" + chalk[util.channels[data.channel].color](util.channels[data.channel].name);
  } else {
    if (typeof data.channel == "string") {
      channel = chalk.white(data.channel)
    } else {
      channel = chalk.white("-")
    }
  }

  data.lines.forEach((line) => {
    let l;

    l = emoji.emojify(line);
    l = util.replaceSlackId(l);
    l = util.decolateText(l);

    let dateFormat = data.time.format("YYYY-MM-DD HH:mm:ss");

    if (util.theme.date) {
      dateFormat = chalk[util.theme.date](dateFormat);
    }

    console.log(
      "%s | %s | %s | %s",
      dateFormat,
      sprintf("%30s", channel),
      sprintf("%28s", name),
      l
    );

    name = chalk.white("|>");
  });
};

core.start = (commander) => {
  let logger;
  let token = commander.token;

  if (commander.debug) {
    logger = getLogger(commander.debug);
  }

  if (commander.settings) {
    util.parseSettingFile(commander.settings);

    if (util.token) {
      token = util.token;
    }
  }

  const {RTMClient} = require("@slack/client");
  const rtm = new RTMClient(token, {logLevel: "error"});
  const twitterClient = new twitter(util.twitter);

  let colors = ["red", "green", "yellow", "blue", "magenta", "cyan", "white", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright", "cyanBright", "whiteBright"];

  util.channels = {};
  util.users = {};
  util.bots = {};
  util.startUp = false;

  let lastestTwId=1;

  let collectTweets = () => {
    twitterClient.get('statuses/home_timeline', {count:30, since_id:lastestTwId}, (error,tweets,response) => {

      if (error) {
        console.log(error);
        return;
      }

      if (Array.isArray(tweets)) {

        if (tweets.length > 0) {
          lastestTwId = tweets[0].id;
          tweets.reverse();
        }

        tweets.forEach((tweet) => {
          let data = {
            bufferKey: "twitter",
            lines: [tweet.text],
            time: moment(tweet.created_at),
            channel: "[Twitter]",
            user: tweet.user.screen_name
          };

          core.display(data);
        });
      }
    });
  };

  setInterval(collectTweets, 1000 * 60);

  rtm.on("authenticated", (rtmStartData) => {
    if (!util.startUp) {
      console.log(
        `Logged in as ${chalk.bold(rtmStartData.self.name)} of team ${chalk.green.bold(rtmStartData.team.name)}, but not yet connected to a channel`
      );

      util.startUp = true;
    }
  });

  rtm.on("message", (message) => {
    let time = moment(message.ts * 1000);
    let text = util.parseText(message);

    if (message.subtype) {
      switch(message.subtype) {
      case "message_deleted":
      case "message_changed":
        return;
      case "file_share":
        break;
      case "message_replied":
        return;
      case "channel_join":
        break;
      case "channel_leave":
        break;
      case "group_leave":
        break;
      case "reply_broadcast":
        return;
      case "file_comment":
        break;
      case "bot_message":
        break;
      case "pinned_item":
        break;
      case "slackbot_response":
        break;
      case "file_mention":
        break;
      default:
        if (commander.debug) {
          logger.error(message);
        }
        return;
      }
    }

    if (text == "") {
      if (Object.prototype.hasOwnProperty.call(message, "attachments")) {
        text = message.attachments[0].text;
      } else {
        text = "";
      }
    }

    let lines;

    if (typeof(text) == "string") {
      lines = text.split(/\r\n|\r|\n/);
    } else {
      lines = [""];

      if (commander.debug) {
        logger.error(message);
      }
    }

    if (lines.length > 8) {
      lines = lines.slice(0, 5);
      lines.push("--- snip ---");
    }

    // Display only specific users. (-u option)
    if (commander.user) {
      let messageUser = (util.users[message.user]) ? util.users[message.user].name : "-";
      if (commander.user != messageUser) {
        return;
      }
    }

    // buffering
    let data = {
      bufferKey: (util.channels[message.channel]) ? "#" + util.channels[message.channel].name : "-",
      lines: lines,
      time: time,
      channel: message.channel,
      user: message.user
    };

    util.addMessageBuffer(data);
    core.display(data);

    // hook
    if (commander.hook) {
      if (util.hook) {
        exec(util.hook, (err) => {
          if (err) {
            console.log(err);
          }
        });
      }
    }

    // hooks
    let hooks = util.hasHooks(message);

    hooks.forEach((hook) => {
      exec(hook, (err) => {
        if (err) {
          console.log(err);
        }
      });
    });
  });

  // Setup
  const {WebClient} = require("@slack/client");
  const web = new WebClient(token, {logLevel: "error"});

  web.users.list().then((response) => {
    response.members.forEach((v, i) => {
      v.color = colors[i % colors.length];
      util.users[v.id] = v;
    });

    return web.channels.list();
  }).then((response) => {
    response.channels.forEach((v, i) => {
      v.color = colors[i % colors.length];
      util.channels[v.id] = v;
    });

    // [pending] bots list
    //return web.bots.info();
  }).then(() => {
    // complete
    rtm.start();
  }).catch((error) => {
    console.log(error);
  });
};

// Declare cli-handler
function handler() {}

handler.prototype.recent = function(args, fn) {
  if (util.buffer[args[0]]) {
    let messageBuffer = util.buffer[args[0]];

    let label = {
      lines: [`--- Show buffer (#${args[0]}) ---`],
      time: moment()
    };

    core.display(label);

    messageBuffer.forEach((data) => {
      core.display(data);
    });

    label.lines = ["--- finish ---"];
    core.display(label);

  }

  fn(null, args);
};

handler.prototype.echo = function(args, fn) {
  fn(null, args);
};

handler.prototype.exit = function(args, fn) {
  fn(null, args);
  this.emit("close");
};

(new cli(new handler())).run();

module.exports = core;
<commit_msg>改行でメッセージを分割する様に修正<commit_after>let moment = require("moment");
let sprintf = require("sprintf-js").sprintf;
let chalk = require("chalk");
let emoji = require("node-emoji");
let winston = require("winston");
let util = require("./utility.js");
let cli = require("./cli.js");
let twitter = require("twitter");

const exec = require("child_process").exec;

let getLogger = (path) => {
  let settings = {
    transports: [
      new winston.transports.File({ filename: path, json: true})
    ],
    exceptionHandlers: [
      new winston.transports.File({ filename: path, json: true})
    ]
  };

  return new (winston.Logger)(settings);
};

let core = {};

core.display = (data)  => {
  if (util.users[data.user]) {
    name = chalk[util.users[data.user].color](util.users[data.user].name);
  } else {
    if (typeof data.user == "string") {
      name = chalk.white(data.user);
    } else {
      name = chalk.white("-");
    }
  }

  if (util.channels[data.channel]) {
    channel = "#" + chalk[util.channels[data.channel].color](util.channels[data.channel].name);
  } else {
    if (typeof data.channel == "string") {
      channel = chalk.white(data.channel)
    } else {
      channel = chalk.white("-")
    }
  }

  data.lines.forEach((line) => {
    let l;

    l = emoji.emojify(line);
    l = util.replaceSlackId(l);
    l = util.decolateText(l);

    let dateFormat = data.time.format("YYYY-MM-DD HH:mm:ss");

    if (util.theme.date) {
      dateFormat = chalk[util.theme.date](dateFormat);
    }

    console.log(
      "%s | %s | %s | %s",
      dateFormat,
      sprintf("%30s", channel),
      sprintf("%28s", name),
      l
    );

    name = chalk.white("|>");
  });
};

core.start = (commander) => {
  let logger;
  let token = commander.token;

  if (commander.debug) {
    logger = getLogger(commander.debug);
  }

  if (commander.settings) {
    util.parseSettingFile(commander.settings);

    if (util.token) {
      token = util.token;
    }
  }

  const {RTMClient} = require("@slack/client");
  const rtm = new RTMClient(token, {logLevel: "error"});
  const twitterClient = new twitter(util.twitter);

  let colors = ["red", "green", "yellow", "blue", "magenta", "cyan", "white", "redBright", "greenBright", "yellowBright", "blueBright", "magentaBright", "cyanBright", "whiteBright"];

  util.channels = {};
  util.users = {};
  util.bots = {};
  util.startUp = false;

  let lastestTwId=1;

  let collectTweets = () => {
    twitterClient.get('statuses/home_timeline', {count:30, since_id:lastestTwId}, (error,tweets,response) => {

      if (error) {
        console.log(error);
        return;
      }

      if (Array.isArray(tweets)) {

        if (tweets.length > 0) {
          lastestTwId = tweets[0].id;
          tweets.reverse();
        }

        tweets.forEach((tweet) => {
          let data = {
            bufferKey: "twitter",
            lines: tweet.text.split(/\n/),
            time: moment(tweet.created_at),
            channel: "[Twitter]",
            user: tweet.user.screen_name
          };

          core.display(data);
        });
      }
    });
  };

  setInterval(collectTweets, 1000 * 60);

  rtm.on("authenticated", (rtmStartData) => {
    if (!util.startUp) {
      console.log(
        `Logged in as ${chalk.bold(rtmStartData.self.name)} of team ${chalk.green.bold(rtmStartData.team.name)}, but not yet connected to a channel`
      );

      util.startUp = true;
    }
  });

  rtm.on("message", (message) => {
    let time = moment(message.ts * 1000);
    let text = util.parseText(message);

    if (message.subtype) {
      switch(message.subtype) {
      case "message_deleted":
      case "message_changed":
        return;
      case "file_share":
        break;
      case "message_replied":
        return;
      case "channel_join":
        break;
      case "channel_leave":
        break;
      case "group_leave":
        break;
      case "reply_broadcast":
        return;
      case "file_comment":
        break;
      case "bot_message":
        break;
      case "pinned_item":
        break;
      case "slackbot_response":
        break;
      case "file_mention":
        break;
      default:
        if (commander.debug) {
          logger.error(message);
        }
        return;
      }
    }

    if (text == "") {
      if (Object.prototype.hasOwnProperty.call(message, "attachments")) {
        text = message.attachments[0].text;
      } else {
        text = "";
      }
    }

    let lines;

    if (typeof(text) == "string") {
      lines = text.split(/\r\n|\r|\n/);
    } else {
      lines = [""];

      if (commander.debug) {
        logger.error(message);
      }
    }

    if (lines.length > 8) {
      lines = lines.slice(0, 5);
      lines.push("--- snip ---");
    }

    // Display only specific users. (-u option)
    if (commander.user) {
      let messageUser = (util.users[message.user]) ? util.users[message.user].name : "-";
      if (commander.user != messageUser) {
        return;
      }
    }

    // buffering
    let data = {
      bufferKey: (util.channels[message.channel]) ? "#" + util.channels[message.channel].name : "-",
      lines: lines,
      time: time,
      channel: message.channel,
      user: message.user
    };

    util.addMessageBuffer(data);
    core.display(data);

    // hook
    if (commander.hook) {
      if (util.hook) {
        exec(util.hook, (err) => {
          if (err) {
            console.log(err);
          }
        });
      }
    }

    // hooks
    let hooks = util.hasHooks(message);

    hooks.forEach((hook) => {
      exec(hook, (err) => {
        if (err) {
          console.log(err);
        }
      });
    });
  });

  // Setup
  const {WebClient} = require("@slack/client");
  const web = new WebClient(token, {logLevel: "error"});

  web.users.list().then((response) => {
    response.members.forEach((v, i) => {
      v.color = colors[i % colors.length];
      util.users[v.id] = v;
    });

    return web.channels.list();
  }).then((response) => {
    response.channels.forEach((v, i) => {
      v.color = colors[i % colors.length];
      util.channels[v.id] = v;
    });

    // [pending] bots list
    //return web.bots.info();
  }).then(() => {
    // complete
    rtm.start();
  }).catch((error) => {
    console.log(error);
  });
};

// Declare cli-handler
function handler() {}

handler.prototype.recent = function(args, fn) {
  if (util.buffer[args[0]]) {
    let messageBuffer = util.buffer[args[0]];

    let label = {
      lines: [`--- Show buffer (#${args[0]}) ---`],
      time: moment()
    };

    core.display(label);

    messageBuffer.forEach((data) => {
      core.display(data);
    });

    label.lines = ["--- finish ---"];
    core.display(label);

  }

  fn(null, args);
};

handler.prototype.echo = function(args, fn) {
  fn(null, args);
};

handler.prototype.exit = function(args, fn) {
  fn(null, args);
  this.emit("close");
};

(new cli(new handler())).run();

module.exports = core;
<|endoftext|>


<commit_before>#!/usr/bin/env node

var mongojs         = require('mongojs')
    ,configDB       = require('../config/database')
    ,db             = mongojs(configDB.url, ['concerts'])
    ,db2            = mongojs(configDB.url, ['ads'])
    ,userlocation   = require('./userlocation')
    ,util           = require('util')
    ,logger         = require('../logger').appLog;

module.exports = function(app) {

    app.get('/', function(req, res){
        var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
        res.locals.url = fullUrl;
        var o = { lat : 48.8588589, lng : 2.3470599, loc : 'unknown' };
        if(Object.keys(req.query).length == 0 || (req.query.p && req.query.p >= 1) ) {
            var ip = req.headers['x-forwarded-for'];
            p = req.query.p || 1;
            logger.debug('ip = ' + ip);
            userlocation.getRemoteGeoLocationFromIp(ip, function(err, results){
                var r = "";
                const DISPLAY_TOTAL = 33;
                const RADIUS = 100;
                r = (results) ? JSON.parse(results) : '{status:' + err +'}';
                if(r.status == "success") {
                    o = {lat : r.lat, lng : r.lon, loc : r.city + ', ' + r.country, p: p};
                    getConcerts(o.lat, o.lng, RADIUS, '', DISPLAY_TOTAL, '', p, function(err, results) {
                        if (!err) {
                            countDocs(o.lat, o.lng, RADIUS, function(err, count) {
                                o.concerts = results;
                                o.totalPages = Math.ceil(count/DISPLAY_TOTAL);
                                res.render('index', o);
                            });
                        }
                    });
                } else {
                    getConcerts(o.lat, o.lng, RADIUS, '', DISPLAY_TOTAL, '', p, function(err, results) {
                        if (!err) {
                            countDocs(o.lat, o.lng, RADIUS, function(err, count) {
                                o.concerts = results;
                                o.totalPages = Math.ceil(count/DISPLAY_TOTAL);
                                res.render('index', o);
                            });
                        }
                    });
                }
            });
        } else {
                res.render('404', {});
        }
    });

    /**
     * MAP route
     * if a specifique request (address and artist name) the corresponding event's score is incremented
     * in order to stimulate the click action!
     */
    app.get('/m', function(req, res){
        var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
        res.locals.url = fullUrl;
        var q = req.query;
        if(Object.keys(q).length != 0){
            res.locals.query = q;
            if (q.artist)
                db.concerts.findAndModify({ query: { artist: q.artist }, update: { $inc: { score: 1 } } });
            getConcerts(q.lat, q.lng, q.range, q.artist, '', '', 1, function(err, results){
                if(!err)
                    res.render('map', {lat: q.lat, lng: q.lng, concerts : results});
                else
                    res.render('404', {});
            });
        }
        else {
            res.locals.query = null;
            res.render('map', {lat: 0, lng: 0, concerts : []});
        }
    });

    app.put('/location', function(req, res){
        db.concerts.findAndModify({ query: { '_id' : req.body['_id'] }, update: { $set: { address: req.body.address } } });
    });

    /*
     * Concerts API
     */
    app.get('/concert', function(req, res){
        var q =  req.query;
        getConcerts(q.lat, q.lng, q.range, q.artist, q.l, q.date, q.page, function(err, results) {
            if (!err) res.send(results);
            else res.send(err);
        });
    });

}

/**
 * METHODS
 */

/**
 * Method to return concerts from server using given params
 * @param lat : latitude of db search
 * @param lng : longitude of db search
 * @param radius : radius of db search
 * @param artists : filter db results with artists
 * @param limit : max number of returned results from db
 * @param date : used to fetch concerts later than date
 * @param fn : callback function (err, results)
 */
function getConcerts (lat, lng, radius, artists, limit, date, page, fn) {
    var l = parseFloat(limit) || 100;
    page = page || 1;
    var newDate = date || new Date();
    var dbQuery = { latlng: { $near:[parseFloat(lat), parseFloat(lng)], $maxDistance: parseFloat(radius)/111.12} };
    if (artists) dbQuery.artist = new RegExp(artists, 'i');
    dbQuery.startDate = { $gte : new Date(newDate)};
    db.concerts.find(dbQuery).sort({'score' : -1}).skip(--page*l).limit(l, function(err, result) {
        if(!err) {
            logger.info('# of concerts returned = ' + result.length + '\n');
            return fn(null, result);
        } else {
            logger.error(err);
            return fn(err, null);
        }
    });
}

function countDocs (lat, lng, radius, fn) {
    var dbQuery = { latlng: { $near:[parseFloat(lat), parseFloat(lng)], $maxDistance: parseFloat(radius)/111.12} };
    var newDate = new Date();
    dbQuery.startDate = { $gte : new Date(newDate)};
    db.concerts.count(dbQuery, function(err, results) {
        if (!err) return fn(null, results);
        else return fn(err, null);
    });
}<commit_msg>Update security fix: extra chars are filtered from range param<commit_after>#!/usr/bin/env node

var mongojs         = require('mongojs')
    ,configDB       = require('../config/database')
    ,db             = mongojs(configDB.url, ['concerts'])
    ,db2            = mongojs(configDB.url, ['ads'])
    ,userlocation   = require('./userlocation')
    ,util           = require('util')
    ,logger         = require('../logger').appLog;

module.exports = function(app) {

    app.get('/', function(req, res){
        var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
        res.locals.url = fullUrl;
        var o = { lat : 48.8588589, lng : 2.3470599, loc : 'unknown' };
        if(Object.keys(req.query).length == 0 || (req.query.p && req.query.p >= 1) ) {
            var ip = req.headers['x-forwarded-for'];
            p = req.query.p || 1;
            logger.debug('ip = ' + ip);
            userlocation.getRemoteGeoLocationFromIp(ip, function(err, results){
                var r = "";
                const DISPLAY_TOTAL = 33;
                const RADIUS = 100;
                r = (results) ? JSON.parse(results) : '{status:' + err +'}';
                if(r.status == "success") {
                    o = {lat : r.lat, lng : r.lon, loc : r.city + ', ' + r.country, p: p};
                    getConcerts(o.lat, o.lng, RADIUS, '', DISPLAY_TOTAL, '', p, function(err, results) {
                        if (!err) {
                            countDocs(o.lat, o.lng, RADIUS, function(err, count) {
                                o.concerts = results;
                                o.totalPages = Math.ceil(count/DISPLAY_TOTAL);
                                res.render('index', o);
                            });
                        }
                    });
                } else {
                    getConcerts(o.lat, o.lng, RADIUS, '', DISPLAY_TOTAL, '', p, function(err, results) {
                        if (!err) {
                            countDocs(o.lat, o.lng, RADIUS, function(err, count) {
                                o.concerts = results;
                                o.totalPages = Math.ceil(count/DISPLAY_TOTAL);
                                res.render('index', o);
                            });
                        }
                    });
                }
            });
        } else {
                res.render('404', {});
        }
    });

    /**
     * MAP route
     * if a specifique request (address and artist name) the corresponding event's score is incremented
     * in order to stimulate the click action!
     */
    app.get('/m', function(req, res){
        var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;
        res.locals.url = fullUrl;
        var q = req.query;
        if(Object.keys(q).length != 0){
            res.locals.query = q;
            if (q.artist)
                db.concerts.findAndModify({ query: { artist: q.artist }, update: { $inc: { score: 1 } } });
            q.range = parseInt(q.range.split(' ')[0]);
            getConcerts(q.lat, q.lng, q.range, q.artist, '', '', 1, function(err, results){
                if(!err)
                    res.render('map', {lat: q.lat, lng: q.lng, concerts : results});
                else
                    res.render('404', {});
            });
        }
        else {
            res.locals.query = null;
            res.render('map', {lat: 0, lng: 0, concerts : []});
        }
    });

    app.put('/location', function(req, res){
        db.concerts.findAndModify({ query: { '_id' : req.body['_id'] }, update: { $set: { address: req.body.address } } });
    });

    /*
     * Concerts API
     */
    app.get('/concert', function(req, res){
        var q =  req.query;
        getConcerts(q.lat, q.lng, q.range, q.artist, q.l, q.date, q.page, function(err, results) {
            if (!err) res.send(results);
            else res.send(err);
        });
    });

}

/**
 * METHODS
 */

/**
 * Method to return concerts from server using given params
 * @param lat : latitude of db search
 * @param lng : longitude of db search
 * @param radius : radius of db search
 * @param artists : filter db results with artists
 * @param limit : max number of returned results from db
 * @param date : used to fetch concerts later than date
 * @param fn : callback function (err, results)
 */
function getConcerts (lat, lng, radius, artists, limit, date, page, fn) {
    var l = parseFloat(limit) || 100;
    page = page || 1;
    var newDate = date || new Date();
    var dbQuery = { latlng: { $near:[parseFloat(lat), parseFloat(lng)], $maxDistance: parseFloat(radius)/111.12} };
    if (artists) dbQuery.artist = new RegExp(artists, 'i');
    dbQuery.startDate = { $gte : new Date(newDate)};
    db.concerts.find(dbQuery).sort({'score' : -1}).skip(--page*l).limit(l, function(err, result) {
        if(!err) {
            logger.info('# of concerts returned = ' + result.length + '\n');
            return fn(null, result);
        } else {
            logger.error(err);
            return fn(err, null);
        }
    });
}

function countDocs (lat, lng, radius, fn) {
    var dbQuery = { latlng: { $near:[parseFloat(lat), parseFloat(lng)], $maxDistance: parseFloat(radius)/111.12} };
    var newDate = new Date();
    dbQuery.startDate = { $gte : new Date(newDate)};
    db.concerts.count(dbQuery, function(err, results) {
        if (!err) return fn(null, results);
        else return fn(err, null);
    });
}<|endoftext|>


<commit_before>// @flow
import React from 'react';
import { Router, Route, IndexRoute } from 'react-router';

import AppContainer from './containers/AppContainer';
import AuthContainer from './containers/auth/AuthContainer';
import ProfileContainer from './containers/profile/ProfileContainer';

import HomePage from './containers/HomePage';
import ProfilePage from './containers/profile/ProfilePage';

import LoginPage from './containers/auth/LoginPage';
import RegisterPage from './containers/auth/RegisterPage';

import InfoPage from './containers/profile/InfoPage';
import AchievementsPage from './containers/profile/AchievementsPage';

export default (
    <Router>
        <Route path="/" component={AppContainer}>
            <IndexRoute component={HomePage} />

            <Route path="profile">
                <IndexRoute component={ProfilePage} />

                <Route path="info" component={InfoPage} />
                <Route path="achievements" component={AchievementsPage} />
            </Route>
        </Route>

        <Route path="/auth" component={AuthContainer}>
            <Route path="login" component={LoginPage} />
            <Route path="register" component={RegisterPage} />
        </Route>
    </Router>
);
<commit_msg>[app] oops<commit_after>// @flow
import React from 'react';
import { Router, Route, IndexRoute } from 'react-router';

import AppContainer from './containers/AppContainer';
import AuthContainer from './containers/auth/AuthContainer';

import HomePage from './containers/HomePage';
import ProfilePage from './containers/profile/ProfilePage';

import LoginPage from './containers/auth/LoginPage';
import RegisterPage from './containers/auth/RegisterPage';

import InfoPage from './containers/profile/InfoPage';
import AchievementsPage from './containers/profile/AchievementsPage';

export default (
    <Router>
        <Route path="/" component={AppContainer}>
            <IndexRoute component={HomePage} />

            <Route path="profile">
                <IndexRoute component={ProfilePage} />

                <Route path="info" component={InfoPage} />
                <Route path="achievements" component={AchievementsPage} />
            </Route>
        </Route>

        <Route path="/auth" component={AuthContainer}>
            <Route path="login" component={LoginPage} />
            <Route path="register" component={RegisterPage} />
        </Route>
    </Router>
);
<|endoftext|>


<commit_before>// load up the user model
var User = require('../app/models/user');

var fs = require('fs');
var path_module = require('path');
var FastSpring = require('./fastspring');
var MailerLite = require('./mailer_lite');

function deleteFolderRecursive(path) {
    if (fs.existsSync(path)) {
        fs.readdirSync(path).forEach(function (file, index) {
            var curPath = path + "/" + file;
            if (fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
}

function checkIsValidDomain(domain) {
    var re = new RegExp(/^((?:(?:(?:\w[\.\-\+]?)*)\w)+)((?:(?:(?:\w[\.\-\+]?){0,62})\w)+)\.(\w{2,6})$/);
    return domain.match(re);
}

module.exports = function (app, passport, nev) {
    var fastSpring = new FastSpring(app.locals.fastspring_config.login, app.locals.fastspring_config.password);
    var mailerLite = new MailerLite();

// normal routes ===============================================================

    // show the home page (will also have our login links)
    app.get('/', function (req, res) {
        res.render('index.ejs');
    });

    app.get('/help', function (req, res) {
        res.render('help.ejs');
    });

    app.get('/private_policy', function (req, res) {
        res.render('private_policy.ejs');
    });

    app.get('/term_of_use', function (req, res) {
        res.render('term_of_use.ejs');
    });

    app.get('/anonim_users_downloads', function (req, res) {
        res.render('anonim_users_downloads.ejs');
        //res.render('login.ejs', {message: req.flash('loginMessage')});
    });

    app.get('/registered_users_downloads', isLoggedIn, function (req, res) {
        res.render('registered_users_downloads.ejs');
    });

    app.get('/subscribed_users_downloads', function (req, res, next) {
        var subscr = req.user.getSubscription();
        if (!subscr) {
            res.redirect('/profile');
        }

        fastSpring.checkSubscriptionState('active', subscr.subscriptionId)
            .then(function (result) {
                if (result) {
                    return next();
                }

                res.redirect('/profile');
            }).catch(function (error) {
            res.redirect('/profile');
        });
    }, function (req, res) {
        res.render('subscribed_users_downloads.ejs');
    });

    app.get('/build_installer_request', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;

        var walk = function (dir, done) {
            console.log('scan folder: ', dir);
            var results = [];
            fs.readdir(dir, function (err, list) {
                if (err) {
                    return done(err, []);
                }
                var pending = list.length;
                if (!pending) {
                    return done(null, results);
                }
                list.forEach(function (file) {
                    var file_name = file;
                    file = path_module.resolve(dir, file);
                    fs.stat(file, function (err, stat) {
                        if (err) {
                            return done(err, []);
                        }

                        if (stat && stat.isDirectory()) {
                            walk(file, function (err, res) {
                                results = results.concat(res);
                                if (!--pending) {
                                    done(null, results);
                                }
                            });
                        } else {
                            var path = file.replace(app.locals.site.public_directory, '');
                            results.push({
                                'path': app.locals.site.domain + path,
                                'file_name': file_name,
                                'size': parseInt(stat.size / 1024)
                            });
                            if (!--pending) {
                                done(null, results);
                            }
                        }
                    });
                });
            });
        };

        walk(app.locals.site.users_directory + '/' + user.email, function (err, results) {
            if (err) {
                console.error(err);
            }

            res.render('build_installer_request.ejs', {
                user: user,
                builded_packages: results
            });
        });
    });

    // CLEAR user packages
    app.post('/clear_packages', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;
        deleteFolderRecursive(app.locals.site.users_directory + '/' + user.email);
        res.render('build_installer_request.ejs', {
            user: user,
            builded_packages: []
        });
    });

    // PROFILE SECTION =========================
    app.get('/profile', isLoggedIn, function (req, res) {
        var subscr = req.user.getSubscription();

        if (subscr) {
            fastSpring.getSubscription(subscr.subscriptionId)
                .then(function (data) {
                    var subscription = JSON.parse(data);

                    req.user.set({subscription_state: subscription.state});
                    req.user.save(function (err) {
                        if (err) {
                            console.error('getSubscription: ', err);
                        }
                    });

                    console.log('Success. Set subscription.');
                    res.render('profile.ejs', {
                        user: req.user,
                        message: req.flash('statusProfileMessage')
                    });
                }).catch(function (error) {
                console.error('getSubscription: ', error);
            });
        } else {
            console.error('Not found `subscr`.', subscr);
            res.render('profile.ejs', {
                user: req.user,
                message: req.flash('statusProfileMessage')
            });
        }
    });

    app.post('/updateProfile', isLoggedIn, function (req, res) {
        var user = req.user;

        user.set({
            first_name: req.body.firstName.trim(),
            last_name: req.body.lastName.trim()
        });

        user.save(function (err) {
            if (err) {
                console.error('Update profile error!');
            }

            mailerLite.updateSubscriber(user.email, {
                type: 'active',
                fields: {
                    name: user.first_name,
                    last_name: user.last_name
                }
            }).then(function () {
                console.log("Update subscribe is completed!");
            }).catch(function (err) {
                console.log("Update subscribe is error!", err);
            });

            res.redirect('/profile');
        });
    });

    // SUBSCRIPTION =============================
    app.post('/subscription', isLoggedIn, function (req, res) {
        var user = req.user;
        if (user.enableSubscription()) {
            var body = JSON.parse(req.body.data);

            if (body.hasOwnProperty('id') && body.hasOwnProperty('reference')) {
                // ===== fastSpring.getOrder
                fastSpring.getOrder(body.id)
                    .then(function (data) {
                        var order = JSON.parse(data);

                        if (order.hasOwnProperty('error')) {
                            return res.status(500).send('ERROR: Subscription was failed!');
                        }

                        if (!order.items.length) {
                            return res.status(500).send('ERROR: Subscription was failed!');
                        }

                        user.set({
                            subscription: JSON.stringify(Object.assign(body, {subscriptionId: order.items[0].subscription}))
                        });
                        user.save(function (err) {
                            if (err) {
                                return res.status(500).send('ERROR: Subscription was failed!');
                            }
                        });

                        res.status(200).send('SUCCESS: Subscription success!');
                    }).catch(function (error) {
                    console.error('getOrder: ', error);
                    return res.status(500).send('ERROR: Subscription was failed!');
                });
                // =====
            } else {
                return res.status(400).send('ERROR: Invalid data!');
            }
        } else {
            return res.status(500).send('ERROR: Subscription is already exist!');
        }
    });

    // CANCEL_SUBSCRIPTION ==============================
    app.post('/cancel_subscription', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;
        var subscr = user.getSubscription();
        fastSpring.cancelSubscription(subscr.subscriptionId)
            .then(function (data) {
                var answer = JSON.parse(data);

                if (answer.result === 'error') {
                    throw new Error('Cancel subscription was failed.');
                }
                res.redirect('/profile');
            }).catch(function (error) {
            console.log('cancelSubscription: ', error);
        });
    });

    // LOGOUT ==============================
    app.get('/logout', function (req, res) {
        req.logout();
        res.redirect('/');
    });

// =============================================================================
// AUTHENTICATE (FIRST LOGIN) ==================================================
// =============================================================================

    // locally --------------------------------
    // LOGIN ===============================
    // show the login form
    app.get('/login', function (req, res) {
        res.render('login.ejs', {message: req.flash('loginMessage')});
    });

    // process the login form
    app.post('/login', passport.authenticate('local-login', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/login', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

    // SIGNUP =================================
    // show the signup form
    app.get('/signup', function (req, res) {
        res.render('signup.ejs', {message: req.flash('signupMessage')});
    });

    // process the signup form
    app.post('/signup', passport.authenticate('local-signup', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/signup', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

    // user accesses the link that is sent
    app.get('/email-verification/:URL', function (req, res) {
        var url = req.params.URL;
        nev.confirmTempUser(url, function (err, user) {
            if (err) {
                return res.status(404).send('ERROR: sending confirmation email FAILED');
            }

            if (!user) {
                return res.status(404).send('ERROR: confirming temp user FAILED');
            }

            var email = user.email;

            if (user.email_subscription) {
                mailerLite.addNewSubscriberToGroup(app.mailer_lite_config.group, {
                    email: email,
                    name: user.first_name,
                    fields: {
                        last_name: user.last_name
                    }
                }).then(function () {
                    console.log("Email subscription is completed!");
                }).catch(function (err_mailer) {
                    console.error("Email subscription failed, error: " + err_mailer);
                });
            }

            console.log("confirm message sent to: " + email);
            res.render('after_confirm.ejs');
        });
    });

    app.get('/after_confirm', function (req, res) {
        res.render('after_confirm.ejs');
    });

// =============================================================================
// AUTHORIZE (ALREADY LOGGED IN / CONNECTING OTHER SOCIAL ACCOUNT) =============
// =============================================================================

    // locally --------------------------------
    app.get('/connect/local', function (req, res) {
        res.render('connect_local.ejs', {message: req.flash('loginMessage')});
    });
    app.post('/connect/local', passport.authenticate('local-signup', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/connect/local', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

};

// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next();
    }

    res.redirect('/');
}

// Note: will be deleted
function isSubscribed(req, res, next) {
    if (req.user.getSubscriptionState() === 'active') {
        return next();
    }

    res.redirect('/profile');
}
<commit_msg>Next Fix<commit_after>// load up the user model
var User = require('../app/models/user');

var fs = require('fs');
var path_module = require('path');
var FastSpring = require('./fastspring');
var MailerLite = require('./mailer_lite');

function deleteFolderRecursive(path) {
    if (fs.existsSync(path)) {
        fs.readdirSync(path).forEach(function (file, index) {
            var curPath = path + "/" + file;
            if (fs.lstatSync(curPath).isDirectory()) { // recurse
                deleteFolderRecursive(curPath);
            } else { // delete file
                fs.unlinkSync(curPath);
            }
        });
        fs.rmdirSync(path);
    }
}

function checkIsValidDomain(domain) {
    var re = new RegExp(/^((?:(?:(?:\w[\.\-\+]?)*)\w)+)((?:(?:(?:\w[\.\-\+]?){0,62})\w)+)\.(\w{2,6})$/);
    return domain.match(re);
}

module.exports = function (app, passport, nev) {
    var fastSpring = new FastSpring(app.locals.fastspring_config.login, app.locals.fastspring_config.password);
    var mailerLite = new MailerLite();

// normal routes ===============================================================

    // show the home page (will also have our login links)
    app.get('/', function (req, res) {
        res.render('index.ejs');
    });

    app.get('/help', function (req, res) {
        res.render('help.ejs');
    });

    app.get('/private_policy', function (req, res) {
        res.render('private_policy.ejs');
    });

    app.get('/term_of_use', function (req, res) {
        res.render('term_of_use.ejs');
    });

    app.get('/anonim_users_downloads', function (req, res) {
        res.render('anonim_users_downloads.ejs');
        //res.render('login.ejs', {message: req.flash('loginMessage')});
    });

    app.get('/registered_users_downloads', isLoggedIn, function (req, res) {
        res.render('registered_users_downloads.ejs');
    });

    app.get('/subscribed_users_downloads', function (req, res, next) {
        var subscr = req.user.getSubscription();
        if (!subscr) {
            res.redirect('/profile');
        }

        fastSpring.checkSubscriptionState('active', subscr.subscriptionId)
            .then(function (result) {
                if (result) {
                    return next();
                }

                res.redirect('/profile');
            }).catch(function (error) {
            res.redirect('/profile');
        });
    }, function (req, res) {
        res.render('subscribed_users_downloads.ejs');
    });

    app.get('/build_installer_request', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;

        var walk = function (dir, done) {
            console.log('scan folder: ', dir);
            var results = [];
            fs.readdir(dir, function (err, list) {
                if (err) {
                    return done(err, []);
                }
                var pending = list.length;
                if (!pending) {
                    return done(null, results);
                }
                list.forEach(function (file) {
                    var file_name = file;
                    file = path_module.resolve(dir, file);
                    fs.stat(file, function (err, stat) {
                        if (err) {
                            return done(err, []);
                        }

                        if (stat && stat.isDirectory()) {
                            walk(file, function (err, res) {
                                results = results.concat(res);
                                if (!--pending) {
                                    done(null, results);
                                }
                            });
                        } else {
                            var path = file.replace(app.locals.site.public_directory, '');
                            results.push({
                                'path': app.locals.site.domain + path,
                                'file_name': file_name,
                                'size': parseInt(stat.size / 1024)
                            });
                            if (!--pending) {
                                done(null, results);
                            }
                        }
                    });
                });
            });
        };

        walk(app.locals.site.users_directory + '/' + user.email, function (err, results) {
            if (err) {
                console.error(err);
            }

            res.render('build_installer_request.ejs', {
                user: user,
                builded_packages: results
            });
        });
    });

    // CLEAR user packages
    app.post('/clear_packages', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;
        deleteFolderRecursive(app.locals.site.users_directory + '/' + user.email);
        res.render('build_installer_request.ejs', {
            user: user,
            builded_packages: []
        });
    });

    // PROFILE SECTION =========================
    app.get('/profile', isLoggedIn, function (req, res) {
        var subscr = req.user.getSubscription();

        if (subscr) {
            fastSpring.getSubscription(subscr.subscriptionId)
                .then(function (data) {
                    var subscription = JSON.parse(data);

                    req.user.set({subscription_state: subscription.state});
                    req.user.save(function (err) {
                        if (err) {
                            console.error('getSubscription: ', err);
                        }
                    });

                    console.log('Success. Set subscription.');
                    res.render('profile.ejs', {
                        user: req.user,
                        message: req.flash('statusProfileMessage')
                    });
                }).catch(function (error) {
                console.error('getSubscription: ', error);
            });
        } else {
            console.error('Not found `subscr`.', subscr);
            res.render('profile.ejs', {
                user: req.user,
                message: req.flash('statusProfileMessage')
            });
        }
    });

    app.post('/updateProfile', isLoggedIn, function (req, res) {
        var user = req.user;

        user.set({
            first_name: req.body.firstName.trim(),
            last_name: req.body.lastName.trim()
        });

        user.save(function (err) {
            if (err) {
                console.error('Update profile error!');
            }

            mailerLite.updateSubscriber(user.email, {
                type: 'active',
                fields: {
                    name: user.first_name,
                    last_name: user.last_name
                }
            }).then(function () {
                console.log("Update subscribe is completed!");
            }).catch(function (err) {
                console.log("Update subscribe is error!", err);
            });

            res.redirect('/profile');
        });
    });

    // SUBSCRIPTION =============================
    app.post('/subscription', isLoggedIn, function (req, res) {
        var user = req.user;
        if (user.enableSubscription()) {
            var body = JSON.parse(req.body.data);

            if (body.hasOwnProperty('id') && body.hasOwnProperty('reference')) {
                // ===== fastSpring.getOrder
                fastSpring.getOrder(body.id)
                    .then(function (data) {
                        var order = JSON.parse(data);

                        if (order.hasOwnProperty('error')) {
                            return res.status(500).send('ERROR: Subscription was failed!');
                        }

                        if (!order.items.length) {
                            return res.status(500).send('ERROR: Subscription was failed!');
                        }

                        user.set({
                            subscription: JSON.stringify(Object.assign(body, {subscriptionId: order.items[0].subscription}))
                        });
                        user.save(function (err) {
                            if (err) {
                                return res.status(500).send('ERROR: Subscription was failed!');
                            }
                        });

                        res.status(200).send('SUCCESS: Subscription success!');
                    }).catch(function (error) {
                    console.error('getOrder: ', error);
                    return res.status(500).send('ERROR: Subscription was failed!');
                });
                // =====
            } else {
                return res.status(400).send('ERROR: Invalid data!');
            }
        } else {
            return res.status(500).send('ERROR: Subscription is already exist!');
        }
    });

    // CANCEL_SUBSCRIPTION ==============================
    app.post('/cancel_subscription', User.checkSubscriptionStatus(app, 'active'), function (req, res) {
        var user = req.user;
        var subscr = user.getSubscription();
        fastSpring.cancelSubscription(subscr.subscriptionId)
            .then(function (data) {
                var answer = JSON.parse(data);

                if (answer.result === 'error') {
                    throw new Error('Cancel subscription was failed.');
                }
                res.redirect('/profile');
            }).catch(function (error) {
            console.log('cancelSubscription: ', error);
        });
    });

    // LOGOUT ==============================
    app.get('/logout', function (req, res) {
        req.logout();
        res.redirect('/');
    });

// =============================================================================
// AUTHENTICATE (FIRST LOGIN) ==================================================
// =============================================================================

    // locally --------------------------------
    // LOGIN ===============================
    // show the login form
    app.get('/login', function (req, res) {
        res.render('login.ejs', {message: req.flash('loginMessage')});
    });

    // process the login form
    app.post('/login', passport.authenticate('local-login', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/login', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

    // SIGNUP =================================
    // show the signup form
    app.get('/signup', function (req, res) {
        res.render('signup.ejs', {message: req.flash('signupMessage')});
    });

    // process the signup form
    app.post('/signup', passport.authenticate('local-signup', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/signup', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

    // user accesses the link that is sent
    app.get('/email-verification/:URL', function (req, res) {
        var url = req.params.URL;
        nev.confirmTempUser(url, function (err, user) {
            if (err) {
                return res.status(404).send('ERROR: sending confirmation email FAILED');
            }

            if (!user) {
                return res.status(404).send('ERROR: confirming temp user FAILED');
            }

            var email = user.email;

            if (user.email_subscription) {
                mailerLite.addNewSubscriberToGroup(app.locals.mailer_lite_config.group, {
                    email: email,
                    name: user.first_name,
                    fields: {
                        last_name: user.last_name
                    }
                }).then(function () {
                    console.log("Email subscription is completed!");
                }).catch(function (err_mailer) {
                    console.error("Email subscription failed, error: " + err_mailer);
                });
            }

            console.log("confirm message sent to: " + email);
            res.render('after_confirm.ejs');
        });
    });

    app.get('/after_confirm', function (req, res) {
        res.render('after_confirm.ejs');
    });

// =============================================================================
// AUTHORIZE (ALREADY LOGGED IN / CONNECTING OTHER SOCIAL ACCOUNT) =============
// =============================================================================

    // locally --------------------------------
    app.get('/connect/local', function (req, res) {
        res.render('connect_local.ejs', {message: req.flash('loginMessage')});
    });
    app.post('/connect/local', passport.authenticate('local-signup', {
        successRedirect: '/profile', // redirect to the secure profile section
        failureRedirect: '/connect/local', // redirect back to the signup page if there is an error
        failureFlash: true // allow flash messages
    }));

};

// route middleware to ensure user is logged in
function isLoggedIn(req, res, next) {
    if (req.isAuthenticated()) {
        return next();
    }

    res.redirect('/');
}

// Note: will be deleted
function isSubscribed(req, res, next) {
    if (req.user.getSubscriptionState() === 'active') {
        return next();
    }

    res.redirect('/profile');
}
<|endoftext|>


<commit_before>(function(){
  var template_cache = {};
  var views = {};

  $(function(){
    new Backbone.Router({
      routes: {
        '': index,
        ':unique_lga/lga_overview': route(lga_overview),
        ':unique_lga/lga_health': route(lga_sector, 'health'),
        ':unique_lga/lga_education': route(lga_sector, 'education'),
        ':unique_lga/lga_water': route(lga_sector, 'water'),
        ':unique_lga/facility_overview': route(facility_overview),
        ':unique_lga/facility_health': route(facility_sector, 'health'),
        ':unique_lga/facility_education': route(facility_sector, 'education'),
        ':unique_lga/facility_water': route(facility_sector, 'water')
      }
    });
    Backbone.history.start();
  });

  // Views
  function _lga_nav(lga, active_view, sector){
    var template = $('#lga_nav_template').html();
    var html = _.template(template, {
      lga: lga,
      active_view: active_view,
      sector: sector
    });
    $('#lga_nav').html(html);
  }

  function index(){
    render('#index_template', {});
    $('#zone-navigation .state-link').click(function(){
      $(this).next('.lga-list').toggle();
      return false;
    });
  }

  function lga_overview(lga){
    _lga_nav(lga, 'lga', 'overview');
    render('#lga_overview_template', {lga: lga});
    leaflet_overview(lga);
  }

  function lga_sector(lga, sector){
    _lga_nav(lga, 'lga', sector);
    render('#lga_sector_template', {
      lga: lga,
      sector: sector
    });
  }

  function facility_overview(lga){
    _lga_nav(lga, 'facility', 'overview');
    render('#facility_overview_template', {lga: lga});
  }

  function facility_sector(lga, sector){
    _lga_nav(lga, 'facility', sector);
  }

  // Helper Functions
  function route(view, sector){
    return function(unique_lga){
      var lga = NMIS.lgas[unique_lga];
      if (typeof lga === 'undefined'){
        var url = '/static/lgas/' + unique_lga + '.json';
        $.getJSON(url, function(lga){
          NMIS.lgas[unique_lga] = lga;
          view(lga, sector);
        });
      } else {
        view(lga, sector);
      }
    }
  }

  function render(template_id, context){
    var template = $(template_id).html();
    context.NMIS = NMIS;
    context.format_value = format_value;
    var html = _.template(template, context);
    $('#content .content').html(html);
  }

  function format_value(value){
    if (typeof value === 'undefined') return '-';
    if (_.isNumber(value) && value % 1 !== 0)
      return value.toFixed(2);
    return value;
  }
})();

function leaflet_overview(lga){
  var map_div = $(".map")[0];
  var lat_lng = new L.LatLng(lga.latitude, lga.longitude);
  var map_zoom = 9;
  var summary_map = L.map(map_div, {})
      .setView(lat_lng, map_zoom);
  var tileset = "nigeria_base";
  var tile_server = "http://{s}.tiles.mapbox.com/v3/modilabs."
                    + tileset
                    + "/{z}/{x}/{y}.png";
  L.tileLayer(tile_server, {
    minZoom: 6,
    maxZoom: 11
  }).addTo(summary_map);
}

function leaflet_facility(lga){
  var map_div = $("#facility_overview_map")[0];

};

<commit_msg>adding leaflet functionalities in facilities<commit_after>(function(){
  var template_cache = {};
  var views = {};

  $(function(){
    new Backbone.Router({
      routes: {
        '': index,
        ':unique_lga/lga_overview': route(lga_overview),
        ':unique_lga/lga_health': route(lga_sector, 'health'),
        ':unique_lga/lga_education': route(lga_sector, 'education'),
        ':unique_lga/lga_water': route(lga_sector, 'water'),
        ':unique_lga/facility_overview': route(facility_overview),
        ':unique_lga/facility_health': route(facility_sector, 'health'),
        ':unique_lga/facility_education': route(facility_sector, 'education'),
        ':unique_lga/facility_water': route(facility_sector, 'water')
      }
    });
    Backbone.history.start();
  });

  // Views
  function _lga_nav(lga, active_view, sector){
    var template = $('#lga_nav_template').html();
    var html = _.template(template, {
      lga: lga,
      active_view: active_view,
      sector: sector
    });
    $('#lga_nav').html(html);
  }

  function index(){
    render('#index_template', {});
    $('#zone-navigation .state-link').click(function(){
      $(this).next('.lga-list').toggle();
      return false;
    });
  }

  function lga_overview(lga){
    _lga_nav(lga, 'lga', 'overview');
    render('#lga_overview_template', {lga: lga});
    leaflet_overview(lga);
  }

  function lga_sector(lga, sector){
    _lga_nav(lga, 'lga', sector);
    render('#lga_sector_template', {
      lga: lga,
      sector: sector
    });
  }

  function facility_overview(lga){
    _lga_nav(lga, 'facility', 'overview');
    render('#facility_overview_template', {lga: lga});
    leaflet_facility(lga);
  }

  function facility_sector(lga, sector){
    _lga_nav(lga, 'facility', sector);
  }

  // Helper Functions
  function route(view, sector){
    return function(unique_lga){
      var lga = NMIS.lgas[unique_lga];
      if (typeof lga === 'undefined'){
        var url = '/static/lgas/' + unique_lga + '.json';
        $.getJSON(url, function(lga){
          NMIS.lgas[unique_lga] = lga;
          view(lga, sector);
        });
      } else {
        view(lga, sector);
      }
    }
  }

  function render(template_id, context){
    var template = $(template_id).html();
    context.NMIS = NMIS;
    context.format_value = format_value;
    var html = _.template(template, context);
    $('#content .content').html(html);
  }

  function format_value(value){
    if (typeof value === 'undefined') return '-';
    if (_.isNumber(value) && value % 1 !== 0)
      return value.toFixed(2);
    return value;
  }
})();

function leaflet_overview(lga){
  var map_div = $(".map")[0];
  var lat_lng = new L.LatLng(lga.latitude, lga.longitude);
  var map_zoom = 9;
  var summary_map = L.map(map_div, {})
      .setView(lat_lng, map_zoom);
  var tileset = "nigeria_base";
  var tile_server = "http://{s}.tiles.mapbox.com/v3/modilabs."
                    + tileset
                    + "/{z}/{x}/{y}.png";
  L.tileLayer(tile_server, {
    minZoom: 6,
    maxZoom: 11
  }).addTo(summary_map);
}

function leaflet_facility(lga){
  var map_div = $("#facility_overview_map")[0];
  var lat_lng = new L.LatLng(lga.latitude, lga.longitude);
  var map_zoom = 5; //TODO: adding nw and se for bounding box
  var facility_map = L.map(map_div, {})
      .setView(lat_lng, map_zoom);
  var tileset = "nigeria_overlays_white";
  var tile_server = "http://{s}.tiles.mapbox.com/v3/modilabs."
                    + tileset
                    + "/{z}/{x}/{y}.png";
  var lga_layer = new L.TileLayer(tile_server, {
    minZoom: 6,
    maxZoom: 11
  });
  lga_layer.addTo(facility_map);
  var osm_server = "http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png";
  var osm_layer = new L.TileLayer(osm_server, {
    minZoom: 0,
    maxZoom: 18
  });
  osm_layer.addTo(facility_map);

};

<|endoftext|>