<commit_before>cuentas = (function ()
{
var instance;

function cuentas()
{
    Gwt.Gui.Window.call (this, "Cuentas");
    this.SetSize (512, 256);
    this.SetPosition (Gwt.Gui.WIN_POS_CENTER);
    this.SetBorderSpacing (12);

    this.EnableMenu ();
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.cabinet.in.svg", "Guardar", this.Insert.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.refresh.svg", "Actualizar", this.Update.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.delete.svg", "Eliminar", this.Delete.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.power.svg", "Salir", function(){window.cuentas.close(); window.gcontrol.open();}, Gwt.Gui.MENU_QUIT_APP);

    //this.title_label.SetWidth ();
    this.code = new Gwt.Gui.Entry ("Código");
    this.code.AddEvent (Gwt.Gui.Event.Keyboard.KeyUp, this.Select.bind(this));
    this.name = new Gwt.Gui.Entry ("Nombre");
    this.layout = new Gwt.Gui.VBox ();

    this.SetLayout (this.layout);

    this.layout.Add (this.code);
    this.layout.Add (this.name);

}

cuentas.prototype = new Gwt.Gui.Window ();
cuentas.prototype.constructor = cuentas;

cuentas.prototype._App = function ()
{
    this.code._Entry ();
    this.name._Entry ();
    this.layout._VBox ();

    this.code = null;
    this.name = null;
    this.layout = null;
}

cuentas.prototype.Select = function (Event)
{
    if(Event.keyCode === Gwt.Gui.Event.Keyboard.KeyCodes.Enter)
    {
        var Query = "SELECT \"Name\" FROM \"AccountingAccount\" WHERE \"Code\"='{0}'".replace("{0}", this.code.GetText());
        new Gwt.Core.SqlQuery (Query, this.SelectResponse.bind(this));
    }
};

cuentas.prototype.SelectResponse = function (Res)
{
    if (Res.Data.length > 0)
    {
        this.name.SetText (Res.Data[0].Name);
    }
    else
    {
        this.Reset();
    }
};

cuentas.prototype.Insert = function (Event)
{
    var Stm = "INSERT INTO \"AccountingAccount\" (\"Code\", \"Name\") VALUES ('{0}', '{1}')".replace("{0}", this.code.GetText ()).replace("{1}", this.name.GetText ());

    new Gwt.Core.SqlStatement (Stm, this.InsertResponse.bind(this));
};

cuentas.prototype.InsertResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Update = function (Event)
{
    var Stm = "UPDATE \"AccountingAccount\" SET \"Name\"='{0}' WHERE \"Code\"='{1}'".replace("{0}", this.name.GetText ()).replace("{1}", this.code.GetText ());

    new Gwt.Core.SqlStatement (Stm, this.UpdateResponse.bind(this));
};

cuentas.prototype.UpdateResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Delete = function (Event)
{
    var Stm = "DELETE FROM \"AccountingAccount\" WHERE \"Code\"='{0}'".replace("{0}", this.code.GetText ());

    new Gwt.Core.SqlStatement (Stm, this.DeleteResponse.bind(this));
};

cuentas.prototype.DeleteResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Reset = function ()
{
    this.code.SetText ("");
    this.name.SetText ("");
};

return new function ()
{
    this.open = function()
    {
        if(instance === undefined)
        {
            instance = new cuentas();
            instance.Open ();
            Gwt.Core.Contrib.SetActiveApp (window.cuentas);
        }
        else
        {
            console.log ("%app yet opened".replace("%app", instance.__proto__.constructor.name));
        }
    };

    this.close = function ()
    {
        if(instance !== undefined)
        {
            instance.Close();
            instance = undefined;
            Gwt.Core.Contrib.RemoveActiveApp ();
        }
    };
};
})();
<commit_msg>update<commit_after>cuentas = (function ()
{
var instance;

function cuentas()
{
    Gwt.Gui.Window.call (this, "Cuentas");
    this.SetSize (512, 256);
    this.SetPosition (Gwt.Gui.WIN_POS_CENTER);
    this.SetBorderSpacing (12);

    this.EnableMenu ();
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.cabinet.in.svg", "Guardar", this.Insert.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.refresh.svg", "Actualizar", this.Update.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.delete.svg", "Eliminar", this.Delete.bind(this));
    this.AddMenuItem (Gwt.Core.Contrib.Images + "appbar.power.svg", "Salir", function(){window.cuentas.close(); window.gcontrol.open();}, Gwt.Gui.MENU_QUIT_APP);

    //this.title_label.SetWidth ();
    this.code = new Gwt.Gui.Entry ("Código");
    this.code.AddEvent (Gwt.Gui.Event.Keyboard.KeyUp, this.Select.bind(this));
    this.name = new Gwt.Gui.Entry ("Nombre");
    this.layout = new Gwt.Gui.VBox ();

    this.SetLayout (this.layout);

    this.layout.Add (this.code);
    this.layout.Add (this.name);

}

cuentas.prototype = new Gwt.Gui.Window ();
cuentas.prototype.constructor = cuentas;

cuentas.prototype._App = function ()
{
    this.code._Entry ();
    this.name._Entry ();
    this.layout._VBox ();

    this.code = null;
    this.name = null;
    this.layout = null;
}

cuentas.prototype.Select = function (Event)
{
    if(Event.keyCode === Gwt.Gui.Event.Keyboard.KeyCodes.Enter)
    {
        var Query = "SELECT \"Name\" FROM \"AccountingAccount\" WHERE \"Code\"='{0}'".replace("{0}", this.code.GetText());
        new Gwt.Core.SqlQuery (Query, this.SelectResponse.bind(this));
    }
};

cuentas.prototype.SelectResponse = function (Res)
{
    if (Res.Data.length > 0)
    {
        this.name.SetText (Res.Data[0].Name);
    }
    else
    {
        this.Reset();
    }
};

cuentas.prototype.Insert = function (Event)
{
    var Stm = "INSERT INTO \"AccountingAccount\" (\"Code\", \"Name\") VALUES ('{0}', '{1}')".replace("{0}", this.code.GetText ()).replace("{1}", this.name.GetText ());

    new Gwt.Core.SqlStatement (Stm, this.InsertResponse.bind(this));
};

cuentas.prototype.InsertResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Update = function (Event)
{
    var Stm = "UPDATE \"AccountingAccount\" SET \"Name\"='{0}' WHERE \"Code\"='{1}'".replace("{0}", this.name.GetText ()).replace("{1}", this.code.GetText ());
    new Gwt.Core.SqlStatement (Stm, this.UpdateResponse.bind(this));
};

cuentas.prototype.UpdateResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Delete = function (Event)
{
    var Stm = "DELETE FROM \"AccountingAccount\" WHERE \"Code\"='{0}'".replace("{0}", this.code.GetText ());

    new Gwt.Core.SqlStatement (Stm, this.DeleteResponse.bind(this));
};

cuentas.prototype.DeleteResponse = function (Res)
{
    if (Res.Result === 1)
    {
        this.Reset ();
    }
};

cuentas.prototype.Reset = function ()
{
    this.code.SetText ("");
    this.name.SetText ("");
};

return new function ()
{
    this.open = function()
    {
        if(instance === undefined)
        {
            instance = new cuentas();
            instance.Open ();
            Gwt.Core.Contrib.SetActiveApp (window.cuentas);
        }
        else
        {
            console.log ("%app yet opened".replace("%app", instance.__proto__.constructor.name));
        }
    };

    this.close = function ()
    {
        if(instance !== undefined)
        {
            instance.Close();
            instance = undefined;
            Gwt.Core.Contrib.RemoveActiveApp ();
        }
    };
};
})();
<|endoftext|>


<commit_before>'use strict';
var _ = require('lodash')
var macros = require('../macros')
var d3 = require('d3')

// base angular stuff
var directiveMgr = require('../directiveMgr')
var BaseDirective = require('../BaseDirective')

//tree stuff
var downloadTree = require('./downloadTree')
var treeMgr = require('./treeMgr')

var WatchClassesModel = require('../watchClassesModel/watchClassesModel')

//thing that calls on download tree, treeMgr, render, popup and help
//manages the page that generates the tree graphs

function Graph() {
	BaseDirective.prototype.constructor.apply(this, arguments);

	//updated on tree callback
	// used to show Nothing Found! or not
	this.classCount = null;

	//controls the state of the spinner
	this.isLoading = false;

	this.graphWidth = window.innerWidth;
	this.graphHeight = window.innerHeight;

	this.nodeWidth = 174
	this.nodeHeight = 50;

	// main d3 force, defined in go
	this.force = null;

	var path = {};

	for (var attrName in this.$routeParams) {
		path[attrName] = decodeURIComponent(this.$routeParams[attrName])
	}

	//if given path, load graph
	if (path.classId && path.subject) {
		this.createGraph(path)
		this.$scope.focusSelector = false;
	}
	else {
		this.$scope.focusSelector = true;
	}

	this.$scope.addClass = this.addClass.bind(this)
}

Graph.$inject = ['$scope', '$routeParams', '$location', '$uibModal', '$compile']

Graph.isPage = true;
Graph.urls = ['/graph/:host/:termId/:subject?/:classId?']
Graph.fnName = 'Graph'

Graph.prototype.addClass = function (aClass) {

	var obj = aClass.getIdentifer().full.obj;

	this.$location.path('/graph/' + encodeURIComponent(obj.host) + '/' + encodeURIComponent(obj.termId) + '/' + encodeURIComponent(obj.subject) + '/' + encodeURIComponent(obj.classId))
};

Graph.prototype.overlap = function (rect1, rect2) {
	if (rect1.x < rect2.x + this.nodeWidth &&
		rect1.x + this.nodeWidth > rect2.x &&
		rect1.y < rect2.y + this.nodeHeight &&
		this.nodeHeight + rect1.y > rect2.y) {
		return true;
	}
	else {
		return false;
	}
}

Graph.prototype.collide = function (node) {
	var nx1 = node.x;
	var nx2 = node.x + this.nodeWidth;
	var ny1 = node.y;
	var ny2 = node.y + this.nodeHeight;
	return function (quad, x1, y1, x2, y2) {
		// var dy;
		if (quad.point && (quad.point !== node)) {
			if (this.overlap(node, quad.point)) {
				// dy = Math.min(node.y2() - quad.point.y, quad.point.y2() - node.y) / 4;
				// node.y -= dy;
				// quad.point.y += dy;
				var dx = Math.min(node.x + this.nodeWidth - quad.point.x, quad.point.x + this.nodeWidth - node.x) / 2;
				node.x -= dx;
				quad.point.x += dx;
			}
		}
		return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
	}.bind(this);
};

