diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
index 50f7345d340aaf873ca74120a900e06122e09323..072fbabeacc4b510c22b75f3374e9b06065615c8 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
@@ -219,7 +219,7 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 			
 			Translator myTrans = userManager.getPropertyHandlerTranslator(getTranslator());
 			userTableModel = new UserSearchFlexiTableModel(Collections.<Identity>emptyList(), resultingPropertyHandlers, isAdministrativeUser, getLocale(), tableColumnModel);
-			tableEl = uifactory.addTableElement(getWindowControl(), "users", userTableModel, myTrans, formLayout);
+			tableEl = uifactory.addTableElement(getWindowControl(), "users", userTableModel, 250, false, myTrans, formLayout);
 			tableEl.setCustomizeColumns(false);
 			tableEl.setMultiSelect(true);
 			tableEl.setSelectAllEnable(true);
@@ -422,7 +422,8 @@ public class UserSearchFlexiController extends FlexiAutoCompleterController {
 		}
 
 		tableEl.reset();
-		List<Identity> users = searchUsers(login,	userPropertiesSearch, true);
+		
+		List<Identity> users = searchUsers(login, userPropertiesSearch, true);
 		if (!users.isEmpty()) {
 			userTableModel.setObjects(users);
 			flc.contextPut("showButton","true");
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurity.java b/src/main/java/org/olat/basesecurity/BaseSecurity.java
index 62c526e1b617b3c4f7629e41680969f1bcf0cc4a..c2445becd78ba24a3d1fc8aa92b68b84719cd7ac 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurity.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurity.java
@@ -173,7 +173,13 @@ public interface BaseSecurity {
 	 */
 	public Identity findIdentityByNumber(String identityNumber);
 	
-
+	/**
+	 * The list of visible identities with a institutional number like in the
+	 * specified list. Deleted ones are not included.
+	 * 
+	 * @param identityNumbers
+	 * @return A list of identities
+	 */
 	public List<Identity> findIdentitiesByNumber(Collection<String> identityNumbers);
 	
 	/**
diff --git a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
index 2b23870a2936cd0ad3b8c8666e1afe81178e9d69..d71ffa545081bac5350051de15ee371f098bb8b6 100644
--- a/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
+++ b/src/main/java/org/olat/basesecurity/BaseSecurityManager.java
@@ -991,13 +991,15 @@ public class BaseSecurityManager implements BaseSecurity {
 		if(identityNumbers == null || identityNumbers.isEmpty()) return Collections.emptyList();
 		
 		StringBuilder sb = new StringBuilder();
-		sb.append("select identity from ").append(IdentityImpl.class.getName()).append(" identity ")
-			.append(" inner join fetch identity.user user ")
-			.append(" where user.").append(UserConstants.INSTITUTIONALUSERIDENTIFIER).append(" in (:idNumbers) ");
+		sb.append("select ident from ").append(IdentityImpl.class.getName()).append(" ident ")
+			.append(" inner join fetch ident.user user ")
+			.append(" where user.").append(UserConstants.INSTITUTIONALUSERIDENTIFIER).append(" in (:idNumbers) ")
+			.append(" and ident.status<:status");
 
 		return dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Identity.class)
 				.setParameter("idNumbers", identityNumbers)
+				.setParameter("status", Identity.STATUS_VISIBLE_LIMIT)
 				.getResultList();
 	}
 
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableSortOptions.java b/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableSortOptions.java
index 711062ebbcd8046f172d8dbe73c0b1e19937b991..531d731dac254b48d6b404b39f7b4b81b16068fa 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableSortOptions.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/elements/FlexiTableSortOptions.java
@@ -59,6 +59,13 @@ public class FlexiTableSortOptions {
 	public boolean isFromColumnModel() {
 		return fromColumnModel;
 	}
+	
+	/**
+	 * @return true if a default order is set
+	 */
+	public boolean hasDefaultOrderBy() {
+		return defaultOrderBy != null;
+	}
 
 	public SortKey getDefaultOrderBy() {
 		return defaultOrderBy;
diff --git a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
index dc7c57381507107468da38f5019891e4c4cbe8c1..b2ee11bf8014481a777d430311cf76f6520b4529 100644
--- a/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
+++ b/src/main/java/org/olat/core/gui/components/form/flexible/impl/elements/table/SortableFlexiTableModelDelegate.java
@@ -167,6 +167,10 @@ public class SortableFlexiTableModelDelegate<T> {
 		}
 		return a.compareTo(b);
 	}
+	
+	protected final int compareDoubles(double a, double b) {
+		return Double.compare(a, b);
+	}
 
 	protected final int compareNullObjects(final Object a, final Object b) {
 		boolean ba = (a == null);
diff --git a/src/main/java/org/olat/course/CourseFactory.java b/src/main/java/org/olat/course/CourseFactory.java
index 5b581a887dbc1e882fd4d98f983f17deddbbaa89..0fc67c15e805620987e8bd9eb925bb8a7ea9eebb 100644
--- a/src/main/java/org/olat/course/CourseFactory.java
+++ b/src/main/java/org/olat/course/CourseFactory.java
@@ -28,6 +28,8 @@ package org.olat.course;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
@@ -711,10 +713,13 @@ public class CourseFactory {
 		// archive course results overview
 		List<Identity> users = ScoreAccountingHelper.loadUsers(course.getCourseEnvironment());
 		List<AssessableCourseNode> nodes = ScoreAccountingHelper.loadAssessableNodes(course.getCourseEnvironment());
-
-		String result = ScoreAccountingHelper.createCourseResultsOverviewTable(users, nodes, course, locale);
-		String fileName = ExportUtil.createFileNameWithTimeStamp(course.getCourseTitle(), "xls");
-		ExportUtil.writeContentToFile(fileName, result, exportDirectory, charset);
+		
+		String fileName = ExportUtil.createFileNameWithTimeStamp(course.getCourseTitle(), "xlsx");
+		try(OutputStream out = new FileOutputStream(new File(exportDirectory, fileName))) {
+			ScoreAccountingHelper.createCourseResultsOverviewXMLTable(users, nodes, course, locale, out);
+		} catch(IOException e) {
+			log.error("", e);
+		}
 
 		// archive all nodes content
 		Visitor archiveV = new NodeArchiveVisitor(locale, course, exportDirectory, charset);
diff --git a/src/main/java/org/olat/course/archiver/ScoreAccountingArchiveController.java b/src/main/java/org/olat/course/archiver/ScoreAccountingArchiveController.java
index 89dbb46493a7f02b5c26f9b9d4a9ff922ef1860d..018b3f9bc90a0a9717b65e5a387eda79de96865e 100644
--- a/src/main/java/org/olat/course/archiver/ScoreAccountingArchiveController.java
+++ b/src/main/java/org/olat/course/archiver/ScoreAccountingArchiveController.java
@@ -26,6 +26,9 @@
 package org.olat.course.archiver;
 
 import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.List;
 
 import org.olat.core.gui.UserRequest;
@@ -46,7 +49,6 @@ import org.olat.course.CourseFactory;
 import org.olat.course.ICourse;
 import org.olat.course.nodes.AssessableCourseNode;
 import org.olat.course.nodes.CourseNode;
-import org.olat.user.UserManager;
 
 /**
  * Description: Course-Results-Archiver using ScoreAccountingHelper.class
@@ -103,18 +105,16 @@ public class ScoreAccountingArchiveController extends BasicController {
 		List<Identity> users = ScoreAccountingHelper.loadUsers(course.getCourseEnvironment());
 		List<AssessableCourseNode> nodes = ScoreAccountingHelper.loadAssessableNodes(course.getCourseEnvironment());
 		
-		String result = ScoreAccountingHelper.createCourseResultsOverviewTable(users, nodes, course, getLocale());
-
 		String courseTitle = course.getCourseTitle();
-
-		String fileName = ExportUtil.createFileNameWithTimeStamp(courseTitle, "xls");
+		String fileName = ExportUtil.createFileNameWithTimeStamp(courseTitle, "xlsx");
 		// location for data export
 		File exportDirectory = CourseFactory.getOrCreateDataExportDirectory(getIdentity(), courseTitle);
-		// the user's charset
-		UserManager um = UserManager.getInstance();
-		String charset = um.getUserCharset(getIdentity());
-		
-		File downloadFile = ExportUtil.writeContentToFile(fileName, result, exportDirectory, charset);
+		File downloadFile = new File(exportDirectory, fileName);
+		try(OutputStream out=new FileOutputStream(downloadFile)) {
+			ScoreAccountingHelper.createCourseResultsOverviewXMLTable(users, nodes, course, getLocale(), out);
+		} catch(IOException e) {
+			logError("", e);
+		}
 
 		vcFeedback = createVelocityContainer("feedback");
 		vcFeedback.contextPut("body", translate("course.res.feedback", new String[] { downloadFile.getName() }));
diff --git a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
index 2a79bade63499db9eb7c0c21cc9f18e19120f3ab..997c3e8092e32bf923fe1c04c120d70ec1bbcaae 100644
--- a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
+++ b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
@@ -40,13 +40,11 @@ import java.util.Set;
 import org.apache.commons.io.IOUtils;
 import org.olat.basesecurity.GroupRoles;
 import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
 import org.olat.core.id.IdentityEnvironment;
 import org.olat.core.id.context.BusinessControlFactory;
 import org.olat.core.id.context.ContextEntry;
-import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.openxml.OpenXMLWorkbook;
@@ -79,314 +77,18 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  * Comment: Provides functionality to get a course results overview.
  */
 public class ScoreAccountingHelper {
- 
+	
 	/**
 	 * The results from assessable nodes are written to one row per user into an excel-sheet. An
      * assessable node will only appear if it is producing at least one of the
      * following variables: score, passed, attempts, comments.
-	 * 
-	 * @param identities
-	 * @param myNodes
-	 * @param course
-	 * @param locale
-	 * @return String
+     * 
+	 * @param identities The list of identities which results need to be archived.
+	 * @param myNodes The assessable nodes to archive.
+	 * @param course The course.
+	 * @param locale The locale.
+	 * @param bos The output stream (which will be closed at the end, if you use a zip stream don't forget to shield it).
 	 */
-	public static String createCourseResultsOverviewTable(List<Identity> identities, List<AssessableCourseNode> myNodes, ICourse course, Locale locale) {
-	  Translator t = Util.createPackageTranslator(ScoreAccountingArchiveController.class, locale);
-	  StringBuilder tableHeader1 = new StringBuilder();
-		StringBuilder tableHeader2 = new StringBuilder();
-		StringBuilder tableContent = new StringBuilder();
-		StringBuilder table = new StringBuilder();
-
-		String sequentialNumber = t.translate("column.header.seqnum");
-		String login = t.translate("column.header.businesspath");
-		// user properties are dynamic
-		String sc = t.translate("column.header.score");
-		String pa = t.translate("column.header.passed");
-		String co = t.translate("column.header.comment");
-		String cco = t.translate("column.header.coachcomment");
-		String at = t.translate("column.header.attempts");
-		String il = t.translate("column.header.initialLaunchDate");
-		String slm = t.translate("column.header.scoreLastModified");
-		String na = t.translate("column.field.notavailable");
-		String mi = t.translate("column.field.missing");
-		String yes = t.translate("column.field.yes");
-		String no = t.translate("column.field.no");
-
-		
-		tableHeader1.append(sequentialNumber);
-		tableHeader1.append("\t");
-		tableHeader2.append("\t");
-		
-		tableHeader1.append(login);
-		tableHeader1.append("\t");
-		tableHeader2.append("\t");
-		// get user property handlers for this export, translate using the fallback
-		// translator configured in the property handler
-		
-			//Initial launch date
-		tableHeader1.append(il).append("\t");
-		tableHeader2.append("\t");
-		
-		List<UserPropertyHandler> userPropertyHandlers = UserManager.getInstance().getUserPropertyHandlersFor(
-				ScoreAccountingHelper.class.getCanonicalName(), true);
-		t = UserManager.getInstance().getPropertyHandlerTranslator(t);
-		for (UserPropertyHandler propertyHandler : userPropertyHandlers) {
-			tableHeader1.append(t.translate(propertyHandler.i18nColumnDescriptorLabelKey()));
-			tableHeader1.append("\t");			
-			tableHeader2.append("\t");
-		}
-
-		// preload user properties cache
-		CourseEnvironment courseEnvironment = course.getCourseEnvironment();
-		
-		boolean firstIteration = true;
-		int rowNumber = 1;
-
-		UserCourseInformationsManager mgr = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
-		OLATResource courseResource = courseEnvironment.getCourseGroupManager().getCourseResource();
-		Map<Long,Date> firstTimes = mgr.getInitialLaunchDates(courseResource, identities);
-		Formatter formatter = Formatter.getInstance(locale);
-
-		int count = 0;
-		for (Identity identity:identities) {
-			ContextEntry ce = BusinessControlFactory.getInstance().createContextEntry(identity);
-			String uname = BusinessControlFactory.getInstance().getAsURIString(Collections.singletonList(ce), false);
-
-			tableContent.append(rowNumber);
-			tableContent.append("\t");
-			tableContent.append(uname);
-			tableContent.append("\t");
-
-			String initialLaunchDate = "";
-			if(firstTimes.containsKey(identity.getKey())) {
-				initialLaunchDate = formatter.formatDateAndTime(firstTimes.get(identity.getKey()));
-			}
-			tableContent.append(initialLaunchDate).append("\t");
-
-			// add dynamic user properties
-			for (UserPropertyHandler propertyHandler : userPropertyHandlers) {
-				String value = propertyHandler.getUserProperty(identity.getUser(), t.getLocale());
-				tableContent.append((StringHelper.containsNonWhitespace(value) ? value : na));
-				tableContent.append("\t");			
-			}
-
-			// create a identenv with no roles, no attributes, no locale
-			IdentityEnvironment ienv = new IdentityEnvironment();
-			ienv.setIdentity(identity);
-			UserCourseEnvironment uce = new UserCourseEnvironmentImpl(ienv, course.getCourseEnvironment());
-			ScoreAccounting scoreAccount = uce.getScoreAccounting();
-			scoreAccount.evaluateAll();
-			AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
-
-			for (AssessableCourseNode acnode:myNodes) {
-				boolean scoreOk = acnode.hasScoreConfigured();
-				boolean passedOk = acnode.hasPassedConfigured();
-				boolean attemptsOk = acnode.hasAttemptsConfigured();
-				boolean commentOk = acnode.hasCommentConfigured();
-
-				if (scoreOk || passedOk || commentOk || attemptsOk) {
-					ScoreEvaluation se = scoreAccount.evalCourseNode(acnode);
-					boolean nodeColumnOk = false;
-					StringBuilder tabs = new StringBuilder();
-
-					if (scoreOk) {
-						Float score = se.getScore();
-						nodeColumnOk = true;
-						tabs.append("\t"); // tabulators for header1 after node title
-
-						if (firstIteration) {
-							tableHeader2.append(sc);
-							tableHeader2.append("\t");
-						}
-
-						if (score != null) {
-							tableContent.append(AssessmentHelper.getRoundedScore(score));
-							tableContent.append("\t");
-						} else { // score == null
-							tableContent.append(mi);
-							tableContent.append("\t");
-						}
-					}
-
-					if (passedOk) {
-						Boolean passed = se.getPassed();
-						nodeColumnOk = true;
-						tabs.append("\t"); // tabulators for header1 after node title
-
-						if (firstIteration) {
-							tableHeader2.append(pa);
-							tableHeader2.append("\t");
-						}
-
-						if (passed != null) {
-							String yesno;
-							if (passed.booleanValue()) {
-								yesno = yes;
-							} else {
-								yesno = no;
-							}
-							tableContent.append(yesno);
-							tableContent.append("\t");
-						} else { // passed == null
-							tableContent.append(mi);
-							tableContent.append("\t");
-						}
-					}
-
-					if (attemptsOk) {
-						Integer attempts = am.getNodeAttempts(acnode, identity);
-						int a = attempts == null ? 0 : attempts.intValue();
-						nodeColumnOk = true;
-						tabs.append("\t"); // tabulators for header1 after node title
-
-						if (firstIteration) {
-							tableHeader2.append(at);
-							tableHeader2.append("\t");
-						}
-
-						tableContent.append(a);
-						tableContent.append("\t");
-					}
-
-					if (firstIteration) {
-						//last Modified
-						tableHeader2.append(slm);
-						tableHeader2.append("\t");
-					}
-
-					String scoreLastModified = "";
-					Date lastModified = am.getScoreLastModifiedDate(acnode, identity);
-					if(lastModified != null) {
-						scoreLastModified = formatter.formatDateAndTime(lastModified);
-					}
-					tableContent.append(scoreLastModified);
-					tableContent.append("\t");
-
-					if (commentOk) {
-					    // Comments for user
-						String comment = am.getNodeComment(acnode, identity);
-						nodeColumnOk = true;
-						tabs.append("\t"); // tabulators for header1 after node title
-
-						if (firstIteration) {
-							tableHeader2.append(co);
-							tableHeader2.append("\t");
-						}
-
-						if (comment != null) {
-							// put comment between double quote in order to prevent that
-							// '\t','\r' or '\n' destroy the excel table
-							// A (double) quote must be represented by two (double) quotes.
-							tableContent.append("\"");
-							tableContent.append(comment.replace("\"", "\"\""));
-							tableContent.append("\"\t");
-						} else {
-							tableContent.append(mi);
-							tableContent.append("\t");
-						}
-						
-						// Comments for tutors
-						String coachComment = am.getNodeCoachComment(acnode, identity);
-						tabs.append("\t"); // tabulators for header1 after node title
-
-						if (firstIteration) {
-							tableHeader2.append(cco);
-							tableHeader2.append("\t");
-						}
-
-						if (coachComment != null) {
-							// put coachComment between double quote in order to prevent that
-							// '\t','\r' or '\n' destroy the excel table
-							// A (double) quote must be represented by two (double) quotes.
-							tableContent.append("\"");
-							tableContent.append(coachComment.replace("\"", "\"\""));
-							tableContent.append("\"\t");
-						} else {
-							tableContent.append(mi);
-							tableContent.append("\t");
-						}
-						
-						
-					}
-
-					if (firstIteration && nodeColumnOk) {
-						String shortTitle = acnode.getShortTitle();
-
-						tableHeader1.append(shortTitle);
-						tableHeader1.append(tabs.toString());
-					}
-
-				}
-			}
-			if (firstIteration) {
-				tableHeader1.append("\t\n");
-				tableHeader2.append("\t\n");
-			}
-			tableContent.append("\t\n");
-			firstIteration = false;
-			rowNumber++;
-			
-			if(count++ % 20 == 0) {
-				DBFactory.getInstance().commitAndCloseSession();
-			}
-		}
-		//fxdiff VCRP-4: assessment overview with max score
-		StringBuilder tableFooter = new StringBuilder();
-		tableFooter.append("\t\n").append("\t\n").append(t.translate("legend")).append("\t\n").append("\t\n");
-		for (AssessableCourseNode acnode:myNodes) {
-			if (!acnode.hasScoreConfigured()) {
-				// only show min/max/cut legend when score configured
-				continue;
-			}
-			String minVal;
-			String maxVal;
-			String cutVal;
-			if(acnode instanceof STCourseNode || !acnode.hasScoreConfigured()) {
-				minVal = maxVal = cutVal = "-";
-			} else {
-				minVal = acnode.getMinScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMinScoreConfiguration());
-				maxVal = acnode.getMaxScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMaxScoreConfiguration());
-				if (acnode.hasPassedConfigured()) {
-					cutVal = acnode.getCutValueConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getCutValueConfiguration());
-				} else {
-					cutVal = "-";
-				}
-			}
-			
-			tableFooter.append('"');
-			tableFooter.append(acnode.getShortTitle());
-			tableFooter.append('"');
-			tableFooter.append('\n');
-
-			tableFooter.append("\t\t");
-			tableFooter.append("minValue");
-			tableFooter.append('\t');
-			tableFooter.append(minVal);
-			tableFooter.append('\n');
-
-			tableFooter.append("\t\t");
-			tableFooter.append("maxValue");
-			tableFooter.append('\t');
-			tableFooter.append(maxVal);
-			tableFooter.append('\n');
-
-			tableFooter.append("\t\t");
-			tableFooter.append("cutValue");
-			tableFooter.append('\t');
-			tableFooter.append(cutVal);
-			tableFooter.append('\n');
-		}
-
-		table.append(tableHeader1);
-		table.append(tableHeader2);
-		table.append(tableContent);
-		table.append(tableFooter);
-		String tab = table.toString();
-
-		return tab;
-	}
-	
 	public static void createCourseResultsOverviewXMLTable(List<Identity> identities, List<AssessableCourseNode> myNodes, ICourse course, Locale locale, OutputStream bos) {
 		OpenXMLWorkbook workbook = new OpenXMLWorkbook(bos, 1);
 		OpenXMLWorksheet sheet = workbook.nextWorksheet();
@@ -409,11 +111,7 @@ public class ScoreAccountingHelper {
 		String no = t.translate("column.field.no");
 		String submitted = t.translate("column.field.submitted");
 
-		AssessableCourseNode firstAcnode = myNodes.get(0);
-		boolean scoreOk = firstAcnode.hasScoreConfigured();
-		boolean passedOk = firstAcnode.hasPassedConfigured();
-		boolean attemptsOk = firstAcnode.hasAttemptsConfigured();
-		boolean commentOk = firstAcnode.hasCommentConfigured();
+
 		
 		Row headerRow1 = sheet.newRow();
 		headerRow1.addCell(headerColCnt++, sequentialNumber);
@@ -428,32 +126,63 @@ public class ScoreAccountingHelper {
 		for (UserPropertyHandler propertyHandler : userPropertyHandlers) {
 			headerRow1.addCell(headerColCnt++, t.translate(propertyHandler.i18nColumnDescriptorLabelKey()));
 		}
-		if (scoreOk || passedOk || commentOk || attemptsOk)
-			headerRow1.addCell(headerColCnt, firstAcnode.getShortTitle());
-
-		Row headerRow2 = sheet.newRow();
-		if (firstAcnode.getType().equals("ita")) {
-			headerRow2.addCell(headerColCnt++, submitted);
+		
+		int header1ColCnt = headerColCnt;
+		for(AssessableCourseNode acNode:myNodes) {
+			headerRow1.addCell(header1ColCnt++, acNode.getShortTitle());
+			header1ColCnt += acNode.getType().equals("ita") ? 1 : 0;
+			
+			boolean scoreOk = acNode.hasScoreConfigured();
+			boolean passedOk = acNode.hasPassedConfigured();
+			boolean attemptsOk = acNode.hasAttemptsConfigured();
+			boolean commentOk = acNode.hasCommentConfigured();
+			if (scoreOk || passedOk || commentOk || attemptsOk) {
+				header1ColCnt += scoreOk ? 1 : 0;
+				header1ColCnt += passedOk ? 1 : 0;
+				header1ColCnt += attemptsOk ? 1 : 0;
+				header1ColCnt++;//last modified
+				header1ColCnt += commentOk ? 1 : 0;
+				header1ColCnt++;//coach comment
+			}
+			header1ColCnt--;//column title
 		}
 
-		if (scoreOk)
-			headerRow2.addCell(headerColCnt++, sc);
-		if (passedOk)
-			headerRow2.addCell(headerColCnt++, pa);
-		if (attemptsOk)
-			headerRow2.addCell(headerColCnt++, at);
-		headerRow2.addCell(headerColCnt++, slm);
-		if (commentOk) {
-			headerRow2.addCell(headerColCnt++, co);
-			headerRow2.addCell(headerColCnt++, cco);
+		int header2ColCnt = headerColCnt;
+		Row headerRow2 = sheet.newRow();
+		for(AssessableCourseNode acNode:myNodes) {
+			if (acNode.getType().equals("ita")) {
+				headerRow2.addCell(header2ColCnt++, submitted);
+			}
+			
+			boolean scoreOk = acNode.hasScoreConfigured();
+			boolean passedOk = acNode.hasPassedConfigured();
+			boolean attemptsOk = acNode.hasAttemptsConfigured();
+			boolean commentOk = acNode.hasCommentConfigured();
+			if (scoreOk || passedOk || commentOk || attemptsOk) {
+				if(scoreOk) {
+					headerRow2.addCell(header2ColCnt++, sc);
+				}
+				if(passedOk) {
+					headerRow2.addCell(header2ColCnt++, pa);
+				}
+				if(attemptsOk) {
+					headerRow2.addCell(header2ColCnt++, at);
+				}
+				headerRow2.addCell(header2ColCnt++, slm);//last modified
+				if (commentOk) {
+					headerRow2.addCell(header2ColCnt++, co);
+				}
+				headerRow2.addCell(header2ColCnt++, cco);//coach comment
+			}
 		}
+		
 		sheet.setHeaderRows(2);
 
 		// preload user properties cache
 		CourseEnvironment courseEnvironment = course.getCourseEnvironment();
 
 		int rowNumber = 0;
-
+		DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
 		UserCourseInformationsManager mgr = CoreSpringFactory.getImpl(UserCourseInformationsManager.class);
 		OLATResource courseResource = courseEnvironment.getCourseGroupManager().getCourseResource();
 		Map<Long,Date> firstTimes = mgr.getInitialLaunchDates(courseResource, identities);
@@ -488,10 +217,10 @@ public class ScoreAccountingHelper {
 			AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
 
 			for (AssessableCourseNode acnode:myNodes) {
-				scoreOk = acnode.hasScoreConfigured();
-				passedOk = acnode.hasPassedConfigured();
-				attemptsOk = acnode.hasAttemptsConfigured();
-				commentOk = acnode.hasCommentConfigured();
+				boolean scoreOk = acnode.hasScoreConfigured();
+				boolean passedOk = acnode.hasPassedConfigured();
+				boolean attemptsOk = acnode.hasAttemptsConfigured();
+				boolean commentOk = acnode.hasCommentConfigured();
 
 				if (acnode.getType().equals("ita")) {
 					String log = acnode.getUserLog(uce);
@@ -502,9 +231,9 @@ public class ScoreAccountingHelper {
 						log = log.substring(0, log.lastIndexOf("submit"));
 						log = log.substring(log.lastIndexOf("date:"));
 						date = log.split("\n")[0].substring(6);
-						DateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm");
 						lastUploaded = df.parse(date);
 					} catch (Exception e) {
+						//
 					}
 					if (lastUploaded != null) {
 						dataRow.addCell(dataColCnt++, lastUploaded, workbook.getStyles().getDateStyle());
@@ -561,18 +290,62 @@ public class ScoreAccountingHelper {
 						} else {
 							dataRow.addCell(dataColCnt++, mi);
 						}
+					}
 
-						// Comments for tutors
-						String coachComment = am.getNodeCoachComment(acnode, identity);
-						if (coachComment != null) {
-							dataRow.addCell(dataColCnt++, coachComment);
-						} else {
-							dataRow.addCell(dataColCnt++, mi);
-						}
+					// Always export comments for tutors
+					String coachComment = am.getNodeCoachComment(acnode, identity);
+					if (coachComment != null) {
+						dataRow.addCell(dataColCnt++, coachComment);
+					} else {
+						dataRow.addCell(dataColCnt++, mi);
 					}
 				}
 			}
 		}
+
+		//min. max. informations
+		boolean first = true;
+		for (AssessableCourseNode acnode:myNodes) {
+			if (!acnode.hasScoreConfigured()) {
+				// only show min/max/cut legend when score configured
+				continue;
+			}
+			
+			if(first) {
+				sheet.newRow().addCell(0, "");
+				sheet.newRow().addCell(0, "");
+				sheet.newRow().addCell(0, t.translate("legend"));
+				sheet.newRow().addCell(0, "");
+				first = false;
+			}
+
+			String minVal;
+			String maxVal;
+			String cutVal;
+			if(acnode instanceof STCourseNode || !acnode.hasScoreConfigured()) {
+				minVal = maxVal = cutVal = "-";
+			} else {
+				minVal = acnode.getMinScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMinScoreConfiguration());
+				maxVal = acnode.getMaxScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMaxScoreConfiguration());
+				if (acnode.hasPassedConfigured()) {
+					cutVal = acnode.getCutValueConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getCutValueConfiguration());
+				} else {
+					cutVal = "-";
+				}
+			}
+			
+			sheet.newRow().addCell(0, acnode.getShortTitle());
+
+			Row minRow = sheet.newRow();
+			minRow.addCell(2, "minValue");
+			minRow.addCell(3, minVal);
+			Row maxRow = sheet.newRow();
+			maxRow.addCell(2, "maxValue");
+			maxRow.addCell(3, maxVal);
+			Row cutRow = sheet.newRow();
+			cutRow.addCell(2, "cutValue");
+			cutRow.addCell(3, cutVal);
+		}
 		
 		IOUtils.closeQuietly(workbook);
 	}
diff --git a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
index 05b943d9d0897652eda6ce82f7365c4a0067434e..6a7d93d4b4950608531e22e8a9907144fd460da3 100644
--- a/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
+++ b/src/main/java/org/olat/course/assessment/ui/tool/IdentityListCourseNodeController.java
@@ -31,12 +31,14 @@ import java.util.concurrent.ConcurrentMap;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.Group;
+import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableFilter;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
 import org.olat.core.gui.components.form.flexible.impl.FormEvent;
@@ -194,8 +196,10 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 				? "select" : null;
 
 		//add the table
+		FlexiTableSortOptions options = new FlexiTableSortOptions();
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(isAdministrativeUser) {
+			options.setDefaultOrderBy(new SortKey(IdentityCourseElementCols.username.sortKey(), true));
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(IdentityCourseElementCols.username, select));
 		}
 		
@@ -204,6 +208,9 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 			UserPropertyHandler userPropertyHandler	= userPropertyHandlers.get(i);
 			boolean visible = UserManager.getInstance().isMandatoryUserProperty(AssessmentToolConstants.usageIdentifyer , userPropertyHandler);
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colIndex, select, true, "userProp-" + colIndex));
+			if(!options.hasDefaultOrderBy()) {
+				options.setDefaultOrderBy(new SortKey("userProp-" + colIndex, true));
+			}
 			colIndex++;
 		}
 		AssessableCourseNode assessableNode = null;
