<file_sep>var StationNetwork = require('../lib/station-network');
var sn = new StationNetwork();

setTimeout(function() {
	var path = sn.shortestPathBetween("0", "70");
	console.log(path);
	process.exit(0);
}, 5000);<file_sep>var Graph = require('../lib/graph');
var Vertex = require('../lib/vertex');
var graph = new Graph();

setTimeout(function() {
	var vertex1 = new Vertex('corinthiansItaquera', {
		name: '<NAME>',
		location: {
			latitude: 23.456,
			longitude: 46.1234
		}
	});

	var vertex2 = new Vertex('arthurAlvim', {
		name: '<NAME>',
		location: {
			latitude: 24.456,
			longitude: 45.12345
		}
	});

	var vertex3 = new Vertex('patriarca', {
		name: 'Patriarca',
		location: {
			latitude: 26.456,
			longitude: 49.1234
		}
	});

	var vertex4 = new Vertex('vilaMatilde', {
		name: '<NAME>',
		location: {
			latitude: 21.456,
			longitude: 41.1234
		}
	});

	var vertex5 = new Vertex('penha', {
		name: 'Penha',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex6 = new Vertex('se', {
		name: 'Sé',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex7 = new Vertex('belem', {
		name: 'belem',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex8 = new Vertex('bras', {
		name: 'bras',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex9 = new Vertex('luz', {
		name: 'luz',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex10 = new Vertex('marechal', {
		name: 'marechal',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex11 = new Vertex('anaRosa', {
		name: '<NAME>',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex12 = new Vertex('ipiranga', {
		name: 'ipiranga',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex13 = new Vertex('paraiso', {
		name: 'paraiso',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex14 = new Vertex('sacoma', {
		name: 'sacoma',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex15 = new Vertex('liberdade', {
		name: 'liberdade',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	var vertex16 = new Vertex('pedroII', {
		name: '<NAME>',
		location: {
			latitude: 22.456,
			longitude: 42.1234
		}
	});

	graph.addEdge(vertex1, vertex2, 1);
	graph.addEdge(vertex1, vertex3, 1);
	graph.addEdge(vertex1, vertex6, 1);
	graph.addEdge(vertex2, vertex3, 1);
	graph.addEdge(vertex2, vertex4, 1);
	graph.addEdge(vertex3, vertex4, 1);
	graph.addEdge(vertex3, vertex5, 1);
	graph.addEdge(vertex4, vertex5, 1);
	graph.addEdge(vertex4, vertex7, 1);
	graph.addEdge(vertex5, vertex8, 1);
	graph.addEdge(vertex7, vertex9, 1);
	graph.addEdge(vertex7, vertex10, 1);
	graph.addEdge(vertex8, vertex9, 1);
	graph.addEdge(vertex8, vertex11, 1);
	graph.addEdge(vertex8, vertex12, 1);
	graph.addEdge(vertex9, vertex10, 1);
	graph.addEdge(vertex10, vertex11, 1);
	graph.addEdge(vertex10, vertex13, 1);
	graph.addEdge(vertex11, vertex12, 1);
	graph.addEdge(vertex11, vertex15, 1);
	graph.addEdge(vertex11, vertex16, 1);
	graph.addEdge(vertex13, vertex14, 1);
	graph.addEdge(vertex15, vertex16, 1);

	graph.print();

	var DepthFirstSearch = require('../lib/dfs');
	var dfs = new DepthFirstSearch(graph, vertex1.vertexId);
	var present = false;

	console.log("Is " + vertex1.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex1.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex2.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex2.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex3.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex3.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex4.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex4.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex5.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex5.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + "santos" + " in Graph?");
	present = dfs.isVertexIdInGraph('santos');
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + "paulista" + " in Graph?");
	present = dfs.isVertexIdInGraph('paulista');
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + "consolacao" + " in Graph?");
	present = dfs.isVertexIdInGraph('consolacao');
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex6.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex6.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex7.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex7.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex8.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex8.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex9.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex9.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex10.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex10.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex11.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex11.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex12.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex12.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex13.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex13.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
	console.log("Is " + vertex14.vertexId + " in Graph?");
	present = dfs.isVertexIdInGraph(vertex14.vertexId);
	console.log("Is in Graph: " + present);
	console.log("=========================");
	console.log();
}, 10000)<file_sep>var mongoose = require('mongoose');
var Schema = mongoose.Schema;

module.exports = function TrainSystem(stationNetwork) {
	this.stationNetwork = stationNetwork || {};

	this.locations = {
		red: [
			[-23.542323, -46.471429], // <NAME>
			[-23.542958, -46.475994],
			[-23.542397, -46.479578],
			[-23.541846, -46.482153],
			[-23.540440, -46.484449], // <NAME>
			[-23.536818, -46.486729],
			[-23.535441, -46.492930],
			[-23.533415, -46.497780],
			[-23.530484, -46.502672], // Patriarca
			[-23.528531, -46.505203],
			[-23.527370, -46.509065],
			[-23.527842, -46.512778],
			[-23.529022, -46.516382], // Guilhermina-Esperança
			[-23.530419, -46.519279],
			[-23.531324, -46.522648],
			[-23.531816, -46.526854],
			[-23.531757, -46.531167], // <NAME>
			[-23.531639, -46.533034],
			[-23.532209, -46.536596],
			[-23.533036, -46.540308],
			[-23.533606, -46.544084], // Penha
			[-23.534344, -46.547797],
			[-23.535446, -46.553247],
			[-23.536764, -46.559641],
			[-23.537551, -46.563847], // Carrão
			[-23.537924, -46.566057],
			[-23.538692, -46.569748],
			[-23.539360, -46.573031],
			[-23.540029, -46.576614], // Tatuapé
			[-23.540501, -46.578588],
			[-23.541210, -46.582300],
			[-23.542469, -46.587150],
			[-23.543078, -46.589811], // Belém
			[-23.543354, -46.593416],
			[-23.544337, -46.598244],
			[-23.545242, -46.602707],
			[-23.546324, -46.607470], // Bresser-Mooca
			[-23.546580, -46.608522],
			[-23.547052, -46.610775],
			[-23.547603, -46.613028],
			[-23.547701, -46.615410], // Brás
			[-23.548095, -46.617727],
			[-23.548724, -46.620753], 
			[-23.549373, -46.623757], 
			[-23.549786, -46.625945], // <NAME>
			[-23.549904, -46.627136], 
			[-23.550376, -46.628767],
			[-23.550907, -46.631642],
			[-23.550632, -46.633284], // Sé
			[-23.550150, -46.634990],
			[-23.549570, -46.636599],
			[-23.548803, -46.638230],
			[-23.547927, -46.639324], // Anhangabaú 
			[-23.547367, -46.640461],
			[-23.546531, -46.641534],
			[-23.545901, -46.642371],
			[-23.544347, -46.642854], // República
			[-23.543373, -46.644431],
			[-23.542252, -46.646223],
			[-23.540856, -46.647897],
			[-23.539646, -46.648927], // Santa Cecília 
			[-23.538210, -46.650665],
			[-23.536636, -46.652617],
			[-23.534983, -46.654398],
			[-23.533764, -46.655986], // <NAME>
			[-23.532052, -46.658518],
			[-23.529691, -46.661200],
			[-23.527704, -46.663518],
			[-23.525756, -46.665792]  // <NAME>
		],
		yellow: [
			[-23.538135, -46.634334], // Luz
			[-23.539827, -46.636480],
			[-23.541165, -46.638154], 
			[-23.543093, -46.640729],
			[-23.544347, -46.642854], // República
			[-23.547106, -46.646823],
			[-23.549820, -46.653131],
			[-23.552574, -46.658496],
			[-23.555016, -46.662197], // Paulista 
			[-23.557927, -46.668248],
			[-23.561978, -46.674771],
			[-23.564575, -46.680050],
			[-23.566070, -46.684427], // <NAME>
			[-23.566502, -46.685929], 
			[-23.566896, -46.687431],
			[-23.567525, -46.689663],
			[-23.567564, -46.692753], // <NAME>
			[-23.567289, -46.695457],
			[-23.567171, -46.697817], 
			[-23.566896, -46.700134],
			[-23.566512, -46.703090], // Pinheiros
			[-23.567495, -46.704506],
			[-23.568676, -46.705965],
			[-23.570092, -46.707253],
			[-23.571508, -46.709012]  // Butantã
		]
	}

	/**
	 * Gets the coordinate of the next location the train is
	 * to move to.
	 */
	this.getNextLocationForTrain = function(train) {
		var indexOfLocation = this.locationIndexForTrain(train);

		/*
		 * Now we need to take care regarding the following:
		 *
		 * 1) If the train is at neither the first location
		 * nor the last, we can just learn its direction and
		 * return indexOfLocation + 1 or indexOfLocation - 1.
		 *
		 * 2) If the train is at the first position and:
		 *		a) is heading forward, we'll retrieve the
		 * 		   location at the second position. 
		 *
		 *		b) is moving backwards, we'll also retrieve
		 * 		   the location at the second position, BUT we'll
		 * 		   change the direction to "forward".
		 *
		 * 3) If the train is at the last location and:
		 *		a) is moving backwards, we'll just retrieve the 
		 *		   location before the last one.
		 *		
		 *		b) is moving forward, we'll retrieve the location
		 *		   before the last one and we'll change the train's 
		 *		   direction to "backwards".
		 */

		// 1)
		if (indexOfLocation > 0 &&
			indexOfLocation < this.locations[train.line].length - 1) {
			
			var nextLatitude = 0;
			var nextLongitude = 0;

			if (train.direction === 'forward') {
				nextLatitude = this.locations[train.line][indexOfLocation + 1][0];
				nextLongitude = this.locations[train.line][indexOfLocation + 1][1];
			} else {
				nextLatitude = this.locations[train.line][indexOfLocation - 1][0];
				nextLongitude = this.locations[train.line][indexOfLocation - 1][1];
			}

			return {
				location: {
					latitude: nextLatitude,
					longitude: nextLongitude
				},
				direction: train.direction
			};
		} else if (indexOfLocation === 0) { // 2)
			var nextLatitude = this.locations[train.line][indexOfLocation + 1][0];
			var nextLongitude = this.locations[train.line][indexOfLocation + 1][1];
			var nextDirection = 'forward';

			return {
				location: {
					latitude: nextLatitude,
					longitude: nextLongitude
				},
				direction: nextDirection
			};
		} else if (indexOfLocation === this.locations[train.line].length - 1) { // 3)
			var nextLatitude = this.locations[train.line][indexOfLocation - 1][0];
			var nextLongitude = this.locations[train.line][indexOfLocation - 1][1];
			var nextDirection = 'backwards';

			return {
				location: {
					latitude: nextLatitude,
					longitude: nextLongitude
				},
				direction: nextDirection
			};
		}

		throw new Error('The train is at an invalid location');
	}

	/**
	 * Gets the closest train to the given "path" (origin and destination)
	 */
	this.getClosestTrainTo = function(origin, destination, callback) {
		// Saving a reference to this instance so we can access it
		// from within callbacks
		self = this;

		this.connection = mongoose.createConnection('mongodb://localhost:27017/appmetro');

		this.connection.once('open', function() {
			self.Train = self.connection.model('Train', new Schema({
				_id: Number,
				location: Schema.Types.Mixed
			}));

			/*
			 * First, we need to know the direction of the train.
			 * For instance: if origin is Carrão and Destination is Sé,
			 * the train should be moving forward. Otherwise, if
			 * origin is Sé and destination is CarrãoM, the train should
			 * be moving backwards.
			 * In order to know the direction, we'll use the Station Network
			 * class.
			 */
			trainDirection = self.stationNetwork.getDirectionForClosestTrain(origin, destination);

			/*
			 * Then, we need to determine which line the closest train should be
			 * on.
			 */
			lineForClosestTrain = self.stationNetwork.getStartLineForPath(origin, destination);

			self.Train
				.find({direction: trainDirection, line: lineForClosestTrain})
				.exec(function(err, docs) {

					/*
					 * In a while, we'll need to know the origin's location
					 * and line in order to determine the closest train.
					 * The station variable below will look like the following:
					 * {
					 *		location: {
					 *			latitude: -23.345231,
					 *			longitude: -46.123345
					 *      },
					 *		line: 'red'
					 * }
					 */
					var station = self.stationNetwork.getStationWithStationId(origin);
					var locationIndexForStation = self.locationIndexForStation({
						location: {
							latitude: station.location.latitude,
							longitude: station.location.longitude
						},
						line: lineForClosestTrain
					});

					/*
					 * The algorithm below will perform the following steps:
					 *
					 * 1 - It iterate through the docs array, and for each
					 *     train, it will: Get the index (in this.locations[line]) of the train's location
					 *	   and will store in another array (that relates the index value
					 *     with the train).
					 *
					 * 2 - Then, it'll sort the resulting array of step one.
					 *
					 * 3 - After having the array sorted, it'll get the train
					 *     that has an index value which is greater than
					 *	   the origin station index value and, aat the same time
					 *	   is the lowest index value of the array.
					 */

					var trains = [];
					for (var i = 0; i < docs.length; i++) {
						// Apparently, docs[i] is NOT a javascript
						// object. In order to turn it into an object
						// we need to call the toObject() method.
						var train = docs[i].toObject();

						var indexOfLocation = self.locationIndexForTrain(train);

						trains.push({index: indexOfLocation, train: train});
					}		   

					// Now we sort the trains array by the index key
					// of each object in it.
					trains.sort(function(elem1, elem2) {
						return elem1.index - elem2.index;
					});

					/* In order to find out the closest train, here's
					 * how the algorithm will work:
					 *
					 * 1 - If the origin station is the first one, the closest
					 *     train will be the one that has the lowest index in the
					 *     trains array
					 *
					 * 2 - If the origin station is the last one, the closest
					 * 	   train will be the one that has the highest index in
					 *	   the trains array.
					 *
					 * 3 - If the origin station is neither the first station
					 *	   nor the last one and:
					 *		
					 *		a) the requested train should be going forward,
					 *		   the chosen train will be the one with index greater
					 *		   than the others but less than the origin's index.
					 *	    
					 *      b) the requested train should be going backwards,
					 *	       the chosen train will be the one with lowest index
					 *		   but greater than the origin's index.
					 */

					var chosenTrain = {};

					if (locationIndexForStation === 0) {
						chosenTrain = trains[0].train;
					} else if (locationIndexForStation === (self.locations[lineForClosestTrain].length - 1)) {
						chosenTrain = trains[trains.length - 1].train;
					}

					if (trainDirection === 'forward') {
						var i = 0;

						// The following loop gets the train with highest index but
						// an index lower than the origin's index
						for (; i < trains.length && (trains[i].index <= locationIndexForStation); i++);

						/*
						 * If i is equal to 0, it means there is no train to is
						 * moving towards the origin station.
						 */
						if (i === 0)
							chosenTrain = {};
						else
							chosenTrain = trains[i-1].train;
					} else if (trainDirection === 'backwards') {
						var i = trains.length - 1;

						// The following loop gets the train with lowest index but
						// an index greater than the origin's index
						for (; i > -1 && (trains[i].index >= locationIndexForStation); i--);

						/*
						 * If i is equal to trains.length - 1, it means there is no train to is
						 * moving towards the origin station.
						 */
						if (i === (trains.length - 1)) 
							chosenTrain = {};
						else
							chosenTrain = trains[i+1].train;
					}

					self.connection.close();
					callback(chosenTrain);
				});
		});
	}

	/*
	 * Calculates the distance between the given train and the given
	 * station. The distance is in meters.
	 */
	this.distanceBetweenTrainAndStation = function(train, stationId) {
		var station = this.stationNetwork.getStationWithStationId(stationId).toObject();

		/*
		 * Before we move on, we need to find out which line
		 * we'll use to get the distance from the train and the station.
		 * Recall that a station can have multiple lines, which means that
		 * we need to pick one. The easiest way is to take the train's line
		 * and get the index of this line in the lines property of station.
		 */
		var lineIndex = station.lines.indexOf(train.line);
		var line = station.lines[lineIndex];

		/*
		 * Now that we know the line, we need to remove the property
		 * lines from station and substitute it for the variable line.
		 */
		delete station["lines"];
		station.line = line;

		var trainIndex = this.locationIndexForTrain(train);
		var stationIndex = this.locationIndexForStation(station);

		var totalDistance = 0;

		for (var i = trainIndex; i < stationIndex; i++) {
			var lat1 = this.locations[station.line][i][0];
			var long1 = this.locations[station.line][i][1];
			var lat2 = station.location.latitude;
			var long2 = station.location.longitude;

			totalDistance += this.distanceInMetersBetweenLocations(lat1, long1, lat2, long2);
		}

		return totalDistance;
	}

	this.distanceInMetersBetweenLocations = function(latitude1, longitude1, latitude2, longitude2) {
		var lat1 = latitude1 * ((Math.PI)/180);
		var long1 = longitude1 * ((Math.PI)/180);
		var lat2 = latitude2 * ((Math.PI)/180);
		var long2 = longitude2 * ((Math.PI)/180);
		var deltaPhi = lat2 - lat1;
		var deltaLambda = long2 - long1;

		var R = 6371000; // Earth's radius in km
		var a = Math.sin(deltaPhi/2.0) * Math.sin(deltaPhi/2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLambda/2.0) * Math.sin(deltaLambda/2.0);
		var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
		var d = R * c;

		return d;
	}

	/**
	 * Gets the index of the locations array that matches
	 * its latitude and logitude with the given train's
	 * latitude and longitude.
	 */
	this.locationIndexForTrain = function(train) {
		var obj = {
			location: {
				latitude: train.location.latitude,
				longitude: train.location.longitude
			},
			line: train.line
		};

		return this.getLocationIndex(obj);
	}

	this.locationIndexForStation = function(station) {
		var obj = {
			location: {
				latitude: station.location.latitude,
				longitude: station.location.longitude
			},
			line: station.line
		};

		return this.getLocationIndex(obj);
	}

	this.getLocationIndex = function(obj) {
		var indexOfLocation = -1;

		this.locations[obj.line].some(function(element, index, array) {
			if ((element[0] == obj.location.latitude) && (element[1] == obj.location.longitude)) 
				indexOfLocation = index;

			return ((element[0] == obj.latitude) && 
					(element[1] == obj.longitude));
		});

		return indexOfLocation;
	}
}	<file_sep>module.exports = function(app) {
	var stationNetworkController = app.controllers.stationNetwork;

	app.get('/stations', stationNetworkController.getStations);
	app.get('/stations/shortest-path', stationNetworkController.shortestPath);
}<file_sep>module.exports = function(app) {
	var trainSystemController = app.controllers.trainSystem;

	app.get('/trains/closest', trainSystemController.closestTrain);
}<file_sep>var express = require('express');
var app = express();
var server = require('http').createServer(app);
var io = require('socket.io')(server);
var MongoOplog = require('mongo-oplog');
var oplog = MongoOplog('mongodb://localhost:27017/local', 'appmetro.trains').tail();
var TrainSystem = require('../lib/train-system');

global.trainId;

var locationChangeDetector = function createLocationChangeDetectorServer(options) {
	var port = options.port || 3812;
	var trainSystem = new TrainSystem(global.stationNetwork);

	server.listen(port, function() {
		console.log('Location change detector server is running on port ' + port);
	});

	io.on('connection', function(socket) {
		console.log('There is a new connection!!!');

		socket.on('trackTrain', function(trainId) {
			global.trainId = trainId;
			console.log('Tracking trainId: ' + global.trainId);
			
			oplog.on('update', function(doc) {
				if (doc.o2._id === global.trainId) {
					console.log('EMITTING EVENT TO TRAIN ID: ' + trainId);

					var latitude = doc.o['$set']['location.latitude'];
					var longitude = doc.o['$set']['location.longitude'];
					socket.emit('trainLocationUpdate', latitude, longitude);
				}
			});
		});

		socket.on('trackDistanceBetweenTrainAndStation', function(train, stationId) {
			global.trainId = train._id;
			global.stationId = stationId;
			console.log('Tracking distance between: ' + global.trainId + ' and ' + global.stationId);

			oplog.on('update', function(doc) {
				if (doc.o2._id === global.trainId) {
					var latitude = doc.o['$set']['location.latitude'];
					var longitude = doc.o['$set']['location.longitude'];	
					var updatedTrain = {
						location: {
							latitude: latitude,
							longitude: longitude
						},
						line: train.line
					}

					var distance = trainSystem.distanceBetweenTrainAndStation(updatedTrain, stationId);

					socket.emit('trainDistanceUpdate', distance);
				}
			});
		});
	});
}

module.exports = locationChangeDetector;<file_sep>var TrainSystem = require('../../lib/train-system');
var trainSystem = new TrainSystem(stationNetwork);

var closestTrain = function(req, res) {
	var origin = req.query.origin;
	var destination = req.query.destination;

	trainSystem.getClosestTrainTo(origin, destination, function(train) {
		res.status(200).set('Access-Control-Allow-Origin', 'http://localhost:4800').json(train);
	});
}

module.exports = function(app) {
	var trainSystemController = {
		closestTrain: closestTrain
	};

	return trainSystemController;
}<file_sep>var path = require('path');
var express = require('express');
var app = express();

app.use(express.static(path.join(__dirname, '../../container')));

var createContainerServer = function(options) {
	var port = options.port || 3100;

	app.listen(port, function() {
		console.log('Container website is running on port ' + port);
	});
};

module.exports = createContainerServer;<file_sep>var PriorityQueue = require('./priority-queue');

module.exports = function ShortestPath(graph) {

	/**
	 * Graph in which the shortest path algorithm will be
	 * applied.
	 */
	this.graph = graph;

	this.findShortestPathBetween = function (source, destination) {
		var nodes = new PriorityQueue();
		var distances = {};
		var	previous = {};
		var	path = [];
		var	smallest; 
		var vertexId; 
		var neighbour;
		var alt;
		var INFINITY = 1/0;

		for (vertexId in this.graph.vertices) {
			if (vertexId === source) {
				distances[vertexId] = 0;
				nodes.enqueue(0, vertexId);
			} else {
				distances[vertexId] = INFINITY;
				nodes.enqueue(INFINITY, vertexId);
			}

			previous[vertexId] = null;
		}

		while(!nodes.isEmpty()) {
			smallest = nodes.dequeue();

			if(smallest === destination) {
				path;

				while(previous[smallest]) {
					path.push(smallest);
					smallest = previous[smallest];
				}

				break;
			}

			if (!smallest || distances[smallest] === INFINITY) {
				continue;
			}

			var adj = this.graph.getAdjacencyList(smallest);
			for (var i = 0; i < adj.length; i++) {
				/**
				 * Neighbour example:
				 * {vertex: "0", weight: 1}
				 */
				var neighbour = adj[i];

				alt = distances[smallest] + neighbour.weight;

				if (alt < distances[neighbour.vertex]) {
					distances[neighbour.vertex] = alt;
					previous[neighbour.vertex] = smallest;

					nodes.enqueue(alt, neighbour.vertex);
				}
			}
		}

		return path;
	}
}<file_sep>var GraphBuilder = require('../lib/graphbuilder');
var mongoose = require('mongoose');
var Schema = mongoose.Schema;

mongoose.connect('mongodb://localhost/appmetro');
var conn = mongoose.connection;

conn.once('open', function() {
	mongoose.model('Station', {
		_id: Number, 
		name: String, 
		location: Schema.Types.Mixed,
		nextStations: [{type: Number, ref: 'Station'}]
	});

	mongoose.model('Station')
		.find({})
		.populate('nextStations')
		.exec(function(err, docs) {
			var graphBuilder = new GraphBuilder(docs, {nextStations: 'Array'});	
			var graph = graphBuilder.build();

			graph.print();
			console.log(docs);
		});
});<file_sep>var path = require('path');
var express = require('express');
var load = require('express-load');
var app = express();
var server = require('http').createServer(app);

// *************************
//     S E R V E R S
// *************************
var createLocationChangeDetectorServer = require('./servers/location-change-detector-server');
var createIonicAppServer = require('./servers/ionic-app-server');
var createContainerServer = require('./servers/container-server');
var startLocationUpdaterScript = require('./servers/location-updater-server');

var StationNetwork = require('./lib/station-network');
global.stationNetwork = new StationNetwork();

/*
 * Before we move on to set up our server, we need to make sure that
 * our station graph was built. The stationNetwork object will have to be
 * accessible throughout the app (so the graph is built just once).
 */
stationNetwork.on('stationGraphWasBuilt', function() {
	console.log('Station Graph was built!');

	load('models', {cwd: 'app'})
		.then('controllers', {cwd: 'app'})
		.then('routes', {cwd: 'app'})
		.into(app);

	// Create the location change detector server
	createLocationChangeDetectorServer({
		port: 3812
	});

	// Start train location updater script

	startLocationUpdaterScript({
		port: 3912
	});

	server.listen(3700, function() {
		console.log('Main server is running on port ' + 3700);
	});
});

/**
 * Calling this function will start the ionic app server, which
 * means we'll be able to access the ionic app without running
 * ionic serve.
 */
createIonicAppServer({
	port: 4800
});

createContainerServer({
	port: 3100
});<file_sep>module.exports = function Vertex(vertexId, vertexContent) {
	// ********************
	//     F I E L D S
	// ********************

	/**
	 * String or Number that uniquely identifies
	 * this vertex in a Graph.
	 */
	this.vertexId = vertexId;

	/**
	 * Content of the vertex (which could be an object, an array, etc).
	 */
	this.content = vertexContent;
}<file_sep>var Vertex = require('./vertex');
var Graph = require('./graph');

/**
 * This class builds a Graph which is a representation of
 * the collection passed.
 */
module.exports = function GraphBuilder(docs, edgeIds) {
	this.docs = docs;
	this.edgeIds = edgeIds;

	this.build = function() {
		var graph = new Graph();

		for (var i = 0; i < this.docs.length; i++) {
			/**
			 * If the _id field of the document is a number,
			 * we should transform it into a String.
			 */
			var vertexId = (!isNaN(this.docs[i]._id)) 
								? (this.docs[i]._id.toString()) 
								: (this.docs[i]._id);

			var sourceVertex = new Vertex(vertexId, this.docs[i]);

			/**
			 * The connections between vertices in the resulting
			 * Graph will be defined by the keys in the this.edgeIds
			 * array. The array looks like the following:
			 * {
			 *		key1: 'Array',
			 *		key2: 'Object',
			 *		...
			 * }
			 *
			 * This means that in the this.docs there is a field
			 * called "key1" which should be used to connect vertices
			 * and that this field is an array. Besides, there's a "key2"
			 * field in the docs which represents an object (one-to-one relationship)
			 */
			for (edgeId in this.edgeIds) {
				if (this.edgeIds[edgeId] === 'Array' || this.edgeIds[edgeId] === 'array') {
					for (var j = 0; j < this.docs[i][edgeId].length; j++) {
						var vertexId = (!isNaN(this.docs[i][edgeId][j].station._id)) 
								? (this.docs[i][edgeId][j].station._id.toString()) 
								: (this.docs[i][edgeId][j].station._id);

						var adjacentVertex = new Vertex(vertexId, this.docs[i][edgeId][j].station);
						
						graph.addEdge(sourceVertex, adjacentVertex, this.docs[i][edgeId][j].weight);
					}
				} else if (this.edgeIds[edgeId] === 'Object' || this.edgeIds[edgeId] === 'object') {
					var vertexId = (!isNaN(this.docs[i][edgeId]._id))
										? (this.docs[i][edgeId]._id.toString())
										: (this.docs[i][edgeId]._id);
					var adjacentVertex = new Vertex(vertexId, this.docs[i][edgeId]);

					graph.addEdge(sourceVertex, adjacentVertex, 1);
				} else {
					throw new Error("The Edge ID " + edgeId + " (" + (typeof edgeId) + ") should be either an Array or an Object");
				}
			}
		}

		return graph;
	}
}<file_sep>var Vertex = require('../lib/vertex');
var Graph = require('../lib/graph');
var ShortestPath = require('../lib/shortest-path');
var graph = new Graph();

var corinthiansItaquera = new Vertex('corinthiansItaquera', {
	name: '<NAME>',
	location: {
		latitude: 23.456,
		longitude: 46.1234
	}
});

var se = new Vertex('se', {
	name: 'Sé',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var belem = new Vertex('belem', {
	name: 'belem',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var bras = new Vertex('bras', {
	name: 'bras',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var luz = new Vertex('luz', {
	name: 'luz',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var carrao = new Vertex('carrao', {
	name: 'Carrão',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var tatuape = new Vertex('tatuape', {
	name: 'Tatuapé',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

var paraiso = new Vertex('paraiso', {
	name: 'Paraiso',
	location: {
		latitude: 22.456,
		longitude: 42.1234
	}
});

graph.addEdge(corinthiansItaquera, belem, 15);
graph.addEdge(corinthiansItaquera, se, 20);
graph.addEdge(belem, se, 4);
graph.addEdge(se, bras, 5);
graph.addEdge(bras, luz, 10);
graph.addEdge(bras, carrao, 9);
graph.addEdge(luz, tatuape, 20);
graph.addEdge(carrao, tatuape, 22);
graph.addEdge(tatuape, paraiso, 30);

setTimeout(function() {
	var dijkstra = new ShortestPath(graph);
	var path = dijkstra.findShortestPathBetween(corinthiansItaquera.vertexId, paraiso.vertexId);
	path.push(corinthiansItaquera.vertexId);
	path.reverse();
	console.log(path);
}, 0);<file_sep>var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var TrainSystem = require('./train-system');

module.exports = function TrainLocationUpdater(delay) {
	this.delay = delay || 3000;
	this.trainSystem = new TrainSystem();

	this.start = function() {
		var self = this;

		this.connection = mongoose.createConnection('mongodb://localhost:27017/appmetro');

		this.connection.once('open', function() {
			self.Train = self.connection.model('Train', new Schema({
				_id: Number,
				location: Schema.Types.Mixed
			}));

			function updateTrainsLocation() {
				self.Train
					.find({})
					.exec(function(err, docs) {
						var bulk = self.Train.collection.initializeUnorderedBulkOp();

						for (var i = 0; i < docs.length; i++) {
							var train = docs[i].toObject();

							/*
							 * result will be like:
							 *
							 * {
							 *  	location: {
							 *			latitude: <NEW_LATITUDE>,
							 *			longitude: <NEW_LONGITUDE>
							 *		},
							 *		direction: <NEW_DIRECTION>
							 * }
							 */
							var result = self.trainSystem.getNextLocationForTrain(train);

							// if (train._id === 23) {
							// 	console.log("Train ID: " + train._id);
							// 	console.log("New Location: (" + result.location.latitude + ", " + result.location.longitude + ")");
							// 	console.log("New Direction: " + result.direction);
							// 	console.log();
							// 	console.log();
							// }

							var findQuery = {_id: train._id};
							var updateQuery = {
								$set: {
									"location.latitude": result.location.latitude, 
									"location.longitude": result.location.longitude,
									"direction": result.direction
								}
							};
							
							bulk.find(findQuery).update(updateQuery);
						}

						bulk.execute(function() {

						});
					});

			}

			setInterval(function() {
				updateTrainsLocation();
			}, self.delay);
		});
	}
}<file_sep>var TrainLocationUpdater = require('../lib/train-location-updater');


setTimeout(function() {
	var trainLocationUpdater = new TrainLocationUpdater();
	trainLocationUpdater.start();
}, 15000);<file_sep>var mongoose = require('mongoose');
var Schema = mongoose.Schema;

var trainSchema = new Schema({
	_id: Number,
	location: Schema.Types.Mixed
});

var Train = mongoose.model('Train', trainSchema);

mongoose.connect('mongodb://localhost:27017/appmetro');

mongoose.connection.once('open', function() {
	function updateTrainsLocation() {
		Train
			.find({})
			.exec(function(err, docs) {
				var bulk = Train.collection.initializeUnorderedBulkOp();

				for (var i = 0; i < docs.length; i++) {
					var train = docs[i];

					var latitude = train.location.latitude + 1;
					var longitude = train.location.longitude + 1;
					var findQuery = {_id: train._id};
					var updateQuery = {$set: {"location.latitude": latitude, "location.longitude": longitude}};
					
					bulk.find(findQuery).update(updateQuery);
				}

				bulk.execute(function() {
					console.log('Finished!');
				});
			});

	}

	setInterval(function() {
		updateTrainsLocation();
	}, 5000);
});<file_sep>var path = require('path');
var express = require('express');
var app = express();

app.use(express.static(path.join(__dirname, '../../client/www')));

var createIonicAppServer = function(options) {
	var port = options.port || 4800;

	app.listen(port, function() {
		console.log('Ionic app server is running on port ' + port);
	});
};

module.exports = createIonicAppServer;<file_sep>var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var GraphBuilder = require('./graphbuilder');
var ShortestPath = require('./shortest-path');
var DepthFirstSearch = require('./dfs');
var EventEmitter = require('events').EventEmitter;
var util = require('util');

var StationNetwork = function() {

	/**
	 * The depth first search algorithm requires
	 * a source at which to start looking for a vertex.
	 * Since Sé station is pretty much in the center of
	 * the station network, we'll use it as source.
	 *
	 * NOTE: If Sé's ID ever change in the database,
	 * plase, change it here as well.
	 */
	this.sourceId = "1200";

	this.FORWARD = 'forward';
	this.BACKWARDS = 'backwards';

	/**
	 * This function grabs the station collection from
	 * our database and build the graph that this collection
	 * represents.
	 */
	this.initialize = function() {
		// Inside mongoose.connection.once, we lose the reference
		// to the StationNetwork instance. Inside once(), 
		// this refers to the mongoose.connection context.
		// Since we need to attach the variable Station to 
		// a StationNetwork instace, we need to store "this"
		// in a variable.
		var self = this;

		/*
		 * Database connection for this object.
		 */
		this.connection = mongoose.createConnection('mongodb://localhost:27017/appmetro');

		this.connection.once('open', function() {
			var nextStationSchema = new Schema({
				station: {type: Number, ref: 'Station'},
				weight: Number
			});

			var stationSchema = new Schema({
				_id: Number, 
				name: String, 
				location: Schema.Types.Mixed,
				nextStations: [nextStationSchema]
			});

			self.Station = self.connection.model('Station', stationSchema);
			self.Station
				.find({})
				.populate('nextStations.station')
				.exec(function(err, docs) {
					for (var i = 0; i < docs.length; i++) {
						docs[i] = docs[i]._doc;

						for (var j = 0; j < docs[i].nextStations.length; j++) {
							docs[i].nextStations[j] = docs[i].nextStations[j]._doc
						}
					}

					var graphBuilder = new GraphBuilder(docs, {nextStations: 'Array'});

					self.graph = graphBuilder.build();
					// self.graph.print();

					// Let the others know that the Graph
					// has already been built.
					self.emit('stationGraphWasBuilt');
				});
		});
	}

	this.shortestPathBetween = function(origin, destination) {
		var shortestPath = new ShortestPath(this.graph);
		var path = shortestPath.findShortestPathBetween(origin, destination);
		path.push(origin);
		path.reverse();

		return path;
	}

	this.getDirectionForClosestTrain = function(origin, destination) {
		if (origin === destination) throw new Error("Origin and destination cannot be the same station!");

		/*
		 * If the origin is the first or the last station on a line
		 * the train direction is not so obvious.
		 * So firstly, we'll determine whether or not the origin is
		 * the first or the last station on a a line.
		 *
		 * In order to do that, we'll need the origin's neighbours.
		 */
		var adj = this.graph.getAdjacencyList(origin);

		/*
		 * The neighbours array is not just the origin's neighbour ID (like, 60, 70 etc).
		 * It looks like the following:
		 * [{vertex: "60", weight: 1}, {vertex: "70", weight: 1}]
		 * So we first need to process this array and assemble a new array
		 * with only vertex IDs.
		 */
		var neighbours = [];
		for (var i = 0; i < adj.length; i++) {
			neighbours[i] = parseInt(adj[i].vertex);
		}

		/*
		 * Now, in order to know whether the origin is the first or last station
		 * this is how the following algorithm will work:
		 * 
		 * 1 - It'll add the origin to the neighbours array
		 * 2 - It'll sort the neighbours array
		 * 3 - It'll find out the index of the origin in the sorted neighbours array.
		 * 4 - If the origin's index is 0, it means it's the first station. Else,
		 *     if the origin's index has the same value of the array's length - 1,
		 *	   it means the origin is the last station. Else, it's in the middle.
		 */
		neighbours.push(parseInt(origin));
		neighbours.sort(function(x, y) {return x - y});
		var indexOfOrigin = neighbours.indexOf(parseInt(origin));

		/*
		 * Origin will be the first station if indexOfOrigin is 0.
		 * Else, if indexOfOrigin is equal to neighbours.length - 1,
		 * it'll be the last station. Else, it's in the middle.
		 *
		 * Now, if origin is the first station, then the train's direction
		 * should be backwards (because there won't be any train that
		 * will be located off of the line).
		 * Else, if the origin is the last station, then the train's direction
		 * should be forward. 
		 */
		if (indexOfOrigin === 0) {
			return this.BACKWARDS;
		} else if (indexOfOrigin === (neighbours.length - 1)) {
			return this.FORWARD;
		}


		/*
		 * The first thing we need to do is to get the
		 * shortest path between origin and destination.
		 */
		var path = this.shortestPathBetween(origin, destination);

		/*
		 * The direction is determined by the subtraction between
		 * the second position of the path and the first position
		 * of the path.
		 * If the second position has a greater value than the first
		 * position, it means the train is going forward. Otherwise,
		 * the train is going backwards.
		 *
		 * NOTE: the "numbers" in the path array are actually strings,
		 * so we need to convert them to numbers before performing
		 * the subtraction.
		 */
		var direction = parseInt(path[1]) - parseInt(path[0]);

		return (direction > 0) ? (this.FORWARD) : (this.BACKWARDS);
	}

	/**
	 * Gets the location and line of the given station (which is
	 * passed as a string.
	 */
	this.getStationWithStationId = function(station) {
		var dfs = new DepthFirstSearch(this.graph, this.sourceId);
		var vertex = dfs.getVertexWithVertexId(station);

		return vertex.content;
	}

	/**
	 * Gets the line on which the closest train should be.
	 */
	this.getStartLineForPath = function(origin, destination) {
		/*
		 * To get the line on which the closest train should be, 
		 * the algorithm will perform the following steps:
		 *
		 * 1 - It'll get the shortest path between origin and destination.
		 * 2 - If origin has more than one line, the chosen line will be
		 * 	   the one of the first element in the shortest path that belongs
		 * 	   to just one line. For instance, if we are at Sé and wish to go to
		 *	   República, there are two possible paths:
		 *		
		 *			a) Sé, Liberdade, ..., Paraíso, ..., Consolação, República
		 *			b) Sé, Anhangabaú and República.
		 *
		 *	   Evidently, the b) path is the shortest. Sé belongs to the red and blue line
		 *	   so we ignore it. Next station we'll look at is Anhangabaú. Anhangabaú belongs
		 *	   to only the red line. So we'll return the red line. If Anhangabaú belonged
		 *     to 2 lines, we'll keep looking until we ind a station that belongs to just one
		 *     line.
		 */
		var path = this.shortestPathBetween(origin, destination);
		var line = undefined;
		var found = false;

		for (var i = 0; (i < path.length) && (!found); i++) {
			var station = this.getStationWithStationId(path[i]);

			console.log(station);

			if (station._doc.lines.length === 1) {
				line = station._doc.lines[0];
				found = !found;
			}
		} 

		if (typeof line === 'undefined') throw new Error('Something went wrong, none of the stations in the path array belonged to any line!');

		return line;
	}

	this.getStations = function(callback) {
		var self = this;

		function getStationsInDatabase() {
			self.Station
				.aggregate([
					{"$unwind": "$lines"},
					{
						"$group": {
							_id: "$lines",
							stations: {
								"$addToSet": {
									_id: "$_id",
									name: "$name",
									location: "$location",
									nextStations: "$nextStations"
								}
							}
						}
					}
				])
				.exec(function(err, docs) {
					// Each doc has an _id that holds the entire object
					// of interest. So we'll remove this _id and return
					// just the doc wrapped by it.
					for (var i = 0; i < docs.length; i++) {
						docs[i] = docs[i]._id;
					}

					callback(err, docs);
				});
		}

		// First we need to make sure we still have a connection
		if (this.connection.readyState === 1) {
			getStationsInDatabase();
		}
	}

	this.getStationModel = function() {
		var stationSchema = new Schema({
			_id: Number, 
			name: String, 
			location: Schema.Types.Mixed,
			nextStations: [{type: Number, ref: 'Station'}]
		});

		return mongoose.model('Station', stationSchema);
	}

	this.print = function() {
		this.graph.print();
	}

	this.initialize();
}

util.inherits(StationNetwork, EventEmitter);

module.exports = StationNetwork;