Graph.prototype.go = function (tree, callback) {
	this.isLoading = true;
	downloadTree.fetchFullTree(tree, function (err, tree) {
		this.isLoading = false;
		if (err) {
			return callback(err);
		};

		treeMgr.go(tree);

		var graph = treeMgr.treeToD3(tree)

		this.classCount = treeMgr.countClassesInTree(tree);
		if (this.classCount === 0) {
			elog('0 classes found?', tree)
		}

		this.force = d3.layout.force()
			.charge(-18000)
			.gravity(0.2)
			.linkDistance(5)
			.size([this.graphWidth, this.graphHeight])

		var svg = d3.select("#d3GraphId").append("svg")
			.attr("width", this.graphWidth)
			.attr("height", this.graphHeight)

		// can move this to the same as above? this was a separate #d3graphId selector
		d3.select("#d3GraphId").on("mousedown", function () {
			d3.event.stopPropagation();
		}.bind(this))

		var container = svg.append("g");

		var zoom = d3.behavior.zoom()
			.scaleExtent([0, 1.5])
			.on("zoom", function () {
				container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
			}.bind(this));

		svg.call(zoom)

		var dragStartedByRightButton = false;
		var nodeDrag = d3.behavior.drag()
			.on("dragstart", function (d, i) {
				if (d3.event.sourceEvent.which == 3) {
					dragStartedByRightButton = true
					return;
				}
				else {
					dragStartedByRightButton = false;
					this.force.alpha(.007)
				}
			}.bind(this))
			.on("drag", function (d, i) {
				if (dragStartedByRightButton) {
					return;
				}
				d.px += d3.event.dx
				d.py += d3.event.dy
				d.x += d3.event.dx
				d.y += d3.event.dy
				this.force.alpha(.007)
			}.bind(this))

		graph.nodes.forEach(function (node) {
			// node.x = node.cx = Math.random() * 100 + 200
			node.height = this.nodeHeight;
			node.width = this.nodeWidth
		}.bind(this))

		var link = container.selectAll(".link")
			.data(graph.links)
			.enter().append("line")
			.attr("class", "link")
			.style("stroke-width", 4);

		for (var i = 0; i < graph.links.length; i++) {
			var currLink = graph.links[i];

			// find the parent of the two nodes the line connects
			var parent;
			var child;
			if (graph.nodes[currLink.source].depth > graph.nodes[currLink.target].depth) {
				parent = graph.nodes[currLink.target];
				child = graph.nodes[currLink.source];
			}
			else {
				parent = graph.nodes[currLink.source];
				child = graph.nodes[currLink.target];
			}

			// if should be 'and', make line darker
			if (parent.prereqs.type == 'and') {
				link[0][i].style.stroke = '#5B5B5B'
			}

			// tbh all nodes should be instanceof Class
			// if (!graph.nodes[currLink.source].downwardLinks) {
			// 	graph.nodes[currLink.source].downwardLinks = []
			// }

			// if (!graph.nodes[currLink.target].downwardLinks) {
			// 	graph.nodes[currLink.target].downwardLinks = []
			// }

			// if (!graph.nodes[currLink.source].upwardLinks) {
			// 	graph.nodes[currLink.source].upwardLinks = []
			// }

			// if (!graph.nodes[currLink.target].upwardLinks) {
			// 	graph.nodes[currLink.target].upwardLinks = []
			// }

			//add line to both nodes links list
			parent.downwardLinks.push(link[0][i])
			child.upwardLinks.push(link[0][i])

			// graph.nodes[currLink.source].links.push(link[0][i])
			// graph.nodes[currLink.target].links.push(link[0][i])
		}

		var node = container.selectAll(".node")
			.data(graph.nodes)
			.enter().append("g")
			.attr("class", "node")
			.attr("width", this.nodeWidth)
			.attr("height", this.nodeHeight)
			.on("mousedown", function () {
				d3.event.stopPropagation();
			})
			.call(nodeDrag)

		var html = '

'

		node.append("foreignObject")
			.attr("width", this.nodeWidth)
			.attr("height", this.nodeHeight)
			.append("xhtml:div")

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

			// create the new scope for each node
			var newScope = this.$scope.$new();

			// set up the links between tree and scope and foreignObject
			newScope.tree = graph.nodes[i]
			graph.nodes[i].$scope = newScope
			graph.nodes[i].foreignObject = node[0][i].lastChild

			$(node[0][i].querySelector('div')).append(this.$compile(html)(newScope))
		}

		setTimeout(function () {
			this.$scope.$apply()

			var multiplyer = 1;

			this.force.nodes(graph.nodes)
				.links(graph.links)

			this.force.on("tick", function (e) {
				var q = d3.geom.quadtree(graph.nodes);
				var k = 0;
				var n = graph.nodes.length;
				while (++k < n) {
					var currNode = graph.nodes[k];

					// collision
					q.visit(this.collide(currNode));

					//possible to get the staticly set width and height here, node[0][node.index].lastChild.width.value
					currNode.y += ((currNode.depth * 200 + 50) - currNode.y) * e.alpha * multiplyer;

					// collision between children on different depths
					if (!currNode.allChildrenAtSameDepth) {
						for (var i = 0; i < currNode.prereqs.values.length; i++) {
							for (var j = i + 1; j < currNode.prereqs.values.length; j++) {
								if (currNode.prereqs.values[i].depth === currNode.prereqs.values[j].depth) {
									continue;
								}
								var diff = currNode.prereqs.values[i].x - currNode.prereqs.values[j].x;
								if (Math.abs(diff) > 100) {
									continue;
								}
								if (diff < 0) {
									currNode.prereqs.values[i].x -= (100 + diff) / 2;
									currNode.prereqs.values[j].x += (100 + diff) / 2;
								}
								else {
									currNode.prereqs.values[i].x += (100 - diff) / 2;
									currNode.prereqs.values[j].x -= (100 - diff) / 2;
								}
							}
						}
					}

				};

				link.attr("x1", function (d) {
						return d.source.x;
					}.bind(this))
					.attr("y1", function (d) {
						return d.source.y;
					}.bind(this))
					.attr("x2", function (d) {
						return d.target.x;
					}.bind(this))
					.attr("y2", function (d) {
						return d.target.y;
					}.bind(this));

				node.attr("transform", function (d) {
					return "translate(" + (d.x - d.width / 2) + "," + (d.y - d.height / 2) + ")";
				}.bind(this));

			}.bind(this))

			this.force.start();

			// Two step process:
			// make nodes find the nodes near them
			var safety = 0;
			// D3 cuts off at .005 alpha and freezes everything
			// the higher it is, the faster it loads, but it will not be done when it moves to the next step
			// You'll want to try out different, "small" values for this
			// perhaps make this higher if on slower hardware??
			while (this.force.alpha() > 0.08) {
				this.force.tick();
				if (safety++ > 500) {
					// Avoids infinite looping in case this solution was a bad idea
					break;
				}
			}

			//2. make nodes go towards their depth level
			multiplyer = 10;
			this.force.start();

			safety = 0;
			while (this.force.alpha() > 0.01) {
				this.force.tick();
				if (safety++ > 500) {
					break;
				}
			}

			this.$scope.tree = tree;

			graph.nodes.forEach(function (tree) {
				tree.height = tree.foreignObject.lastChild.offsetHeight
			}.bind(this))

			callback(null, tree)
		}.bind(this), 0)

	}.bind(this))
};

Graph.prototype.createGraph = function (tree, callback) {
	if (!callback) {
		callback = function () {}
	}

	//process tree takes in a callback
	this.go(tree, function (err, tree) {
		if (err) {
			console.log('error processing tree', err, tree);
			return callback(err);
		}

		treeMgr.logTree(tree, {
			type: 'createTree'
		})
		callback(null, tree);
	}.bind(this));
}

Graph.prototype.showClasses = function (classList, callback) {
	if (classList.length < 1) {
		console.log('error show classes was called with 0 classes!')
		return;
	};

	//this is ghetto
	//remove the prereqs from classes so we don't load all the result's prereqs
	classList.forEach(function (aClass) {

		if (aClass.prereqs) {
			aClass.prereqs.values = []
		};

	}.bind(this))

	var treeParams = {
		host: this.$routeParams.host,
		termId: this.$routeParams.termId,
		subject: this.$routeParams.subject,
		prereqs: {
			type: 'or',
			values: classList
		},
		isClass: false,
		hidden: true
	}

	this.go(treeParams, callback)
}

//search

Graph.prototype.getCollegeName = function () {
	return selectorsMgr.college.getText();
};

Graph.prototype.openWatchModel = function ($scope) {
	WatchClassesModel.open(this, $scope.tree)
};

Graph.prototype.Graph = Graph;
module.exports = Graph;
directiveMgr.addDirective(Graph)
<commit_msg>\'limit zoom out max\'<commit_after>'use strict';
var _ = require('lodash')
var macros = require('../macros')
var d3 = require('d3')

// base angular stuff
var directiveMgr = require('../directiveMgr')
var BaseDirective = require('../BaseDirective')

//tree stuff
var downloadTree = require('./downloadTree')
var treeMgr = require('./treeMgr')

var WatchClassesModel = require('../watchClassesModel/watchClassesModel')

//thing that calls on download tree, treeMgr, render, popup and help
//manages the page that generates the tree graphs

function Graph() {
	BaseDirective.prototype.constructor.apply(this, arguments);

	//updated on tree callback
	// used to show Nothing Found! or not
	this.classCount = null;

	//controls the state of the spinner
	this.isLoading = false;

	this.graphWidth = window.innerWidth;
	this.graphHeight = window.innerHeight;

	this.nodeWidth = 174
	this.nodeHeight = 50;

	// main d3 force, defined in go
	this.force = null;

	var path = {};

	for (var attrName in this.$routeParams) {
		path[attrName] = decodeURIComponent(this.$routeParams[attrName])
	}

	//if given path, load graph
	if (path.classId && path.subject) {
		this.createGraph(path)
		this.$scope.focusSelector = false;
	}
	else {
		this.$scope.focusSelector = true;
	}

	this.$scope.addClass = this.addClass.bind(this)
}

Graph.$inject = ['$scope', '$routeParams', '$location', '$uibModal', '$compile']

Graph.isPage = true;
Graph.urls = ['/graph/:host/:termId/:subject?/:classId?']
Graph.fnName = 'Graph'

Graph.prototype.addClass = function (aClass) {

	var obj = aClass.getIdentifer().full.obj;

	this.$location.path('/graph/' + encodeURIComponent(obj.host) + '/' + encodeURIComponent(obj.termId) + '/' + encodeURIComponent(obj.subject) + '/' + encodeURIComponent(obj.classId))
};

Graph.prototype.overlap = function (rect1, rect2) {
	if (rect1.x < rect2.x + this.nodeWidth &&
		rect1.x + this.nodeWidth > rect2.x &&
		rect1.y < rect2.y + this.nodeHeight &&
		this.nodeHeight + rect1.y > rect2.y) {
		return true;
	}
	else {
		return false;
	}
}

Graph.prototype.collide = function (node) {
	var nx1 = node.x;
	var nx2 = node.x + this.nodeWidth;
	var ny1 = node.y;
	var ny2 = node.y + this.nodeHeight;
	return function (quad, x1, y1, x2, y2) {
		// var dy;
		if (quad.point && (quad.point !== node)) {
			if (this.overlap(node, quad.point)) {
				// dy = Math.min(node.y2() - quad.point.y, quad.point.y2() - node.y) / 4;
				// node.y -= dy;
				// quad.point.y += dy;
				var dx = Math.min(node.x + this.nodeWidth - quad.point.x, quad.point.x + this.nodeWidth - node.x) / 2;
				node.x -= dx;
				quad.point.x += dx;
			}
		}
		return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
	}.bind(this);
};