@@ -245,7 +252,8 @@ public class IdentityListCourseNodeController extends FormBasicController implem
 		tableEl.setExportEnabled(true);
 		tableEl.setSearchEnabled(new AssessedIdentityListProvider(getIdentity(), courseEntry, referenceEntry, courseNode.getIdent(), assessmentCallback), ureq.getUserSession());
 		tableEl.setMultiSelect(!coachCourseEnv.isCourseReadOnly());
-		
+		tableEl.setSortSettings(options);
+
 		List<FlexiTableFilter> filters = new ArrayList<>();
 		filters.add(new FlexiTableFilter(translate("filter.showAll"), "showAll", true));
 		filters.add(FlexiTableFilter.SPACER);
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberBySearchController.java b/src/main/java/org/olat/course/member/wizard/ImportMemberBySearchController.java
index d65c4cf6345e854192668fbb266ca6087b81504a..d4b86ac953b21b644882ad8a8829257372c11064 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberBySearchController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberBySearchController.java
@@ -19,7 +19,6 @@
  */
 package org.olat.course.member.wizard;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -58,16 +57,11 @@ public class ImportMemberBySearchController extends StepFormBasicController {
 	protected void event(UserRequest ureq, Controller source, Event event) {
 		if(event instanceof SingleIdentityChosenEvent) {
 			SingleIdentityChosenEvent e = (SingleIdentityChosenEvent)event;
-			String key = e.getChosenIdentity().getKey().toString();
-			addToRunContext("keys", Collections.singletonList(key));
+			addToRunContext("keyIdentities", Collections.singletonList(e.getChosenIdentity()));
 			fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 		} else if(event instanceof MultiIdentityChosenEvent) {
 			MultiIdentityChosenEvent e = (MultiIdentityChosenEvent)event;
-			List<String> keys = new ArrayList<>();
-			for(Identity identity: e.getChosenIdentities()) {
-				keys.add(identity.getKey().toString());
-			}
-			addToRunContext("keys", keys);
+			addToRunContext("keyIdentities", e.getChosenIdentities());
 			fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 		} else {
 			super.event(ureq, source, event);
@@ -80,11 +74,7 @@ public class ImportMemberBySearchController extends StepFormBasicController {
 		if(identities.isEmpty()) {
 			searchController.doSearch();
 		} else {
-			List<String> keys = new ArrayList<>(identities.size());
-			for(Identity identity: identities) {
-				keys.add(identity.getKey().toString());
-			}
-			addToRunContext("keys", keys);
+			addToRunContext("keyIdentities", identities);
 			fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 		}
 	}
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
index 2249ce0eff809757ef4b47323a81facff24d1351..90d8973787bb8612db1ef4ec537350c09f8b8331 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
@@ -20,7 +20,9 @@
 package org.olat.course.member.wizard;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import org.olat.admin.user.UserTableDataModel;
 import org.olat.basesecurity.BaseSecurity;
@@ -28,7 +30,6 @@ import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.persistence.PersistenceHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
@@ -47,6 +48,7 @@ import org.olat.core.id.Identity;
 import org.olat.core.id.UserConstants;
 import org.olat.user.UserManager;
 import org.olat.user.propertyhandlers.UserPropertyHandler;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -60,9 +62,12 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 	private List<String> notfounds;
 	private boolean isAdministrativeUser;
 	
-	private final UserManager userManager;
-	private final BaseSecurity securityManager;
-	private final BaseSecurityModule securityModule;
+	@Autowired
+	private UserManager userManager;
+	@Autowired
+	private BaseSecurity securityManager;
+	@Autowired
+	private BaseSecurityModule securityModule;
 
 	public ImportMemberOverviewIdentitiesController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) {
 		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
@@ -78,6 +83,10 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 			@SuppressWarnings("unchecked")
 			List<String> keys = (List<String>)runContext.get("keys");
 			loadModel(keys);
+		} else if(containsRunContextKey("keyIdentities")) {
+			@SuppressWarnings("unchecked")
+			List<Identity> keys = (List<Identity>)runContext.get("keyIdentities");
+			loadModelByIdentities(keys);
 		}
 
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
@@ -129,28 +138,50 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 	}
 	
 	private void loadModel(List<String> keys) {
-		oks = new ArrayList<Identity>();
-		List<String> isanonymous = new ArrayList<String>();
-		notfounds = new ArrayList<String>();
-
+		notfounds = new ArrayList<>();
+		
+		Set<Identity> okSet = new HashSet<>();
 		SecurityGroup anonymousSecGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
+		List<Identity> anonymousUsers = securityManager.getIdentitiesOfSecurityGroup(anonymousSecGroup);
+
 		for (String identityKey : keys) {
 			Identity ident = securityManager.loadIdentityByKey(Long.parseLong(identityKey));
 			if (ident == null) { // not found, add to not-found-list
 				notfounds.add(identityKey);
-			} else if (securityManager.isIdentityInSecurityGroup(ident, anonymousSecGroup)) {
-				isanonymous.add(identityKey);
-			} else if (!PersistenceHelper.containsPersistable(oks, ident)) {
-				oks.add(ident);
+			} else if (anonymousUsers.contains(ident)) {
+				//ignore
+			} else if (!okSet.contains(ident)) {
+				okSet.add(ident);
 			}
 		}
+		oks = new ArrayList<>(okSet);
+	}
+	
+	private void loadModelByIdentities(List<Identity> keys) {
+		notfounds = new ArrayList<>();
+		
+		Set<Identity> okSet = new HashSet<>();
+		SecurityGroup anonymousSecGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
+		List<Identity> anonymousUsers = securityManager.getIdentitiesOfSecurityGroup(anonymousSecGroup);
+
+		for (Identity ident : keys) {
+			if (ident == null || anonymousUsers.contains(ident)) {
+				//ignore
+			} else if (!okSet.contains(ident)) {
+				okSet.add(ident);
+			}
+		}
+		oks = new ArrayList<>(okSet);
 	}
 	
 	private void loadModel(String inp) {
-		oks = new ArrayList<Identity>();
-		notfounds = new ArrayList<String>();
+		oks = new ArrayList<>();
+		notfounds = new ArrayList<>();
+		
+		Set<Identity> okSet = new HashSet<>();
 
-		SecurityGroup anonymousSecGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
+		SecurityGroup anonymousGroup = securityManager.findSecurityGroupByName(Constants.GROUP_ANONYMOUS);
+		Set<Identity> anonymousUsers = new HashSet<>(securityManager.getIdentitiesOfSecurityGroup(anonymousGroup));
 
 		List<String> identList = new ArrayList<String>();
 		String[] lines = inp.split("\r?\n");
@@ -168,13 +199,12 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 			if(userIdent != null) {
 				identList.remove(userIdent);
 			}
-			if (!PersistenceHelper.containsPersistable(oks, identity)
-					&& !securityManager.isIdentityInSecurityGroup(identity, anonymousSecGroup)) {
-				oks.add(identity);
+			if (!okSet.contains(identity) && !anonymousUsers.contains(identity)) {
+				okSet.add(identity);
 			}
 		}
 		// make a lowercase copy of identList for processing username and email
-		List<String> identListLowercase = new ArrayList<String>(identList.size());
+		List<String> identListLowercase = new ArrayList<>(identList.size());
 		for (String ident:identList) {
 			identListLowercase.add(ident.toLowerCase());
 		}
@@ -182,14 +212,20 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 		List<Identity> identities = securityManager.findIdentitiesByNameCaseInsensitive(identListLowercase);
 		for(Identity identity:identities) {
 			identListLowercase.remove(identity.getName().toLowerCase());
-			if (!PersistenceHelper.containsPersistable(oks, identity)
-					&& !securityManager.isIdentityInSecurityGroup(identity, anonymousSecGroup)) {
-				oks.add(identity);
+			if (!okSet.contains(identity) && !anonymousUsers.contains(identity)) {
+				okSet.add(identity);
 			}
 		}
 		
 		//search by email, case insensitive
-		List<Identity> mailIdentities = userManager.findIdentitiesByEmail(identListLowercase);
+		List<String> emailListLowercase = new ArrayList<>(identList.size());
+		for (String ident:identList) {
+			if(ident.indexOf('@') > 0) {
+				emailListLowercase.add(ident.toLowerCase());
+			}
+		}
+		
+		List<Identity> mailIdentities = userManager.findIdentitiesByEmail(emailListLowercase);
 		for(Identity identity:mailIdentities) {
 			String email = identity.getUser().getProperty(UserConstants.EMAIL, null);
 			if(email != null) {
@@ -199,13 +235,13 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 			if(institutEmail != null) {
 				identListLowercase.remove(institutEmail.toLowerCase());
 			}
-			if (!PersistenceHelper.containsPersistable(oks, identity)
-					&& !securityManager.isIdentityInSecurityGroup(identity, anonymousSecGroup)) {
-				oks.add(identity);
+			if (!okSet.contains(identity) && !anonymousUsers.contains(identity)) {
+				okSet.add(identity);
 			}
 		}
 		
 		notfounds.addAll(identListLowercase);
+		oks = new ArrayList<>(okSet);
 	}
 
 	public boolean validate() {
diff --git a/src/main/java/org/olat/course/nodes/TACourseNode.java b/src/main/java/org/olat/course/nodes/TACourseNode.java
index 01c7728dae986c57b763838ba786663a8f4cc3be..1c3555b4ce569d06f0dfce5d23e51332a293d300 100644
--- a/src/main/java/org/olat/course/nodes/TACourseNode.java
+++ b/src/main/java/org/olat/course/nodes/TACourseNode.java
@@ -37,7 +37,6 @@ import java.util.Set;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipOutputStream;
 
-import org.apache.commons.io.IOUtils;
 import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.modules.bc.FolderConfig;
 import org.olat.core.commons.modules.bc.vfs.OlatNamedContainerImpl;
@@ -63,6 +62,7 @@ import org.olat.core.util.Formatter;
 import org.olat.core.util.StringHelper;
 import org.olat.core.util.Util;
 import org.olat.core.util.ZipUtil;
+import org.olat.core.util.io.ShieldOutputStream;
 import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.course.ICourse;
@@ -861,13 +861,13 @@ public class TACourseNode extends GenericCourseNode implements PersistentAssessa
 			}
 			
 			String courseTitle = course.getCourseTitle();
-			String fileName = ExportUtil.createFileNameWithTimeStamp(courseTitle, "xls");
+			String fileName = ExportUtil.createFileNameWithTimeStamp(courseTitle, "xlsx");
 			List<AssessableCourseNode> nodes = Collections.<AssessableCourseNode>singletonList(this);
-			String s = ScoreAccountingHelper.createCourseResultsOverviewTable(users, nodes, course, locale);
 			// write course results overview table to filesystem
 			try {
 				exportStream.putNextEntry(new ZipEntry(dirName + "/" + fileName));
-				IOUtils.write(s, exportStream);
+				ScoreAccountingHelper.createCourseResultsOverviewXMLTable(users, nodes, course, locale,
+						new ShieldOutputStream(exportStream));
 				exportStream.closeEntry();
 			} catch (IOException e) {
 				log.error("", e);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
index df3461698648dc67e1e98794118c0906e8c75852..2284d4566e6fe6e6ae435c5e1b8772af5ef88c6f 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentController.java
@@ -202,7 +202,8 @@ public class CheckListAssessmentController extends FormBasicController implement
 		
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(isAdministrativeUser) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal(),
+					true, Cols.username.name()));
 		}
 		
 		int i=0;
@@ -247,7 +248,7 @@ public class CheckListAssessmentController extends FormBasicController implement
 		}
 
 		List<CheckListAssessmentRow> datas = loadDatas();
-		model = new CheckListAssessmentDataModel(checkboxList, datas, columnsModel);
+		model = new CheckListAssessmentDataModel(checkboxList, datas, columnsModel, getLocale());
 		table = uifactory.addTableElement(getWindowControl(), "checkbox-list", model, getTranslator(), formLayout);
 		if(coachCourseEnv instanceof UserCourseEnvironmentImpl) {
 			UserCourseEnvironmentImpl env = (UserCourseEnvironmentImpl)coachCourseEnv;
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java
index 6d0d718aaeda8197049e88215d39ae4dc1518326..5d04477f146e9ee7d5aaff40503db39b06875fe8 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModel.java
@@ -24,6 +24,7 @@ import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.List;
+import java.util.Locale;
 
 import org.apache.commons.lang.StringEscapeUtils;
 import org.olat.core.commons.persistence.SortKey;
@@ -36,7 +37,6 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiColum
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableComponent;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
 import org.olat.core.gui.media.MediaResource;
 import org.olat.core.gui.render.EmptyURLBuilder;
 import org.olat.core.gui.render.StringOutput;
@@ -70,13 +70,15 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che
 	public static final int USER_PROPS_OFFSET = 500;
 	public static final int CHECKBOX_OFFSET = 5000;
 	
+	private final Locale locale;
 	private final CheckboxList checkboxList;
 	private List<CheckListAssessmentRow> backupRows;
 	
 	public CheckListAssessmentDataModel(CheckboxList checkboxList, List<CheckListAssessmentRow> datas,
-			FlexiTableColumnModel columnModel) {
+			FlexiTableColumnModel columnModel, Locale locale) {
 		super(datas, columnModel);
 		backupRows = datas;
+		this.locale = locale;
 		this.checkboxList = checkboxList;
 	}
 	
@@ -89,13 +91,12 @@ public class CheckListAssessmentDataModel extends DefaultFlexiTableDataModel<Che
 
 	@Override
 	public DefaultFlexiTableDataModel<CheckListAssessmentRow> createCopyWithEmptyList() {
-		return new CheckListAssessmentDataModel(checkboxList, new ArrayList<CheckListAssessmentRow>(), getTableColumnModel());
+		return new CheckListAssessmentDataModel(checkboxList, new ArrayList<CheckListAssessmentRow>(), getTableColumnModel(), locale);
 	}
 	
 	@Override
 	public void sort(SortKey orderBy) {
-		SortableFlexiTableModelDelegate<CheckListAssessmentRow> sorter
-			= new SortableFlexiTableModelDelegate<>(orderBy, this, null);
+		CheckListAssessmentDataModelSorter sorter = new CheckListAssessmentDataModelSorter(orderBy, this, locale);
 		List<CheckListAssessmentRow> views = sorter.sort();
 		super.setObjects(views);
 	}
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModelSorter.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModelSorter.java
new file mode 100644
index 0000000000000000000000000000000000000000..d1916d141f552ec72955d538ae90f246b34eca99
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListAssessmentDataModelSorter.java
@@ -0,0 +1,92 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course.nodes.cl.ui;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+
+/**
+ * 
+ * Initial date: 5 févr. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CheckListAssessmentDataModelSorter extends SortableFlexiTableModelDelegate<CheckListAssessmentRow> {
+
+	public CheckListAssessmentDataModelSorter(SortKey orderBy, CheckListAssessmentDataModel model, Locale locale) {
+		super(orderBy, model, locale);
+	}
+	
+	@Override
+	protected void sort(List<CheckListAssessmentRow> rows) {
+		int columnIndex = getColumnIndex();
+		if(columnIndex >= CheckListAssessmentDataModel.CHECKBOX_OFFSET) {
+			int checkBoxIndex = columnIndex - CheckListAssessmentDataModel.CHECKBOX_OFFSET;
+			Collections.sort(rows, new CheckBoxComparator(checkBoxIndex));
+			
+		} else {
+			super.sort(rows);
+		}
+	}
+	
+	private class CheckBoxComparator implements Comparator<CheckListAssessmentRow> {
+		
+		private final int checkBoxIndex;
+		
+		public CheckBoxComparator(int checkBoxIndex) {
+			this.checkBoxIndex = checkBoxIndex;
+		}
+		
+		@Override
+		public int compare(CheckListAssessmentRow o1, CheckListAssessmentRow o2) {
+			if(o1 == null || o2 == null) {
+				return compareNullObjects(o1, o2);
+			}
+			
+			boolean c1 = isCheck(o1);
+			boolean c2 = isCheck(o2);
+			int c = compareBooleans(c1, c2);
+			return c;
+		}
+		
+		private boolean isCheck(CheckListAssessmentRow row) {
+			if(row.getCheckedEl() != null) {
+				//edit mode
+				MultipleSelectionElement[] checked = row.getCheckedEl();
+				if(checked != null && checkBoxIndex >= 0 && checkBoxIndex < checked.length) {
+					return checked[checkBoxIndex].isAtLeastSelected(1);
+				}
+			}
+			
+			Boolean[] checked = row.getChecked();
+			if(checked != null && checkBoxIndex >= 0 && checkBoxIndex < checked.length
+					&& checked[checkBoxIndex] != null) {
+				return checked[checkBoxIndex].booleanValue();
+			}
+			return false;
+		}
+	}
+}
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
index 208d65a756a51f298d42340326bf846696635973..940cf1297817f80ea662d19804f70c4cc9f1d55a 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentController.java
@@ -130,10 +130,10 @@ public class CheckboxAssessmentController extends FormBasicController {
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
 		setFormDescription("assessment.checkbox.description");
 
-
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(isAdministrativeUser) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.username.i18nKey(), Cols.username.ordinal(),
+					true, Cols.username.name()));
 		}
 		
 		int i=0;
@@ -157,9 +157,11 @@ public class CheckboxAssessmentController extends FormBasicController {
 			}
 		}
 
-		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.check.i18nKey(), Cols.check.ordinal()));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.check.i18nKey(), Cols.check.ordinal(),
+				true, Cols.check.name()));
 		if(withScore) {
-			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.points.i18nKey(), Cols.points.ordinal()));
+			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(Cols.points.i18nKey(), Cols.points.ordinal(),
+					true, Cols.points.name()));
 		}
 		int numOfCheckbox = checkboxList.getList().size();
 		String[] keys = new String[numOfCheckbox];
@@ -217,7 +219,7 @@ public class CheckboxAssessmentController extends FormBasicController {
 			boxRows.add(row);
 		}
 
-		model = new CheckboxAssessmentDataModel(boxRows, columnsModel);
+		model = new CheckboxAssessmentDataModel(boxRows, columnsModel, getLocale());
 		table = uifactory.addTableElement(getWindowControl(), "checkbox-list", model, getTranslator(), formLayout);
 		table.setCustomizeColumns(true);
 		table.setEditMode(true);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModel.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModel.java
index 0bfd163eee68cb8382fd20f1b5c153388a168ba1..94ad376fdb7b51743f86d274e070e9ee3a12a444 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModel.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModel.java
@@ -21,12 +21,12 @@ package org.olat.course.nodes.cl.ui;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiTableDataModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableDataModel;
-import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
 
 /**
  * 
@@ -36,20 +36,22 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFl
  */
 public class CheckboxAssessmentDataModel extends DefaultFlexiTableDataModel<CheckboxAssessmentRow>
 	implements SortableFlexiTableDataModel<CheckboxAssessmentRow> {
+	
+	private final Locale locale;
 
-	public CheckboxAssessmentDataModel(List<CheckboxAssessmentRow> datas, FlexiTableColumnModel columnModel) {
+	public CheckboxAssessmentDataModel(List<CheckboxAssessmentRow> datas, FlexiTableColumnModel columnModel, Locale locale) {
 		super(datas, columnModel);
+		this.locale = locale;
 	}
 
 	@Override
 	public DefaultFlexiTableDataModel<CheckboxAssessmentRow> createCopyWithEmptyList() {
-		return new CheckboxAssessmentDataModel(new ArrayList<CheckboxAssessmentRow>(), getTableColumnModel());
+		return new CheckboxAssessmentDataModel(new ArrayList<CheckboxAssessmentRow>(), getTableColumnModel(), locale);
 	}
 	
 	@Override
 	public void sort(SortKey orderBy) {
-		SortableFlexiTableModelDelegate<CheckboxAssessmentRow> sorter
-			= new SortableFlexiTableModelDelegate<>(orderBy, this, null);
+		CheckboxAssessmentDataModelSorter sorter = new CheckboxAssessmentDataModelSorter(orderBy, this, locale);
 		List<CheckboxAssessmentRow> views = sorter.sort();
 		super.setObjects(views);
 	}
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModelSorter.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModelSorter.java
new file mode 100644
index 0000000000000000000000000000000000000000..657ca3acb19b966b7994211ad5aaa9956056ed70
--- /dev/null
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckboxAssessmentDataModelSorter.java
@@ -0,0 +1,88 @@
+package org.olat.course.nodes.cl.ui;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.commons.persistence.SortKey;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.elements.TextElement;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.SortableFlexiTableModelDelegate;
+import org.olat.core.util.StringHelper;
+import org.olat.course.nodes.cl.ui.CheckboxAssessmentDataModel.Cols;
+
+/**
+ * 
+ * Initial date: 5 févr. 2017<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class CheckboxAssessmentDataModelSorter extends SortableFlexiTableModelDelegate<CheckboxAssessmentRow> {
+
+	public CheckboxAssessmentDataModelSorter(SortKey orderBy, CheckboxAssessmentDataModel model, Locale locale) {
+		super(orderBy, model, locale);
+	}
+	
+	@Override
+	protected void sort(List<CheckboxAssessmentRow> rows) {
+		int columnIndex = getColumnIndex();
+		if(columnIndex == Cols.check.ordinal()) {
+			Collections.sort(rows, new CheckBoxComparator());
+			
+		} else if(columnIndex == Cols.points.ordinal()) {
+			Collections.sort(rows, new PointsComparator());
+		} else {
+			super.sort(rows);
+		}
+	}
+	
+	private class PointsComparator implements Comparator<CheckboxAssessmentRow> {
+		@Override
+		public int compare(CheckboxAssessmentRow o1, CheckboxAssessmentRow o2) {
+			if(o1 == null || o2 == null) {
+				return compareNullObjects(o1, o2);
+			}
+			
+			TextElement e1 = o1.getPointEl();
+			TextElement e2 = o2.getPointEl();
+			if(e1 == null || e2 == null) {
+				return compareNullObjects(e1, e2);
+			}
+			
+			double t1 = parseDouble(e1);
+			double t2 = parseDouble(e2);
+			return compareDoubles(t1, t2);
+		}
+		
+		private double parseDouble(TextElement el) {
+			if(el != null && StringHelper.containsNonWhitespace(el.getValue())) {
+				try {
+					return Double.parseDouble(el.getValue());
+				} catch (NumberFormatException e) {
+					//ignore parsing error, the validation take this
+				}
+			}
+			return 0.0d;
+		}
+	}
+	
+	private class CheckBoxComparator implements Comparator<CheckboxAssessmentRow> {
+		@Override
+		public int compare(CheckboxAssessmentRow o1, CheckboxAssessmentRow o2) {
+			if(o1 == null || o2 == null) {
+				return compareNullObjects(o1, o2);
+			}
+			
+			MultipleSelectionElement e1 = o1.getCheckedEl();
+			MultipleSelectionElement e2 = o2.getCheckedEl();
+			if(e1 == null || e2 == null) {
+				return compareNullObjects(e1, e2);
+			}
+			
+			boolean b1 = e1.isAtLeastSelected(1);
+			boolean b2 = e2.isAtLeastSelected(1);
+			return compareBooleans(b1, b2);
+		}
+	}
+}
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 24884835631432e12e45a441484ec51012c6659f..fe75173fcd7ed7ee2a386575b98a2ac23c782870 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -1811,9 +1811,13 @@ public class RepositoryManager {
 
 		boolean allOk = repositoryEntryRelationDao.removeMembers(re, members);
 		if (allOk) {
+			int count = 0;
 			List<RepositoryEntryMembershipModifiedEvent> deferredEvents = new ArrayList<>();
 			for(Identity identity:members) {
 				deferredEvents.add(RepositoryEntryMembershipModifiedEvent.removed(identity, re));
+				if(++count % 100 == 0) {
+					dbInstance.commitAndCloseSession();
+				}
 			}
 			dbInstance.commit();
 			sendDeferredEvents(deferredEvents, re);
@@ -2268,12 +2272,16 @@ public class RepositoryManager {
 	public void updateRepositoryEntryMemberships(Identity ureqIdentity, Roles ureqRoles, RepositoryEntry re,
 			List<RepositoryEntryPermissionChangeEvent> changes, MailPackage mailing) {
 
+		int count = 0;
 		List<RepositoryEntryMembershipModifiedEvent> deferredEvents = new ArrayList<>();
 		for(RepositoryEntryPermissionChangeEvent e:changes) {
 			updateRepositoryEntryMembership(ureqIdentity, ureqRoles, re, e, mailing, deferredEvents);
+			if(++count % 100 == 0) {
+				dbInstance.commitAndCloseSession();
+			}
 		}
 
-		dbInstance.commit();
+		dbInstance.commitAndCloseSession();
 		sendDeferredEvents(deferredEvents, re);
 	}
 	
diff --git a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
index 459a6519ba81662e0c57fa59f0c0b6d57ab7c793..6d7bebaca35260ca20361fcd776c6c9fddf58973 100644
--- a/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
+++ b/src/main/java/org/olat/repository/manager/RepositoryEntryRelationDAO.java
@@ -181,6 +181,14 @@ public class RepositoryEntryRelationDAO {
 		return groupDao.removeMemberships(group, role);
 	}
 
+	/**
+	 * Retrieve the default group of the repository entry (the one
+	 * marked with the flag defaultGroup=true). The query is cached
+	 * by hibernate 2nd level cache.
+	 * 
+	 * @param re The repository entry
+	 * @return The group
+	 */
 	public Group getDefaultGroup(RepositoryEntryRef re) {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select baseGroup from ").append(RepositoryEntry.class.getName()).append(" as v ")
@@ -190,6 +198,7 @@ public class RepositoryEntryRelationDAO {
 
 		return dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Group.class)
 				.setParameter("repoKey", re.getKey())
+				.setHint("org.hibernate.cacheable", Boolean.TRUE)
 				.getSingleResult();
 	}
 	
diff --git a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
index 91e6fd1d8264bf4edde6bdc8e76bdf8df7661bfc..e68fb702172729c90ef3bd5c88d4fedd3c71acc7 100644
--- a/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
+++ b/src/test/java/org/olat/basesecurity/BaseSecurityManagerTest.java
@@ -247,6 +247,26 @@ public class BaseSecurityManagerTest extends OlatTestCase {
 		Assert.assertTrue(foundIds.contains(id2));
 	}
 	
+	@Test
+	public void findIdentitiesByNumber() {
+		//create a user it
+		String username = "fINd-ME-6-" + UUID.randomUUID();
+		String institutionalNumber = UUID.randomUUID().toString();
+		Identity id = JunitTestHelper.createAndPersistIdentityAsUser(username);
+		id.getUser().setProperty(UserConstants.INSTITUTIONALUSERIDENTIFIER, institutionalNumber);
+		userManager.updateUserFromIdentity(id);
+		dbInstance.commitAndCloseSession();
+		
+		List<String> numbers = new ArrayList<String>(2);
+		numbers.add(institutionalNumber);
+
+		//find it
+		List<Identity> foundIds = securityManager.findIdentitiesByNumber(numbers);
+		Assert.assertNotNull(foundIds);
+		Assert.assertEquals(1, foundIds.size());
+		Assert.assertTrue(foundIds.contains(id));
+	}
+	
 	@Test
 	public void loadIdentityShortByKey() {
 		//create a user it