From a3080c337cfaca9d600911396cae5a9233d43554 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Thu, 15 Feb 2018 01:34:00 +0100
Subject: [PATCH] 'update'

---
 README.md                                     |   2 -
 gulpfile.js                                   |   2 -
 models/course.js                              |   6 +-
 models/{assessment.js => evaluation.js}       | 164 ++++++++---------
 public/javascripts/components/statements.js   |   8 +-
 public/javascripts/course.js                  | 116 ++++++------
 .../{assessment.js => evaluation.js}          |  82 ++++-----
 public/javascripts/grade.js                   |  18 +-
 public/javascripts/monitor.js                 |  34 ++--
 public/javascripts/utils/validation.js        |   4 +-
 routes/all.js                                 |   2 +-
 routes/{assessments.js => evaluations.js}     |  60 +++---
 routes/pages.js                               |  40 ++--
 setup/database.js                             |   4 +-
 sockets.js                                    |   8 +-
 views/course.pug                              | 171 +++++++-----------
 views/{assessment.pug => evaluation.pug}      |   0
 views/grade.pug                               |  18 +-
 views/monitor.pug                             |  14 +-
 19 files changed, 356 insertions(+), 397 deletions(-)
 rename models/{assessment.js => evaluation.js} (69%)
 rename public/javascripts/{assessment.js => evaluation.js} (80%)
 rename routes/{assessments.js => evaluations.js} (60%)
 rename views/{assessment.pug => evaluation.pug} (100%)

diff --git a/README.md b/README.md
index 0fc0587..3de47b1 100644
--- a/README.md
+++ b/README.md
@@ -27,8 +27,6 @@ As a teacher, first create an account from the upper-left "login" menu.
 Then create a course using the appropriate button in the middle of the screen.
 Finally, create some exams ("new assessment" button). The syntax for a series of questions is described by the following example:
 
-	> Global (HTML) introduction [optional]
-
 	Question 1 text or introduction (optional if there are subquestions)
 
 		Text for question 1.1 (index detected from indentation)
diff --git a/gulpfile.js b/gulpfile.js
index a1286c5..b05610e 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -9,8 +9,6 @@ var nodemonOptions = {
 	watch: ['./','config','utils','routes','models','entities']
 };
 