Graph.prototype.go = function (tree, callback) {
	this.isLoading = true;
	downloadTree.fetchFullTree(tree, function (err, tree) {
		this.isLoading = false;
		if (err) {
			return callback(err);
		};

		treeMgr.go(tree);

		var graph = treeMgr.treeToD3(tree)

		this.classCount = treeMgr.countClassesInTree(tree);
		if (this.classCount === 0) {
			elog('0 classes found?', tree)
		}

		this.force = d3.layout.force()
			.charge(-18000)
			.gravity(0.2)
			.linkDistance(5)
			.size([this.graphWidth, this.graphHeight])

		var svg = d3.select("#d3GraphId").append("svg")
			.attr("width", this.graphWidth)
			.attr("height", this.graphHeight)

		// can move this to the same as above? this was a separate #d3graphId selector
		d3.select("#d3GraphId").on("mousedown", function () {
			d3.event.stopPropagation();
		}.bind(this))

		var container = svg.append("g");

		var zoom = d3.behavior.zoom()
			.scaleExtent([.1, 1.5])
			.on("zoom", function () {
				container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")");
			}.bind(this));

		svg.call(zoom)

		var dragStartedByRightButton = false;
		var nodeDrag = d3.behavior.drag()
			.on("dragstart", function (d, i) {
				if (d3.event.sourceEvent.which == 3) {
					dragStartedByRightButton = true
					return;
				}
				else {
					dragStartedByRightButton = false;
					this.force.alpha(.007)
				}
			}.bind(this))
			.on("drag", function (d, i) {
				if (dragStartedByRightButton) {
					return;
				}
				d.px += d3.event.dx
				d.py += d3.event.dy
				d.x += d3.event.dx
				d.y += d3.event.dy
				this.force.alpha(.007)
			}.bind(this))

		graph.nodes.forEach(function (node) {
			// node.x = node.cx = Math.random() * 100 + 200
			node.height = this.nodeHeight;
			node.width = this.nodeWidth
		}.bind(this))

		var link = container.selectAll(".link")
			.data(graph.links)
			.enter().append("line")
			.attr("class", "link")
			.style("stroke-width", 4);

		for (var i = 0; i < graph.links.length; i++) {
			var currLink = graph.links[i];

			// find the parent of the two nodes the line connects
			var parent;
			var child;
			if (graph.nodes[currLink.source].depth > graph.nodes[currLink.target].depth) {
				parent = graph.nodes[currLink.target];
				child = graph.nodes[currLink.source];
			}
			else {
				parent = graph.nodes[currLink.source];
				child = graph.nodes[currLink.target];
			}

			// if should be 'and', make line darker
			if (parent.prereqs.type == 'and') {
				link[0][i].style.stroke = '#5B5B5B'
			}

			// tbh all nodes should be instanceof Class
			// if (!graph.nodes[currLink.source].downwardLinks) {
			// 	graph.nodes[currLink.source].downwardLinks = []
			// }

			// if (!graph.nodes[currLink.target].downwardLinks) {
			// 	graph.nodes[currLink.target].downwardLinks = []
			// }

			// if (!graph.nodes[currLink.source].upwardLinks) {
			// 	graph.nodes[currLink.source].upwardLinks = []
			// }

			// if (!graph.nodes[currLink.target].upwardLinks) {
			// 	graph.nodes[currLink.target].upwardLinks = []
			// }

			//add line to both nodes links list
			parent.downwardLinks.push(link[0][i])
			child.upwardLinks.push(link[0][i])

			// graph.nodes[currLink.source].links.push(link[0][i])
			// graph.nodes[currLink.target].links.push(link[0][i])
		}

		var node = container.selectAll(".node")
			.data(graph.nodes)
			.enter().append("g")
			.attr("class", "node")
			.attr("width", this.nodeWidth)
			.attr("height", this.nodeHeight)
			.on("mousedown", function () {
				d3.event.stopPropagation();
			})
			.call(nodeDrag)

		var html = '

'

		node.append("foreignObject")
			.attr("width", this.nodeWidth)
			.attr("height", this.nodeHeight)
			.append("xhtml:div")

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

			// create the new scope for each node
			var newScope = this.$scope.$new();

			// set up the links between tree and scope and foreignObject
			newScope.tree = graph.nodes[i]
			graph.nodes[i].$scope = newScope
			graph.nodes[i].foreignObject = node[0][i].lastChild

			$(node[0][i].querySelector('div')).append(this.$compile(html)(newScope))
		}

		setTimeout(function () {
			this.$scope.$apply()

			var multiplyer = 1;

			this.force.nodes(graph.nodes)
				.links(graph.links)

			this.force.on("tick", function (e) {
				var q = d3.geom.quadtree(graph.nodes);
				var k = 0;
				var n = graph.nodes.length;
				while (++k < n) {
					var currNode = graph.nodes[k];

					// collision
					q.visit(this.collide(currNode));

					//possible to get the staticly set width and height here, node[0][node.index].lastChild.width.value
					currNode.y += ((currNode.depth * 200 + 50) - currNode.y) * e.alpha * multiplyer;

					// collision between children on different depths
					if (!currNode.allChildrenAtSameDepth) {
						for (var i = 0; i < currNode.prereqs.values.length; i++) {
							for (var j = i + 1; j < currNode.prereqs.values.length; j++) {
								if (currNode.prereqs.values[i].depth === currNode.prereqs.values[j].depth) {
									continue;
								}
								var diff = currNode.prereqs.values[i].x - currNode.prereqs.values[j].x;
								if (Math.abs(diff) > 100) {
									continue;
								}
								if (diff < 0) {
									currNode.prereqs.values[i].x -= (100 + diff) / 2;
									currNode.prereqs.values[j].x += (100 + diff) / 2;
								}
								else {
									currNode.prereqs.values[i].x += (100 - diff) / 2;
									currNode.prereqs.values[j].x -= (100 - diff) / 2;
								}
							}
						}
					}

				};

				link.attr("x1", function (d) {
						return d.source.x;
					}.bind(this))
					.attr("y1", function (d) {
						return d.source.y;
					}.bind(this))
					.attr("x2", function (d) {
						return d.target.x;
					}.bind(this))
					.attr("y2", function (d) {
						return d.target.y;
					}.bind(this));

				node.attr("transform", function (d) {
					return "translate(" + (d.x - d.width / 2) + "," + (d.y - d.height / 2) + ")";
				}.bind(this));

			}.bind(this))

			this.force.start();

			// Two step process:
			// make nodes find the nodes near them
			var safety = 0;
			// D3 cuts off at .005 alpha and freezes everything
			// the higher it is, the faster it loads, but it will not be done when it moves to the next step
			// You'll want to try out different, "small" values for this
			// perhaps make this higher if on slower hardware??
			while (this.force.alpha() > 0.08) {
				this.force.tick();
				if (safety++ > 500) {
					// Avoids infinite looping in case this solution was a bad idea
					break;
				}
			}

			//2. make nodes go towards their depth level
			multiplyer = 10;
			this.force.start();

			safety = 0;
			while (this.force.alpha() > 0.01) {
				this.force.tick();
				if (safety++ > 500) {
					break;
				}
			}

			this.$scope.tree = tree;

			graph.nodes.forEach(function (tree) {
				tree.height = tree.foreignObject.lastChild.offsetHeight
			}.bind(this))

			callback(null, tree)
		}.bind(this), 0)

	}.bind(this))
};

Graph.prototype.createGraph = function (tree, callback) {
	if (!callback) {
		callback = function () {}
	}

	//process tree takes in a callback
	this.go(tree, function (err, tree) {
		if (err) {
			console.log('error processing tree', err, tree);
			return callback(err);
		}

		treeMgr.logTree(tree, {
			type: 'createTree'
		})
		callback(null, tree);
	}.bind(this));
}

Graph.prototype.showClasses = function (classList, callback) {
	if (classList.length < 1) {
		console.log('error show classes was called with 0 classes!')
		return;
	};

	//this is ghetto
	//remove the prereqs from classes so we don't load all the result's prereqs
	classList.forEach(function (aClass) {

		if (aClass.prereqs) {
			aClass.prereqs.values = []
		};

	}.bind(this))

	var treeParams = {
		host: this.$routeParams.host,
		termId: this.$routeParams.termId,
		subject: this.$routeParams.subject,
		prereqs: {
			type: 'or',
			values: classList
		},
		isClass: false,
		hidden: true
	}

	this.go(treeParams, callback)
}

//search

Graph.prototype.getCollegeName = function () {
	return selectorsMgr.college.getText();
};

Graph.prototype.openWatchModel = function ($scope) {
	WatchClassesModel.open(this, $scope.tree)
};

Graph.prototype.Graph = Graph;
module.exports = Graph;
directiveMgr.addDirective(Graph)
<|endoftext|>


<commit_before>import Piece from './piece';
import { NullPiece } from './pieces/index';
import _ from 'lodash';
import * as CONST from './constants/boardTypes';

export default class Board {
  constructor(board = undefined) {
    board ? this.setBoard(board) : this.setBoard(CONST.USI_INITIAL_BOARD);
  }

  setBoard(board) {
    this.board = this.createBoard(board);
  }

  createBoard(board) {
    var _board = board.map((row, y) => {
      var yCor = this.transposeToCorY(y);
      var rows = row.map((type, x) => {
        var xCor = this.transposeToCorX(x);
        return (
          Piece.create({ type: type, x: xCor, y: yCor })
        );
      });
      return(rows);
    });

    return _board;
  }

  movePiece(fromPiece, toPiece) {
    this.checkPieceExisted(fromPiece);
    this.checkPieceExisted(toPiece);

    if (! this.enhanceMovablePoint(fromPiece).findPiece(toPiece).movable) {
      return this;
    }

    const newBoard = this.movePosition(fromPiece, toPiece);
    return newBoard;
  }

  movePosition(fromPiece, toPiece) {
    const newBoard = this.cloneBoard();

    const [toCorX, toCorY] = [toPiece.x, toPiece.y];
    const [toIdxX, toIdxY] = this.invertCor(toCorX, toCorY);
    const [fromCorX, fromCorY] = [fromPiece.x, fromPiece.y];
    const [fromIdxX, fromIdxY] = this.invertCor(fromCorX, fromCorY);

    fromPiece.x = toCorX;
    fromPiece.y = toCorY;

    newBoard.board[toIdxY][toIdxX] = fromPiece;
    newBoard.board[fromIdxY][fromIdxX] = new NullPiece({ x: fromCorX, y: fromCorY });

    return newBoard;
  }

  enhancePlaceablePoint(placePiece) {
    if (placePiece.type === 'P' || placePiece.type === 'p') {
      var pawnXcors = this.IndexXOfPiece(placePiece);
    }

    this.board.forEach((rows, y) => {
      rows.forEach((piece, x) => {
        var moveDef = placePiece.moveDef();

        if (placePiece.type === 'P') {
          // NOTE: Does not move, if placed a piece in this point.
          if (y + moveDef.just[0][1] < 0) { return; }

          // NOTE: NIFU
          if (_.includes(pawnXcors, x)) { return; }
        }

        if (placePiece.type === 'p') {
          // NOTE: Does not move, if placed a piece in this point.
          if (y + moveDef.just[0][1] > 8) { return; }
          if (_.includes(pawnXcors, x)) { return; }
        }

        if (placePiece.type === 'L') {
          if (y + moveDef.fly[0][1] < 0) { return; }
        }

        if (placePiece.type === 'l') {
          if (y + moveDef.fly[0][1] > 8) { return; }
        }

        if (placePiece.type === 'N') {
          if (y + moveDef.just[0][1] < 0) { return; }
        }

        if (placePiece.type === 'n') {
          if (y + moveDef.just[0][1] > 8) { return; }
        }

        if (piece.type == '*') { piece.isPlaced = true; }
      });
    });
  }

  IndexXOfPiece(searchPiece) {
    var pieces = this.board.map((rows) => {
      return rows.map((piece, x) => {
        return piece.type === searchPiece.type ? x : undefined;
      });
    });

    return _.chain(pieces).flattenDeep().compact().uniq().value();
  }

  enhanceMovablePoint(piece) {
    this.checkPieceExisted(piece);

    var moveDef = piece.moveDef();
    var newBoard = this.cloneBoard();

    if (typeof moveDef === 'undefined') {
      return this;
    }

    // if moveDef has just property, piece moves just coordinates on board.
    //
    if (moveDef.just) {
      newBoard.movablePointsByJust(piece);
    }

    // if moveDef has fly property, piece moves recursion on board.
    //
    if (moveDef.fly) {
      newBoard.movablePointsByFly(piece);
    }

    return newBoard;
  }

  // if piece of argument is match in the board, return true, else return false
  //
  matchPiece(piece) {
    var isUndefined = typeof this.findPiece(piece) === 'undefined';
    var isEqualPiece = this.findPiece(piece).equals(
      Piece.create({
        x: piece.x,
        y: piece.y,
        type: piece.type,
        movable: piece.movable
      })
    );

    return (isUndefined || isEqualPiece);
  }

  checkPieceExisted(piece) {
    if (this.matchPiece(piece)) {
      return true;
    } else {
      const message = `type = ${piece.type}, xCor = ${piece.x}, yCor = ${piece.y}`;
      throw new Error(`Does not match coordinates in board. ${message}`);
    }
  }

  // if moveDef has just property, piece moves just coordinates on board.
  //
  movablePointsByJust(piece) {
    var [xCor, yCor] = [piece.x, piece.y];
    var moveDef = piece.moveDef();
    var [x, y] = this.invertCor(xCor, yCor);

    moveDef.just.forEach((def) => {
      var [defX, defY] = def;
      var fetchPiece = this.fetchPiece(x + defX, y + defY);

      if (fetchPiece && !piece.isOwnTeam(fetchPiece)) {
        fetchPiece.movable = true;
      }
    });
  }

  movablePointsByFly(piece) {
    var [xCor, yCor] = [piece.x, piece.y];
    var moveDef = piece.moveDef();
    var [x, y] = this.invertCor(xCor, yCor);

    moveDef.fly.forEach((def) => {
      var [defX, defY] = def;
      var dx, dy;

      dx = x + defX;
      dy = y + defY;

      var fetchPiece = this.fetchPiece(dx, dy);

      while (fetchPiece) {
        if (fetchPiece.type === '*') {
          fetchPiece.movable = true;
        } else if (piece.isOwnTeam(fetchPiece)) {
          break;
        } else {
          fetchPiece.movable = true;
          break;
        }

        dx = dx + defX;
        dy = dy + defY;

        fetchPiece = this.fetchPiece(dx, dy);
      }
    });
  }

  cloneBoard() {
    const dupBoard = _.cloneDeep(this.board);
    const newBoard = new Board;
    newBoard.board = dupBoard;
    return newBoard;
  }

  transposeToCorX(xIndex) {
    return 10 - xIndex - 1;
  }

  transposeToCorY(yIndex) {
    return yIndex + 1;
  }

  invertToIndexX(xCor) {
    return 9 - xCor;
  }

  invertToIndexY(yCor) {
    return yCor - 1;
  }

  invertCor(xCor, yCor) {
    return [this.invertToIndexX(xCor), this.invertToIndexY(yCor)];
  }

  fetchPiece(xIndex, yIndex) {
    var row = this.board[yIndex];
    return row ? row[xIndex] : undefined;
  }

  findPiece(piece) {
    var [toCorX, toCorY] = [piece.x, piece.y];
    var [toIdxX, toIdxY] = this.invertCor(toCorX, toCorY);
    return this.fetchPiece(toIdxX, toIdxY);
  }

  toArray() {
    return this.board.map((row) => {
      return row.map((piece) => {
        return piece.type;
      });
    });
  }
};
<commit_msg>Refactor for optimize object creation.<commit_after>import Piece from './piece';
import { NullPiece } from './pieces/index';
import _ from 'lodash';
import * as CONST from './constants/boardTypes';

export default class Board {
  constructor(board = undefined) {
    board ? this.setBoard(board) : this.setBoard(CONST.USI_INITIAL_BOARD);
  }

  setBoard(board) {
    this.board = this.createBoard(board);
  }

  createBoard(board) {
    var _board = board.map((row, y) => {
      var yCor = this.transposeToCorY(y);
      var rows = row.map((type, x) => {
        var xCor = this.transposeToCorX(x);
        return (
          Piece.create({ type: type, x: xCor, y: yCor })
        );
      });
      return(rows);
    });

    return _board;
  }

  movePiece(fromPiece, toPiece) {
    this.checkPieceExisted(fromPiece);
    this.checkPieceExisted(toPiece);

    if (! this.enhanceMovablePoint(fromPiece).findPiece(toPiece).movable) {
      return this;
    }

    const newBoard = this.movePosition(fromPiece, toPiece);
    return newBoard;
  }

  movePosition(fromPiece, toPiece) {
    const newBoard = this.cloneBoard();

    const [toCorX, toCorY] = [toPiece.x, toPiece.y];
    const [toIdxX, toIdxY] = this.invertCor(toCorX, toCorY);
    const [fromCorX, fromCorY] = [fromPiece.x, fromPiece.y];
    const [fromIdxX, fromIdxY] = this.invertCor(fromCorX, fromCorY);

    fromPiece.x = toCorX;
    fromPiece.y = toCorY;

    newBoard.board[toIdxY][toIdxX] = fromPiece;
    newBoard.board[fromIdxY][fromIdxX] = new NullPiece({ x: fromCorX, y: fromCorY });

    return newBoard;
  }

  enhancePlaceablePoint(placePiece) {
    if (placePiece.type === 'P' || placePiece.type === 'p') {
      var pawnXcors = this.IndexXOfPiece(placePiece);
    }

    this.board.forEach((rows, y) => {
      rows.forEach((piece, x) => {
        var moveDef = placePiece.moveDef();

        if (placePiece.type === 'P') {
          // NOTE: Does not move, if placed a piece in this point.
          if (y + moveDef.just[0][1] < 0) { return; }

          // NOTE: NIFU
          if (_.includes(pawnXcors, x)) { return; }
        }

        if (placePiece.type === 'p') {
          // NOTE: Does not move, if placed a piece in this point.
          if (y + moveDef.just[0][1] > 8) { return; }
          if (_.includes(pawnXcors, x)) { return; }
        }

        if (placePiece.type === 'L') {
          if (y + moveDef.fly[0][1] < 0) { return; }
        }

        if (placePiece.type === 'l') {
          if (y + moveDef.fly[0][1] > 8) { return; }
        }

        if (placePiece.type === 'N') {
          if (y + moveDef.just[0][1] < 0) { return; }
        }

        if (placePiece.type === 'n') {
          if (y + moveDef.just[0][1] > 8) { return; }
        }

        if (piece.type == '*') { piece.isPlaced = true; }
      });
    });
  }

  IndexXOfPiece(searchPiece) {
    var pieces = this.board.map((rows) => {
      return rows.map((piece, x) => {
        return piece.type === searchPiece.type ? x : undefined;
      });
    });

    return _.chain(pieces).flattenDeep().compact().uniq().value();
  }

  enhanceMovablePoint(piece) {
    this.checkPieceExisted(piece);
    var moveDef = piece.moveDef();

    if (typeof moveDef === 'undefined') {
      return this;
    }

    var newBoard = this.cloneBoard();

    // if moveDef has just property, piece moves just coordinates on board.
    //
    if (moveDef.just) {
      newBoard.movablePointsByJust(piece);
    }

    // if moveDef has fly property, piece moves recursion on board.
    //
    if (moveDef.fly) {
      newBoard.movablePointsByFly(piece);
    }

    return newBoard;
  }

  // if piece of argument is match in the board, return true, else return false
  //
  matchPiece(piece) {
    var isUndefined = typeof this.findPiece(piece) === 'undefined';
    var isEqualPiece = this.findPiece(piece).equals(
      Piece.create({
        x: piece.x,
        y: piece.y,
        type: piece.type,
        movable: piece.movable
      })
    );

    return (isUndefined || isEqualPiece);
  }

  checkPieceExisted(piece) {
    if (this.matchPiece(piece)) {
      return true;
    } else {
      const message = `type = ${piece.type}, xCor = ${piece.x}, yCor = ${piece.y}`;
      throw new Error(`Does not match coordinates in board. ${message}`);
    }
  }

  // if moveDef has just property, piece moves just coordinates on board.
  //
  movablePointsByJust(piece) {
    var [xCor, yCor] = [piece.x, piece.y];
    var moveDef = piece.moveDef();
    var [x, y] = this.invertCor(xCor, yCor);

    moveDef.just.forEach((def) => {
      var [defX, defY] = def;
      var fetchPiece = this.fetchPiece(x + defX, y + defY);

      if (fetchPiece && !piece.isOwnTeam(fetchPiece)) {
        fetchPiece.movable = true;
      }
    });
  }

  movablePointsByFly(piece) {
    var [xCor, yCor] = [piece.x, piece.y];
    var moveDef = piece.moveDef();
    var [x, y] = this.invertCor(xCor, yCor);

    moveDef.fly.forEach((def) => {
      var [defX, defY] = def;
      var dx, dy;

      dx = x + defX;
      dy = y + defY;

      var fetchPiece = this.fetchPiece(dx, dy);

      while (fetchPiece) {
        if (fetchPiece.type === '*') {
          fetchPiece.movable = true;
        } else if (piece.isOwnTeam(fetchPiece)) {
          break;
        } else {
          fetchPiece.movable = true;
          break;
        }

        dx = dx + defX;
        dy = dy + defY;

        fetchPiece = this.fetchPiece(dx, dy);
      }
    });
  }

  cloneBoard() {
    const dupBoard = _.cloneDeep(this.board);
    const newBoard = new Board;
    newBoard.board = dupBoard;
    return newBoard;
  }

  transposeToCorX(xIndex) {
    return 10 - xIndex - 1;
  }

  transposeToCorY(yIndex) {
    return yIndex + 1;
  }

  invertToIndexX(xCor) {
    return 9 - xCor;
  }

  invertToIndexY(yCor) {
    return yCor - 1;
  }

  invertCor(xCor, yCor) {
    return [this.invertToIndexX(xCor), this.invertToIndexY(yCor)];
  }

  fetchPiece(xIndex, yIndex) {
    var row = this.board[yIndex];
    return row ? row[xIndex] : undefined;
  }

  findPiece(piece) {
    var [toCorX, toCorY] = [piece.x, piece.y];
    var [toIdxX, toIdxY] = this.invertCor(toCorX, toCorY);
    return this.fetchPiece(toIdxX, toIdxY);
  }

  toArray() {
    return this.board.map((row) => {
      return row.map((piece) => {
        return piece.type;
      });
    });
  }
};
<|endoftext|>


<commit_before>'use strict';

//Shelf service used for communicating with the shelf REST endpoints
angular
    .module('recipes')
    .factory('MealService', MealService);

MealService.$inject = ['$resource'];

function MealService($resource) {
    var Meal = $resource('api/meal/:mealId', {
        mealId: '@number'
    }, {
        update: {
            method: 'PUT'
        }
    });

    angular.extend(Meal.prototype, {
        createOrUpdate: function () {
            var meal = this;
            return createOrUpdate(meal);
        }
    });

    return Meal;

    function createOrUpdate(meal) {
        if (meal.id) {
            return meal.$update(onSuccess, onError);
        } else {
            return meal.$save(onSuccess, onError);
        }
    }

    function onSuccess(menu) {
        // Any required internal processing from inside the service, goes here.
    }

    // Handle error response
    function onError(errorResponse) {
        var error = errorResponse.data;
        // Handle error internally
        handleError(error);
    }

    function handleError(error) {
        // Log error
        console.log(error);
    }
}<commit_msg>feat: получение рецепта у блюда<commit_after>'use strict';

//Shelf service used for communicating with the shelf REST endpoints
angular
    .module('recipes')
    .factory('MealService', MealService);

MealService.$inject = ['$resource', 'RecipeService'];

function MealService($resource, RecipeService) {
    var Meal = $resource('api/meal/:mealId', {
        mealId: '@number'
    }, {
        update: {
            method: 'PUT'
        }
    });

    angular.extend(Meal.prototype, {
        createOrUpdate: function () {
            var meal = this;
            return createOrUpdate(meal);
        },
        getRecipe: function () {
            var meal = this;
            return getRecipe(meal);
        }
    });

    return Meal;

    function createOrUpdate(meal) {
        if (meal.id) {
            return meal.$update(onSuccess, onError);
        } else {
            return meal.$save(onSuccess, onError);
        }
    }

    function getRecipe(meal) {
        return RecipeService.get(
            {
                recipeId: meal.recipeId
            }
        ).$promise;
    }

    function onSuccess(menu) {
        // Any required internal processing from inside the service, goes here.
    }

    // Handle error response
    function onError(errorResponse) {
        var error = errorResponse.data;
        // Handle error internally
        handleError(error);
    }

    function handleError(error) {
        // Log error
        console.log(error);
    }
}<|endoftext|>


<commit_before>var test = require('tape');
var bar = require('../src/event-bar.js');

function setup () {
  function add (type, className) {
    var element = document.createElement(type);
    element.className = className;
    document.body.appendChild(element);
  }
  add('input', 'square');
  add('div', 'barman');
  add('div', 'result');
  add('div', 'clear');
  bar();
}

function teardown () {
  var selectors = ['.barman', '.square', '.result', '.clear'];
  selectors.forEach(function (selector) {
    var element = document.querySelector(selector);
    element.parentNode.removeChild(element);
  });
}

function testCase (name, cb) {
  var t = test(name, cb);
  t.once('prerun', setup); // setup before each test case
  t.once('end', teardown); // teardown after each test case
}

testCase('clicking barman without input should result in an error message', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var result;

  // Act
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'error');
  t.equal(result[0].innerText, 'Do you even know what a number is?');
});

testCase('clicking barman with an integer should result in an error message', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var result;

  // Act
  square.value = '2';
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'error');
  t.equal(result[0].innerText, 'You are such a unit. Integers cannot be rounded!');
});

testCase('clicking barman with a number should result in a rounded number', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var value = 2.4;
  var result;

  // Act
  square.value = value.toString();
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'rounded');
  t.equal(result[0].innerText, 'Rounded to ' + Math.round(value) + '. Another round?');
});

testCase('clicking barman with two values should produce two results', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var value = 2.4;
  var result;

  // Act
  square.value = value.toString();
  barman.click();
  square.value = '3';
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(6);
  t.ok(barman);
  t.equal(result.length, 2);
  t.equal(result[0].className, 'rounded');
  t.equal(result[0].innerText, 'Rounded to ' + Math.round(value) + '. Another round?');
  t.equal(result[1].className, 'error');
  t.equal(result[1].innerText, 'You are such a unit. Integers cannot be rounded!');
});