-// TODO: tasks for uglify / sass / use webpack
-
 gulp.task('server', function () {
 	nodemon(nodemonOptions)
 	.on('restart', function () {
diff --git a/models/course.js b/models/course.js
index 631bab9..cbe2c44 100644
--- a/models/course.js
+++ b/models/course.js
@@ -1,5 +1,5 @@
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const db = require("../utils/database");
 
 const CourseModel =
@@ -159,8 +159,8 @@ const CourseModel =
 		CourseModel.getById(cid, (err,course) => {
 			if (!!err || !course || !course.uid.equals(uid))
 				return cb({errmsg:"Not your course"},{});
-			// 2) remove all associated assessments
-			AssessmentModel.removeGroup(cid, (err2,ret) => {
+			// 2) remove all associated evaluations
+			EvaluationModel.removeGroup(cid, (err2,ret) => {
 				if (!!err)
 					return cb(err,{});
 				// 3) remove course (with its students)
diff --git a/models/assessment.js b/models/evaluation.js
similarity index 69%
rename from models/assessment.js
rename to models/evaluation.js
index de3d2d7..89f2560 100644
--- a/models/assessment.js
+++ b/models/evaluation.js
@@ -4,7 +4,7 @@ const ObjectId = require("bson-objectid");
 const TokenGen = require("../utils/tokenGenerator");
 const db = require("../utils/database");
 
-const AssessmentModel =
+const EvaluationModel =
 {
 	/*
 	 * Structure:
@@ -24,7 +24,7 @@ const AssessmentModel =
 	 *     options: array of varchar --> if present, question type == quiz!
 	 *     fixed: bool, options in fixed order (default: false)
 	 *     answer: array of integers (for quiz) or html text (for paper); striped in exam mode
-	 *     active: boolean, is question in current assessment?
+	 *     active: boolean, is question in current evaluation?
 	 *     points: points for this question (default 1)
 	 *     param: parameter (if applicable)
 	 *   papers : array of
@@ -40,17 +40,17 @@ const AssessmentModel =
 	//////////////////
 	// BASIC FUNCTIONS
 
-	getById: function(aid, callback)
+	getById: function(eid, callback)
 	{
-		db.assessments.findOne(
-			{ _id: aid },
+		db.evaluations.findOne(
+			{ _id: eid },
 			callback
 		);
 	},
 
 	getByPath: function(cid, name, callback)
 	{
-		db.assessments.findOne(
+		db.evaluations.findOne(
 			{
 				cid: cid,
 				name: name,
@@ -61,7 +61,7 @@ const AssessmentModel =
 
 	insert: function(cid, name, callback)
 	{
-		db.assessments.insert(
+		db.evaluations.insert(
 			{
 				name: name,
 				cid: cid,
@@ -81,34 +81,34 @@ const AssessmentModel =
 
 	getByCourse: function(cid, callback)
 	{
-		db.assessments.find(
+		db.evaluations.find(
 			{ cid: cid },
 			callback
 		);
 	},
 
-	// arg: full assessment without _id field
-	replace: function(aid, assessment, cb)
+	// arg: full evaluation without _id field
+	replace: function(eid, evaluation, cb)
 	{
 		// Should be: (but unsupported by mongojs)
-//		db.assessments.replaceOne(
-//			{ _id: aid },
-//			assessment,
+//		db.evaluations.replaceOne(
+//			{ _id: eid },
+//			evaluation,
 //			cb
 //		);
 		// Temporary workaround:
-		db.assessments.update(
-			{ _id: aid },
-			{ $set: assessment },
+		db.evaluations.update(
+			{ _id: eid },
+			{ $set: evaluation },
 			cb
 		);
 	},
 
-	getQuestions: function(aid, callback)
+	getQuestions: function(eid, callback)
 	{
-		db.assessments.findOne(
+		db.evaluations.findOne(
 			{
-				_id: aid,
+				_id: eid,
 				display: "all",
 			},
 			{ questions: 1},
@@ -118,11 +118,11 @@ const AssessmentModel =
 		);
 	},
 
-	getQuestion: function(aid, index, callback)
+	getQuestion: function(eid, index, callback)
 	{
-		db.assessments.findOne(
+		db.evaluations.findOne(
 			{
-				_id: aid,
+				_id: eid,
 				display: "one",
 			},
 			{ questions: 1},
@@ -137,11 +137,11 @@ const AssessmentModel =
 		);
 	},
 
-	getPaperByNumber: function(aid, number, callback)
+	getPaperByNumber: function(eid, number, callback)
 	{
-		db.assessments.findOne(
+		db.evaluations.findOne(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 			},
 			(err,a) => {
@@ -159,11 +159,11 @@ const AssessmentModel =
 	// NOTE: no callbacks for 2 next functions, failures are not so important
 	// (because monitored: teachers can see what's going on)
 
-	addDisco: function(aid, number, deltaTime)
+	addDisco: function(eid, number, deltaTime)
 	{
-		db.assessments.update(
+		db.evaluations.update(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 			},
 			{ $inc: {
@@ -174,21 +174,21 @@ const AssessmentModel =
 		);
 	},
 
-	setDiscoTime: function(aid, number)
+	setDiscoTime: function(eid, number)
 	{
-		db.assessments.update(
+		db.evaluations.update(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 			},
 			{ $set: { "papers.$.discoTime": Date.now() } }
 		);
 	},
 
-	getDiscoTime: function(aid, number, cb)
+	getDiscoTime: function(eid, number, cb)
 	{
-		db.assessments.findOne(
-			{ _id: aid },
+		db.evaluations.findOne(
+			{ _id: eid },
 			(err,a) => {
 				if (!!err)
 					return cb(err, null);
@@ -198,11 +198,11 @@ const AssessmentModel =
 		);
 	},
 
-	hasInput: function(aid, number, password, idx, cb)
+	hasInput: function(eid, number, password, idx, cb)
 	{
-		db.assessments.findOne(
+		db.evaluations.findOne(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 				"papers.password": password,
 			},
@@ -221,11 +221,11 @@ const AssessmentModel =
 	},
 
 	// https://stackoverflow.com/questions/27874469/mongodb-push-in-nested-array
-	setInput: function(aid, number, password, input, callback) //input: index + arrayOfInt (or txt)
+	setInput: function(eid, number, password, input, callback) //input: index + arrayOfInt (or txt)
 	{
-		db.assessments.update(
+		db.evaluations.update(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 				"papers.password": password,
 			},
@@ -234,11 +234,11 @@ const AssessmentModel =
 		);
 	},
 
-	endAssessment: function(aid, number, password, callback)
+	endEvaluation: function(eid, number, password, callback)
 	{
-		db.assessments.update(
+		db.evaluations.update(
 			{
-				_id: aid,
+				_id: eid,
 				"papers.number": number,
 				"papers.password": password,
 			},
@@ -250,17 +250,17 @@ const AssessmentModel =
 		);
 	},
 
-	remove: function(aid, cb)
+	remove: function(eid, cb)
 	{
-		db.assessments.remove(
-			{ _id: aid },
+		db.evaluations.remove(
+			{ _id: eid },
 			cb
 		);
 	},
 
 	removeGroup: function(cid, cb)
 	{
-		db.assessments.remove(
+		db.evaluations.remove(
 			{ cid: cid },
 			cb
 		);
@@ -277,24 +277,24 @@ const AssessmentModel =
 			CourseModel.getByPath(user._id, code, (err2,course) => {
 				if (!!err2 || !course)
 					return cb(err2 || {errmsg: "Course not found"});
-				AssessmentModel.getByPath(course._id, name, (err3,assessment) => {
-					if (!!err3 || !assessment)
-						return cb(err3 || {errmsg: "Assessment not found"});
-					cb(null,assessment);
+				EvaluationModel.getByPath(course._id, name, (err3,evaluation) => {
+					if (!!err3 || !evaluation)
+						return cb(err3 || {errmsg: "Evaluation not found"});
+					cb(null,evaluation);
 				});
 			});
 		});
 	},
 
-	checkPassword: function(aid, number, password, cb)
+	checkPassword: function(eid, number, password, cb)
 	{
-		AssessmentModel.getById(aid, (err,assessment) => {
-			if (!!err || !assessment)
-				return cb(err, assessment);
-			const paperIdx = assessment.papers.findIndex( item => { return item.number == number; });
+		EvaluationModel.getById(eid, (err,evaluation) => {
+			if (!!err || !evaluation)
+				return cb(err, evaluation);
+			const paperIdx = evaluation.papers.findIndex( item => { return item.number == number; });
 			if (paperIdx === -1)
 				return cb({errmsg: "Paper not found"}, false);
-			cb(null, assessment.papers[paperIdx].password == password);
+			cb(null, evaluation.papers[paperIdx].password == password);
 		});
 	},
 
@@ -306,35 +306,35 @@ const AssessmentModel =
 				return cb({errmsg: "Course retrieval failure"});
 			if (!course.uid.equals(uid))
 				return cb({errmsg:"Not your course"},undefined);
-			// 2) Insert new blank assessment
-			AssessmentModel.insert(cid, name, cb);
+			// 2) Insert new blank evaluation
+			EvaluationModel.insert(cid, name, cb);
 		});
 	},
 
-	update: function(uid, assessment, cb)
+	update: function(uid, evaluation, cb)
 	{
-		const aid = ObjectId(assessment._id);
-		// 1) Check that assessment is owned by user of ID uid
-		AssessmentModel.getById(aid, (err,assessmentOld) => {
-			if (!!err || !assessmentOld)
-				return cb({errmsg: "Assessment retrieval failure"});
-			CourseModel.getById(ObjectId(assessmentOld.cid), (err2,course) => {
+		const eid = ObjectId(evaluation._id);
+		// 1) Check that evaluation is owned by user of ID uid
+		EvaluationModel.getById(eid, (err,evaluationOld) => {
+			if (!!err || !evaluationOld)
+				return cb({errmsg: "Evaluation retrieval failure"});
+			CourseModel.getById(ObjectId(evaluationOld.cid), (err2,course) => {
 				if (!!err2 || !course)
 					return cb({errmsg: "Course retrieval failure"});
 				if (!course.uid.equals(uid))
 					return cb({errmsg:"Not your course"},undefined);
-				// 2) Replace assessment
-				delete assessment["_id"];
-				assessment.cid = ObjectId(assessment.cid);
-				AssessmentModel.replace(aid, assessment, cb);
+				// 2) Replace evaluation
+				delete evaluation["_id"];
+				evaluation.cid = ObjectId(evaluation.cid);
+				EvaluationModel.replace(eid, evaluation, cb);
 			});
 		});
 	},
 
 	// Set password in responses collection
-	startSession: function(aid, number, password, cb)
+	startSession: function(eid, number, password, cb)
 	{
-		AssessmentModel.getPaperByNumber(aid, number, (err,paper) => {
+		EvaluationModel.getPaperByNumber(eid, number, (err,paper) => {
 			if (!!err)
 				return cb(err,null);
 			if (!paper && !!password)
@@ -346,14 +346,14 @@ const AssessmentModel =
 				if (paper.password != password)
 					return cb({errmsg: "Wrong password"});
 			}
-			AssessmentModel.getQuestions(aid, (err2,questions) => {
+			EvaluationModel.getQuestions(eid, (err2,questions) => {
 				if (!!err2)
 					return cb(err2,null);
 				if (!!paper)
 					return cb(null,{paper:paper});
 				const pwd = TokenGen.generate(12); //arbitrary number, 12 seems enough...
-				db.assessments.update(
-					{ _id: aid },
+				db.evaluations.update(
+					{ _id: eid },
 					{ $push: { papers: {
 						number: number,
 						startTime: Date.now(),
@@ -370,15 +370,15 @@ const AssessmentModel =
 		});
 	},
 
-	newAnswer: function(aid, number, password, input, cb)
+	newAnswer: function(eid, number, password, input, cb)
 	{
 		// Check that student hasn't already answered
-		AssessmentModel.hasInput(aid, number, password, input.index, (err,ret) => {
+		EvaluationModel.hasInput(eid, number, password, input.index, (err,ret) => {
 			if (!!err)
 				return cb(err,null);
 			if (!!ret)
 				return cb({errmsg:"Question already answered"},null);
-			AssessmentModel.setInput(aid, number, password, input, (err2,ret2) => {
+			EvaluationModel.setInput(eid, number, password, input, (err2,ret2) => {
 				if (!!err2 || !ret2)
 					return cb(err2,ret2);
 				return cb(null,ret2);
@@ -388,14 +388,14 @@ const AssessmentModel =
 
 	// NOTE: no callbacks for next function, failures are not so important
 	// (because monitored: teachers can see what's going on)
-	newConnection: function(aid, number)
+	newConnection: function(eid, number)
 	{
 		//increment discoCount, reset discoTime to NULL, update totalDisco
-		AssessmentModel.getDiscoTime(aid, number, (err,discoTime) => {
+		EvaluationModel.getDiscoTime(eid, number, (err,discoTime) => {
 			if (!!discoTime)
-				AssessmentModel.addDisco(aid, number, Date.now() - discoTime);
+				EvaluationModel.addDisco(eid, number, Date.now() - discoTime);
 		});
 	},
 }
 
-module.exports = AssessmentModel;
+module.exports = EvaluationModel;
diff --git a/public/javascripts/components/statements.js b/public/javascripts/components/statements.js
index 64057f9..824ce76 100644
--- a/public/javascripts/components/statements.js
+++ b/public/javascripts/components/statements.js
@@ -15,6 +15,8 @@ Imaginary example: (using math.js)
 	$$\begin{matrix}7 & x\\y & -3\end{matrix}$$</div>
 	* ...
 
++ fixed + question time (syntax ?)
+
 --> input of type text (number, or vector, or matrix e.g. in R syntax)
 --> parameter stored in question.param (TODO)
 
@@ -91,8 +93,8 @@ Vue.component("statements", {
 								"input",
 								{
 									domProps: {
-										checked: this.inputs[q.index][idx],
-										disabled: monitoring,
+										checked: !!this.inputs && this.inputs[q.index][idx],
+										disabled: monitoring || this.display == "solution",
 									},
 									attrs: {
 										id: this.inputId(q.index,idx),
@@ -125,7 +127,7 @@ Vue.component("statements", {
 									"class": {
 										option: true,
 										choiceCorrect: this.display == "solution" && q.answer.includes(idx),
-										choiceWrong: this.display == "solution" && this.inputs[q.index][idx] && !q.answer.includes(idx),
+										choiceWrong: this.display == "solution" && !!this.inputs && this.inputs[q.index][idx] && !q.answer.includes(idx),
 									},
 								},
 								option
diff --git a/public/javascripts/course.js b/public/javascripts/course.js
index ab17fe3..65b6ab7 100644
--- a/public/javascripts/course.js
+++ b/public/javascripts/course.js
@@ -1,7 +1,5 @@
 /*Draft format (compiled to json)
 
-> Some global (HTML) intro
-
 <some html question (or/+ exercise intro)>
 
 	<some html subQuestion>
@@ -27,31 +25,32 @@
 new Vue({
 	el: '#course',
 	data: {
-		display: "assessments", //or "students", or "grades" (admin mode)
+		display: "evaluations", //or "students", or "grades" (admin mode)
 		course: course,
-		mode: "view", //or "edit" (some assessment)
 		monitorPwd: "",
-		newAssessment: { name: "" },
-		assessmentArray: assessmentArray,
-		assessmentIndex: 0, //current edited assessment index
-		assessment: { }, //copy of assessment at editing index in array
-		assessmentText: "", //questions in an assessment, in text format
+		newEvaluation: { name: "" },
+		evaluationArray: evaluationArray,
+		mode: "view", //or "edit" (some evaluation)
+		evaluationIndex: 0, //current edited evaluation index
+		evaluation: { }, //copy of evaluation at editing index in array
+		questionsText: "", //questions in an evaluation, in text format
 	},
 	mounted: function() {
+		
+		
+		
 		$('.modal').each( (i,elem) => {
-			if (elem.id != "assessmentEdit")
+			if (elem.id != "evaluationEdit")
 				$(elem).modal();
 		});
-		$('ul.tabs').tabs();
-		$('#assessmentEdit').modal({
+		$('ul.tabs').tabs(); //--> migrate to grade.js
+		
+		
+		
+		$('#evaluationEdit').modal({
 			complete: () => {
-				this.parseAssessment();
-				Vue.nextTick( () => {
-					$("#questionList").find("code[class^=language-]").each( (i,elem) => {
-						Prism.highlightElement(elem);
-					});
-					MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]);
-				});
+				this.parseEvaluation();
+				Vue.nextTick(statementsLibsRefresh);
 			},
 		});
 	},
@@ -108,29 +107,29 @@ new Vue({
 				},
 			});
 		},
-		// ASSESSMENT:
-		addAssessment: function() {
+		// evaluation:
+		addEvaluation: function() {
 			if (!admin)
 				return;
 			// modal, fill code and description
-			let error = Validator.checkObject(this.newAssessment, "Assessment");
+			let error = Validator.checkObject(this.newEvaluation, "Evaluation");
 			if (!!error)
 				return alert(error);
 			else
-				$('#newAssessment').modal('close');
-			$.ajax("/assessments",
+				$('#newEvaluation').modal('close');
+			$.ajax("/evaluations",
 				{
 					method: "POST",
 					data: {
-						name: this.newAssessment.name,
+						name: this.newEvaluation.name,
 						cid: course._id,
 					},
 					dataType: "json",
 					success: res => {
 						if (!res.errmsg)
 						{
-							this.newAssessment["name"] = "";
-							this.assessmentArray.push(res);
+							this.newEvaluation["name"] = "";
+							this.evaluationArray.push(res);
 						}
 						else
 							alert(res.errmsg);
@@ -142,15 +141,15 @@ new Vue({
 			$("#" + id).modal("open");
 			Materialize.updateTextFields(); //textareas, time field...
 		},
-		updateAssessment: function() {
-			$.ajax("/assessments", {
+		updateEvaluation: function() {
+			$.ajax("/evaluations", {
 				method: "PUT",
-				data: {assessment: JSON.stringify(this.assessment)},
+				data: {evaluation: JSON.stringify(this.evaluation)},
 				dataType: "json",
 				success: res => {
 					if (!res.errmsg)
 					{
-						this.assessmentArray[this.assessmentIndex] = this.assessment;
+						this.evaluationArray[this.evaluationIndex] = this.evaluation;
 						this.mode = "view";
 					}
 					else
@@ -158,20 +157,20 @@ new Vue({
 				},
 			});
 		},
-		deleteAssessment: function(assessment) {
+		deleteEvaluation: function(evaluation) {
 			if (!admin)
 				return;
-			if (confirm("Delete assessment '" + assessment.name + "' ?"))
+			if (confirm("Delete evaluation '" + evaluation.name + "' ?"))
 			{
-				$.ajax("/assessments",
+				$.ajax("/evaluations",
 					{
 						method: "DELETE",
-						data: { qid: this.assessment._id },
+						data: { qid: this.evaluation._id },
 						dataType: "json",
 						success: res => {
 							if (!res.errmsg)
-								this.assessmentArray.splice( this.assessmentArray.findIndex( item => {
-									return item._id == assessment._id;
+								this.evaluationArray.splice( this.evaluationArray.findIndex( item => {
+									return item._id == evaluation._id;
 								}), 1 );
 							else
 								alert(res.errmsg);
@@ -181,16 +180,16 @@ new Vue({
 			}
 		},
 		toggleState: function(questionIndex) {
-			// add or remove from activeSet of current assessment
-			let activeIndex = this.assessment.activeSet.findIndex( item => { return item == questionIndex; });
+			// add or remove from activeSet of current evaluation
+			let activeIndex = this.evaluation.activeSet.findIndex( item => { return item == questionIndex; });
 			if (activeIndex >= 0)
-				this.assessment.activeSet.splice(activeIndex, 1);
+				this.evaluation.activeSet.splice(activeIndex, 1);
 			else
-				this.assessment.activeSet.push(questionIndex);
+				this.evaluation.activeSet.push(questionIndex);
 		},
-		setAssessmentText: function() {
+		setEvaluationText: function() {
 			let txt = "";
-			this.assessment.questions.forEach( q => {
+			this.evaluation.questions.forEach( q => {
 				txt += q.wording; //already ended by \n
 				q.options.forEach( (o,i) => {
 					let symbol = q.answer.includes(i) ? "+" : "-";
@@ -198,11 +197,11 @@ new Vue({
 				});
 				txt += "\n"; //separate questions by new line
 			});
-			this.assessmentText = txt;
+			this.questionsText = txt;
 		},
-		parseAssessment: function() {
+		parseEvaluation: function() {
 			let questions = [ ];
-			let lines = this.assessmentText.split("\n").map( L => { return L.trim(); })
+			let lines = this.questionsText.split("\n").map( L => { return L.trim(); })
 			lines.push(""); //easier parsing
 			let emptyQuestion = () => {
 				return {
@@ -239,28 +238,23 @@ new Vue({
 					}
 				}
 			});
-			this.assessment.questions = questions;
+			this.evaluation.questions = questions;
 		},
-		actionAssessment: function(index) {
+		actionEvaluation: function(index) {
 			if (admin)
 			{
 				// Edit screen
-				this.assessmentIndex = index;
-				this.assessment = $.extend(true, {}, this.assessmentArray[index]);
-				this.setAssessmentText();
+				this.evaluationIndex = index;
+				this.evaluation = $.extend(true, {}, this.evaluationArray[index]);
+				this.setEvaluationText();
 				this.mode = "edit";
-				Vue.nextTick( () => {
-					$("#questionList").find("code[class^=language-]").each( (i,elem) => {
-						Prism.highlightElement(elem);
-					});
-					MathJax.Hub.Queue(["Typeset",MathJax.Hub,"questionList"]);
-				});
+				Vue.nextTick(statementsLibsRefresh);
 			}
-			else //external user: show assessment
-				this.redirect(this.assessmentArray[index].name);
+			else //external user: show evaluation
+				this.redirect(this.evaluationArray[index].name);
 		},
-		redirect: function(assessmentName) {
-			document.location.href = "/" + initials + "/" + course.code + "/" + assessmentName;
+		redirect: function(evaluationName) {
+			document.location.href = "/" + initials + "/" + course.code + "/" + evaluationName;
 		},
 		setPassword: function() {
 			let hashPwd = Sha1.Compute(this.monitorPwd);
diff --git a/public/javascripts/assessment.js b/public/javascripts/evaluation.js
similarity index 80%
rename from public/javascripts/assessment.js
rename to public/javascripts/evaluation.js
index 2a451e4..565794f 100644
--- a/public/javascripts/assessment.js
+++ b/public/javascripts/evaluation.js
@@ -1,6 +1,6 @@
 let socket = null; //monitor answers in real time
 
-if (assessment.mode == "secure" && !checkWindowSize())
+if (evaluation.mode == "secure" && !checkWindowSize())
 	document.location.href= "/fullscreen";
 
 function checkWindowSize()
@@ -13,9 +13,9 @@ function checkWindowSize()
 }
 
 new Vue({
-	el: "#assessment",
+	el: "#evaluation",
 	data: {
-		assessment: assessment,
+		evaluation: evaluation,
 		answers: { }, //filled later with answering parameters
 		student: { }, //filled later (name, password)
 		// Stage 0: unauthenticated (number),
@@ -23,13 +23,13 @@ new Vue({
 		//       2: locked: password set, exam started
 		//       3: completed
 		//       4: show answers
-		remainingTime: assessment.time, //integer or array
-		stage: assessment.mode != "open" ? 0 : 1,
+		remainingTime: evaluation.time, //integer or array
+		stage: evaluation.mode != "open" ? 0 : 1,
 		warnMsg: "",
 	},
 	computed: {
 		countdown: function() {
-			const remainingTime = assessment.display == "one" && _.isArray(assessment.time)
+			const remainingTime = evaluation.display == "one" && _.isArray(evaluation.time)
 				? this.remainingTime[this.answers.index]
 				: this.remainingTime;
 			let seconds = remainingTime % 60;
@@ -39,12 +39,12 @@ new Vue({
 	},
 	mounted: function() {
 		$(".modal").modal();
-		if (["exam","open"].includes(assessment.mode))
+		if (["exam","open"].includes(evaluation.mode))
 			return;
 		window.addEventListener("blur", () => {
 			if (this.stage != 2)
 				return;
-			if (assessment.mode == "secure")
+			if (evaluation.mode == "secure")
 			{
 				this.sendAnswer();
 				document.location.href= "/noblur";
@@ -52,7 +52,7 @@ new Vue({
 			else //"watch" mode
 				socket.emit(message.studentBlur, {number:this.student.number});
 		}, false);
-		if (assessment.mode == "watch")
+		if (evaluation.mode == "watch")
 		{
 			window.addEventListener("focus", () => {
 				if (this.stage != 2)
@@ -63,7 +63,7 @@ new Vue({
 		window.addEventListener("resize", e => {
 			if (this.stage != 2)
 				return;
-			if (assessment.mode == "secure")
+			if (evaluation.mode == "secure")
 			{
 				this.sendAnswer();
 				document.location.href = "/fullscreen";
@@ -94,7 +94,7 @@ new Vue({
 				method: "GET",
 				data: {
 					number: this.student.number,
-					cid: assessment.cid,
+					cid: evaluation.cid,
 				},
 				dataType: "json",
 				success: s => {
@@ -111,7 +111,7 @@ new Vue({
 			this.stage = 0;
 		},
 		// stage 1 --> 2 (get all questions, set password)
-		startAssessment: function() {
+		startEvaluation: function() {
 			let initializeStage2 = paper => {
 				$("#leftButton, #rightButton").hide();
 				// Initialize structured answer(s) based on questions type and nesting (TODO: more general)
@@ -121,21 +121,21 @@ new Vue({
 				
 				
 				if (!!questions)
-					assessment.questions = questions;
+					evaluation.questions = questions;
 				this.answers.inputs = [ ];
-				for (let q of assessment.questions)
+				for (let q of evaluation.questions)
 					this.answers.inputs.push( _(q.options.length).times( _.constant(false) ) );
 				if (!paper)
 				{
-					this.answers.indices = assessment.fixed
-						? _.range(assessment.questions.length)
-						: _.shuffle( _.range(assessment.questions.length) );
+					this.answers.indices = evaluation.fixed
+						? _.range(evaluation.questions.length)
+						: _.shuffle( _.range(evaluation.questions.length) );
 				}
 				else
 				{
 					// Resuming
 					let indices = paper.inputs.map( input => { return input.index; });
-					let remainingIndices = _.difference( _.range(assessment.questions.length).map(String), indices );
+					let remainingIndices = _.difference( _.range(evaluation.questions.length).map(String), indices );
 					this.answers.indices = indices.concat( _.shuffle(remainingIndices) );
 				}
 
@@ -145,29 +145,29 @@ new Vue({
 
 
 
-				if (assessment.time > 0)
+				if (evaluation.time > 0)
 				{
 
 // TODO: distinguish total exam time AND question time
 
 					const deltaTime = !!paper ? Date.now() - paper.startTime : 0;
-					this.remainingTime = assessment.time * 60 - Math.round(deltaTime / 1000);
+					this.remainingTime = evaluation.time * 60 - Math.round(deltaTime / 1000);
 					this.runTimer();
 				}
 
 
 				this.answers.index = !!paper ? paper.inputs.length : 0;
-				this.answers.displayAll = assessment.display == "all";
+				this.answers.displayAll = evaluation.display == "all";
 				this.answers.showSolution = false;
 				this.stage = 2;
 			};
-			if (assessment.mode == "open")
+			if (evaluation.mode == "open")
 				return initializeStage2();
-			$.ajax("/assessments/start", {
+			$.ajax("/evaluations/start", {
 				method: "PUT",
 				data: {
 					number: this.student.number,
-					aid: assessment._id
+					aid: evaluation._id
 				},
 				dataType: "json",
 				success: s => {
@@ -186,7 +186,7 @@ new Vue({
 						// action (power failure, computer down, ...)
 					}
 					socket = io.connect("/", {
-						query: "aid=" + assessment._id + "&number=" + this.student.number + "&password=" + this.student.password
+						query: "aid=" + evaluation._id + "&number=" + this.student.number + "&password=" + this.student.password
 					});
 					socket.on(message.allAnswers, this.setAnswers);
 					initializeStage2(s.questions, s.paper);
@@ -197,7 +197,7 @@ new Vue({
 
 		// stage 2
 		runGlobalTimer: function() {
-			if (assessment.time <= 0)
+			if (evaluation.time <= 0)
 				return;
 			let self = this;
 			setInterval( function() {
@@ -205,13 +205,13 @@ new Vue({
 				if (self.remainingTime <= 0)
 				{
 					if (self.stage == 2)
-						self.endAssessment();
+						self.endEvaluation();
 					clearInterval(this);
 				}
 			}, 1000);
 		},
 		runQuestionTimer: function(idx) {
-			if (assessment.questions[idx].time <= 0)
+			if (evaluation.questions[idx].time <= 0)
 				return;
 			let self = this; //TODO: question remaining time
 			setInterval( function() {
@@ -219,7 +219,7 @@ new Vue({
 				if (self.remainingTime <= 0)
 				{
 					if (self.stage == 2)
-						self.endAssessment();
+						self.endEvaluation();
 					clearInterval(this);
 				}
 			}, 1000);
@@ -231,16 +231,16 @@ new Vue({
 		sendOneAnswer: function() {
 			const realIndex = this.answers.indices[this.answers.index];
 			let gotoNext = () => {
-				if (this.answers.index == assessment.questions.length - 1)
-					this.endAssessment();
+				if (this.answers.index == evaluation.questions.length - 1)
+					this.endEvaluation();
 				else
 					this.answers.index++;
 				this.$children[0].$forceUpdate(); //TODO: bad HACK, and shouldn't be required...
 			};
-			if (assessment.mode == "open")
+			if (evaluation.mode == "open")
 				return gotoNext(); //only local
 			let answerData = {
-				aid: assessment._id,
+				aid: evaluation._id,
 				answer: JSON.stringify({
 					index: realIndex.toString(),
 					input: this.answers.inputs[realIndex]
@@ -251,7 +251,7 @@ new Vue({
 				number: this.student.number,
 				password: this.student.password,
 			};
-			$.ajax("/assessments/answer", {
+			$.ajax("/evaluations/answer", {
 				method: "PUT",
 				data: answerData,
 				dataType: "json",
@@ -265,27 +265,27 @@ new Vue({
 		},
 		// TODO: I don't like that + sending should not be definitive in exam mode with display = all
 		sendAnswer: function() {
-			if (assessment.display == "one")
+			if (evaluation.display == "one")
 				this.sendOneAnswer();
 			else
-				assessment.questions.forEach(this.sendOneAnswer);
+				evaluation.questions.forEach(this.sendOneAnswer);
 		},
 		// stage 2 --> 3 (or 4)
 		// from a message by statements component, or time over
-		endAssessment: function() {
+		endEvaluation: function() {
 			// Set endTime, destroy password
 			$("#leftButton, #rightButton").show();
-			if (assessment.mode == "open")
+			if (evaluation.mode == "open")
 			{
 				this.stage = 4;
 				this.answers.showSolution = true;
 				this.answers.displayAll = true;
 				return;
 			}
-			$.ajax("/assessments/end", {
+			$.ajax("/evaluations/end", {
 				method: "PUT",
 				data: {
-					aid: assessment._id,
+					aid: evaluation._id,
 					number: this.student.number,
 					password: this.student.password,
 				},
@@ -302,7 +302,7 @@ new Vue({
 		setAnswers: function(m) {
 			const answers = JSON.parse(m.answers);
 			for (let i=0; i<answers.length; i++)
-				assessment.questions[i].answer = answers[i];
+				evaluation.questions[i].answer = answers[i];
 			this.answers.showSolution = true;
 			this.answers.displayAll = true;
 			this.stage = 4;
diff --git a/public/javascripts/grade.js b/public/javascripts/grade.js
index 334b2a3..d0f04cf 100644
--- a/public/javascripts/grade.js
+++ b/public/javascripts/grade.js
@@ -3,7 +3,7 @@
 new Vue({
 	el: '#grade',
 	data: {
-		assessmentArray: assessmentArray,
+		evaluationArray: evaluationArray,
 		settings: {
 			totalPoints: 20,
 			halfPoints: false,
@@ -29,16 +29,16 @@ new Vue({
 				let gradesCount = 0;
 				if (!!this.grades[s.number])
 				{
-					Object.keys(this.grades[s.number]).forEach( assessmentName => {
-						s[assessmentName] = this.grades[s.number][assessmentName];
-						if (_.isNumeric(s[assessmentName]) && !isNaN(s[assessmentName]))
+					Object.keys(this.grades[s.number]).forEach( evaluationName => {
+						s[evaluationName] = this.grades[s.number][evaluationName];
+						if (_.isNumeric(s[evaluationName]) && !isNaN(s[evaluationName]))
 						{
-							finalGrade += s[assessmentName];
+							finalGrade += s[evaluationName];
 							gradesCount++;
 						}
 						if (gradesCount >= 1)
 							finalGrade /= gradesCount;
-						s["final"] = finalGrade; //TODO: forbid "final" as assessment name
+						s["final"] = finalGrade; //TODO: forbid "final" as evaluation name
 					});
 				}
 				data.push(s); //number,name,group,assessName1...assessNameN,final
@@ -65,10 +65,10 @@ new Vue({
 			});
 			return _.range(1,maxGrp+1);
 		},
-		grade: function(assessmentIndex, studentNumber) {
-			if (!this.grades[assessmentIndex] || !this.grades[assessmentIndex][studentNumber])
+		grade: function(evaluationIndex, studentNumber) {
+			if (!this.grades[evaluationIndex] || !this.grades[evaluationIndex][studentNumber])
 				return ""; //no grade yet
-			return this.grades[assessmentIndex][studentNumber];
+			return this.grades[evaluationIndex][studentNumber];
 		},
 		groupId: function(group, prefix) {
 			return (prefix || "") + "group" + group;
diff --git a/public/javascripts/monitor.js b/public/javascripts/monitor.js
index 29ce858..9b3964b 100644
--- a/public/javascripts/monitor.js
+++ b/public/javascripts/monitor.js
@@ -4,7 +4,7 @@ new Vue({
 	el: "#monitor",
 	data: {
 		password: "", //from password field
-		assessment: { }, //obtained after authentication
+		evaluation: { }, //obtained after authentication
 		// Stage 0: unauthenticated (password),
 		//       1: authenticated (password hash validated), start monitoring
 		stage: 0,
@@ -15,7 +15,7 @@ new Vue({
 			index : -1,
 		},
 		students: [ ], //to know their names
-		display: "assessment", //or student's answers
+		display: "evaluation", //or student's answers
 	},
 	methods: {
 		// TODO: redundant code, next 4 funcs already exist in course.js
@@ -52,11 +52,11 @@ new Vue({
 			{
 				if (!s.present)
 					continue;
-				const paperIdx = this.assessment.papers.findIndex( item => { return item.number == s.number; });
+				const paperIdx = this.evaluation.papers.findIndex( item => { return item.number == s.number; });
 				if (paperIdx === -1)
 					return false;
-				const paper = this.assessment.papers[paperIdx];
-				if (paper.inputs.length < this.assessment.questions.length)
+				const paper = this.evaluation.papers[paperIdx];
+				if (paper.inputs.length < this.evaluation.questions.length)
 					return false;
 			}
 			return true;
@@ -64,16 +64,16 @@ new Vue({
 		getColor: function(number, qIdx) {
 			// For the moment, green if correct and red if wrong; grey if unanswered yet
 			// TODO: in-between color for partially right (especially for multi-questions)
-			const paperIdx = this.assessment.papers.findIndex( item => { return item.number == number; });
+			const paperIdx = this.evaluation.papers.findIndex( item => { return item.number == number; });
 			if (paperIdx === -1)
 				return "grey"; //student didn't start yet
-			const inputIdx = this.assessment.papers[paperIdx].inputs.findIndex( item => {
+			const inputIdx = this.evaluation.papers[paperIdx].inputs.findIndex( item => {
 				const qNum = parseInt(item.index.split(".")[0]); //indexes separated by dots
 				return qIdx == qNum;
 			});
 			if (inputIdx === -1)
 				return "grey";
-			if (_.isEqual(this.assessment.papers[paperIdx].inputs[inputIdx].input, this.assessment.questions[qIdx].answer))
+			if (_.isEqual(this.evaluation.papers[paperIdx].inputs[inputIdx].input, this.evaluation.questions[qIdx].answer))
 				return "green";
 			return "red";
 		},
@@ -82,7 +82,7 @@ new Vue({
 		},
 		// stage 0 --> 1
 		startMonitoring: function() {
-			$.ajax("/assessments/monitor", {
+			$.ajax("/evaluations/monitor", {
 				method: "GET",
 				data: {
 					password: Sha1.Compute(this.password),
@@ -94,8 +94,8 @@ new Vue({
 				success: s => {
 					if (!!s.errmsg)
 						return alert(s.errmsg);
-					this.assessment = s.assessment;
-					this.answers.inputs = s.assessment.questions.map( q => {
+					this.evaluation = s.evaluation;
+					this.answers.inputs = s.evaluation.questions.map( q => {
 						let input = _(q.options.length).times( _.constant(false) );
 						q.answer.forEach( idx => { input[idx] = true; });
 						return input;
@@ -104,7 +104,7 @@ new Vue({
 					this.students.forEach( s => { s.present = true; }); //a priori...
 					this.stage = 1;
 					socket = io.connect("/", {
-						query: "aid=" + this.assessment._id + "&secret=" + s.secret
+						query: "aid=" + this.evaluation._id + "&secret=" + s.secret
 					});
 					socket.on(message.studentBlur, m => {
 						const sIdx = this.students.findIndex( item => { return item.number == m.number; });
@@ -134,20 +134,20 @@ new Vue({
 						this.students[sIdx].disco = false;
 					});
 					socket.on(message.newAnswer, m => {
-						let paperIdx = this.assessment.papers.findIndex( item => {
+						let paperIdx = this.evaluation.papers.findIndex( item => {
 							return item.number == m.number;
 						});
 						if (paperIdx === -1)
 						{
 							// First answer
-							paperIdx = this.assessment.papers.length;
-							this.assessment.papers.push({
+							paperIdx = this.evaluation.papers.length;
+							this.evaluation.papers.push({
 								number: m.number,
 								inputs: [ ], //other fields irrelevant here
 							});
 						}
 						// TODO: notations not coherent (input / answer... when, which ?)
-						this.assessment.papers[paperIdx].inputs.push(JSON.parse(m.answer)); //input+index
+						this.evaluation.papers[paperIdx].inputs.push(JSON.parse(m.answer)); //input+index
 					});
 				},
 			});
@@ -157,7 +157,7 @@ new Vue({
 			// TODO: disable this button until everyone finished (need ability to mark absents)
 			socket.emit(
 				message.allAnswers,
-				{ answers: JSON.stringify(this.assessment.questions.map( q => { return q.answer; })) }
+				{ answers: JSON.stringify(this.evaluation.questions.map( q => { return q.answer; })) }
 			);
 		},
 	},
diff --git a/public/javascripts/utils/validation.js b/public/javascripts/utils/validation.js
index 625fb42..f604f77 100644
--- a/public/javascripts/utils/validation.js
+++ b/public/javascripts/utils/validation.js
@@ -2,7 +2,7 @@ try { var _ = require("underscore"); } catch (err) {} //for server
 
 let Validator = { };
 
-// Cell in assessment.questions array
+// Cell in evaluation.questions array
 Validator.Question = {
 	"index": "section", //"2.2.1", "3.2", "1" ...etc
 	"wording": "string",
@@ -32,7 +32,7 @@ Validator.Paper = {
 	"password": "password",
 };
 
-Validator.Assessment = {
+Validator.Evaluation = {
 	"_id": "bson",
 	"cid": "bson",
 	"name": "code",
diff --git a/routes/all.js b/routes/all.js
index 1c0d052..4ca00ea 100644
--- a/routes/all.js
+++ b/routes/all.js
@@ -3,7 +3,7 @@ var router = require("express").Router();
 // AJAX requests:
 router.use("/", require("./users"));
 router.use("/", require("./courses"));
-router.use("/", require("./assessments"));
+router.use("/", require("./evaluations"));
 
 // Pages:
 router.use("/", require("./pages"));
diff --git a/routes/assessments.js b/routes/evaluations.js
similarity index 60%
rename from routes/assessments.js
rename to routes/evaluations.js
index 03e483e..18f57f7 100644
--- a/routes/assessments.js
+++ b/routes/evaluations.js
@@ -1,7 +1,7 @@
 let router = require("express").Router();
 const access = require("../utils/access");
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const CourseModel = require("../models/course");
 const params = require("../config/parameters");
 const validator = require("../public/javascripts/utils/validation");
@@ -17,47 +17,47 @@ const sanitizeOpts = {
 	},
 };
 
-router.post("/assessments", access.ajax, access.logged, (req,res) => {
+router.post("/evaluations", access.ajax, access.logged, (req,res) => {
 	const name = req.body["name"];
 	const cid = req.body["cid"];
-	let error = validator({cid:cid, name:name}, "Assessment");
+	let error = validator({cid:cid, name:name}, "Evaluation");
 	if (error.length > 0)
 		return res.json({errmsg:error});
-	AssessmentModel.add(req.user._id, ObjectId(cid), name, (err,assessment) => {
-		access.checkRequest(res, err, assessment, "Assessment addition failed", () => {
-			res.json(assessment);
+	EvaluationModel.add(req.user._id, ObjectId(cid), name, (err,evaluation) => {
+		access.checkRequest(res, err, evaluation, "Evaluation addition failed", () => {
+			res.json(evaluation);
 		});
 	});
 });
 
-router.put("/assessments", access.ajax, access.logged, (req,res) => {
-	const assessment = JSON.parse(req.body["assessment"]);
-	let error = validator(assessment, "Assessment");
+router.put("/evaluations", access.ajax, access.logged, (req,res) => {
+	const evaluation = JSON.parse(req.body["evaluation"]);
+	let error = validator(evaluation, "Evaluation");
 	if (error.length > 0)
 		return res.json({errmsg:error});
-	assessment.introduction = sanitizeHtml(assessment.introduction, sanitizeOpts);
-	assessment.questions.forEach( q => {
+	evaluation.introduction = sanitizeHtml(evaluation.introduction, sanitizeOpts);
+	evaluation.questions.forEach( q => {
 		q.wording = sanitizeHtml(q.wording, sanitizeOpts);
 		//q.answer = sanitizeHtml(q.answer); //if text (TODO: it's an array in this case?!)
 		for (let i=0; i<q.options.length; i++) //if QCM
 			q.options[i] = sanitizeHtml(q.options[i], sanitizeOpts);
 	});
-	AssessmentModel.update(req.user._id, assessment, (err,ret) => {
-		access.checkRequest(res, err, ret, "Assessment update failed", () => {
+	EvaluationModel.update(req.user._id, evaluation, (err,ret) => {
+		access.checkRequest(res, err, ret, "Evaluation update failed", () => {
 			res.json({});
 		});
 	});
 });
 
 // Generate and set student password, return it
-router.put("/assessments/start", access.ajax, (req,res) => {
+router.put("/evaluations/start", access.ajax, (req,res) => {
 	let number = req.body["number"];
-	let aid = req.body["aid"];
+	let eid = req.body["eid"];
 	let password = req.cookies["password"]; //potentially from cookies, resuming
-	let error = validator({ _id:aid, papers:[{number:number,password:password || "samplePwd"}] }, "Assessment");
+	let error = validator({ _id:eid, papers:[{number:number,password:password || "samplePwd"}] }, "Evaluation");
 	if (error.length > 0)
 		return res.json({errmsg:error});
-	AssessmentModel.startSession(ObjectId(aid), number, password, (err,ret) => {
+	EvaluationModel.startSession(ObjectId(eid), number, password, (err,ret) => {
 		access.checkRequest(res,err,ret,"Failed session initialization", () => {
 			if (!password)
 			{
@@ -72,7 +72,7 @@ router.put("/assessments/start", access.ajax, (req,res) => {
 	});
 });
 
-router.get("/assessments/monitor", access.ajax, (req,res) => {
+router.get("/evaluations/monitor", access.ajax, (req,res) => {
 	const password = req.query["password"];
 	const examName = req.query["aname"];
 	const courseCode = req.query["ccode"];
@@ -82,11 +82,11 @@ router.get("/assessments/monitor", access.ajax, (req,res) => {
 		access.checkRequest(res,err,course,"Course not found", () => {
 			if (password != course.password)
 				return res.json({errmsg: "Wrong password"});
-			AssessmentModel.getByRefs(initials, courseCode, examName, (err2,assessment) => {
-				access.checkRequest(res,err2,assessment,"Assessment not found", () => {
+			EvaluationModel.getByRefs(initials, courseCode, examName, (err2,evaluation) => {
+				access.checkRequest(res,err2,evaluation,"Evaluation not found", () => {
 					res.json({
 						students: course.students,
-						assessment: assessment,
+						evaluation: evaluation,
 						secret: params.secret,
 					});
 				});
@@ -95,31 +95,31 @@ router.get("/assessments/monitor", access.ajax, (req,res) => {
 	});
 });
 
-router.put("/assessments/answer", access.ajax, (req,res) => {
-	let aid = req.body["aid"];
+router.put("/evaluations/answer", access.ajax, (req,res) => {
+	let eid = req.body["eid"];
 	let number = req.body["number"];
 	let password = req.body["password"];
 	let input = JSON.parse(req.body["answer"]);
-	let error = validator({ _id:aid, papers:[{number:number,password:password,inputs:[input]}] }, "Assessment");
+	let error = validator({ _id:eid, papers:[{number:number,password:password,inputs:[input]}] }, "Evaluation");
 	if (error.length > 0)
 		return res.json({errmsg:error});
-	AssessmentModel.newAnswer(ObjectId(aid), number, password, input, (err,ret) => {
+	EvaluationModel.newAnswer(ObjectId(eid), number, password, input, (err,ret) => {
 		access.checkRequest(res,err,ret,"Cannot send answer", () => {
 			res.json({});
 		});
 	});
 });
 
-router.put("/assessments/end", access.ajax, (req,res) => {
-	let aid = req.body["aid"];
+router.put("/evaluations/end", access.ajax, (req,res) => {
+	let eid = req.body["eid"];
 	let number = req.body["number"];
 	let password = req.body["password"];
-	let error = validator({ _id:aid, papers:[{number:number,password:password}] }, "Assessment");
+	let error = validator({ _id:eid, papers:[{number:number,password:password}] }, "Evaluation");
 	if (error.length > 0)
 		return res.json({errmsg:error});
 	// Destroy pwd, set endTime
-	AssessmentModel.endAssessment(ObjectId(aid), number, password, (err,ret) => {
-		access.checkRequest(res,err,ret,"Cannot end assessment", () => {
+	EvaluationModel.endEvaluation(ObjectId(eid), number, password, (err,ret) => {
+		access.checkRequest(res,err,ret,"Cannot end evaluation", () => {
 			res.clearCookie('password');
 			res.json({});
 		});
diff --git a/routes/pages.js b/routes/pages.js
index c92f2e7..2acefc0 100644
--- a/routes/pages.js
+++ b/routes/pages.js
@@ -1,12 +1,12 @@
 let router = require("express").Router();
 const access = require("../utils/access");
 const UserModel = require("../models/user");
-const AssessmentModel = require("../models/assessment");
+const EvaluationModel = require("../models/evaluation");
 const CourseModel = require("../models/course");
 
 // Actual pages (least specific last)
 
-// List initials and count assessments
+// List initials and count evaluations
 router.get("/", (req,res) => {
 	UserModel.getAll( (err,userArray) => {
 		if (!!err)
@@ -75,7 +75,7 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)", (req,res) => {
 	let code = req.params["courseCode"];
 	CourseModel.getByRefs(initials, code, (err,course) => {
 		access.checkRequest(res, err, course, "Course not found", () => {
-			AssessmentModel.getByCourse(course._id, (err2,assessmentArray) => {
+			EvaluationModel.getByCourse(course._id, (err2,evaluationArray) => {
 				if (!!err)
 					return res.json(err);
 				access.getUser(req, res, (err2,user) => {
@@ -86,7 +86,7 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)", (req,res) => {
 					res.render("course", {
 						title: "course " + initials + "/" + code,
 						course: course,
-						assessmentArray: assessmentArray,
+						evaluationArray: evaluationArray,
 						teacher: isTeacher,
 						initials: initials,
 					});
@@ -108,17 +108,17 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/grade", (req,res) =>
 	});
 });
 
-// Display assessment (exam or open status)
-router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)", (req,res) => {
+// Display evaluation (exam or open status)
+router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:evaluationName([a-z0-9._-]+)", (req,res) => {
 	let initials = req.params["initials"];
 	let code = req.params["courseCode"];
-	let name = req.params["assessmentName"];
-	AssessmentModel.getByRefs(initials, code, name, (err,assessment) => {
-		access.checkRequest(res, err, assessment, "Assessment not found", () => {
-			if (!assessment.active)
-				return res.json({errmsg: "Assessment is idle"});
-			delete assessment["papers"]; //always remove recorded students answers
-			if (assessment.mode == "exam")
+	let name = req.params["evaluationName"];
+	EvaluationModel.getByRefs(initials, code, name, (err,evaluation) => {
+		access.checkRequest(res, err, evaluation, "Evaluation not found", () => {
+			if (!evaluation.active)
+				return res.json({errmsg: "Evaluation is idle"});
+			delete evaluation["papers"]; //always remove recorded students answers
+			if (evaluation.mode == "exam")
 			{
 				if (!!req.headers['user-agent'].match(/(SpecialAgent|HeadlessChrome|PhantomJS)/))
 				{
@@ -126,24 +126,24 @@ router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z
 					return res.json({errmsg: "Headless browser detected"});
 				}
 				// Strip questions if exam mode (stepwise process)
-				delete assessment["questions"];
+				delete evaluation["questions"];
 			}
-			res.render("assessment", {
-				title: "assessment " + initials + "/" + code + "/" + name,
-				assessment: assessment,
+			res.render("evaluation", {
+				title: "evaluation " + initials + "/" + code + "/" + name,
+				evaluation: evaluation,
 			});
 		});
 	});
 });
 
 // Monitor: --> after identification (password), always send secret with requests
-router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:assessmentName([a-z0-9._-]+)/monitor", (req,res) => {
+router.get("/:initials([a-z0-9]+)/:courseCode([a-z0-9._-]+)/:evaluationName([a-z0-9._-]+)/monitor", (req,res) => {
 	let initials = req.params["initials"];
 	let code = req.params["courseCode"];
-	let name = req.params["assessmentName"];
+	let name = req.params["evaluationName"];
 	// TODO: if (main) teacher, also send secret, saving one request
 	res.render("monitor", {
-		title: "monitor assessment " + code + "/" + name,
+		title: "monitor evaluation " + code + "/" + name,
 		initials: initials,
 		courseCode: code,
 		examName: name,
diff --git a/setup/database.js b/setup/database.js
index b9a392d..2070e71 100644
--- a/setup/database.js
+++ b/setup/database.js
@@ -6,8 +6,8 @@
 // courses
 //   unique (code,uid)
 //   index (code,uid)
-// assessments
+// evaluations
 //   unique (cid, name)
 //   index (cid, name)
-// db.assessments.createIndex( { cid: 1, name: 1 } );
+// db.evaluations.createIndex( { cid: 1, name: 1 } );
 // https://docs.mongodb.com/manual/core/index-compound/
diff --git a/sockets.js b/sockets.js
index 30beb32..dafe6d9 100644
--- a/sockets.js
+++ b/sockets.js
@@ -1,6 +1,6 @@
 const message = require("./public/javascripts/utils/socketMessages");
 const params = require("./config/parameters");
-const AssessmentModel = require("./models/assessment");
+const EvaluationModel = require("./models/evaluation");
 const ObjectId = require("bson-objectid");
 
 module.exports = function(io)
@@ -20,10 +20,10 @@ module.exports = function(io)
 		{
 			const number = socket.handshake.query.number;
 			const password = socket.handshake.query.password;
-			AssessmentModel.checkPassword(ObjectId(aid), number, password, (err,ret) => {
+			EvaluationModel.checkPassword(ObjectId(aid), number, password, (err,ret) => {
 				if (!!err || !ret)
 					return; //wrong password, or some unexpected error...
-				AssessmentModel.newConnection(ObjectId(aid), number);
+				EvaluationModel.newConnection(ObjectId(aid), number);
 				socket.broadcast.to(aid + "_teacher").emit(message.studentConnect, {number: number});
 				socket.join(aid + "_student");
 				socket.on(message.newAnswer, m => { //got answer from student client
@@ -42,7 +42,7 @@ module.exports = function(io)
 					socket.broadcast.to(aid + "_teacher").emit(message.studentFullscreen, m);
 				});
 				socket.on("disconnect", () => { //notify monitor + server
-					AssessmentModel.setDiscoTime(ObjectId(aid), number);
+					EvaluationModel.setDiscoTime(ObjectId(aid), number);
 					socket.broadcast.to(aid + "_teacher").emit(message.studentDisconnect, {number: number});
 				});
 			});
diff --git a/views/course.pug b/views/course.pug
index 34bf462..9d84018 100644
--- a/views/course.pug
+++ b/views/course.pug
@@ -7,74 +7,19 @@ block append stylesheets
 block content
 	.container#course
 		if teacher
-			#newAssessment.modal
+			#newevaluation.modal
 				.modal-content
-					form(@submit.prevent="addAssessment")
+					form(@submit.prevent="addevaluation")
 						.input-field
-							input#assessmentName(type="text" v-model="newAssessment.name" required)
-							label(for="assessmentName") Name
+							input#evaluationName(type="text" v-model="newEvaluation.name" required)
+							label(for="evaluationName") Name
 				.modal-footer
 					.center-align
-						a.waves-effect.waves-light.btn(href="#!" @click="addAssessment()")
+						a.waves-effect.waves-light.btn(href="#!" @click="addEvaluation()")
 							span Submit
 							i.material-icons.right send
-		.row(v-show="mode=='view'")
-			
-			
-			
-			
-			
-			
-			
-			
-			#assessmentEdit
-				form
-					p
-						input#active(type="checkbox" v-model="assessment.active")
-						label(for="active") Assessment is active
-					div
-						h4 Questions mode:
-						span(title="Exam mode, secured (class only): students cannot lose focus or exit fullscreen")
-							input#secure(name="status" type="radio" value="secure" v-model="assessment.mode")
-							label(for="secure") secure
-						span(title="Exam mode, watched (class only): teachers are notified when students lose focus or resize window")
-							input#watch(name="status" type="radio" value="watch" v-model="assessment.mode")
-							label(for="watch") watch
-						span(title="Exam mode, unwatched: students can browse the web freely")
-							input#exam(name="status" type="radio" value="exam" v-model="assessment.mode")
-							label(for="exam") exam
-						span(title="Questions list open to the world (useful mode after an exam, or for a 'questions bank'")
-							input#open(name="status" type="radio" value="open" v-model="assessment.mode")
-							label(for="open") open
-					p
-						input#fixed(type="checkbox" v-model="assessment.fixed")
-						label(for="fixed") Fixed questions order
-					div
-						h4 Display type:
-						span(title="Show only one question at a time (with potential sub-questions)")
-							input#displayOne(name="display" type="radio" value="one" v-model="assessment.display")
-							label(for="displayOne") one
-						span(title="Always show all questions (with an optional navigator)")
-							input#displayAll(name="display" type="radio" value="all" v-model="assessment.display")
-							label(for="displayAll") all
-					.input-field
-						input#time(type="number" v-model.number="assessment.time")
-						label(for="time") Time (minutes)
-					.input-field
-						textarea#introduction.materialize-textarea(v-model="assessment.introduction")
-						label(for="introduction") Introduction
-					.input-field
-						textarea#assessmentEdition.materialize-textarea(v-model="assessmentText")
-						label(for="assessmentEdition") Assessment in text format
-			
-			
-			
-			
-			
-			
-			
-			.col.s12.m10.offset-m1
-				if teacher
+			.row
+				.col.s12.m10.offset-m1
 					h4.title(@click="toggleDisplay('students')") Students
 					.card(v-show="display=='students'")
 						.center-align
@@ -91,11 +36,13 @@ block content
 									td {{ student.number }}
 									td {{ student.name }}
 									td {{ student.group }}
-				h4.title(@click="toggleDisplay('assessments')") Assessments
-				.card(v-show="display=='assessments'")
+		.row
+			.col.s12.m10.offset-m1
+				h4.title(@click="toggleDisplay('evaluations')") evaluations
+				.card(v-show="display=='evaluations'")
 					if teacher
 						.center-align
-							a.on-left.waves-effect.waves-light.btn.modal-trigger(href="#newAssessment") New assessment
+							a.on-left.waves-effect.waves-light.btn.modal-trigger(href="#newevaluation") New evaluation
 							input#password(type="password" v-model="monitorPwd" @keyup.enter="setPassword"
 									placeholder="Password" title="Monitoring password")
 					table
@@ -104,54 +51,74 @@ block content
 								th Name
 								th Mode
 								th #Questions
-								th Time
 						tbody
-							tr.assessment(v-for="(assessment,i) in assessmentArray" :class="{idle:!assessment.active}"
-									@click.left="actionAssessment(i)" @contextmenu.prevent="deleteAssessment(assessment)")
-								td {{ assessment.name }}
-								td {{ assessment.mode }}
-								td {{ assessment.questions.reduce( (a,b) => { return b.active ? a+1 : a; }, 0) }}
-								td {{ assessment.time }}
+							tr.evaluation(v-for="(evaluation,i) in evaluationArray" :class="{idle:!evaluation.active}"
+									@click.left="actionevaluation(i)" @contextmenu.prevent="deleteevaluation(evaluation)")
+								td {{ evaluation.name }}
+								td {{ evaluation.mode }}
+								td {{ evaluation.questions.length }}
 		if teacher
-			.row(v-show="mode=='edit'")
+			.row
 				.col.s12.m10.offset-m1
-
-
-
-
-					// TODO: always edit mode, with a modal preview
-
-
-
-					h4 {{ assessment.name }}
-					.card
-						.center-align
-							button.waves-effect.waves-light.btn.on-left(@click="materialOpenModal('assessmentSettings')") Settings
-							button.waves-effect.waves-light.btn.on-left(@click="materialOpenModal('assessmentEdit')") Content
-							button.waves-effect.waves-light.btn(@click="redirect(assessment.name)") View
-						#questionList
-							.introduction(v-html="assessment.introduction")
-							.question(v-for="(question,i) in assessment.questions" :class="{questionInactive:!question.active}")
-								.wording(v-html="question.wording")
-								.option(v-for="(option,j) in question.options" :class="{choiceCorrect:question.answer.includes(j)}" v-html="option")
-								p
-									input(:id="checkboxFixedId(i)" type="checkbox" v-model="question.fixed")
-									label.on-left(:for="checkboxFixedId(i)") Fixed
-									input(:id="checkboxActiveId(i)" type="checkbox" v-model="question.active")
-									label(:for="checkboxActiveId(i)") Active
-									input(time default 0 = untimed)
-									label Time for the question
+					h4 {{ evaluation.name }}
+					.card(v-show="mode=='view'")
 						.center-align
-							button.waves-effect.waves-light.btn.on-left(@click="mode='view'") Cancel
-							button.waves-effect.waves-light.btn(@click="updateAssessment") Send
+							button.waves-effect.waves-light.btn.on-left(@click="mode='edit'") Edit
+							button.waves-effect.waves-light.btn(@click="redirect(evaluation.name)") View
+						div
+							.introduction(v-html="evaluation.introduction")
+							statements(:questions="evaluation.questions" :display="solution")
+					.card(v-show="mode=='edit'")
+						form(@submit.prevent)
+							p
+								input#active(type="checkbox" v-model="evaluation.active")
+								label(for="active") evaluation is active
+							div
+								h4 Questions mode:
+								span(title="Exam mode, secured (class only): students cannot lose focus or exit fullscreen")
+									input#secure(name="status" type="radio" value="secure" v-model="evaluation.mode")
+									label(for="secure") secure
+								span(title="Exam mode, watched (class only): teachers are notified when students lose focus or resize window")
+									input#watch(name="status" type="radio" value="watch" v-model="evaluation.mode")
+									label(for="watch") watch
+								span(title="Exam mode, unwatched: students can browse the web freely")
+									input#exam(name="status" type="radio" value="exam" v-model="evaluation.mode")
+									label(for="exam") exam
+								span(title="Questions list open to the world (useful mode after an exam, or for a 'questions bank'")
+									input#open(name="status" type="radio" value="open" v-model="evaluation.mode")
+									label(for="open") open
+							p
+								input#fixed(type="checkbox" v-model="evaluation.fixed")
+								label(for="fixed") Fixed questions order
+							div
+								h4 Display type:
+								span(title="Show only one question at a time (with potential sub-questions)")
+									input#displayOne(name="display" type="radio" value="one" v-model="evaluation.display")
+									label(for="displayOne") one
+								span(title="Always show all questions (with an optional navigator)")
+									input#displayAll(name="display" type="radio" value="all" v-model="evaluation.display")
+									label(for="displayAll") all
+							.input-field
+								input#time(type="number" v-model.number="evaluation.time")
+								label(for="time") Time (minutes)
+							.input-field
+								textarea#introduction.materialize-textarea(v-model="evaluation.introduction")
+								label(for="introduction") Introduction
+							.input-field
+								textarea#evaluationEdition.materialize-textarea(v-model="evaluationText")
+								label(for="evaluationEdition") evaluation in text format
+							.center-align
+								button.waves-effect.waves-light.btn.on-left(@click="updateEvaluation()") Send
+								button.waves-effect.waves-light.btn(@click="mode='view'") Cancel
 
 block append javascripts
 	script(src="//cdnjs.cloudflare.com/ajax/libs/PapaParse/4.3.6/papaparse.min.js")
 	script.
-		let assessmentArray = !{JSON.stringify(assessmentArray)};
+		let evaluationArray = !{JSON.stringify(evaluationArray)};
 		const course = !{JSON.stringify(course)};
 		const initials = "#{initials}";
 		const admin = #{teacher};
 	script(src="/javascripts/utils/sha1.js")
 	script(src="/javascripts/utils/validation.js")
+	script(src="/javascripts/components/statements.js")
 	script(src="/javascripts/course.js")
diff --git a/views/assessment.pug b/views/evaluation.pug
similarity index 100%
rename from views/assessment.pug
rename to views/evaluation.pug
diff --git a/views/grade.pug b/views/grade.pug
index d38032a..2c5c03e 100644
--- a/views/grade.pug
+++ b/views/grade.pug
@@ -32,11 +32,11 @@ block rightMenu
 						thead
 							tr
 								th Number
-								th(v-for="assessment in assessmentArray") {{ assessment.name }}
+								th(v-for="evaluation in evaluationArray") {{ evaluation.name }}
 						tbody
 							tr.grade(v-for="student in studentList(group)")
 								td {{ student.number }}
-								td(v-for="(assessment,i) in assessmentArray" @click="togglePresence(student.number,i)")
+								td(v-for="(evaluation,i) in evaluationArray" @click="togglePresence(student.number,i)")
 									| {{ grade(i,student.number) }}
 				.modal-footer
 					.center-align
@@ -59,17 +59,17 @@ block content
 						thead
 							tr
 								th Name
-								th(v-for="(q,i) in assessment.questions") Q.{{ (i+1) }}
+								th(v-for="(q,i) in evaluation.questions") Q.{{ (i+1) }}
 						tbody
-							tr.assessment(v-for="s in studentList(group)")
+							tr.evaluation(v-for="s in studentList(group)")
 								td {{ s.name }}
-								td(v-for="(q,i) in assessment.questions" :style="{background-color: getColor(number,i)}" @click="seeDetails(number,i)") &nbsp;
-				h4.title(@click="toggleDisplay('assessment')") Assessment
-				div(v-show="display=='assessment'")
+								td(v-for="(q,i) in evaluation.questions" :style="{background-color: getColor(number,i)}" @click="seeDetails(number,i)") &nbsp;
+				h4.title(@click="toggleDisplay('evaluation')") evaluation
+				div(v-show="display=='evaluation'")
 					.card
-						.introduction(v-html="assessment.introduction")
+						.introduction(v-html="evaluation.introduction")
 					.card
-						statements(:questions="assessment.questions" :answers:"answers")
+						statements(:questions="evaluation.questions" :answers:"answers")
 
 
 
diff --git a/views/monitor.pug b/views/monitor.pug
index 671b136..c904f00 100644
--- a/views/monitor.pug
+++ b/views/monitor.pug
@@ -29,17 +29,17 @@ block content
 							thead
 								tr
 									th Name
-									th(v-for="(q,i) in assessment.questions") Q.{{ (i+1) }}
+									th(v-for="(q,i) in evaluation.questions") Q.{{ (i+1) }}
 							tbody
-								tr.assessment(v-for="s in studentList(group)" :class="{absent:!s.present}")
+								tr.evaluation(v-for="s in studentList(group)" :class="{absent:!s.present}")
 									td(:class="{blur:!!s.blur,resize:!!s.resize,disconnect:!!s.disco}" @click="togglePresence(s)") {{ s.name }}
-									td(v-for="(q,i) in assessment.questions" :style="{backgroundColor: getColor(s.number,i)}" @click="seeDetails(s.number,i)") &nbsp;
-					h4.title(@click="toggleDisplay('assessment')") Assessment
-					div(v-show="display=='assessment'")
+									td(v-for="(q,i) in evaluation.questions" :style="{backgroundColor: getColor(s.number,i)}" @click="seeDetails(s.number,i)") &nbsp;
+					h4.title(@click="toggleDisplay('evaluation')") evaluation
+					div(v-show="display=='evaluation'")
 						.card
-							.introduction(v-html="assessment.introduction")
+							.introduction(v-html="evaluation.introduction")
 						.card
-							statements(:questions="assessment.questions" :answers="answers")
+							statements(:questions="evaluation.questions" :answers="answers")
 
 block append javascripts
 	script.
-- 
2.44.0