testCase('clicking clear when the list is empty does not throw', function (t) {
  // Arrange
  var clear = document.querySelector('.clear');

  // Assert
  t.plan(2);
  t.ok(clear);
  t.doesNotThrow(function () {
    clear.click();
  });
});

testCase('clicking clear removes any results in the list', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var clear = document.querySelector('.clear');
  var result;

  // Act
  square.value = '3.4';
  barman.click();
  square.value = '3';
  barman.click();
  square.value = '';
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(2);
  t.equal(result.length, 3);
  clear.click();
  result = document.querySelectorAll('.result p');
  t.equal(result.length, 0);
});
<commit_msg>fixes #16<commit_after>var test = require('tape');
var bar = require('../src/event-bar.js');

function setup () {
  function add (type, className) {
    var element = document.createElement(type);
    element.className = className;
    document.body.appendChild(element);
  }
  add('input', 'square');
  add('div', 'barman');
  add('div', 'result');
  add('div', 'clear');
  bar();
}

function teardown () {
  var selectors = ['.barman', '.square', '.result', '.clear'];
  selectors.forEach(function (selector) {
    var element = document.querySelector(selector);
    element.parentNode.removeChild(element);
  });
}

function testCase (name, cb) {
  var t = test(name, cb);
  t.once('prerun', setup); // setup before each test case
  t.once('end', teardown); // teardown after each test case
}

testCase('clicking barman without input should result in an error message', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var result;

  // Act
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'error');
  t.equal(result[0].innerText, 'Do you even know what a number is?');
});

testCase('clicking barman with an integer should result in an error message', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var result;

  // Act
  square.value = '2';
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'error');
  t.equal(result[0].innerText, 'You are such a unit. Integers cannot be rounded!');
});

testCase('clicking barman with a number should result in a rounded number', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var value = 2.4;
  var result;

  // Act
  square.value = value.toString();
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(4);
  t.ok(barman);
  t.equal(result.length, 1);
  t.equal(result[0].className, 'rounded');
  t.equal(result[0].innerText, 'Rounded to ' + Math.round(value) + '. Another round?');
});

testCase('clicking barman with two values should produce two results', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var value = 2.4;
  var result;

  // Act
  square.value = value.toString();
  barman.click();
  square.value = '3';
  barman.click();
  result = document.querySelectorAll('.result p');

  // Assert
  t.plan(6);
  t.ok(barman);
  t.equal(result.length, 2);
  t.equal(result[0].className, 'rounded');
  t.equal(result[0].innerText, 'Rounded to ' + Math.round(value) + '. Another round?');
  t.equal(result[1].className, 'error');
  t.equal(result[1].innerText, 'You are such a unit. Integers cannot be rounded!');
});

testCase('clicking clear when the list is empty does not throw', function (t) {
  // Arrange
  var clear = document.querySelector('.clear');

  // Assert
  t.plan(2);
  t.ok(clear);
  t.doesNotThrow(function () {
    clear.click();
  });
});

testCase('clicking clear removes any results in the list', function (t) {
  // Arrange
  var barman = document.querySelector('.barman');
  var square = document.querySelector('.square');
  var clear = document.querySelector('.clear');
  var result;
  var resultCleared;

  // Act
  square.value = '3.4';
  barman.click();
  square.value = '3';
  barman.click();
  square.value = '';
  barman.click();
  result = document.querySelectorAll('.result p');
  clear.click();
  resultCleared = document.querySelectorAll('.result p');

  // Assert
  t.plan(2);
  t.equal(result.length, 3);
  t.equal(resultCleared.length, 0);
});
<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const Collection = require('discord.js').Collection;
const Schema = mongoose.Schema;

/**
* The channel config Schema
* @typedef {Object} ChannelConfigSchema
* @property {String} guildName - Guild Name
* @property {String} guildID Guild Id
* @property {String} channelName Channel Name
* @property {String} channelID Channel Id
* @property {Array} repos Array of repos to event to channel
* @property {Array} repo Repo to use for gitlab commands in channel
* @property {Array} disabledEvents Github events to disable in this channel
* @property {Boolean} embed Use embeds for events or not
*/
const channelConfigSchema = Schema({
  guildName: String,
  guildID: String,
  channelName: String,
  channelID: String,
  repos: Array,
  repo: String,
  embed: Boolean,
  disabledEvents: {
    type: Array,
    default: [
      'merge_request/update',
      'pipeline',
    ],
  },
  ignoredUsers: Array,
  ignoredBranches: Array,
});

const channelConfig = mongoose.model('ChannelConfig', channelConfigSchema);

/**
* A Channel Config Item
*/
class ChannelConfigItem {
  constructor(client, config) {
    /**
    * The bot client
    * @type Client
    * @private
    */
    this._client = client;
    for (let key in config) {
      if (config.hasOwnProperty(key)) {
        this[key] = config[key];
      }
    }
  }
  /**
  * Set a specific config property to a value for this config item
  * @param {String} prop Property to modify
  * @param {String} value The new value for the property
  * @see ChannelConfig#set
  * @return {Promise}
  */
  set(prop, value) {
    return this._client.set(this.channelID, prop, value);
  }
  /**
  * Delete repo events from channel
  * @param {String} repo Repo events to delete from channel
  * @return {Promise}
  */
  deleteRepo(repo) {
    let repos = this.repos;
    repos.splice(repos.indexOf(repo), 1);
    return this.set('repos', repos);
  }
}

/**
* The Channel Config manager
*/
class ChannelConfig {
  constructor() {
    /**
    * All the config
    * @type {Collection}
    * @private
    */
    this._data = new Collection();
    this.setup();
    this.validKeys = [
      'repos',
      'repo',
      'embed',
      'disabledEvents',
      'ignoredUsers',
      'ignoredBranches',
    ];
    this.setupEvents = false;

    /**
    * Loaded
    * @type {Boolean}
    */
    this.loaded = false;
  }
  /**
  * Get config from database and add to this._data
  */
  setup() {
    channelConfig.find({}).then(configs => {
      this.loaded = true;
      configs.forEach(row => {
        this._data.set(row.channelID, new ChannelConfigItem(this, row._doc));
      });
    }).catch(Log.error);
  }
  /**
  * Initialize configuration and Discord bot events
  * @param {external:Client} bot Client instance
  */
  init(bot) {
    if (!this.loaded) {
      setTimeout(() => this.init(bot), 5000);
      return;
    }

    for (const ch of bot.channels) {
      const channel = ch[1];
      if (!channel || channel.type !== 'text') continue;
      if (!this.has(channel.id)) {
        Log.info(`ChannelConf | Adding "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.add(channel).catch(e => bot.emit('error', e));
      }
    }

    if (!this.setupEvents) {
      this.setupEvents = true;
      bot.on('channelDelete', channel => {
        if (!channel || channel.type !== 'text') return;
        Log.info(`ChannelConf | Deleting "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.delete(channel.id).catch(Log.error);
      });
      bot.on('channelCreate', channel => {
        if (!channel || channel.type !== 'text') return;
        if (this.has(channel.id)) return;
        Log.info(`ChannelConf | Adding "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.add(channel).catch(e => bot.emit('error', e));
      });
    }
  }
  /**
  * Find channels with events for repo
  * @param {String} repo Repo for the events
  * @return {ChannelConfigItem}
  */
  findByRepo(repo) {
    let re = repo.toLowerCase();
    return this._data.filter(e => e.repos.filter(r => r === re)[0]);
  }
  /**
  * Get channel config
  * @param {String} channel Channel ID
  * @return {ChannelConfigItem}
  */
  get(channel) {
    return this._data.get(channel);
  }

  /**
  * Has channel in config
  * @param {String} channel Channel ID
  * @return {Boolean}
  */
  has(channel) {
    return this._data.has(channel);
  }

  /**
  * Delete all repo events from channel
  * @param {String} channelID Channel ID with the events to delete
  * @return {Promise<ChannelConfig>}
  */
  delete(channelID) {
    return channelConfig.findOneAndRemove({
      channelID: channelID,
    }).then(() => {
      this._data.delete(channelID);
      return Promise.resolve(this);
    });
  }

  /**
  * Delete all channels from guild
  * @param  {String} guildID Guild ID to delete channel configs for
  * @return {Promise}
  */
  deleteFromGuild(guildID) {
    return Promise.all(
      this._data
      .filter(c => c.guildID === guildID)
      .map(c => {
        Log.info(`ChannelConf | Deleting "${c.guildName}"'s #${c.channelName} (${c.channelID})`);
        return this.delete(c.channelID);
      })
    ).then(() => this);
  }

  /**
  * Add channel to config
  * @param {Channel} channel Channel to add repo events
  * @return {Promise<ChannelConfig>}
  */
  add(channel) {
    if (!channel || !channel.id) return Promise.reject(`No channel passed!`);
    if (channel && channel.id && this.get(channel.id)) return Promise.reject(`Channel already has an entry in database`);
    const conf = {
      guildID: channel.guild && channel.guild.id,
      guildName: channel.guild && channel.guild.name,
      channelID: channel.id,
      channelName: channel.name,
      repos: [],
      prefix: `GL! `,
      disabledEvents: [
        'merge_request/update',
        'pipeline',
      ],
    };
    return channelConfig.create(conf).then(() => {
      const item = new ChannelConfigItem(this, conf);
      this._data.set(conf.channelID, item);
      return item;
    });
  }

  /**
  * Add all channels from guild
  * @param  {Guild} guild Guild obj to add channel configs for
  * @return {Promise}
  */
  addFromGuild(guild) {
    return Promise.all(
      guild.channels
      .filter(c => c.type === 'text')
      .map(c => {
        Log.info(`ChannelConf | Adding "${c.guildName}"'s #${c.channelName} (${c.channelID})`);
        return this.add(c);
      })
    ).then(() => this);
  }

  /**
  * Replace specific channel config prop with value
  * @param {String} channel Channel with the repo events
  * @param {String} prop Property to set
  * @param {String} value Value to set property to
  * @return {Promise<ChannelConfig>} updated config item
  */
  set(channel, prop, value) {
    return new Promise((resolve, reject) => {
      let oldConfig = this._data.find('channelID', channel);
      let newConfig = oldConfig;
      newConfig[prop] = value;
      channelConfig.findOneAndUpdate({
        channelID: channel,
      }, newConfig, {
        new: true,
      }, (err) => {
        if (err) return reject(err);
        this._data.set(channel, new ChannelConfigItem(this, newConfig));
        resolve(this);
      });
    });
  }

  /**
  * Add repo to channel
  * @param {Channel} channel Channel to add repo to
  * @param {String} repo repo to add to channel
  * @see ChannelConfig#set
  * @return {Promise<ChannelConfig>}
  */
  addRepoToChannel(channel, repo) {
    if (!channel || !repo) return Promise.reject(`Invalid arguments.`);
    let conf = this.get(channel);
    let repos = conf.repos;
    repos.push(repo.toLowerCase());
    return this.set(channel, 'repos', repos);
  }

  /**
  * Delete repo events from specific channel
  * @param {String} channel Channel with the repo events
  * @param {String} repo Repo event to remove from Channel
  * @see ChannelConfig#set
  * @return {Promise<ChannelConfig>}
  */
  deleteRepo(channel, repo) {
    return channelConfig.findOneAndRemove({
      repo,
    }).then(() => {
      let oldRepos = this._data.find('channelID', channel);
      let newRepos = oldRepos.slice(0, oldRepos.indexOf(repo));
      return this.set(channel, 'repos', newRepos);
    });
  }
}

module.exports = new ChannelConfig();
<commit_msg>fix(models: channelconfig): maybe fix e.repos not being defined, set e.repos to [] if null<commit_after>const mongoose = require('mongoose');
const Collection = require('discord.js').Collection;
const Schema = mongoose.Schema;

/**
* The channel config Schema
* @typedef {Object} ChannelConfigSchema
* @property {String} guildName - Guild Name
* @property {String} guildID Guild Id
* @property {String} channelName Channel Name
* @property {String} channelID Channel Id
* @property {Array} repos Array of repos to event to channel
* @property {Array} repo Repo to use for gitlab commands in channel
* @property {Array} disabledEvents Github events to disable in this channel
* @property {Boolean} embed Use embeds for events or not
*/
const channelConfigSchema = Schema({
  guildName: String,
  guildID: String,
  channelName: String,
  channelID: String,
  repos: Array,
  repo: String,
  embed: Boolean,
  disabledEvents: {
    type: Array,
    default: [
      'merge_request/update',
      'pipeline',
    ],
  },
  ignoredUsers: Array,
  ignoredBranches: Array,
});

const channelConfig = mongoose.model('ChannelConfig', channelConfigSchema);

/**
* A Channel Config Item
*/
class ChannelConfigItem {
  constructor(client, config) {
    /**
    * The bot client
    * @type Client
    * @private
    */
    this._client = client;
    for (let key in config) {
      if (config.hasOwnProperty(key)) {
        this[key] = config[key];
      }
    }

    this.repos = this.repos || [];
  }
  /**
  * Set a specific config property to a value for this config item
  * @param {String} prop Property to modify
  * @param {String} value The new value for the property
  * @see ChannelConfig#set
  * @return {Promise}
  */
  set(prop, value) {
    return this._client.set(this.channelID, prop, value);
  }
  /**
  * Delete repo events from channel
  * @param {String} repo Repo events to delete from channel
  * @return {Promise}
  */
  deleteRepo(repo) {
    let repos = this.repos;
    repos.splice(repos.indexOf(repo), 1);
    return this.set('repos', repos);
  }
}

/**
* The Channel Config manager
*/
class ChannelConfig {
  constructor() {
    /**
    * All the config
    * @type {Collection}
    * @private
    */
    this._data = new Collection();
    this.setup();
    this.validKeys = [
      'repos',
      'repo',
      'embed',
      'disabledEvents',
      'ignoredUsers',
      'ignoredBranches',
    ];
    this.setupEvents = false;

    /**
    * Loaded
    * @type {Boolean}
    */
    this.loaded = false;
  }
  /**
  * Get config from database and add to this._data
  */
  setup() {
    channelConfig.find({}).then(configs => {
      this.loaded = true;
      configs.forEach(row => {
        this._data.set(row.channelID, new ChannelConfigItem(this, row._doc));
      });
    }).catch(Log.error);
  }
  /**
  * Initialize configuration and Discord bot events
  * @param {external:Client} bot Client instance
  */
  init(bot) {
    if (!this.loaded) {
      setTimeout(() => this.init(bot), 5000);
      return;
    }

    for (const ch of bot.channels) {
      const channel = ch[1];
      if (!channel || channel.type !== 'text') continue;
      if (!this.has(channel.id)) {
        Log.info(`ChannelConf | Adding "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.add(channel).catch(e => bot.emit('error', e));
      }
    }

    if (!this.setupEvents) {
      this.setupEvents = true;
      bot.on('channelDelete', channel => {
        if (!channel || channel.type !== 'text') return;
        Log.info(`ChannelConf | Deleting "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.delete(channel.id).catch(Log.error);
      });
      bot.on('channelCreate', channel => {
        if (!channel || channel.type !== 'text') return;
        if (this.has(channel.id)) return;
        Log.info(`ChannelConf | Adding "${channel.guild.name}"'s #${channel.name} (${channel.id})`);
        this.add(channel).catch(e => bot.emit('error', e));
      });
    }
  }
  /**
  * Find channels with events for repo
  * @param {String} repo Repo for the events
  * @return {ChannelConfigItem}
  */
  findByRepo(repo) {
    let re = repo.toLowerCase();
    return this._data.filter(e => e.repos.filter(r => r === re)[0]);
  }
  /**
  * Get channel config
  * @param {String} channel Channel ID
  * @return {ChannelConfigItem}
  */
  get(channel) {
    return this._data.get(channel);
  }

  /**
  * Has channel in config
  * @param {String} channel Channel ID
  * @return {Boolean}
  */
  has(channel) {
    return this._data.has(channel);
  }

  /**
  * Delete all repo events from channel
  * @param {String} channelID Channel ID with the events to delete
  * @return {Promise<ChannelConfig>}
  */
  delete(channelID) {
    return channelConfig.findOneAndRemove({
      channelID: channelID,
    }).then(() => {
      this._data.delete(channelID);
      return Promise.resolve(this);
    });
  }

  /**
  * Delete all channels from guild
  * @param  {String} guildID Guild ID to delete channel configs for
  * @return {Promise}
  */
  deleteFromGuild(guildID) {
    return Promise.all(
      this._data
      .filter(c => c.guildID === guildID)
      .map(c => {
        Log.info(`ChannelConf | Deleting "${c.guildName}"'s #${c.channelName} (${c.channelID})`);
        return this.delete(c.channelID);
      })
    ).then(() => this);
  }

  /**
  * Add channel to config
  * @param {Channel} channel Channel to add repo events
  * @return {Promise<ChannelConfig>}
  */
  add(channel) {
    if (!channel || !channel.id) return Promise.reject(`No channel passed!`);
    if (channel && channel.id && this.get(channel.id)) return Promise.reject(`Channel already has an entry in database`);
    const conf = {
      guildID: channel.guild && channel.guild.id,
      guildName: channel.guild && channel.guild.name,
      channelID: channel.id,
      channelName: channel.name,
      repos: [],
      prefix: `GL! `,
      disabledEvents: [
        'merge_request/update',
        'pipeline',
      ],
    };
    return channelConfig.create(conf).then(() => {
      const item = new ChannelConfigItem(this, conf);
      this._data.set(conf.channelID, item);
      return item;
    });
  }

  /**
  * Add all channels from guild
  * @param  {Guild} guild Guild obj to add channel configs for
  * @return {Promise}
  */
  addFromGuild(guild) {
    return Promise.all(
      guild.channels
      .filter(c => c.type === 'text')
      .map(c => {
        Log.info(`ChannelConf | Adding "${c.guildName}"'s #${c.channelName} (${c.channelID})`);
        return this.add(c);
      })
    ).then(() => this);
  }

  /**
  * Replace specific channel config prop with value
  * @param {String} channel Channel with the repo events
  * @param {String} prop Property to set
  * @param {String} value Value to set property to
  * @return {Promise<ChannelConfig>} updated config item
  */
  set(channel, prop, value) {
    return new Promise((resolve, reject) => {
      let oldConfig = this._data.find('channelID', channel);
      let newConfig = oldConfig;
      newConfig[prop] = value;
      channelConfig.findOneAndUpdate({
        channelID: channel,
      }, newConfig, {
        new: true,
      }, (err) => {
        if (err) return reject(err);
        this._data.set(channel, new ChannelConfigItem(this, newConfig));
        resolve(this);
      });
    });
  }

  /**
  * Add repo to channel
  * @param {Channel} channel Channel to add repo to
  * @param {String} repo repo to add to channel
  * @see ChannelConfig#set
  * @return {Promise<ChannelConfig>}
  */
  addRepoToChannel(channel, repo) {
    if (!channel || !repo) return Promise.reject(`Invalid arguments.`);
    let conf = this.get(channel);
    let repos = conf.repos;
    repos.push(repo.toLowerCase());
    return this.set(channel, 'repos', repos);
  }

  /**
  * Delete repo events from specific channel
  * @param {String} channel Channel with the repo events
  * @param {String} repo Repo event to remove from Channel
  * @see ChannelConfig#set
  * @return {Promise<ChannelConfig>}
  */
  deleteRepo(channel, repo) {
    return channelConfig.findOneAndRemove({
      repo,
    }).then(() => {
      let oldRepos = this._data.find('channelID', channel);
      let newRepos = oldRepos.slice(0, oldRepos.indexOf(repo));
      return this.set(channel, 'repos', newRepos);
    });
  }
}

module.exports = new ChannelConfig();
<|endoftext|>


<commit_before>var PlanningSession = require('./PlanningSession');

module.exports = PlanningSessionStore;

function PlanningSessionStore(socketio) {
  if(!(this instanceof PlanningSessionStore)) {
    return new PlanningSessionStore(socketio);
  }

  this.socketio = socketio;

  this.seed = 1;

  this.planningSessions = new Map();

  this.reap();

};

PlanningSessionStore.prototype.createSessionToken = function() {
  do {
    var x = Math.sin(this.seed++) * 10000;
    var token = ""+((x - Math.floor(x)) * 10000).toFixed(0);
    if (token.length > 4) {

    }
    while(token.lenght < 4) {
      token = "0" + token;
    }
  } while(this.planningSessions.has(token));
  return token;
}

PlanningSessionStore.prototype.createPlanningSession = function(participant, data) {
  var sessionToken = this.createSessionToken();
  participant.sessionToken = sessionToken;
  participant.nickname = data.nickname;
  this.planningSessions.set(sessionToken, PlanningSession(participant, data.hostKey, sessionToken, this.socketio))
  return participant;
}

PlanningSessionStore.prototype.getPlanningSession = function(sessionToken) {
  /*var index = planningSessions.length;
  while(index > 0) {
    index --;
    if (planningSessions[index].sessionToken == sessionToken) {
      return planningSessions[index];
    }
    return null;
  }*/
  return this.planningSessions.get(sessionToken);
}

PlanningSessionStore.prototype.reap = function() {
  var threshold = Date.now() - (8*60*60*1000) - (10*60*10000);
  var oldestPlanningSession = Date.now();
  /*var index = this.planningSessions.length;
  while(index > 0) {
    index--
    if (this.planningSessions[index].sessionStart < threshold) {
      var removed = this.planningSession.splice(index, 1);
      if (removed.length == 1) {
        usedTokens[removed[0].sessionToken] = false;
      }
    } else {
      oldestPlanningSession = Math.min(this.planningSessions[index].sessionStart, oldestPlanningSession);
    }
  }*/
  for (var entry of this.planningSessions.entries()) {
    if (entry[1].sessionStart < threshold) {
      this.planningSessions.delete(entry[0]);
    } else {
      oldestPlanningSession = Math.min(entry[1].sessionStart, oldestPlanningSession);
    }
  }
  setTimeout(this.reap, oldestPlanningSession - threshold).unref();
}
<commit_msg>binding reap function to this when calling setTimeout<commit_after>var PlanningSession = require('./PlanningSession');

module.exports = PlanningSessionStore;

function PlanningSessionStore(socketio) {
  if(!(this instanceof PlanningSessionStore)) {
    return new PlanningSessionStore(socketio);
  }

  this.socketio = socketio;

  this.seed = 1;

  this.planningSessions = new Map();

  this.reap();

};

PlanningSessionStore.prototype.createSessionToken = function() {
  do {
    var x = Math.sin(this.seed++) * 10000;
    var token = ""+((x - Math.floor(x)) * 10000).toFixed(0);
    if (token.length > 4) {

    }
    while(token.lenght < 4) {
      token = "0" + token;
    }
  } while(this.planningSessions.has(token));
  return token;
}

PlanningSessionStore.prototype.createPlanningSession = function(participant, data) {
  var sessionToken = this.createSessionToken();
  participant.sessionToken = sessionToken;
  participant.nickname = data.nickname;
  this.planningSessions.set(sessionToken, PlanningSession(participant, data.hostKey, sessionToken, this.socketio))
  return participant;
}

PlanningSessionStore.prototype.getPlanningSession = function(sessionToken) {
  return this.planningSessions.get(sessionToken);
}

PlanningSessionStore.prototype.reap = function() {
  console.log("Start reaping, current number of PlanningSessions: " + this.planningSessions.size);
  var removed = 0;
  var threshold = Date.now() - (8*60*60*1000) - (10*60*10000);
  var oldestPlanningSession = Date.now();

  for (var entry of this.planningSessions.entries()) {
    if (entry[1].sessionStart < threshold) {
      if (this.planningSessions.delete(entry[0])) {
        removed += 1;
      }
    } else {
      oldestPlanningSession = Math.min(entry[1].sessionStart, oldestPlanningSession);
    }
  }
  console.log("Finised reaping, removed: " + removed + " and will reap again in: " + (oldestPlanningSession - threshold));
  setTimeout(this.reap.bind(this), oldestPlanningSession - threshold).unref();
}
<|endoftext|>


<commit_before>import React from "react";
import { JssProvider, SheetsRegistry } from "react-jss";
import { MuiThemeProvider, createGenerateClassName } from "material-ui/styles";
import { renderToString } from "react-dom/server";
import { Provider } from "react-redux";
require("dotenv").config();

import createStore from "./src/state/store";
import theme from "./src/styles/theme";

function minifyCssString(css) {
  return css.replace(/\n/g, "").replace(/\s\s+/g, " ");
}

exports.replaceRenderer = ({ bodyComponent, replaceBodyHTMLString, setHeadComponents }) => {
  const sheetsRegistry = new SheetsRegistry();

  const generateClassName = createGenerateClassName();

  const store = createStore();

  replaceBodyHTMLString(
    renderToString(
      <Provider store={store}>
        <JssProvider registry={sheetsRegistry} generateClassName={generateClassName}>
          <MuiThemeProvider theme={theme} sheetsManager={new Map()}>
            {bodyComponent}
          </MuiThemeProvider>
        </JssProvider>
      </Provider>
    )
  );

  setHeadComponents([


<commit_before>var FtreesController = function($scope, $state, $stateParams, $location, ftrees, notification) {
	var self = this;

	this.individuals = [];
	this.search_params = {};
	this.query = '';
	this.advanced_search = false;

	this.search_modifiers = {
		first_name: 	'',
		last_name: 		'',
		birth_place: 	'',
		marriage_place: '',
		death_place: 	''
	};
	this.fudge_factors = {
		birth_year: 	0,
		marriage_year: 	0,
		death_year: 	0
	};

	this.$state = $state;
	this.$stateParams = $stateParams;
	this.$scope = $scope;
	this.$location = $location;
	this.ftrees = ftrees;
	this.notification = notification;

	Object.defineProperty($scope, '$stateParams', {
		get: function() {
			return $stateParams;
		}
	});

	//search
	var BreakException= {};
	var parameters = [];
	try {
		Object.keys($stateParams).forEach(function(key) {
			if ($stateParams[key]) {

				// read state params & update bound objects to update view accordingly
				for (var param in $stateParams) {
					if ( $stateParams[param] !== undefined ) {
						parameters.push($stateParams[param]);

						// handle search modifiers & fudge factors in query string
						if ( $stateParams[param].indexOf('~') !== -1 ) {
							var parts = $stateParams[param].split('~');
							self.search_params[param] = parts[0];
							self.fudge_factors[param] = parts[1];
						}
						else if ( $stateParams[param].indexOf(';') !== -1 ) {
							var parts = $stateParams[param].split(';');
							self.search_params[param] = parts[0];
							self.search_modifiers[param] = parts[1];
						}
						else {
							self.search_params[param] = $stateParams[param];
						}
					}
					self.query = parameters.join(' + ');
				};

				self.search($stateParams);
				throw BreakException;
			}
		});
	}
	catch(e) {
		 if (e !== BreakException) throw e;
	}
};

FtreesController.prototype = {
	search: function(search_params) {
		var self = this;

		this.notification.put({
			en:'Searching family trees...',
			he: 'מחפש בעצי משפחה...'
		});

		this.ftrees.search(search_params).
			then(function(individuals) {
				self.individuals = individuals;

				if (self.results_per_page > individuals.length) {
					if (individuals.length === 0) {
						self.results_per_page = 15;
					}
					else {
						self.results_per_page = (individuals.length - individuals.length % 5) || 5;
					}
				}

				self.notification.put({
					en: 'Family Trees Search has finished successfully.',
					he: 'חיפוש בעצי משפחה הסתיים בהצלחה.'
				});

			}, function() {
				self.notification.put({
					en: 'Family Trees Search has failed.',
					he: 'חיפוש בעצי משפחה נכשל.'
				});
			});
	},

	fetch_more: function() {
		var self = this;
		var search_params = angular.copy(this.search_params);
		search_params.start = self.individuals.items.length;
		var individuals = self.individuals;
		this.ftrees.search(search_params).
			then(function (r){
				self.individuals.items = individuals.items.concat(r.items);
			});
    },

	update: function() {
		var self = this;
		var search_params = angular.copy(this.search_params);

		for (var param in search_params) {
			if (search_params[param] === '') {
				delete search_params[param];
			}
		}

		if (search_params.ind_index) {
			delete(search_params.ind_index);
		}

		// insert search modifiers & fudge_factors into query string
		for (var modifier in this.search_modifiers) {
			var modifier_string = this.search_modifiers[modifier];
			if (search_params[modifier] !== undefined && modifier_string !== '') {
				search_params[modifier] += ';' + modifier_string;
			}
		}
		for (var factor in this.fudge_factors) {
			var fudge_val = this.fudge_factors[factor];
			if (search_params[factor] !== undefined && fudge_val !== 0) {
				search_params[factor] += '~' + fudge_val;
			}
		}

		// avoid conflict with parameter from state ftree-view.ftree-item
		search_params.tree_number = search_params.filters_tree_number;
		delete search_params.filters_tree_number;

		for (var param in this.search_params) {
			this.$location.search(param, search_params[param]);
		}
	},

	get_href: function (individual) {
		// TODO: support languages
		return this.$state.href('person-view', {tree_number: individual.GTN,
							   			   node_id: individual.II});
	},

	read_about_center: function (collection_name) {
        this.$state.go('about_center', {collection: collection_name});
    }
};

angular.module('main').controller('FtreesController', ['$scope', '$state', '$stateParams', '$location', 'ftrees', 'notification', FtreesController]);
<commit_msg>restore the clear_filters function<commit_after>var FtreesController = function($scope, $state, $stateParams, $location, ftrees, notification) {
	var self = this;

	this.individuals = [];
	this.search_params = {};
	this.query = '';
	this.advanced_search = false;

	this.search_modifiers = {
		first_name: 	'',
		last_name: 		'',
		birth_place: 	'',
		marriage_place: '',
		death_place: 	''
	};
	this.fudge_factors = {
		birth_year: 	0,
		marriage_year: 	0,
		death_year: 	0
	};

	this.$state = $state;
	this.$stateParams = $stateParams;
	this.$scope = $scope;
	this.$location = $location;
	this.ftrees = ftrees;
	this.notification = notification;

	Object.defineProperty($scope, '$stateParams', {
		get: function() {
			return $stateParams;
		}
	});

	//search
	var BreakException= {};
	var parameters = [];
	try {
		Object.keys($stateParams).forEach(function(key) {
			if ($stateParams[key]) {

				// read state params & update bound objects to update view accordingly
				for (var param in $stateParams) {
					if ( $stateParams[param] !== undefined ) {
						parameters.push($stateParams[param]);

						// handle search modifiers & fudge factors in query string
						if ( $stateParams[param].indexOf('~') !== -1 ) {
							var parts = $stateParams[param].split('~');
							self.search_params[param] = parts[0];
							self.fudge_factors[param] = parts[1];
						}
						else if ( $stateParams[param].indexOf(';') !== -1 ) {
							var parts = $stateParams[param].split(';');
							self.search_params[param] = parts[0];
							self.search_modifiers[param] = parts[1];
						}
						else {
							self.search_params[param] = $stateParams[param];
						}
					}
					self.query = parameters.join(' + ');
				};

				self.search($stateParams);
				throw BreakException;
			}
		});
	}
	catch(e) {
		 if (e !== BreakException) throw e;
	}
};

FtreesController.prototype = {
	search: function(search_params) {
		var self = this;

		this.notification.put({
			en:'Searching family trees...',
			he: 'מחפש בעצי משפחה...'
		});

		this.ftrees.search(search_params).
			then(function(individuals) {
				self.individuals = individuals;

				if (self.results_per_page > individuals.length) {
					if (individuals.length === 0) {
						self.results_per_page = 15;
					}
					else {
						self.results_per_page = (individuals.length - individuals.length % 5) || 5;
					}
				}

				self.notification.put({
					en: 'Family Trees Search has finished successfully.',
					he: 'חיפוש בעצי משפחה הסתיים בהצלחה.'
				});

			}, function() {
				self.notification.put({
					en: 'Family Trees Search has failed.',
					he: 'חיפוש בעצי משפחה נכשל.'
				});
			});
	},

	fetch_more: function() {
		var self = this;
		var search_params = angular.copy(this.search_params);
		search_params.start = self.individuals.items.length;
		var individuals = self.individuals;
		this.ftrees.search(search_params).
			then(function (r){
				self.individuals.items = individuals.items.concat(r.items);
			});
    },

	update: function() {
		var self = this;
		var search_params = angular.copy(this.search_params);

		for (var param in search_params) {
			if (search_params[param] === '') {
				delete search_params[param];
			}
		}

		if (search_params.ind_index) {
			delete(search_params.ind_index);
		}

		// insert search modifiers & fudge_factors into query string
		for (var modifier in this.search_modifiers) {
			var modifier_string = this.search_modifiers[modifier];
			if (search_params[modifier] !== undefined && modifier_string !== '') {
				search_params[modifier] += ';' + modifier_string;
			}
		}
		for (var factor in this.fudge_factors) {
			var fudge_val = this.fudge_factors[factor];
			if (search_params[factor] !== undefined && fudge_val !== 0) {
				search_params[factor] += '~' + fudge_val;
			}
		}

		// avoid conflict with parameter from state ftree-view.ftree-item
		search_params.tree_number = search_params.filters_tree_number;
		delete search_params.filters_tree_number;

		for (var param in this.search_params) {
			this.$location.search(param, search_params[param]);
		}
	},

 	clear_filters: function() {
 		for (var modifier in this.search_modifiers) {
 			this.search_params[modifier] = '';
 		}
 	},

	get_href: function (individual) {
		// TODO: support languages
		return this.$state.href('person-view', {tree_number: individual.GTN,
							   			   node_id: individual.II});
	},

	read_about_center: function (collection_name) {
        this.$state.go('about_center', {collection: collection_name});
    }
};

angular.module('main').controller('FtreesController', ['$scope', '$state', '$stateParams', '$location', 'ftrees', 'notification', FtreesController]);
<|endoftext|>


<commit_before>
/**
 * Expose `InteractiveDialog`.
 */

exports.InteractiveDialog = InteractiveDialog;

/**
 * Return a new `InteractiveDialog` dialog with the given
 * `title` and `msg`.
 *
 * @param {String} title or msg
 * @param {String} msg
 * @return {Dialog}
 * @api public
 */

exports.interactiveDialog = function(title, msg){
  switch (arguments.length) {
    case 2:
      return new InteractiveDialog({ title: title, message: msg });
    case 1:
      return new InteractiveDialog({ message: title });
  }
};

/**
 * Initialize a new `InteractiveDialog` dialog.
 *
 * Options:
 *
 *    - `title` dialog title
 *    - `message` a message to display
 *
 * Emits:
 *
 *    - `cancel` the user pressed cancel or closed the dialog
 *    - `ok` the user clicked ok
 *    - `show` when visible
 *    - `hide` when hidden
 *
 * @param {Object} options
 * @api public
 */

function InteractiveDialog(options) {
  ui.Dialog.call(this, options);
}

/**
 * Inherit from `Dialog.prototype`.
 */

InteractiveDialog.prototype = new ui.Dialog();

/**
 * Change "cancel" button `selector`.
 *
 * @param {String} selector
 * @return {InteractiveDialog}
 * @api public
 */

InteractiveDialog.prototype.cancel = function(selector){
  var cancel = this.el.find('.cancel');
  if (cancel.length > 0) { cancel.replaceWith(selector); }
  else { cancel = this.el.find(selector); }
  cancel.addClass('cancel').removeClass('hide');
  return this;
};

/**
 * Change "ok" button `selector`.
 *
 * @param {String} selector
 * @return {InteractiveDialog}
 * @api public
 */

InteractiveDialog.prototype.ok = function(selector){
  var ok = this.el.find('.ok');
  if (ok.length > 0) { ok.replaceWith(selector); }
  else { ok = this.el.find(selector); }
  ok.addClass('ok').removeClass('hide');
  return this;
};

/**
 * Show the confirmation dialog and invoke `fn(ok)`.
 *
 * @param {Function} fn
 * @return {InteractiveDialog} for chaining
 * @api public
 */

InteractiveDialog.prototype.show = function(fn){
  ui.Dialog.prototype.show.call(this);
  this.el.find('.ok').focus();
  this.callback = fn || function(){};
  return this;
};

/**
 * Render with the given `options`.
 *
 * @param {Object} options
 * @api public
 */

InteractiveDialog.prototype.render = function(options){
  ui.Dialog.prototype.render.call(this, options);
  var self = this
    , actions = $(html);

  this.el.addClass('interactive');
  this.el.append(actions);

  // Cancel/close
  this.el.on('click', '.cancel', function(e){
    e.preventDefault();
    self.emit('close');
    self.callback(false);
    self.hide();
  });

  // OK
  var ok = function() {
    self.emit('ok');
    self.emit('close');
    self.callback(true);
    self.hide();
  }.bind(this);

  this.el.on('click', '.ok', function(e){
    e.preventDefault();
    ok();
  });

  // "Ok" on enter
  this.el.on('keydown', function (e) {
    if(e.which === 13 || e.keyCode === 13){
      ok();
      e.preventDefault();
    }
  }.bind(this));

  // Focus on first input element
  setTimeout(function(){
      this.el.find('input:first').focus();
  }.bind(this));
};
<commit_msg>Overlay area click to close moved into dialog.js file<commit_after>
/**
 * Expose `InteractiveDialog`.
 */

exports.InteractiveDialog = InteractiveDialog;

/**
 * Return a new `InteractiveDialog` dialog with the given
 * `title` and `msg`.
 *
 * @param {String} title or msg
 * @param {String} msg
 * @return {Dialog}
 * @api public
 */

exports.interactiveDialog = function(title, msg){
  switch (arguments.length) {
    case 2:
      return new InteractiveDialog({ title: title, message: msg });
    case 1:
      return new InteractiveDialog({ message: title });
  }
};

/**
 * Initialize a new `InteractiveDialog` dialog.
 *
 * Options:
 *
 *    - `title` dialog title
 *    - `message` a message to display
 *
 * Emits:
 *
 *    - `cancel` the user pressed cancel or closed the dialog
 *    - `ok` the user clicked ok
 *    - `show` when visible
 *    - `hide` when hidden
 *
 * @param {Object} options
 * @api public
 */

function InteractiveDialog(options) {
  ui.Dialog.call(this, options);
}

/**
 * Inherit from `Dialog.prototype`.
 */

InteractiveDialog.prototype = new ui.Dialog();

/**
 * Change "cancel" button `selector`.
 *
 * @param {String} selector
 * @return {InteractiveDialog}
 * @api public
 */

InteractiveDialog.prototype.cancel = function(selector){
  var cancel = this.el.find('.cancel');
  if (cancel.length > 0) { cancel.replaceWith(selector); }
  else { cancel = this.el.find(selector); }
  cancel.addClass('cancel').removeClass('hide');
  return this;
};

/**
 * Change "ok" button `selector`.
 *
 * @param {String} selector
 * @return {InteractiveDialog}
 * @api public
 */

InteractiveDialog.prototype.ok = function(selector){
  var ok = this.el.find('.ok');
  if (ok.length > 0) { ok.replaceWith(selector); }
  else { ok = this.el.find(selector); }
  ok.addClass('ok').removeClass('hide');
  return this;
};

/**
 * Show the confirmation dialog and invoke `fn(ok)`.
 *
 * @param {Function} fn
 * @return {InteractiveDialog} for chaining
 * @api public
 */

InteractiveDialog.prototype.show = function(fn){
  ui.Dialog.prototype.show.call(this);
  this.el.find('.ok').focus();
  this.callback = fn || function(){};
  return this;
};

/**
 * Render with the given `options`.
 *
 * @param {Object} options
 * @api public
 */

InteractiveDialog.prototype.render = function(options){
  ui.Dialog.prototype.render.call(this, options);
  var self = this
    , actions = $(html);

  this.el.addClass('interactive');
  this.el.append(actions);

  // Cancel/close
  var close = function() {
    self.callback(false);
    self.hide();
  };

  this.on('close', close);
  this.el.on('click', '.cancel', function(e){
    e.preventDefault();
    self.emit('close');
    close();
  });

  // OK
  var ok = function() {
    self.emit('ok');
    self.emit('close');
    self.callback(true);
    self.hide();
  }.bind(this);

  this.el.on('click', '.ok', function(e){
    e.preventDefault();
    ok();
  });

  // "Ok" on enter
  this.el.on('keydown', function (e) {
    if(e.which === 13 || e.keyCode === 13){
      ok();
      e.preventDefault();
    }
  }.bind(this));

  // Focus on first input element
  setTimeout(function(){
      this.el.find('input:first').focus();
  }.bind(this));
};
<|endoftext|>


<commit_before>import {faMinus, faPlus} from '@fortawesome/free-solid-svg-icons'
import get from 'lodash/get'
import React from 'react'

import Select from '../select'
import {Button} from '../buttons'
import Icon from '../icon'
import {Group as FormGroup} from '../input'

/**
 * Select routes without selecting patterns
 */
export default function SelectFeedAndRoutes(p) {
  const selectedFeedId = get(p, 'selectedFeed.id')
  const routeIds = get(p, 'selectedRouteIds', [])

  function _selectFeed(feed) {
    p.onChange({feed: get(feed, 'id'), routes: null})
  }

  function _selectRoute(routes) {
    p.onChange({
      feed: get(p.selectedFeed, 'id'),
      routes: !routes
        ? []
        : Array.isArray(routes)
        ? routes.map(r => (r ? r.route_id : ''))
        : [routes.route_id]
    })
  }

  function _deselectAllRoutes() {
    p.onChange({
      feed: get(p.selectedFeed, 'id'),
      routes: []
    })
  }

  function _selectAllRoutes() {
    if (p.selectedFeed) {
      p.onChange({
        feed: p.selectedFeed.id,
        routes: p.selectedFeed.routes.map(r => r.route_id)
      })
    }
  }

  const selectedRoutes = routeIds.map(id =>
    p.selectedFeed.routes.find(r => r.route_id === id)
  )
  const allRoutesSelected =
    p.selectedFeed &&
    selectedRoutes.length > 1 &&
    selectedRoutes.length === p.selectedFeed.routes.length
  return (
    <>
      <FormGroup>
        Select feed and routes
        <Select
          name='Feed'
          getOptionLabel={f => get(f, 'name', f.id)}
          getOptionValue={f => f.id}
          onChange={_selectFeed}
          options={p.feeds}
          placeholder='Select feed'
          value={p.selectedFeed}
        />
      </FormGroup>

      {p.selectedFeed && (
        <>
          {allRoutesSelected ? (

              All routes selected

                This modification will apply to all routes in this feed. Select
                a single route to modify specific parts of that route.

          ) : (
            <FormGroup>
              <Select
                getOptionLabel={r => r.label}
                getOptionValue={r => r.route_id}
                isMulti={p.allowMultipleRoutes}
                name='Route'
                onChange={_selectRoute}
                options={p.selectedFeed.routes}
                placeholder='Select route'
                value={
                  p.allowMultipleRoutes ? selectedRoutes : selectedRoutes[0]
                }
              />
            </FormGroup>
          )}
        </>
      )}

      {p.allowMultipleRoutes && (
        <>
          {routeIds.length > 1 && (
            <FormGroup>
              <Button block style='warning' onClick={_deselectAllRoutes}>
                <Icon icon={faMinus} /> Deselect all routes
              </Button>
            </FormGroup>
          )}
          {routeIds.length < p.selectedFeed.routes.length && (
            <FormGroup>
              <Button block style='info' onClick={_selectAllRoutes}>
                <Icon icon={faPlus} /> Select all routes
              </Button>
            </FormGroup>
          )}
        </>
      )}
    </>
  )
}
<commit_msg>Fix NPE when route ids is empty<commit_after>import {faMinus, faPlus} from '@fortawesome/free-solid-svg-icons'
import get from 'lodash/get'
import React from 'react'

import Select from '../select'
import {Button} from '../buttons'
import Icon from '../icon'
import {Group as FormGroup} from '../input'

/**
 * Select routes without selecting patterns
 */
export default function SelectFeedAndRoutes(p) {
  const routeIds = get(p, 'selectedRouteIds') || []

  function _selectFeed(feed) {
    p.onChange({feed: get(feed, 'id'), routes: null})
  }

  function _selectRoute(routes) {
    p.onChange({
      feed: get(p.selectedFeed, 'id'),
      routes: !routes
        ? []
        : Array.isArray(routes)
        ? routes.map(r => (r ? r.route_id : ''))
        : [routes.route_id]
    })
  }

  function _deselectAllRoutes() {
    p.onChange({
      feed: get(p.selectedFeed, 'id'),
      routes: []
    })
  }

  function _selectAllRoutes() {
    if (p.selectedFeed) {
      p.onChange({
        feed: p.selectedFeed.id,
        routes: p.selectedFeed.routes.map(r => r.route_id)
      })
    }
  }

  const selectedRoutes = routeIds.map(id =>
    p.selectedFeed.routes.find(r => r.route_id === id)
  )
  const allRoutesSelected =
    p.selectedFeed &&
    selectedRoutes.length > 1 &&
    selectedRoutes.length === p.selectedFeed.routes.length
  return (
    <>
      <FormGroup>
        Select feed and routes
        <Select
          name='Feed'
          getOptionLabel={f => get(f, 'name', f.id)}
          getOptionValue={f => f.id}
          onChange={_selectFeed}
          options={p.feeds}
          placeholder='Select feed'
          value={p.selectedFeed}
        />
      </FormGroup>

      {p.selectedFeed && (
        <>
          {allRoutesSelected ? (

              All routes selected

                This modification will apply to all routes in this feed. Select
                a single route to modify specific parts of that route.

          ) : (
            <FormGroup>
              <Select
                getOptionLabel={r => r.label}
                getOptionValue={r => r.route_id}
                isMulti={p.allowMultipleRoutes}
                name='Route'
                onChange={_selectRoute}
                options={p.selectedFeed.routes}
                placeholder='Select route'
                value={
                  p.allowMultipleRoutes ? selectedRoutes : selectedRoutes[0]
                }
              />
            </FormGroup>
          )}
        </>
      )}

      {p.allowMultipleRoutes && (
        <>
          {routeIds.length > 1 && (
            <FormGroup>
              <Button block style='warning' onClick={_deselectAllRoutes}>
                <Icon icon={faMinus} /> Deselect all routes
              </Button>
            </FormGroup>
          )}
          {routeIds.length < p.selectedFeed.routes.length && (
            <FormGroup>
              <Button block style='info' onClick={_selectAllRoutes}>
                <Icon icon={faPlus} /> Select all routes
              </Button>
            </FormGroup>
          )}
        </>
      )}
    </>
  )
}
<|endoftext|>


<commit_before>//Connection url
//mongodb://USERNAME:PASSWORD@DBHOST:DBPORT/DBNAME

//Import dependencies
var MongoClient = require('mongodb').MongoClient;

//Database
var db = null;

//Connect to database
exports.Connect = function(opt, callback)
{
	//Check the database status
	if(db){ return callback(); }

	//Create the url
	var url = 'mongodb://' + opt.user + ':' + opt.pass + '@' + opt.host + ':' + opt.port + '/' + opt.db;

	//Else, connect to database
  MongoClient.connect(url, function(err, datab){

		//Check for error
		if(err)
		{
			//Show error in console
			console.error(err);

			//Return with error
			return callback(err);
		}

		//Save the database connection
    db = datab;

		//Do the callback
    callback();

  });
};

//Get the database
exports.Get = function(){ return db; };

//Close the connection
exports.Close = function(callback){

	//Check the database status
  if(state.db)
	{
		//Close the connection to the database
    state.db.close(function(err, result){

			//Destroy the database
			db = null;

			//Do the callback
      callback(err);
    });

  }
};
<commit_msg>Add authSource<commit_after>//Connection url
//mongodb://USERNAME:PASSWORD@DBHOST:DBPORT/DBNAME?authSource=DATABASEADMIN

//Import dependencies
var MongoClient = require('mongodb').MongoClient;

//Database
var db = null;

//Connect to database
exports.Connect = function(opt, callback)
{
	//Check the database status
	if(db){ return callback(); }

	//Create the url
	var url = 'mongodb://' + opt.user + ':' + opt.pass + '@' + opt.host + ':' + opt.port + '/' + opt.db + '?authSource=' + opt.auth;

	//Else, connect to database
	MongoClient.connect(url, function(err, datab){

		//Check for error
		if(err)
		{
			//Show error in console
			console.error(err);

			//Return with error
			return callback(err);
		}

		//Save the database connection
    db = datab;

		//Do the callback
    callback();

  });
};

//Get the database
exports.Get = function(){ return db; };

//Close the connection
exports.Close = function(callback){

	//Check the database status
	if(state.db)
	{
		//Close the connection to the database
    state.db.close(function(err, result){

			//Destroy the database
			db = null;

			//Do the callback
      callback(err);
    });

  }
};
<|endoftext|>