diff --git a/.hgtags b/.hgtags
index 7c06ef4f6f4735a77a006f548ad9dc64733ecc5c..1b0a3cd0c32ac7a8e7c655a0670ff7c14959e522 100644
--- a/.hgtags
+++ b/.hgtags
@@ -32,3 +32,6 @@ be1c6b822eb317f3a48d392eb27055e7d4d52cc3 OpenOLAT 8.2.0
 0aa945a2fb9c6dad38b10aaca595d3049aa27965 OpenOLAT 8.3.1
 0aa945a2fb9c6dad38b10aaca595d3049aa27965 OpenOLAT 8.3.1
 8676836e1178a4b0e798623733dcc263e675f4c0 OpenOLAT 8.3.1
+8676836e1178a4b0e798623733dcc263e675f4c0 OpenOLAT 8.3.1
+4e8dde0bdfecb7d408237cfcac5c24a8337cc21e OpenOLAT 8.3.1
+0db1cf58d37858b5096cc6fe97b0a9159d626c37 OpenOLAT 8.3.2
diff --git a/src/main/java/de/bps/ims/qti/repository/handlers/QTISurveyHandlerOnyx.java b/src/main/java/de/bps/ims/qti/repository/handlers/QTISurveyHandlerOnyx.java
index 4752c486e3e00202b1f0b910c72f7c043eb9c891..68818462bd01b324448265d983caa6cd40b8365e 100644
--- a/src/main/java/de/bps/ims/qti/repository/handlers/QTISurveyHandlerOnyx.java
+++ b/src/main/java/de/bps/ims/qti/repository/handlers/QTISurveyHandlerOnyx.java
@@ -66,7 +66,7 @@ class QTISurveyHandlerOnyx extends QTISurveyHandler {
 	private static final boolean DOWNLOADEABLE = true;
 	private static final boolean EDITABLE = true;
 
-	static List supportedTypes;
+	static List<String> supportedTypes;
 
 	/**
 	 * Default constructor.
@@ -78,48 +78,57 @@ class QTISurveyHandlerOnyx extends QTISurveyHandler {
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getSupportedTypes()
 	 */
-	public List getSupportedTypes() {
+	public List<String> getSupportedTypes() {
 		return supportedTypes;
 	}
 
 	static { // initialize supported types
-		supportedTypes = new ArrayList(1);
+		supportedTypes = new ArrayList<String>(1);
 		supportedTypes.add(SurveyFileResource.TYPE_NAME);
 	}
 	
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsLaunch()
 	 */
-	public boolean supportsLaunch() { return LAUNCHEABLE; }
+	public boolean supportsLaunch() {
+		return LAUNCHEABLE;
+	}
 
 	//<OLATCE-1025>	
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsDownload()
 	 */
-	public boolean supportsDownload() { return DOWNLOADEABLE; }
+	public boolean supportsDownload() {
+		return DOWNLOADEABLE;
+	}
+	
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsEdit()
 	 */
+	@Override
 	public boolean supportsEdit(RepositoryEntry repoEntry) {
 		if (OnyxModule.isOnyxTest(repoEntry.getOlatResource())) {
 			return false;
 		}
 		return EDITABLE; 
-		}
+	}
 	//</OLATCE-1025>	
-	
+
 	//<OLATCE-1025>	
-	public MainLayoutController createLaunchController(OLATResourceable res, String initialViewIdentifier, UserRequest ureq, WindowControl wControl) {
-		return (MainLayoutController) getLaunchController( res,  ureq,  wControl);
-	}
+
 	//</OLATCE-1025>	
-	
+	@Override
+	public MainLayoutController createLaunchController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
+		return (MainLayoutController)getLaunchController( res,  ureq,  wControl);
+	}
+
 	/**
 	 * @param res
 	 * @param ureq
 	 * @param wControl
 	 * @return Controller
 	 */
+	@Override
 	public Controller getLaunchController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
 	//<OLATCE-1025>	
 		if (OnyxModule.isOnyxTest(res)) {
@@ -142,6 +151,7 @@ class QTISurveyHandlerOnyx extends QTISurveyHandler {
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getEditorController(org.olat.core.id.OLATResourceable org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
 	 */
+	@Override
 	public Controller createEditorController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
 		//<OLATCE-1025>	
 		if (OnyxModule.isOnyxTest(res)) {
@@ -149,38 +159,26 @@ class QTISurveyHandlerOnyx extends QTISurveyHandler {
 		} else {
 			return super.createEditorController(res, ureq, wControl);
 		}
-		
-//		SurveyFileResource fr = new SurveyFileResource();
-//		fr.overrideResourceableId(res.getResourceableId());
-//		
-//		//check if we can edit in restricted mode -> only typos 
-//		ReferenceManager refM = ReferenceManager.getInstance();
-//		List referencees = refM.getReferencesTo(res);
-//		//String referencesSummary = refM.getReferencesToSummary(res, ureq.getLocale());
-//		//boolean restrictedEdit = referencesSummary != null;
-//		QTIEditorMainController editor =  new QTIEditorMainController(referencees,ureq, wControl, fr);
-//		if (editor.isLockedSuccessfully()) {
-//			return editor;
-//		} else {
-//			return null;
-//		}
 		//</OLATCE-1025>	
 	}
 
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getAddController(org.olat.repository.controllers.RepositoryAddCallback, java.lang.Object, org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
 	 */
+	@Override
 	public IAddController createAddController(RepositoryAddCallback callback, Object userObject, UserRequest ureq, WindowControl wControl) {
 		if (userObject == null || userObject.equals(RepositoryAddController.PROCESS_ADD))
 			return new AddFileResourceController(callback, supportedTypes, new String[] {"zip"}, ureq, wControl);
 		else//RepositoryAddController.PROCESS_NEW
 			return new AddNewQTIDocumentController(AssessmentInstance.QMD_ENTRY_TYPE_SURVEY, callback, ureq, wControl);
 	}
-	
+
+	@Override
 	protected String getDeletedFilePrefix() {
 		return "del_qtisurvey_"; 
 	}
-	
+
+	@Override
 	public WizardCloseResourceController createCloseResourceController(UserRequest ureq, WindowControl wControl, RepositoryEntry repositoryEntry) {
 		throw new AssertException("not implemented");
 	}
diff --git a/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java b/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java
index dbc755a1763aeeb43cced52a5d2a8f295b53af5e..5e229ba033ea427bfee5144e6e7266e2055f1501 100644
--- a/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java
+++ b/src/main/java/de/bps/ims/qti/repository/handlers/QTITestHandlerOnyx.java
@@ -39,15 +39,9 @@ import org.olat.core.gui.control.generic.layout.MainLayoutController;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.logging.AssertException;
 import org.olat.ims.qti.editor.AddNewQTIDocumentController;
-import org.olat.ims.qti.editor.QTIEditorMainController;
 import org.olat.ims.qti.fileresource.TestFileResource;
 import org.olat.ims.qti.process.AssessmentInstance;
-import org.olat.ims.qti.process.ImsRepositoryResolver;
-import org.olat.ims.qti.process.Resolver;
 import org.olat.ims.qti.repository.handlers.QTITestHandler;
-import org.olat.modules.iq.IQManager;
-import org.olat.modules.iq.IQPreviewSecurityCallback;
-import org.olat.modules.iq.IQSecurityCallback;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.controllers.AddFileResourceController;
 import org.olat.repository.controllers.IAddController;
@@ -55,7 +49,6 @@ import org.olat.repository.controllers.RepositoryAddCallback;
 import org.olat.repository.controllers.RepositoryAddController;
 import org.olat.repository.controllers.WizardCloseResourceController;
 import org.olat.resource.accesscontrol.ui.RepositoryMainAccessControllerWrapper;
-import org.olat.resource.references.ReferenceManager;
 
 import de.bps.onyx.plugin.OnyxModule;
 import de.bps.onyx.plugin.run.OnyxRunController;
@@ -74,28 +67,31 @@ public class QTITestHandlerOnyx extends QTITestHandler {
 	private static final boolean DOWNLOADEABLE = true;
 	private static final boolean EDITABLE = true;
 
-	static List supportedTypes;
+	static List<String> supportedTypes;
 
 	/**
-	 * Default construcotr.
+	 * Default constructor.
 	 */
-	public QTITestHandlerOnyx() { super(); } 
+	public QTITestHandlerOnyx() { 
+		super();
+	} 
 
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getSupportedTypes()
 	 */
-	public List getSupportedTypes() {
+	public List<String> getSupportedTypes() {
 		return supportedTypes;
 	}
 
 	static { // initialize supported types
-		supportedTypes = new ArrayList(1);
+		supportedTypes = new ArrayList<String>(1);
 		supportedTypes.add(TestFileResource.TYPE_NAME);
 	}
 	
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsLaunch()
 	 */
+	@Override
 	public boolean supportsLaunch(RepositoryEntry repoEntry) { 
 		return LAUNCHEABLE; 
 	}
@@ -103,18 +99,24 @@ public class QTITestHandlerOnyx extends QTITestHandler {
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsDownload()
 	 */
-	public boolean supportsDownload(RepositoryEntry repoEntry) { return DOWNLOADEABLE; }
+	@Override
+	public boolean supportsDownload(RepositoryEntry repoEntry) {
+		return DOWNLOADEABLE;
+	}
+	
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#supportsEdit()
 	 */
+	@Override
 	public boolean supportsEdit(RepositoryEntry repoEntry) {
 		if (OnyxModule.isOnyxTest(repoEntry.getOlatResource())) {
 			return false;
 		}
 		return EDITABLE; 
-		}
+	}
 	
-	public MainLayoutController createLaunchController(OLATResourceable res, String initialViewIdentifier, UserRequest ureq, WindowControl wControl) {
+	@Override
+	public MainLayoutController createLaunchController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
 		MainLayoutController layoutCtr = (MainLayoutController) getLaunchController( res,  ureq,  wControl);
 		//fxdiff VCRP-1: access control of learn resources
 		RepositoryMainAccessControllerWrapper wrapper = new RepositoryMainAccessControllerWrapper(ureq, wControl, res, layoutCtr);
@@ -127,11 +129,9 @@ public class QTITestHandlerOnyx extends QTITestHandler {
 	 * @param wControl
 	 * @return Controller
 	 */
+	@Override
 	public Controller getLaunchController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
-		
 		if (OnyxModule.isOnyxTest(res)) {
-			Resolver resolver = new ImsRepositoryResolver(res);
-			IQSecurityCallback secCallback = new IQPreviewSecurityCallback();
 			// <OLATCE-1054>
 			Controller runController = new OnyxRunController(ureq, wControl, res, false);
 			// </OLATCE-1054>
@@ -148,33 +148,19 @@ public class QTITestHandlerOnyx extends QTITestHandler {
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getEditorController(org.olat.core.id.OLATResourceable org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
 	 */
+	@Override
 	public Controller createEditorController(OLATResourceable res, UserRequest ureq, WindowControl wControl) {
-		
 		if (OnyxModule.isOnyxTest(res)) {
 			return null;
 		} else {
 			return super.createEditorController(res, ureq, wControl);
 		}
-		
-//		TestFileResource fr = new TestFileResource();
-//		fr.overrideResourceableId(res.getResourceableId());
-//		
-//		//check if we can edit in restricted mode -> only typos 
-//		ReferenceManager refM = ReferenceManager.getInstance();
-//		List referencees = refM.getReferencesTo(res);
-//		//String referencesSummary = refM.getReferencesToSummary(res, ureq.getLocale());
-//		//boolean restrictedEdit = referencesSummary != null;
-//		QTIEditorMainController editor =  new QTIEditorMainController(referencees,ureq, wControl, fr);
-//		if (editor.isLockedSuccessfully()) {
-//			return editor;
-//		} else {
-//			return null;
-//		}
 	}
 
 	/**
 	 * @see org.olat.repository.handlers.RepositoryHandler#getAddController(org.olat.repository.controllers.RepositoryAddCallback, java.lang.Object, org.olat.core.gui.UserRequest, org.olat.core.gui.control.WindowControl)
 	 */
+	@Override
 	public IAddController createAddController(RepositoryAddCallback callback, Object userObject, UserRequest ureq, WindowControl wControl) {
 		if (userObject == null || userObject.equals(RepositoryAddController.PROCESS_ADD))
 			return new AddFileResourceController(callback, supportedTypes, new String[] {"zip"}, ureq, wControl);
@@ -182,12 +168,13 @@ public class QTITestHandlerOnyx extends QTITestHandler {
 			return new AddNewQTIDocumentController(AssessmentInstance.QMD_ENTRY_TYPE_ASSESS, callback, ureq, wControl);
 	}
 
+	@Override
 	protected String getDeletedFilePrefix() {
 		return "del_qtitest_"; 
 	}
-	
+
+	@Override
 	public WizardCloseResourceController createCloseResourceController(UserRequest ureq, WindowControl wControl, RepositoryEntry repositoryEntry) {
 		throw new AssertException("not implemented");
 	}
-
 }
diff --git a/src/main/java/org/olat/NewControllerFactory.java b/src/main/java/org/olat/NewControllerFactory.java
index 04ad67dfbc78512ddc15b0d4c74e25de06797925..d537ff9f1bffdc928686f6364a11cfce9bc62b43 100644
--- a/src/main/java/org/olat/NewControllerFactory.java
+++ b/src/main/java/org/olat/NewControllerFactory.java
@@ -240,9 +240,12 @@ public class NewControllerFactory extends LogDelegator {
 				}
 
 				dt.setController(launchC);
-				dts.addDTab(ureq, dt);
-				dts.activate(ureq, dt, context.getContext()); // null: do not activate to a certain view
-				return true;
+				if(dts.addDTab(ureq, dt)) {
+					dts.activate(ureq, dt, context.getContext()); // null: do not activate to a certain view
+					return true;
+				} else {
+					return false;
+				}
 			}
 		}
 	}
diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
index 799b58523c612749f5adc496110f8eed95acece1..2d5c1ff42b49231a228bbe6ec755c5b0b860e4b9 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiController.java
@@ -135,7 +135,7 @@ public class UserSearchFlexiController extends FormBasicController {
 
 			Roles roles = ureq.getUserSession().getRoles();
 			isAdministrativeUser = securityModule.isUserAllowedAdminProps(roles);
-			searchform = new UserSearchForm(ureq, getWindowControl(), isAdministrativeUser, false, formLayout.getRootForm());
+			searchform = new UserSearchForm(ureq, getWindowControl(), isAdministrativeUser, false, mainForm);
 			listenTo(searchform);
 			
 			searchPanel.setContent(searchform.getInitialComponent());
@@ -175,7 +175,7 @@ public class UserSearchFlexiController extends FormBasicController {
 			tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("select"));
 			
 			Translator myTrans = userManager.getPropertyHandlerTranslator(getTranslator());
-			userTableModel = new UserSearchFlexiTableModel(Collections.<UserResultWrapper>emptyList(), resultingPropertyHandlers, getLocale(), tableColumnModel);
+			userTableModel = new UserSearchFlexiTableModel(Collections.<UserResultWrapper>emptyList(), resultingPropertyHandlers, isAdministrativeUser, getLocale(), tableColumnModel);
 			tableEl = uifactory.addTableElement("users", userTableModel, myTrans, formLayout);
 
 			selectAll = uifactory.addFormLink("selectall", formLayout);
diff --git a/src/main/java/org/olat/admin/user/UserSearchFlexiTableModel.java b/src/main/java/org/olat/admin/user/UserSearchFlexiTableModel.java
index 2c262d6425c93588658640559ec83be43d663336..31c4231fffc7b9ef90cc5e8b9462f27d270248d4 100644
--- a/src/main/java/org/olat/admin/user/UserSearchFlexiTableModel.java
+++ b/src/main/java/org/olat/admin/user/UserSearchFlexiTableModel.java
@@ -34,13 +34,16 @@ import org.olat.user.propertyhandlers.UserPropertyHandler;
  */
 public class UserSearchFlexiTableModel extends DefaultTableDataModel<UserResultWrapper> implements FlexiTableDataModel {
 	private Locale locale;
+	private boolean isAdministrativeUser;
 	private FlexiTableColumnModel columnModel;
 	private List<UserPropertyHandler> userPropertyHandlers;
 	
 	public UserSearchFlexiTableModel(List<UserResultWrapper> identities, List<UserPropertyHandler> userPropertyHandlers,
-			Locale locale, FlexiTableColumnModel columnModel) {
+			boolean isAdministrativeUser, Locale locale, FlexiTableColumnModel columnModel) {
 		super(identities);
+		this.locale = locale;
 		this.columnModel = columnModel;
+		this.isAdministrativeUser = isAdministrativeUser;
 		this.userPropertyHandlers = userPropertyHandlers;
 	}
 
@@ -62,24 +65,25 @@ public class UserSearchFlexiTableModel extends DefaultTableDataModel<UserResultW
 	@Override
 	public Object getValueAt(int row, int col) {
 		UserResultWrapper option = getObject(row);
-		switch(col) {
-			case 0: return option.getSelectEl();
-			case 1: return option.getIdentity().getName();
-			default: {
-				int pos = col - 2;
-				if(pos >= 0 && pos < userPropertyHandlers.size()) {
-					UserPropertyHandler handler = userPropertyHandlers.get(pos);
-					return handler.getUserProperty(option.getIdentity().getUser(), locale);
-				} else if(pos > 0) {
-					return option.getSelectLink();
-				}
-				return "";
-			}
+		if(col == 0) {
+			return option.getSelectEl();
 		}
+		if(col == 1 && isAdministrativeUser) {
+			return option.getIdentity().getName();
+		} 
+
+		int pos = isAdministrativeUser ? col - 2 : col - 1;
+		if(pos >= 0 && pos < userPropertyHandlers.size()) {
+			UserPropertyHandler handler = userPropertyHandlers.get(pos);
+			return handler.getUserProperty(option.getIdentity().getUser(), locale);
+		} else if(pos > 0) {
+			return option.getSelectLink();
+		}
+		return "";
 	}
 
 	@Override
 	public UserSearchFlexiTableModel createCopyWithEmptyList() {
-		return new UserSearchFlexiTableModel(new ArrayList<UserResultWrapper>(), userPropertyHandlers, locale, columnModel);
+		return new UserSearchFlexiTableModel(new ArrayList<UserResultWrapper>(), userPropertyHandlers, isAdministrativeUser, locale, columnModel);
 	}
 }
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
index e61b15f12586aa19571edf29863ca6a24e827f38..6ffbe54d0d2c3ccfd62f3ec472192378bab871b4 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_de.properties
@@ -27,6 +27,8 @@ edit.uprop=Properties
 edit.upwd=Passwort \u00E4ndern
 edit.uquota=Quota
 edit.uroles=Rollen
+email.sent=$org.olat.user\:email.sent
+email.notsent=$org.olat.user\:email.notsent
 error.no.user.found=Es konnte kein Benutzer mit diesen Angaben gefunden werden. Bitte versuchen Sie es noch einmal.
 error.noaccess.to.user=Sie haben nicht gen\u00FCgend Berechtigungen um diesen Benutzer zu editieren. Wenden Sie Sich an {0}.
 error.password.nomatch=Die beiden neuen Passw\u00F6rter stimmen nicht \u00FCberein.
diff --git a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
index 7dba14a1215a92b75ed84fd60b4f8767fe1d4a83..cf767ed7e929e6db91022d57647fcd627f355251 100644
--- a/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/user/_i18n/LocalStrings_en.properties
@@ -27,6 +27,8 @@ edit.uprop=Properties
 edit.upwd=Change password
 edit.uquota=Quota
 edit.uroles=Roles
+email.sent=$org.olat.user\:email.sent
+email.notsent=$org.olat.user\:email.notsent
 error.no.user.found=No user was found with these attributes. Please try again.
 error.noaccess.to.user=You do not have enough rights to edit this user. Please contact {0}.
 error.password.nomatch=The two new passwords do not match.
diff --git a/src/main/java/org/olat/commons/calendar/ImportCalendarManager.java b/src/main/java/org/olat/commons/calendar/ImportCalendarManager.java
index 91d35a566be6683d4045f0699ef7ae1861b725b4..c8ba9c16dd2f84a86a0b888a68f7c8a17b92f997 100644
--- a/src/main/java/org/olat/commons/calendar/ImportCalendarManager.java
+++ b/src/main/java/org/olat/commons/calendar/ImportCalendarManager.java
@@ -279,16 +279,15 @@ public class ImportCalendarManager extends BasicManager {
 	 * @param calId
 	 */
 	private static void reloadCalendarFromUrl(String importUrl, String calType, String calId) {
-	    try {
-	        String calendarContent = getContentFromUrl(importUrl);
-	        CalendarManager calManager = CalendarManagerFactory.getInstance().getCalendarManager();
-	        Kalendar kalendar = calManager.buildKalendarFrom(calendarContent, calType, calId);
-	        calManager.persistCalendar(kalendar);
-        } catch (IOException e) {
-        	log.error("Could not reload calendar from url=" + importUrl, e);
-        }
-	    
+    try {
+    	String calendarContent = getContentFromUrl(importUrl);
+    	CalendarManager calManager = CalendarManagerFactory.getInstance().getCalendarManager();
+    	Kalendar kalendar = calManager.buildKalendarFrom(calendarContent, calType, calId);
+    	calManager.persistCalendar(kalendar);
+    } catch (Exception e) {
+      	log.error("Could not reload calendar from url=" + importUrl, e);
     }
+	}
 
 	/**
 	 * Get a temporary calendarID for upload
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
index 3441d3049f2c9ceb3b6f151dbe5a108142f28c9e..468162a5ccd9292f1fa3fd2eb833218bcf74d5d6 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
+++ b/src/main/java/org/olat/core/commons/fullWebApp/BaseFullWebappController.java
@@ -252,8 +252,8 @@ public class BaseFullWebappController extends BasicController implements Generic
 				BaseFullWebappController.this.activateStatic(ureq, className, null, entries);
 			}
 
-			public void addDTab(UserRequest ureq, DTab dt) {
-				BaseFullWebappController.this.addDTab(ureq, dt);
+			public boolean addDTab(UserRequest ureq, DTab dt) {
+				return BaseFullWebappController.this.addDTab(ureq, dt);
 			}
 			//fxdiff BAKS-7 Resume function
 			public DTab createDTab(OLATResourceable ores, String title) {
@@ -543,10 +543,10 @@ public class BaseFullWebappController extends BasicController implements Generic
 			updateBusinessPath(ureq, dt);
 		} else {
 			StateEntry s = state.getTransientState();
-			if(s instanceof StateSite && sites != null) {
+			if(s instanceof StateSite && ((StateSite)s).getSite() != null && sites != null) {
 				SiteInstance site = ((StateSite)s).getSite();
 				for(SiteInstance savedSite:sites) {
-					if(site.getClass().equals(savedSite.getClass())) {
+					if(savedSite != null && site.getClass().equals(savedSite.getClass())) {
 						activateSite(savedSite, ureq, null, entries);
 						//updateBusinessPath(ureq, savedSite);
 					}
@@ -867,13 +867,17 @@ public class BaseFullWebappController extends BasicController implements Generic
 	/**
 	 * @see org.olat.core.gui.control.generic.dtabs.DTabs#addDTab(org.olat.core.gui.control.generic.dtabs.DTab)
 	 */
-	public void addDTab(UserRequest ureq, DTab dt) {
+	public boolean addDTab(UserRequest ureq, DTab dt) {
+		if(isDisposed()) {
+			return false;
+		}
+
 		DTab old = getDTab(dt.getOLATResourceable());
 		if (old != null) {
 			//do make a red screen for that
 			//throw new AssertException("dtabs already contained: " + old);
 			getWindowControl().getWindowBackOffice().getWindow().setAttribute("BUSPATH", dt.getWindowControl());
-			return;
+			return true;
 		}
 		// add to tabs list
 		synchronized (dtabs) {
@@ -911,7 +915,7 @@ public class BaseFullWebappController extends BasicController implements Generic
 		//set current BusPath for extraction in the TopNav Controller
 		//FIXME:pb:2009-06-21:move core
 		getWindowControl().getWindowBackOffice().getWindow().setAttribute("BUSPATH", dt.getWindowControl());		
-		
+		return true;
 	}
 
 	/**
diff --git a/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperDAO.java b/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperDAO.java
index 2202907eee96ae312893b742b641c1812cd300f9..36b959083653fb7350b26d1c8e9f0a6b687cf333 100644
--- a/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperDAO.java
+++ b/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperDAO.java
@@ -23,7 +23,6 @@ import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
 
-import javax.persistence.LockModeType;
 import javax.persistence.TemporalType;
 
 import org.olat.core.commons.persistence.DB;
@@ -57,25 +56,29 @@ public class MapperDAO {
 		return m;
 	}
 	
-	public void updateConfiguration(String mapperId, Serializable mapper) {
+	public boolean updateConfiguration(String mapperId, Serializable mapper) {
 		PersistedMapper m = loadForUpdate(mapperId);
+		if(m == null) {
+			return false;
+		}
 		
 		String configuration = XStreamHelper.createXStreamInstance().toXML(mapper);
 		m.setXmlConfiguration(configuration);
 		m.setLastModified(new Date());
-		
 		dbInstance.getCurrentEntityManager().merge(m);
+		return true;
 	}
 	
 	private PersistedMapper loadForUpdate(String mapperId) {
 		StringBuilder q = new StringBuilder();
 		q.append("select mapper from ").append(PersistedMapper.class.getName()).append(" as mapper ")
-		 .append(" where mapper.mapperId=:mapperId");
+		 .append(" where mapper.mapperId=:mapperId order by mapper.key");
 		
 		List<PersistedMapper> mappers = dbInstance.getCurrentEntityManager()
 				.createQuery(q.toString(), PersistedMapper.class)
 				.setParameter("mapperId", mapperId)
-				.setLockMode(LockModeType.PESSIMISTIC_WRITE)
+				.setFirstResult(0)
+				.setMaxResults(1)
 				.getResultList();
 		return mappers.isEmpty() ? null : mappers.get(0);
 	}
diff --git a/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperServiceImpl.java b/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperServiceImpl.java
index 1de2c879587b56b3075589dd5e235f027e28968c..a168bc9c1e12763ccf55792fc107fe84a3bcf14a 100644
--- a/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperServiceImpl.java
+++ b/src/main/java/org/olat/core/dispatcher/mapper/manager/MapperServiceImpl.java
@@ -30,6 +30,7 @@ import java.util.UUID;
 import org.olat.core.dispatcher.DispatcherAction;
 import org.olat.core.dispatcher.mapper.Mapper;
 import org.olat.core.dispatcher.mapper.MapperService;
+import org.olat.core.dispatcher.mapper.model.PersistedMapper;
 import org.olat.core.id.OLATResourceable;
 import org.olat.core.util.Encoder;
 import org.olat.core.util.StringHelper;
@@ -84,16 +85,7 @@ public class MapperServiceImpl implements MapperService {
 	@Override
 	public String register(UserSession session, Mapper mapper) {
 		String mapid = UUID.randomUUID().toString().replace("-", "");
-		return register(session, mapid, mapper);
-	}	
-		
-	@Override
-	public String register(UserSession session, String mapid, Mapper mapper) {
-		String saveMapperID = Encoder.encrypt(mapid);
-		return internRegister(session, saveMapperID, mapper);
-	}
-	
-	private String internRegister(UserSession session, String mapid, Mapper mapper) {
+		mapid = Encoder.encrypt(mapid);
 		mapperIdToMapper.put(mapid, mapper);
 		mapperToMapperId.put(mapper, mapid);
 		if(session.getSessionInfo() == null) {
@@ -113,6 +105,35 @@ public class MapperServiceImpl implements MapperService {
 			mapperDao.persistMapper(sessionId, mapid, (Serializable)mapper);
 		}
 		return WebappHelper.getServletContextPath() + DispatcherAction.PATH_MAPPED + mapid;
+	}	
+	
+	/**
+	 * Cacheable mapper, not session dependant
+	 */
+	@Override
+	public String register(UserSession session, String mapperId, Mapper mapper) {
+		String encryptedMapId = Encoder.encrypt(mapperId);
+		boolean alreadyLoaded = mapperIdToMapper.containsKey(encryptedMapId);
+		if(mapper instanceof Serializable) {
+			if(alreadyLoaded) {
+				if(!mapperDao.updateConfiguration(encryptedMapId, (Serializable)mapper)) {
+					mapperDao.persistMapper(null, encryptedMapId, (Serializable)mapper);
+				}
+			} else {
+				PersistedMapper persistedMapper = mapperDao.loadByMapperId(encryptedMapId);
+				if(persistedMapper == null) {
+					mapperDao.persistMapper(null, encryptedMapId, (Serializable)mapper);
+				} else {
+					mapperDao.updateConfiguration(encryptedMapId, (Serializable)mapper);
+				}
+			}
+		}
+		mapperIdToMapper.put(encryptedMapId, mapper);
+		mapperToMapperId.put(mapper, encryptedMapId);
+		if(session.getSessionInfo() == null) {
+			return WebappHelper.getServletContextPath() + DispatcherAction.PATH_MAPPED + encryptedMapId;
+		}
+		return WebappHelper.getServletContextPath() + DispatcherAction.PATH_MAPPED + encryptedMapId;
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java b/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
index a4d005cc075af7c3caa3bf6fcf220b14a5925945..ebd0744b91ffc567476de5b5f71e5339d73830ff 100644
--- a/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
+++ b/src/main/java/org/olat/core/gui/components/table/DefaultColumnDescriptor.java
@@ -147,20 +147,22 @@ public class DefaultColumnDescriptor implements ColumnDescriptor {
 		Object a = table.getTableDataModel().getValueAt(rowa,dataColumn);
 		Object b = table.getTableDataModel().getValueAt(rowb,dataColumn);
 		// depending on the class of the Objects, we compare
-		// FIXME:fj:c Use CollationKeys for Performance to compare Strings
-		 
 		if (a == null || b == null) {
 			return compareNullObjects(a, b);
 		}
 		if (a instanceof String && b instanceof String) {
 			return collator.compare(a, b);
-		} else if (a instanceof Comparable && b instanceof Comparable) {
-			return compareComparablesAndTimestamps(a, b);
-		} else if (a instanceof Boolean && b instanceof Boolean) { // faster than string compare
-			return compareBooleans((Boolean)a, (Boolean)b);
-		} else { // don't know how to compare, use the String value
-			return a.toString().compareTo(b.toString());
 		}
+		if(a instanceof Date && b instanceof Date) {
+			return compareDateAndTimestamps((Date)a, (Date)b);
+		}
+		if (a instanceof Comparable && b instanceof Comparable) {
+			return ((Comparable)a).compareTo((Comparable)b);
+		}
+		/*if (a instanceof Boolean && b instanceof Boolean) { // faster than string compare, boolean are comparable
+			return compareBooleans((Boolean)a, (Boolean)b);
+		}*/
+		return a.toString().compareTo(b.toString());
 	}
 	
 	protected int compareString(final String a, final String b) {
@@ -172,21 +174,22 @@ public class DefaultColumnDescriptor implements ColumnDescriptor {
 		boolean bb = b.booleanValue();
 		return ba? (bb? 0: -1):(bb? 1: 0);
 	}
-
-	protected int compareComparablesAndTimestamps(final Object a, final Object b) {
-		// grmpf, we need to check on timestamp since Timestamp cannot compare dates (ClassCastException)
-		// See also http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5103041 for the java 1.4/1.5 code bug
-		if (a instanceof Timestamp && b instanceof Date) { // a timestamp (a) cannot compare a date (b), but vice versa is ok.
-			Timestamp ta = (Timestamp)a;
-			Date aAsDate = new Date(ta.getTime());
-			return aAsDate.compareTo((Date)b);
-		} else if (a instanceof Date && b instanceof Timestamp) {
+	
+	protected int compareDateAndTimestamps(Date a, Date b) {
+		if (a instanceof Timestamp) { // a timestamp (a) cannot compare a date (b), but vice versa is ok.
+			if(b instanceof Timestamp) {
+				return ((Timestamp)a).compareTo((Timestamp)b);
+			} else {
+				Timestamp ta = (Timestamp)a;
+				Date aAsDate = new Date(ta.getTime());
+				return aAsDate.compareTo((Date)b);
+			}
+		} else if (b instanceof Timestamp) {
 			Timestamp tb = (Timestamp)b;
 			Date bAsDate = new Date(tb.getTime());
 			return ((Date)a).compareTo(bAsDate);
-		} else {
-			return ((Comparable)a).compareTo(b);
 		}
+		return a.compareTo(b);
 	}
 
 	protected int compareNullObjects(final Object a, final Object b) {
diff --git a/src/main/java/org/olat/core/gui/components/table/DefaultTableDataModel.java b/src/main/java/org/olat/core/gui/components/table/DefaultTableDataModel.java
index 371903ebf55cac4127f4488a05b2a4f6c5143d3d..d504e39d7b027958d24d4fe7a05376109dc2aa75 100644
--- a/src/main/java/org/olat/core/gui/components/table/DefaultTableDataModel.java
+++ b/src/main/java/org/olat/core/gui/components/table/DefaultTableDataModel.java
@@ -126,6 +126,6 @@ public abstract class DefaultTableDataModel<U> implements TableDataModel<U> {
 	}
 
 	public Object createCopyWithEmptyList() {
-		throw new AssertException("createCopyWithEmptyList not implemented!"); 
+		throw new AssertException("createCopyWithEmptyList not implemented for model:" + this.getClass().getName()); 
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/gui/components/table/Table.java b/src/main/java/org/olat/core/gui/components/table/Table.java
index 36534bbcd143a1a7ca23d8acb828752f8a6dfad0..93e10459f3a7a2a654c772bd7f9b64ddf2a31ebc 100644
--- a/src/main/java/org/olat/core/gui/components/table/Table.java
+++ b/src/main/java/org/olat/core/gui/components/table/Table.java
@@ -577,14 +577,13 @@ public class Table extends Component implements Comparator {
 			}
 			currentSortingCd.sortingAboutToStart();
 			long start = 0;
-			long stop = 0;
 			boolean logDebug = Tracing.isDebugEnabled(Table.class);
 			if (logDebug){
 				start = System.currentTimeMillis();
 			}
 			Collections.sort(sorter, this);
 			if (logDebug) {
-				stop = System.currentTimeMillis();
+				long stop = System.currentTimeMillis();
 				TableDataModel model = getTableDataModel();
 				Tracing.logDebug("sorting time for " + (model==null ? "null" : model.getRowCount()) + " rows:" + (stop - start) + " ms", Table.class);
 			}
diff --git a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabImpl.java b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabImpl.java
index 877fb4853525d1d1f5548c84f730c9070e7e1295..6e2aaefe0b44e500f426da69d7666619aced07dd 100644
--- a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabImpl.java
+++ b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabImpl.java
@@ -68,14 +68,17 @@ public class DTabImpl implements Disposable, DTab {
 		this.title = title;
 		//Root the JumpInPath - typically all resources are opened in tabs
 		StackedBusinessControl businessControl = new StackedBusinessControl(null, wOrigControl.getBusinessControl());
-		this.wControl = BusinessControlFactory.getInstance().createBusinessWindowControl(businessControl, wOrigControl);
+		wControl = BusinessControlFactory.getInstance().createBusinessWindowControl(businessControl, wOrigControl);
 		
-		//TODO:fj:c calculate truncation depending on how many tabs are already open
 		String typeName = ores.getResourceableTypeName();
-		String shortTitle = title;
-		if (!title.startsWith(I18nManager.IDENT_PREFIX)) {
+		String shortTitle;
+		if(title == null) {
+			shortTitle = "???";
+		} else if (!title.startsWith(I18nManager.IDENT_PREFIX)) {
 			// don't truncate titles when in inline translation mode (OLAT-3811)
 			shortTitle = Formatter.truncate(title,15);
+		} else {
+			shortTitle = title;
 		}
 		navElement = new DefaultNavElement(shortTitle, title, "b_resource_" + typeName.replace(".", "-"));
 	}
diff --git a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
index 1d922473a8371ab23d126d717cbcb0ad96b9d2b7..e563067b8f9bca4dea97b682aec072333fb595dc 100644
--- a/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
+++ b/src/main/java/org/olat/core/gui/control/generic/dtabs/DTabs.java
@@ -79,7 +79,7 @@ public interface DTabs {
 	 * adds the tab. (upon Event.DONE of the contained controller && if controller is DTabAware -> controller.dispose called by dtabs)
 	 * @param dt
 	 */
-	public void addDTab(UserRequest ureq, DTab dt);
+	public boolean addDTab(UserRequest ureq, DTab dt);
 
 	/**
 	 * Remove a tab from tabs-list.
diff --git a/src/main/java/org/olat/core/logging/activity/ThreadLocalUserActivityLogger.java b/src/main/java/org/olat/core/logging/activity/ThreadLocalUserActivityLogger.java
index 4190de14a34eeed1be09b3badf1c9d21e0ba931a..ffa8b72100759a42d718a0f661fdff694f03b7c1 100644
--- a/src/main/java/org/olat/core/logging/activity/ThreadLocalUserActivityLogger.java
+++ b/src/main/java/org/olat/core/logging/activity/ThreadLocalUserActivityLogger.java
@@ -104,7 +104,7 @@ public class ThreadLocalUserActivityLogger {
 	public static Identity getLoggedIdentity() {
 		IUserActivityLogger logger = userActivityLogger_.get();
 		if (logger!=null) {
-			logger.getLoggedIdentity();
+			return logger.getLoggedIdentity();
 		}
 		return null;
 	}
diff --git a/src/main/java/org/olat/core/util/mail/manager/MailManager.java b/src/main/java/org/olat/core/util/mail/manager/MailManager.java
index 07b7615d0a0ad8abca5099aabc70d5cd962ea314..81bcf376b3704ce39f4eaf51f1a95e818616ae6e 100644
--- a/src/main/java/org/olat/core/util/mail/manager/MailManager.java
+++ b/src/main/java/org/olat/core/util/mail/manager/MailManager.java
@@ -1208,6 +1208,9 @@ public class MailManager extends BasicManager {
 				//we want not send really e-mails
 			} else if (mailModule.isMailHostEnabled() && result.getReturnCode() == MailerResult.OK) {
 				// now send the mail
+				if(Settings.isDebuging()) {
+					logInfo("E-mail send: " + msg.getSubject());
+				}
 				Transport.send(msg);
 			} else {
 				result.setReturnCode(MailerResult.MAILHOST_UNDEFINED);
diff --git a/src/main/java/org/olat/core/util/mail/ui/MailListController.java b/src/main/java/org/olat/core/util/mail/ui/MailListController.java
index eeb04464c1a93ef7a942ffd5e8f442360ef61e53..b1e9370e698eda721e471b06172b6bb7e57436f6 100644
--- a/src/main/java/org/olat/core/util/mail/ui/MailListController.java
+++ b/src/main/java/org/olat/core/util/mail/ui/MailListController.java
@@ -66,6 +66,7 @@ import org.olat.core.util.mail.model.DBMail;
 import org.olat.core.util.mail.model.DBMailImpl;
 import org.olat.core.util.mail.model.DBMailRecipient;
 import org.olat.core.util.mail.ui.MailDataModel.Columns;
+import org.olat.core.util.mail.ui.MailDataModel.ContextPair;
 import org.olat.core.util.resource.OresHelper;
 
 
@@ -135,7 +136,19 @@ public class MailListController extends BasicController implements Activateable2
 		if(outbox) {
 			//context / recipients / subject / sendDate
 			tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.context.i18nKey(), Columns.context.ordinal(), null,
-					getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator())));
+					getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator())) {
+					@Override
+					public int compareTo(int rowa, int rowb) {
+						Object a = table.getTableDataModel().getValueAt(rowa,dataColumn);
+						Object b = table.getTableDataModel().getValueAt(rowb,dataColumn);
+						if(a instanceof ContextPair && b instanceof ContextPair) {
+							ContextPair p1 = (ContextPair)a;
+							ContextPair p2 = (ContextPair)b;
+							return super.compareString(p1.getName(), p2.getName());
+						}
+						return super.compareTo(rowa, rowb);
+					}
+			});
 			tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.recipients.i18nKey(), Columns.recipients.ordinal(), null, getLocale()));
 			tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.subject.i18nKey(), Columns.subject.ordinal(), CMD_READ, getLocale()));
 			tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.sendDate.i18nKey(), Columns.sendDate.ordinal(), null, getLocale()));
@@ -148,7 +161,19 @@ public class MailListController extends BasicController implements Activateable2
 			tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.marked.i18nKey(), Columns.marked.ordinal(), CMD_MARK_TOGGLE, 
 					getLocale(), ColumnDescriptor.ALIGNMENT_CENTER, markRenderer));
 			tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.context.i18nKey(), Columns.context.ordinal(), null,
-					getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator())));
+					getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailContextCellRenderer(this, tableVC, getTranslator())){
+						@Override
+						public int compareTo(int rowa, int rowb) {
+							Object a = table.getTableDataModel().getValueAt(rowa,dataColumn);
+							Object b = table.getTableDataModel().getValueAt(rowb,dataColumn);
+							if(a instanceof ContextPair && b instanceof ContextPair) {
+								ContextPair p1 = (ContextPair)a;
+								ContextPair p2 = (ContextPair)b;
+								return super.compareString(p1.getName(), p2.getName());
+							}
+							return super.compareTo(rowa, rowb);
+						}
+			});
 			tableCtr.addColumnDescriptor(new CustomRenderColumnDescriptor(Columns.from.i18nKey(), Columns.from.ordinal(), null,
 					getLocale(), ColumnDescriptor.ALIGNMENT_LEFT, new MailFromCellRenderer(this, tableVC, getTranslator())));
 			tableCtr.addColumnDescriptor(new DefaultColumnDescriptor(Columns.subject.i18nKey(), Columns.subject.ordinal(), CMD_READ, getLocale()));
@@ -373,7 +398,9 @@ public class MailListController extends BasicController implements Activateable2
 			if(DialogBoxUIFactory.isYesEvent(event)) {
 				BitSet deleteMails = (BitSet)deleteConfirmationBox.getUserObject();
 				for (int i=deleteMails.nextSetBit(0); i >= 0; i=deleteMails.nextSetBit(i+1)) {
-					DBMailImpl mail = (DBMailImpl) tableCtr.getTableDataModel().getObject(i);
+					DBMail mail = (DBMail)tableCtr.getTableDataModel().getObject(i);
+					//reload the message
+					mail = mailManager.getMessageByKey(mail.getKey());
 					boolean deleteMetaMail = outbox && !StringHelper.containsNonWhitespace(metaId);
 					mailManager.delete(mail, getIdentity(), deleteMetaMail);
 					// Do not remove from model to prevent concurrent modification
diff --git a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
index 21362745c7ce5b854495e19f54edd1082db77215..380330477ff36849f6dfeeaf6dd6baeb8da0dcd1 100644
--- a/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
+++ b/src/main/java/org/olat/course/archiver/ScoreAccountingHelper.java
@@ -325,7 +325,6 @@ public class ScoreAccountingHelper {
 			} else {
 				minVal = acnode.getMinScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMinScoreConfiguration());
 				maxVal = acnode.getMaxScoreConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getMaxScoreConfiguration());
-				cutVal = acnode.getCutValueConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getCutValueConfiguration());
 				if (acnode.hasPassedConfigured()) {
 					cutVal = acnode.getCutValueConfiguration() == null ? "-" : AssessmentHelper.getRoundedScore(acnode.getCutValueConfiguration());
 				} else {
diff --git a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
index 69fb769a1fbea6cd7a08121fb49235a1d5d47eea..235f35d6a81a8df6c7008d9f60487c31860c7745 100644
--- a/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/ConditionInterpreter.java
@@ -116,6 +116,7 @@ public class ConditionInterpreter {
 		env.addFunction(IsUserFunction.name, new IsUserFunction(userCourseEnv));
 		env.addFunction(IsGuestFunction.name, new IsGuestFunction(userCourseEnv));
 		env.addFunction(IsGlobalAuthorFunction.name, new IsGlobalAuthorFunction(userCourseEnv));
+		env.addFunction(Sleep.name, new Sleep(userCourseEnv));
 		EvalAttributeFunction eaf;
 		eaf = new EvalAttributeFunction(userCourseEnv, EvalAttributeFunction.FUNCTION_TYPE_HAS_ATTRIBUTE);
 		env.addFunction(eaf.name, eaf);
diff --git a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
index 0c9f6152cbce30482527eea85fe1a8b7dcd8c135..52d865f6520e6b413069e4cb96249967753fa2ee 100644
--- a/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
+++ b/src/main/java/org/olat/course/condition/interpreter/OnlyGroupConditionInterpreter.java
@@ -78,6 +78,7 @@ public class OnlyGroupConditionInterpreter extends ConditionInterpreter{
 		env.addFunction(IsUserFunction.name, new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(IsGuestFunction.name, new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(IsGlobalAuthorFunction.name, new DummyBooleanFunction(userCourseEnv));
+		env.addFunction(Sleep.name, new Sleep(userCourseEnv));
 		env.addFunction("hasAttribute", new DummyBooleanFunction(userCourseEnv));
 		env.addFunction("isInAttribute", new DummyBooleanFunction(userCourseEnv));
 		env.addFunction(GetUserPropertyFunction.name, new DummyStringFunction(userCourseEnv));
diff --git a/src/main/java/org/olat/course/condition/interpreter/Sleep.java b/src/main/java/org/olat/course/condition/interpreter/Sleep.java
new file mode 100644
index 0000000000000000000000000000000000000000..df7499351797c2c7df919b2c38b756497668298e
--- /dev/null
+++ b/src/main/java/org/olat/course/condition/interpreter/Sleep.java
@@ -0,0 +1,78 @@
+/**
+ * <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.condition.interpreter;
+
+import org.olat.core.helpers.Settings;
+import org.olat.core.logging.OLog;
+import org.olat.core.logging.Tracing;
+import org.olat.course.editor.CourseEditorEnv;
+import org.olat.course.run.userview.UserCourseEnvironment;
+
+/**
+ * 
+ * To use in debug mode to catch concurrency issues
+ * 
+ * Initial date: 29.01.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class Sleep extends AbstractFunction {
+	private static final OLog log = Tracing.createLoggerFor(Sleep.class);
+	
+	public static final String name = "sleep";
+
+	/**
+	 * @param userCourseEnv
+	 */
+	public Sleep(UserCourseEnvironment userCourseEnv) {
+		super(userCourseEnv);
+	}
+
+	/**
+	 * @see com.neemsoft.jmep.FunctionCB#call(java.lang.Object[])
+	 */
+	public Object call(Object[] inStack) {
+		
+		CourseEditorEnv cev = getUserCourseEnv().getCourseEditorEnv();
+		if (cev != null) {
+			// return a valid value to continue with condition evaluation test
+			return defaultValue();
+		} else if(Settings.isDebuging()) {
+			long sleep = 30000;
+			if(inStack == null || inStack.length == 0) {
+				//stay with default
+			} else if(inStack[0] instanceof String) {
+				String sleepStr = (String)inStack[0];
+				sleep = Long.parseLong(sleepStr);
+			}
+			
+			try {
+				Thread.sleep(sleep);
+			} catch (InterruptedException e) {
+				log.error("", e);
+			}
+		}
+		return ConditionInterpreter.INT_TRUE;
+	}
+
+	protected Object defaultValue() {
+		return ConditionInterpreter.INT_TRUE;
+	}
+}
diff --git a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
index ec19f4c4c770d67d0472e7cafa4d838123fc0378..db3979112d8cd75fd417c5a4c3e30c8b2b515d94 100644
--- a/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/member/_i18n/LocalStrings_de.properties
@@ -9,6 +9,7 @@ dedup.members=Mitglieder bereinigen
 dedup.done=Bereinigung der Kursmitglieder und Gruppenmitglieder wurde erfolgreich beendet
 dedup.members.notfound=Es gibt kein Mitglieder die sowohl Kursmitglieder als auch Gruppenmitglieder sind
 dialog.modal.bg.leave.text=Wollen Sie wirklich die Person(en) {0} aus dem Kurs und allen Gruppen entfernen?
+dialog.modal.bg.send.mail=$org.olat.group.ui.main\:dialog.modal.bg.send.mail
 edit.member=Mitglied bearbeiten
 edit.member.groups=Gruppenmitgliedschaften
 edit.member.groups.desc=F\u00FCgen Sie den Benutzer den unten aufgef\u00FChrten Gruppen durch Ausw\u00E4hlen der entsprechenden Checkbox(en) hinzu.
diff --git a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewDataModel.java b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewDataModel.java
new file mode 100644
index 0000000000000000000000000000000000000000..95caece510b40f42e7225d29b077a3df5932706f
--- /dev/null
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewDataModel.java
@@ -0,0 +1,85 @@
+/**
+ * <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.member.wizard;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModel;
+import org.olat.core.gui.components.table.DefaultTableDataModel;
+import org.olat.core.id.Identity;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class ImportMemberOverviewDataModel extends DefaultTableDataModel<Identity> implements FlexiTableDataModel {
+	private final Locale locale;
+	private final boolean isAdministrativeUser;
+	private FlexiTableColumnModel columnModel;
+	private final List<UserPropertyHandler> userPropertyHandlers;
+	
+	public ImportMemberOverviewDataModel(List<Identity> identities, List<UserPropertyHandler> userPropertyHandlers,
+			boolean isAdministrativeUser, Locale locale, FlexiTableColumnModel columnModel) {
+		super(identities);
+		this.locale = locale;
+		this.columnModel = columnModel;
+		this.isAdministrativeUser = isAdministrativeUser;
+		this.userPropertyHandlers = userPropertyHandlers;
+	}
+
+	@Override
+	public FlexiTableColumnModel getTableColumnModel() {
+		return columnModel;
+	}
+
+	@Override
+	public void setTableColumnModel(FlexiTableColumnModel tableColumnModel) {
+		columnModel = tableColumnModel;
+	}
+
+	@Override
+	public int getColumnCount() {
+		return columnModel.getColumnCount();
+	}
+
+	@Override
+	public Object getValueAt(int row, int col) {
+		Identity identity = getObject(row);
+		if(col == 0 && isAdministrativeUser) {
+			return identity.getName();
+		}
+
+		int pos = isAdministrativeUser ? col - 1 : col;
+		if(pos >= 0 && pos < userPropertyHandlers.size()) {
+			UserPropertyHandler handler = userPropertyHandlers.get(pos);
+			return handler.getUserProperty(identity.getUser(), locale);
+		}
+		return "";
+	}
+
+	@Override
+	public ImportMemberOverviewDataModel createCopyWithEmptyList() {
+		return new ImportMemberOverviewDataModel(new ArrayList<Identity>(), userPropertyHandlers, isAdministrativeUser, locale, columnModel);
+	}
+}
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 245b813c367f22623829862f3d994b221de26f79..b9e865f7797cdbfc69dfdb7cf16408c21e0eea90 100644
--- a/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
+++ b/src/main/java/org/olat/course/member/wizard/ImportMemberOverviewIdentitiesController.java
@@ -23,8 +23,9 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-import org.olat.admin.securitygroup.gui.UserControllerFactory;
+import org.olat.admin.user.UserTableDataModel;
 import org.olat.basesecurity.BaseSecurity;
+import org.olat.basesecurity.BaseSecurityModule;
 import org.olat.basesecurity.Constants;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.core.CoreSpringFactory;
@@ -32,27 +33,39 @@ import org.olat.core.commons.persistence.SyncHelper;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.impl.Form;
-import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
-import org.olat.core.gui.components.table.TableController;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.DefaultFlexiColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableColumnModel;
+import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.gui.control.generic.wizard.StepFormBasicController;
 import org.olat.core.gui.control.generic.wizard.StepsEvent;
 import org.olat.core.gui.control.generic.wizard.StepsRunContext;
+import org.olat.core.gui.translator.Translator;
 import org.olat.core.id.Identity;
+import org.olat.user.UserManager;
+import org.olat.user.propertyhandlers.UserPropertyHandler;
 
 /**
  * 
  * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
  */
 public class ImportMemberOverviewIdentitiesController extends StepFormBasicController {
-	private TableController identityTableCtrl;
+	
+	private static final String usageIdentifyer = UserTableDataModel.class.getCanonicalName();
+	
 	private List<Identity> oks;
+	private boolean isAdministrativeUser;
+	
+	private final UserManager userManager;
 	private final BaseSecurity securityManager;
+	private final BaseSecurityModule securityModule;
 
 	public ImportMemberOverviewIdentitiesController(UserRequest ureq, WindowControl wControl, Form rootForm, StepsRunContext runContext) {
-		super(ureq, wControl, rootForm, runContext, LAYOUT_CUSTOM, "confirm_identities");
+		super(ureq, wControl, rootForm, runContext, LAYOUT_VERTICAL, null);
+		userManager = UserManager.getInstance();
 		securityManager = CoreSpringFactory.getImpl(BaseSecurity.class);
+		securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class);
 
 		oks = null;
 		if(containsRunContextKey("logins")) {
@@ -63,14 +76,38 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 			List<String> keys = (List<String>)runContext.get("keys");
 			oks = loadModel(keys);
 		}
-		
-		
-		identityTableCtrl = UserControllerFactory.createTableControllerFor(null, oks, ureq, getWindowControl(), null);
-		listenTo(identityTableCtrl);
+
+		isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
 
 		initForm (ureq);
 	}
 	
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		
+		//add the table
+		FlexiTableColumnModel tableColumnModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
+		if(isAdministrativeUser) {
+			tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel("table.user.login"));
+		}
+		List<UserPropertyHandler> userPropertyHandlers = userManager.getUserPropertyHandlersFor(usageIdentifyer, isAdministrativeUser);
+		List<UserPropertyHandler> resultingPropertyHandlers = new ArrayList<UserPropertyHandler>();
+		// followed by the users fields
+		for (int i = 0; i < userPropertyHandlers.size(); i++) {
+			UserPropertyHandler userPropertyHandler	= userPropertyHandlers.get(i);
+			boolean visible = UserManager.getInstance().isMandatoryUserProperty(usageIdentifyer , userPropertyHandler);
+			if(visible) {
+				resultingPropertyHandlers.add(userPropertyHandler);
+				tableColumnModel.addFlexiColumnModel(new DefaultFlexiColumnModel(userPropertyHandler.i18nColumnDescriptorLabelKey()));
+			}
+		}
+		
+		Translator myTrans = userManager.getPropertyHandlerTranslator(getTranslator());
+		ImportMemberOverviewDataModel userTableModel = new ImportMemberOverviewDataModel(oks, resultingPropertyHandlers,
+				isAdministrativeUser, getLocale(), tableColumnModel);
+		uifactory.addTableElement("users", userTableModel, myTrans, formLayout);
+	}
+	
 	private List<Identity> loadModel(List<String> keys) {
 		List<Identity> existIdents = Collections.emptyList();//securityManager.getIdentitiesOfSecurityGroup(securityGroup);
 
@@ -153,14 +190,6 @@ public class ImportMemberOverviewIdentitiesController extends StepFormBasicContr
 		fireEvent(ureq, StepsEvent.ACTIVATE_NEXT);
 	}
 
-	@Override
-	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		if(formLayout instanceof FormLayoutContainer) {
-			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
-			layoutCont.put("identityList", identityTableCtrl.getInitialComponent());	
-		}
-	}
-
 	@Override
 	protected void doDispose() {
 		//
diff --git a/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_de.properties
index 6274269b9d7d2d24615cdd370aaded8751a54796..e1834de00714b9ea1c5e364b886e1ebed00be26f 100644
--- a/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_de.properties
@@ -5,4 +5,5 @@ import.confirm.title=
 import.permission.title=Berechtigungen
 import.mail.title=E-Mail-Benachrichtigung
 form.names.example=test01<br/>author02<br/>
-form.addusers=Benutzername
\ No newline at end of file
+form.addusers=Benutzername
+table.user.login=$org.olat.group.ui.main\:table.header.login
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_en.properties
index ce33ce12273124324b16116b2e99ed0f6079ebff..4d5a8bd565cc73942242609b6ad427bfa7a30667 100644
--- a/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/member/wizard/_i18n/LocalStrings_en.properties
@@ -6,3 +6,4 @@ import.import.title=Enter user names
 import.choose.title=Indicate user name
 import.mail.title=E-Mail notification
 import.permission.title=Rights
+table.user.login=$org.olat.group.ui.main\:table.header.login
diff --git a/src/main/java/org/olat/course/run/preview/PreviewConfigController.java b/src/main/java/org/olat/course/run/preview/PreviewConfigController.java
index 72c0ccc8a489b53b0d4be52a3d1b1b65fcb1824f..f5d020e24bb1c58707144a60a2857fcf1029cc4c 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewConfigController.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewConfigController.java
@@ -48,6 +48,7 @@ import org.olat.course.ICourse;
 import org.olat.course.Structure;
 import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.auditing.UserNodeAuditManager;
+import org.olat.course.config.CourseConfig;
 import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.properties.CoursePropertyManager;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -180,9 +181,10 @@ public class PreviewConfigController extends MainLayoutBasicController {
 		final CoursePropertyManager cpm = new PreviewCoursePropertyManager();
 		final Structure runStructure = course.getEditorTreeModel().createStructureForPreview();
 		final String title = course.getCourseTitle();
+		final CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig();
 
 		simCourseEnv = new PreviewCourseEnvironment(title, runStructure, psf.getDate(), course.getCourseFolderContainer(), course
-				.getCourseBaseContainer(),course.getResourceableId(), cpm, cgm, auditman, am);
+				.getCourseBaseContainer(),course.getResourceableId(), cpm, cgm, auditman, am, courseConfig);
 		simIdentEnv = new IdentityEnvironment();
 		simIdentEnv.setRoles(new Roles(false, false, false, isGlobalAuthor, isGuestOnly, false, false));
 		final Identity ident = new PreviewIdentity();
diff --git a/src/main/java/org/olat/course/run/preview/PreviewConfigHelper.java b/src/main/java/org/olat/course/run/preview/PreviewConfigHelper.java
index ece4970305bf208aeae0333a332191fe88d3e399..ed50a7e1cb19ca375b1ac98b93a605ba3bce7e40 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewConfigHelper.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewConfigHelper.java
@@ -31,6 +31,7 @@ import org.olat.course.ICourse;
 import org.olat.course.Structure;
 import org.olat.course.assessment.AssessmentManager;
 import org.olat.course.auditing.UserNodeAuditManager;
+import org.olat.course.config.CourseConfig;
 import org.olat.course.groupsandrights.CourseGroupManager;
 import org.olat.course.properties.CoursePropertyManager;
 import org.olat.course.run.environment.CourseEnvironment;
@@ -57,9 +58,10 @@ public class PreviewConfigHelper {
 		final CoursePropertyManager cpm = new PreviewCoursePropertyManager();
 		final Structure runStructure = course.getEditorTreeModel().createStructureForPreview();
 		final String title = course.getCourseTitle();
+		final CourseConfig courseConfig = course.getCourseEnvironment().getCourseConfig();
 
 		CourseEnvironment previewCourseEnvironment = new PreviewCourseEnvironment(title, runStructure, new Date(), course.getCourseFolderContainer(), 
-				course.getCourseBaseContainer(),course.getResourceableId(), cpm, cgm, auditman, am);			
+				course.getCourseBaseContainer(),course.getResourceableId(), cpm, cgm, auditman, am, courseConfig);			
 		
 		return previewCourseEnvironment;
 	}
diff --git a/src/main/java/org/olat/course/run/preview/PreviewCourseEnvironment.java b/src/main/java/org/olat/course/run/preview/PreviewCourseEnvironment.java
index 2e70c9fbd7644e217c0553a11efb6dba8c949343..50e0f4b35c4aa0737469b329e41e9170b0208188 100644
--- a/src/main/java/org/olat/course/run/preview/PreviewCourseEnvironment.java
+++ b/src/main/java/org/olat/course/run/preview/PreviewCourseEnvironment.java
@@ -53,9 +53,11 @@ final class PreviewCourseEnvironment implements CourseEnvironment {
 	private final AssessmentManager am;
 	private final long simulatedDateTime;
 	private Long resourceablId;
+	private CourseConfig courseConfig;
 
-	PreviewCourseEnvironment(String title, Structure runStructure, Date simulatedDateTime, VFSContainer courseFolderContainer, OlatRootFolderImpl courseBaseContainer,
-			Long courseResourceableID, CoursePropertyManager cpm, CourseGroupManager cgm, UserNodeAuditManager auditman, AssessmentManager am) {
+	PreviewCourseEnvironment(String title, Structure runStructure, Date simulatedDateTime, VFSContainer courseFolderContainer,
+			OlatRootFolderImpl courseBaseContainer, Long courseResourceableID, CoursePropertyManager cpm, CourseGroupManager cgm,
+			UserNodeAuditManager auditman, AssessmentManager am, CourseConfig courseConfig) {
 		super();
 		this.title = title;
 		this.simulatedDateTime = simulatedDateTime.getTime();
@@ -67,6 +69,7 @@ final class PreviewCourseEnvironment implements CourseEnvironment {
 		this.auditman = auditman;
 		this.am = am;
 		this.resourceablId = courseResourceableID;
+		this.courseConfig = courseConfig.clone();
 	}
 
 	/**
@@ -135,14 +138,14 @@ final class PreviewCourseEnvironment implements CourseEnvironment {
 	}
 
 	public CourseConfig getCourseConfig() {
-		throw new UnsupportedOperationException("never to be called in preview mode");
+		return courseConfig;
 	}
 
 	/**
 	 * @see org.olat.course.run.environment.CourseEnvironment#setCourseConfig()
 	 */
 	public void setCourseConfig(CourseConfig cc) {
-		throw new UnsupportedOperationException("never to be called in preview mode");
+		courseConfig = (cc == null ? null : cc.clone());
 	}
 
 	/**
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
index fb3c99f50eb7a2fa34a5d5eca093ed83516b6a81..f4c752186e9945bd82f5c8c1d1b8362bbbc01a6e 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_de.properties
@@ -102,6 +102,7 @@ resources.noresources=Diese Gruppe wird in keinem Kurs verwendet. Bitte w\u00E4h
 resources.remove=entfernen
 
 
+dialog.modal.bg.send.mail=$org.olat.group.ui.main\:dialog.modal.bg.send.mail
 add.member=$org.olat.group.ui.main\:add.member
 edit.member=$org.olat.group.ui.main\:edit.member
 edit.member.groups=$org.olat.group.ui.main\:edit.member.groups
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
index f4a1896aaba8546661a29fe7948f0b1635117d12..f6fdf192034c2d9d861f4510eddac58b712e0162 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_en.properties
@@ -69,6 +69,7 @@ chkBox.show.partips=Members can see participants
 chkBox.show.waitingList=Members can see waiting list
 cmd.addresource=Add course
 dialog.modal.bg.leave.text=$org.olat.group.ui.main\:dialog.modal.bg.leave.text
+dialog.modal.bg.send.mail=$org.olat.group.ui.main\:dialog.modal.bg.send.mail
 edit.member=$org.olat.group.ui.main\:edit.member
 edit.member.groups=$org.olat.group.ui.main\:edit.member.groups
 error.message.locked=This group is being edited by user {0} ({1}) and therefore locked. Please try again later.
diff --git a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
index a7078814fc955a6463bd3ad7053b811f69b43c20..9b67c79860658847d166ef6d1aa2e5f1643a53b6 100644
--- a/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
+++ b/src/main/java/org/olat/group/ui/main/AbstractMemberListController.java
@@ -71,6 +71,7 @@ import org.olat.core.util.mail.MailerWithTemplate;
 import org.olat.course.member.MemberListController;
 import org.olat.group.BusinessGroup;
 import org.olat.group.BusinessGroupMembership;
+import org.olat.group.BusinessGroupModule;
 import org.olat.group.BusinessGroupService;
 import org.olat.group.BusinessGroupShort;
 import org.olat.group.model.BusinessGroupMembershipChange;
@@ -100,14 +101,15 @@ public abstract class AbstractMemberListController extends BasicController imple
 	public static final String TABLE_ACTION_REMOVE = "tbl_remove";
 	public static final String TABLE_ACTION_GRADUATE = "tbl_graduate";
 	
-	//protected final MemberListTableModel memberListModel;
 	protected final TableController memberListCtr;
 	protected final VelocityContainer mainVC;
 	
-	private DialogBoxController leaveDialogBox;
 	protected CloseableModalController cmc;
-	private EditMembershipController editMemberCtrl;
+	private EditMembershipController editMembersCtrl;
+	private EditSingleMembershipController editSingleMemberCtrl;
 	private ContactFormController contactCtrl;
+	private MemberLeaveConfirmationController leaveDialogBox;
+	private DialogBoxController confirmSendMailBox;
 	private final List<UserPropertyHandler> userPropertyHandlers;
 
 	private final RepositoryEntry repoEntry;
@@ -120,6 +122,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 	private final BaseSecurityModule securityModule;
 	private final RepositoryManager repositoryManager;
 	private final BusinessGroupService businessGroupService;
+	private final BusinessGroupModule groupModule;
 	private final ACService acService;
 	
 	private static final CourseMembershipComparator MEMBERSHIP_COMPARATOR = new CourseMembershipComparator();
@@ -143,6 +146,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 		securityModule = CoreSpringFactory.getImpl(BaseSecurityModule.class);
 		repositoryManager = CoreSpringFactory.getImpl(RepositoryManager.class);
 		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
+		groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class);
 		acService = CoreSpringFactory.getImpl(ACService.class);
 
 		isAdministrativeUser = securityModule.isUserAllowedAdminProps(ureq.getUserSession().getRoles());
@@ -156,7 +160,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 		memberListCtr = new TableController(tableConfig, ureq, getWindowControl(), getTranslator(), true);
 		listenTo(memberListCtr);
 
-		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, false);
+		userPropertyHandlers = userManager.getUserPropertyHandlersFor(USER_PROPS_ID, isAdministrativeUser);
 		initColumns();
 		MemberListTableModel memberListModel = new MemberListTableModel(userPropertyHandlers);
 		memberListCtr.setTableDataModel(memberListModel);
@@ -240,6 +244,7 @@ public abstract class AbstractMemberListController extends BasicController imple
 				}
 			} else if (event instanceof TableMultiSelectEvent) {
 				TableMultiSelectEvent te = (TableMultiSelectEvent)event;
+				@SuppressWarnings("unchecked")
 				List<MemberView> selectedItems = memberListCtr.getObjects(te.getSelection());
 				if(TABLE_ACTION_REMOVE.equals(te.getAction())) {
 					confirmDelete(ureq, selectedItems);
@@ -252,24 +257,34 @@ public abstract class AbstractMemberListController extends BasicController imple
 				}
 			}
 		} else if (source == leaveDialogBox) {
-			if (event != Event.CANCELLED_EVENT && DialogBoxUIFactory.isYesEvent(event)) {
-				@SuppressWarnings("unchecked")
-				List<Identity> members = (List<Identity>)leaveDialogBox.getUserObject();
-				doLeave(members);
+			if (Event.DONE_EVENT == event) {
+				List<Identity> members = leaveDialogBox.getIdentities();
+				doLeave(members, leaveDialogBox.isSendMail());
 				reloadModel();
 			}
-		} else if(source == editMemberCtrl) {
+			cmc.deactivate();
+			cleanUpPopups();
+		} else if(source == editMembersCtrl) {
+			cmc.deactivate();
 			if(event instanceof MemberPermissionChangeEvent) {
 				MemberPermissionChangeEvent e = (MemberPermissionChangeEvent)event;
-				if(e.getMember() != null) {
-					doChangePermission(ureq, e);
-				} else {
-					doChangePermission(ureq, e, editMemberCtrl.getMembers());
-				}
+				doConfirmChangePermission(ureq, e, editMembersCtrl.getMembers());
 			}
-			
+		} else if(source == editSingleMemberCtrl) {
 			cmc.deactivate();
-			cleanUpPopups();
+			if(event instanceof MemberPermissionChangeEvent) {
+				MemberPermissionChangeEvent e = (MemberPermissionChangeEvent)event;
+				doConfirmChangePermission(ureq, e, null);
+			}
+		} else if(confirmSendMailBox == source) {
+			boolean sendMail = DialogBoxUIFactory.isYesEvent(event) || DialogBoxUIFactory.isOkEvent(event);
+			MailConfirmation confirmation = (MailConfirmation)confirmSendMailBox.getUserObject();
+			MemberPermissionChangeEvent e =confirmation.getE();
+			if(e.getMember() != null) {
+				doChangePermission(ureq, e, sendMail);
+			} else {
+				doChangePermission(ureq, e, confirmation.getMembers(), sendMail);
+			}
 		} else if (source == contactCtrl) {
 			cmc.deactivate();
 			cleanUpPopups();
@@ -283,13 +298,15 @@ public abstract class AbstractMemberListController extends BasicController imple
 	 */
 	protected void cleanUpPopups() {
 		removeAsListenerAndDispose(cmc);
-		removeAsListenerAndDispose(editMemberCtrl);
+		removeAsListenerAndDispose(editMembersCtrl);
+		removeAsListenerAndDispose(editSingleMemberCtrl);
 		removeAsListenerAndDispose(leaveDialogBox);
 		removeAsListenerAndDispose(contactCtrl);
 		cmc = null;
 		contactCtrl = null;
 		leaveDialogBox = null;
-		editMemberCtrl = null;
+		editMembersCtrl = null;
+		editSingleMemberCtrl = null;
 	}
 	
 	protected void confirmDelete(UserRequest ureq, List<MemberView> members) {
@@ -305,15 +322,15 @@ public abstract class AbstractMemberListController extends BasicController imple
 				numOfRemovedOwner++;
 			}
 		}
-		if(numOfOwners - numOfRemovedOwner > 0) {
+		if(numOfRemovedOwner == 0 || numOfOwners - numOfRemovedOwner > 0) {
 			List<Identity> ids = securityManager.loadIdentityByKeys(identityKeys);
-			StringBuilder sb = new StringBuilder();
-			for(Identity id:ids) {
-				if(sb.length() > 0) sb.append(" / ");
-				sb.append(userManager.getUserDisplayName(id.getUser()));
-			}
-			leaveDialogBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.leave.text", sb.toString()), leaveDialogBox);
-			leaveDialogBox.setUserObject(ids);
+			leaveDialogBox = new MemberLeaveConfirmationController(ureq, getWindowControl(), ids);
+			listenTo(leaveDialogBox);
+			
+			cmc = new CloseableModalController(getWindowControl(), translate("close"), leaveDialogBox.getInitialComponent(),
+					true, translate("edit.member"));
+			cmc.activate();
+			listenTo(cmc);
 		} else {
 			showWarning("error.atleastone");
 		}
@@ -321,9 +338,9 @@ public abstract class AbstractMemberListController extends BasicController imple
 	
 	protected void openEdit(UserRequest ureq, MemberView member) {
 		Identity identity = securityManager.loadIdentityByKey(member.getIdentityKey());
-		editMemberCtrl = new EditMembershipController(ureq, getWindowControl(), identity, repoEntry, businessGroup);
-		listenTo(editMemberCtrl);
-		cmc = new CloseableModalController(getWindowControl(), translate("close"), editMemberCtrl.getInitialComponent(),
+		editSingleMemberCtrl = new EditSingleMembershipController(ureq, getWindowControl(), identity, repoEntry, businessGroup);
+		listenTo(editSingleMemberCtrl);
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), editSingleMemberCtrl.getInitialComponent(),
 				true, translate("edit.member"));
 		cmc.activate();
 		listenTo(cmc);
@@ -332,52 +349,77 @@ public abstract class AbstractMemberListController extends BasicController imple
 	protected void openEdit(UserRequest ureq, List<MemberView> members) {
 		List<Long> identityKeys = getMemberKeys(members);
 		List<Identity> identities = securityManager.loadIdentityByKeys(identityKeys);
-		editMemberCtrl = new EditMembershipController(ureq, getWindowControl(), identities, repoEntry, businessGroup);
-		listenTo(editMemberCtrl);
-		cmc = new CloseableModalController(getWindowControl(), translate("close"), editMemberCtrl.getInitialComponent(),
+		editMembersCtrl = new EditMembershipController(ureq, getWindowControl(), identities, repoEntry, businessGroup);
+		listenTo(editMembersCtrl);
+		cmc = new CloseableModalController(getWindowControl(), translate("close"), editMembersCtrl.getInitialComponent(),
 				true, translate("edit.member"));
 		cmc.activate();
 		listenTo(cmc);
 	}
 	
-	protected void doChangePermission(UserRequest ureq, MemberPermissionChangeEvent e) {
+	protected void doConfirmChangePermission(UserRequest ureq, MemberPermissionChangeEvent e, List<Identity> members) {
+		boolean groupChangesEmpty = e.getGroupChanges() == null || e.getGroupChanges().isEmpty();
+		boolean repoChangesEmpty = e.getRepoOwner() == null && e.getRepoParticipant() == null && e.getRepoTutor() == null;
+		if(groupChangesEmpty && repoChangesEmpty) {
+			//nothing to do
+			return;
+		}
+
+		boolean mailMandatory = groupModule.isMandatoryEnrolmentEmail(ureq.getUserSession().getRoles());
+		if(mailMandatory) {
+			if(members == null) {
+				doChangePermission(ureq, e, true);
+			} else {
+				doChangePermission(ureq, e, members, true);
+			}
+		} else {
+			confirmSendMailBox = activateYesNoDialog(ureq, null, translate("dialog.modal.bg.send.mail"), confirmSendMailBox);
+			confirmSendMailBox.setUserObject(new MailConfirmation(e, members));
+		}
+	}
+	
+	protected void doChangePermission(UserRequest ureq, MemberPermissionChangeEvent e, boolean sendMail) {
+		MailPackage mailing = new MailPackage(sendMail);
 		if(repoEntry != null) {
 			List<RepositoryEntryPermissionChangeEvent> changes = Collections.singletonList((RepositoryEntryPermissionChangeEvent)e);
-			repositoryManager.updateRepositoryEntryMembership(getIdentity(), ureq.getUserSession().getRoles(), repoEntry, changes, null);
+			repositoryManager.updateRepositoryEntryMembership(getIdentity(), ureq.getUserSession().getRoles(), repoEntry, changes, mailing);
 		}
 
-		businessGroupService.updateMemberships(getIdentity(), e.getGroupChanges(), null);
+		businessGroupService.updateMemberships(getIdentity(), e.getGroupChanges(), mailing);
 		//make sure all is committed before loading the model again (I see issues without)
 		DBFactory.getInstance().commitAndCloseSession();
 		
-		if(e.getGroupChanges() != null && !e.getGroupChanges().isEmpty()) {
+		/*if(sendMail && e.getGroupChanges() != null && !e.getGroupChanges().isEmpty()) {
 			for (BusinessGroupMembershipChange mod : e.getGroupChanges()) {
 				sendMailAfterChangePermission(mod);
 			}
-		}
+		}*/
 
 		reloadModel();
 	}
 	
-	protected void doChangePermission(UserRequest ureq, MemberPermissionChangeEvent changes, List<Identity> members) {
+	protected void doChangePermission(UserRequest ureq, MemberPermissionChangeEvent changes, List<Identity> members, boolean sendMail) {
+
+		MailPackage mailing = new MailPackage(sendMail);
 		if(repoEntry != null) {
 			List<RepositoryEntryPermissionChangeEvent> repoChanges = changes.generateRepositoryChanges(members);
-			repositoryManager.updateRepositoryEntryMembership(getIdentity(), ureq.getUserSession().getRoles(), repoEntry, repoChanges, null);
+			repositoryManager.updateRepositoryEntryMembership(getIdentity(), ureq.getUserSession().getRoles(), repoEntry, repoChanges, mailing);
 		}
 
 		//commit all changes to the group memberships
 		List<BusinessGroupMembershipChange> allModifications = changes.generateBusinessGroupMembershipChange(members);
-		businessGroupService.updateMemberships(getIdentity(), allModifications, null);
+		businessGroupService.updateMemberships(getIdentity(), allModifications, mailing);
 		DBFactory.getInstance().commitAndCloseSession();
 		
-		if(allModifications != null && !allModifications.isEmpty()) {
+		/*if(sendMail && allModifications != null && !allModifications.isEmpty()) {
 			for (BusinessGroupMembershipChange mod : allModifications) {
 				sendMailAfterChangePermission(mod);
 			}
 		}
 
 		//make sure all is committed before loading the model again (I see issues without)
-		DBFactory.getInstance().commitAndCloseSession();
+		//DBFactory.getInstance().commitAndCloseSession();
+		*/
 		reloadModel();
 	}
 	
@@ -407,8 +449,8 @@ public abstract class AbstractMemberListController extends BasicController imple
 		}
 	}
 	
-	protected void doLeave(List<Identity> members) {
-		MailPackage mailing = new MailPackage();
+	protected void doLeave(List<Identity> members, boolean sendMail) {
+		MailPackage mailing = new MailPackage(sendMail);
 		if(repoEntry != null) {
 			repositoryManager.removeMembers(members, repoEntry);
 			businessGroupService.removeMembers(getIdentity(), members, repoEntry.getOlatResource(), mailing);
@@ -435,7 +477,6 @@ public abstract class AbstractMemberListController extends BasicController imple
 				true, translate("mail.member"));
 		cmc.activate();
 		listenTo(cmc);
-		
 	}
 	
 	protected void doGraduate(UserRequest ureq, List<MemberView> members) {
@@ -672,4 +713,22 @@ public abstract class AbstractMemberListController extends BasicController imple
 		
 		memberList.removeAll(members);
 	}
+	
+	private class MailConfirmation {
+		private final List<Identity> members;
+		private final MemberPermissionChangeEvent e;
+		
+		public MailConfirmation(MemberPermissionChangeEvent e, List<Identity> members) {
+			this.e = e;
+			this.members = members;
+		}
+
+		public List<Identity> getMembers() {
+			return members;
+		}
+
+		public MemberPermissionChangeEvent getE() {
+			return e;
+		}
+	}
 }
diff --git a/src/main/java/org/olat/group/ui/main/EditMembershipController.java b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
index 5b0f8396b0e5a1c8d595e14f491e86b666d0ac9c..77648487ac9edd6a1e14334f37ce8a6ceb752f6e 100644
--- a/src/main/java/org/olat/group/ui/main/EditMembershipController.java
+++ b/src/main/java/org/olat/group/ui/main/EditMembershipController.java
@@ -66,8 +66,6 @@ public class EditMembershipController extends FormBasicController {
 	
 	private EditMemberTableDataModel tableDataModel;
 	private MultipleSelectionElement repoRightsEl;
-	private MemberInfoController infoController;
-	private boolean needMemberInfoController = false;
 	private boolean withButtons;
 	
 	private static final String[] repoRightsKeys = {"owner", "tutor", "participant"};
@@ -97,7 +95,6 @@ public class EditMembershipController extends FormBasicController {
 		businessGroupService = CoreSpringFactory.getImpl(BusinessGroupService.class);
 		
 		memberships = repositoryManager.getRepositoryEntryMembership(repoEntry, member);
-		needMemberInfoController = true;
 		initForm(ureq);
 		loadModel(member);
 		
@@ -119,7 +116,6 @@ public class EditMembershipController extends FormBasicController {
 				}
 			}
 		}
-		infoController.setMembershipCreation(membershipCreation);
 	}
 	
 	public EditMembershipController(UserRequest ureq, WindowControl wControl, List<Identity> members,
@@ -200,12 +196,6 @@ public class EditMembershipController extends FormBasicController {
 		
 		if(formLayout instanceof FormLayoutContainer) {
 			FormLayoutContainer layoutCont = (FormLayoutContainer)formLayout;
-			if(needMemberInfoController) {
-				infoController = new MemberInfoController(ureq, getWindowControl(), member, repoEntry, mainForm);
-				listenTo(infoController);
-				layoutCont.put("infos", infoController.getInitialComponent());
-			}
-			
 			String name = repoEntry == null ? businessGroup.getName() : repoEntry.getDisplayname();
 			String title = translate("edit.member.title", new String[]{ name });
 			layoutCont.contextPut("editTitle", title);
@@ -271,7 +261,7 @@ public class EditMembershipController extends FormBasicController {
 	protected void formCancelled(UserRequest ureq) {
 		fireEvent(ureq, Event.CANCELLED_EVENT);
 	}
-	
+
 	public void collectRepoChanges(MemberPermissionChangeEvent e) {
 		if(repoEntry == null) return;
 		
diff --git a/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java b/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java
new file mode 100644
index 0000000000000000000000000000000000000000..bffaa3c5f760e188847b8d455a10126bcf4ce221
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/EditSingleMembershipController.java
@@ -0,0 +1,74 @@
+/**
+ * <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.group.ui.main;
+
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.velocity.VelocityContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.controller.BasicController;
+import org.olat.core.id.Identity;
+import org.olat.group.BusinessGroup;
+import org.olat.repository.RepositoryEntry;
+
+/**
+ * 
+ * Initial date: 30.01.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class EditSingleMembershipController extends BasicController {
+	
+	private final MemberInfoController infoCtrl;
+	private final EditMembershipController membershipCtrl;
+
+	public EditSingleMembershipController(UserRequest ureq, WindowControl wControl,  Identity identity,
+			RepositoryEntry repoEntry, BusinessGroup group) {
+		super(ureq, wControl);
+		
+		VelocityContainer mainVC = createVelocityContainer("edit_single_member");
+		infoCtrl = new MemberInfoController(ureq, wControl, identity, repoEntry);
+		listenTo(infoCtrl);
+		mainVC.put("infos", infoCtrl.getInitialComponent());
+		
+		membershipCtrl = new EditMembershipController(ureq, wControl, identity, repoEntry, group);
+		listenTo(membershipCtrl);
+		mainVC.put("edit", membershipCtrl.getInitialComponent());
+		
+		putInitialPanel(mainVC);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Component source, Event event) {
+		fireEvent(ureq, event);
+	}
+
+	@Override
+	protected void event(UserRequest ureq, Controller source, Event event) {
+		fireEvent(ureq, event);
+	}
+}
diff --git a/src/main/java/org/olat/group/ui/main/MemberChangeConfirmationController.java b/src/main/java/org/olat/group/ui/main/MemberChangeConfirmationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..931c129b06056c350c1e434bb9524a627be98dd5
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/MemberChangeConfirmationController.java
@@ -0,0 +1,112 @@
+/**
+ * <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.group.ui.main;
+
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.group.BusinessGroupModule;
+import org.olat.user.UserManager;
+
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MemberChangeConfirmationController extends FormBasicController {
+	
+	private static final String[] keys = { "mail" };
+	
+	private final List<Identity> identities;
+	private MultipleSelectionElement mailEl;
+	
+	private final UserManager userManager;
+	private final BusinessGroupModule groupModule;
+	
+	public MemberChangeConfirmationController(UserRequest ureq, WindowControl wControl, List<Identity> identities) {
+		super(ureq, wControl, "confirm_delete");
+		this.identities = identities;
+		userManager = CoreSpringFactory.getImpl(UserManager.class);
+		groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class);
+		initForm(ureq);
+	}
+
+	public List<Identity> getIdentities() {
+		return identities;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(identities != null && formLayout instanceof FormLayoutContainer) {
+			StringBuilder sb = new StringBuilder(identities.size() * 25);
+			for(Identity id:identities) {
+				if(sb.length() > 0) sb.append(" / ");
+				sb.append(userManager.getUserDisplayName(id.getUser()));
+			}
+			((FormLayoutContainer)formLayout).contextPut("identities", sb.toString());
+		}
+		
+		boolean mandatoryEmail = groupModule.isMandatoryEnrolmentEmail(ureq.getUserSession().getRoles());
+		FormLayoutContainer optionsCont = FormLayoutContainer.createDefaultFormLayout("options", getTranslator());
+		formLayout.add(optionsCont);
+		formLayout.add("options", optionsCont);
+		String[] values = new String[] {
+				translate("remove.send.mail")
+		};
+		mailEl = uifactory.addCheckboxesVertical("typ", "remove.send.mail.label", optionsCont, keys, values, null, 1);
+		mailEl.select(keys[0], true);
+		mailEl.setEnabled(!mandatoryEmail);
+		
+		FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonCont);
+		formLayout.add("buttons", buttonCont);
+		uifactory.addFormSubmitButton("ok", buttonCont);
+		uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl());
+	}
+	
+	public boolean isSendMail() {
+		return mailEl.isSelected(0);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/MemberInfoController.java b/src/main/java/org/olat/group/ui/main/MemberInfoController.java
index 7102fdad056ed5426dd9400874782caa7332f1a1..93dd982b6d807f28e74d4893c2ec11ea4f66a633 100644
--- a/src/main/java/org/olat/group/ui/main/MemberInfoController.java
+++ b/src/main/java/org/olat/group/ui/main/MemberInfoController.java
@@ -25,15 +25,14 @@ import java.util.List;
 import org.olat.NewControllerFactory;
 import org.olat.core.CoreSpringFactory;
 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.FormLink;
 import org.olat.core.gui.components.form.flexible.elements.StaticTextElement;
-import org.olat.core.gui.components.form.flexible.impl.Form;
 import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormEvent;
 import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
-import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
 import org.olat.core.id.Identity;
 import org.olat.core.util.Formatter;
@@ -62,8 +61,8 @@ public class MemberInfoController extends FormBasicController {
 	private final UserCourseInformationsManager efficiencyStatementManager;
 	
 	public MemberInfoController(UserRequest ureq, WindowControl wControl, Identity identity,
-			RepositoryEntry repoEntry, Form rootForm) {
-		super(ureq, wControl, LAYOUT_CUSTOM, "info_member", rootForm);
+			RepositoryEntry repoEntry) {
+		super(ureq, wControl, "info_member");
 		setTranslator(Util.createPackageTranslator(UserPropertyHandler.class, ureq.getLocale(), getTranslator()));
 
 		userManager = CoreSpringFactory.getImpl(UserManager.class);
@@ -149,9 +148,14 @@ public class MemberInfoController extends FormBasicController {
 	protected void doDispose() {
 		//
 	}
+	
+	@Override
+	protected void formOK(UserRequest ureq) {
+		//
+	}
 
 	@Override
-	public void event(UserRequest ureq, Component source, Event event) {
+	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(source == homeLink) {
 			String businessPath = "[Identity:" + identity.getKey() + "]";
 			NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());
@@ -163,9 +167,4 @@ public class MemberInfoController extends FormBasicController {
 			NewControllerFactory.getInstance().launch(businessPath, ureq, getWindowControl());	
 		}
 	}
-	
-	@Override
-	protected void formOK(UserRequest ureq) {
-		//
-	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/MemberLeaveConfirmationController.java b/src/main/java/org/olat/group/ui/main/MemberLeaveConfirmationController.java
new file mode 100644
index 0000000000000000000000000000000000000000..1fa0d180a9a400afc19aae47538c20e42c6b54fb
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/MemberLeaveConfirmationController.java
@@ -0,0 +1,112 @@
+/**
+ * <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.group.ui.main;
+
+import java.util.List;
+
+import org.olat.core.CoreSpringFactory;
+import org.olat.core.gui.UserRequest;
+import org.olat.core.gui.components.form.flexible.FormItemContainer;
+import org.olat.core.gui.components.form.flexible.elements.MultipleSelectionElement;
+import org.olat.core.gui.components.form.flexible.impl.FormBasicController;
+import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
+import org.olat.core.gui.control.Controller;
+import org.olat.core.gui.control.Event;
+import org.olat.core.gui.control.WindowControl;
+import org.olat.core.id.Identity;
+import org.olat.group.BusinessGroupModule;
+import org.olat.user.UserManager;
+
+
+/**
+ * 
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ *
+ */
+public class MemberLeaveConfirmationController extends FormBasicController {
+	
+	private static final String[] keys = { "mail" };
+	
+	private final List<Identity> identities;
+	private MultipleSelectionElement mailEl;
+	
+	private final UserManager userManager;
+	private final BusinessGroupModule groupModule;
+	
+	public MemberLeaveConfirmationController(UserRequest ureq, WindowControl wControl, List<Identity> identities) {
+		super(ureq, wControl, "confirm_delete");
+		this.identities = identities;
+		userManager = CoreSpringFactory.getImpl(UserManager.class);
+		groupModule = CoreSpringFactory.getImpl(BusinessGroupModule.class);
+		initForm(ureq);
+	}
+
+	public List<Identity> getIdentities() {
+		return identities;
+	}
+
+	@Override
+	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		if(identities != null && formLayout instanceof FormLayoutContainer) {
+			StringBuilder sb = new StringBuilder(identities.size() * 25);
+			for(Identity id:identities) {
+				if(sb.length() > 0) sb.append(" / ");
+				sb.append(userManager.getUserDisplayName(id.getUser()));
+			}
+			((FormLayoutContainer)formLayout).contextPut("identities", sb.toString());
+		}
+		
+		boolean mandatoryEmail = groupModule.isMandatoryEnrolmentEmail(ureq.getUserSession().getRoles());
+		FormLayoutContainer optionsCont = FormLayoutContainer.createDefaultFormLayout("options", getTranslator());
+		formLayout.add(optionsCont);
+		formLayout.add("options", optionsCont);
+		String[] values = new String[] {
+				translate("remove.send.mail")
+		};
+		mailEl = uifactory.addCheckboxesVertical("typ", "remove.send.mail.label", optionsCont, keys, values, null, 1);
+		mailEl.select(keys[0], true);
+		mailEl.setEnabled(!mandatoryEmail);
+		
+		FormLayoutContainer buttonCont = FormLayoutContainer.createButtonLayout("buttons", getTranslator());
+		formLayout.add(buttonCont);
+		formLayout.add("buttons", buttonCont);
+		uifactory.addFormSubmitButton("ok", buttonCont);
+		uifactory.addFormCancelButton("cancel", buttonCont, ureq, getWindowControl());
+	}
+	
+	public boolean isSendMail() {
+		return mailEl.isSelected(0);
+	}
+	
+	@Override
+	protected void doDispose() {
+		//
+	}
+
+	@Override
+	protected void formOK(UserRequest ureq) {
+		fireEvent(ureq, Event.DONE_EVENT);
+	}
+
+	@Override
+	protected void formCancelled(UserRequest ureq) {
+		fireEvent(ureq, Event.CANCELLED_EVENT);
+	}
+}
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_content/confirm_delete.html b/src/main/java/org/olat/group/ui/main/_content/confirm_delete.html
new file mode 100644
index 0000000000000000000000000000000000000000..85fb884385a8f76ce8e1b0bbc7f72cbd73e5df4c
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/_content/confirm_delete.html
@@ -0,0 +1,3 @@
+<p>$r.translate("dialog.modal.bg.remove.text",$identities)</p>
+$r.render("options")
+$r.render("buttons")
diff --git a/src/main/java/org/olat/group/ui/main/_content/edit_member.html b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
index a9d9b08270e429c9104af63752be9e4661a9abab..2bde8eae942b8baa644f2376d01cdf9866ab7075 100644
--- a/src/main/java/org/olat/group/ui/main/_content/edit_member.html
+++ b/src/main/java/org/olat/group/ui/main/_content/edit_member.html
@@ -1,6 +1,3 @@
-#if($r.available("infos"))
-	$r.render("infos")<br/>
-#end
 #if($r.available("repoRights"))
 	<fieldset>
 		<legend>$editTitle</legend>
diff --git a/src/main/java/org/olat/group/ui/main/_content/edit_single_member.html b/src/main/java/org/olat/group/ui/main/_content/edit_single_member.html
new file mode 100644
index 0000000000000000000000000000000000000000..1941711c9365a0dec17e695cb268d448e684b461
--- /dev/null
+++ b/src/main/java/org/olat/group/ui/main/_content/edit_single_member.html
@@ -0,0 +1,2 @@
+$r.render("infos")<br/>
+$r.render("edit")
\ No newline at end of file
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
index b3eb6487822a7c7d7bb45668ee16753cf58e8f2c..5b04f9066b4c85b456fb8b3d4f31d7ffba7414db 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_de.properties
@@ -14,7 +14,13 @@ dedup.members.info4=W
 dialog.modal.bg.delete.title=Gruppe l\u00F6schen?
 dialog.modal.bg.delete.text=Wollen Sie die Gruppe "{0}" wirklich l\u00F6schen?
 dialog.modal.bg.mail.text=Wollen Sie die Mitglieder per Mail benachrichtigen?
-dialog.modal.bg.leave.text=Wenn Sie die Gruppe "{0}" verlassen, haben Sie keinen Zugang mehr. <br> Wollen Sie die Gruppe wirklich verlassen?<p>
+dialog.modal.bg.leave.text=Wenn Sie die Gruppe "{0}" verlassen, haben Sie keinen Zugang mehr.<br/> Wollen Sie die Gruppe wirklich verlassen?
+dialog.modal.bg.remove.text=Wollen Sie wirklich "{0}" aus dieser Gruppe entfernen?
+dialog.modal.bg.send.mail=Wollen Sie die betroffene(n) Person(en) per E-mail benachrichtigen?
+remove.send.mail=Benachrichtigung
+remove.send.mail.label=E-mail versenden
+error.atleastone=$org.olat.course.member\:error.atleastone
+
 main.menu.title=Gruppen
 main.menu.title.alt=Gruppen
 index.header=Gruppen
diff --git a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
index 48c229fca5ef3568fe87253de4c577fb7af33046..cf47456250c125f55ce7f8bd51735d45a22eb886 100644
--- a/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/group/ui/main/_i18n/LocalStrings_en.properties
@@ -33,6 +33,10 @@ dialog.modal.bg.delete.text=Do you really want to delete the group "{0}" ?<p>
 dialog.modal.bg.delete.title=Delete group?
 dialog.modal.bg.leave.text=If you leave the group "{0}" you will no longer have access. <br>Do you really want to leave this group?<p>
 dialog.modal.bg.mail.text=Do you want to inform the members of this group by email?
+dialog.modal.bg.remove.text=Do you really want to remove these persons "{0}" from the group?
+dialog.modal.bg.send.mail=Would you like to notify the respective members?
+remove.send.mail=Notification
+remove.send.mail.label=Send E-mail
 edit.member=Edit membership
 edit.member.groups=Group memberships
 edit.member.title=Member rights course {0}
diff --git a/src/main/java/org/olat/login/LoginAuthprovidersController.java b/src/main/java/org/olat/login/LoginAuthprovidersController.java
index 182c02639f60daff0008d4bf8cec03d4bf23c6f6..911b8f0f0d4b936690224bf2b3e6979c763b26a0 100644
--- a/src/main/java/org/olat/login/LoginAuthprovidersController.java
+++ b/src/main/java/org/olat/login/LoginAuthprovidersController.java
@@ -363,7 +363,7 @@ public class LoginAuthprovidersController extends MainLayoutBasicController impl
 		root.addChild(gtn);
 		root.setDelegate(gtn);		
 
-		if (LoginModule.isGuestLoginLinksEnabled()) {
+		if (LoginModule.isGuestLoginLinksEnabled() && !AuthHelper.isLoginBlocked()) {
 			gtn = new GenericTreeNode("guest_item");		
 			gtn.setTitle(translate("menu.guest"));
 			gtn.setUserObject(ACTION_GUEST);
diff --git a/src/main/java/org/olat/login/OLATAuthenticationController.java b/src/main/java/org/olat/login/OLATAuthenticationController.java
index a24c5b0da89e8b34f15e668cfc4e4ad4ec1e996a..ac5c5dbe778a9d5f0d92cdafb8f0f3e7d9c24515 100644
--- a/src/main/java/org/olat/login/OLATAuthenticationController.java
+++ b/src/main/java/org/olat/login/OLATAuthenticationController.java
@@ -113,6 +113,7 @@ public class OLATAuthenticationController extends AuthenticationController imple
 		if (LoginModule.isGuestLoginLinksEnabled()) {
 			anoLink = LinkFactory.createLink("_olat_login_guest", "menu.guest", loginComp, this);
 			anoLink.setCustomEnabledLinkCSS("o_login_guests b_with_small_icon_left");
+			anoLink.setEnabled(!AuthHelper.isLoginBlocked());
 		}
 		
 		
diff --git a/src/main/java/org/olat/modules/wiki/WikiManager.java b/src/main/java/org/olat/modules/wiki/WikiManager.java
index 5c7cfb668e211b10411351a999b01454fa8f3c40..1498936eab89859efebf261c433c105457049646 100644
--- a/src/main/java/org/olat/modules/wiki/WikiManager.java
+++ b/src/main/java/org/olat/modules/wiki/WikiManager.java
@@ -410,8 +410,11 @@ public class WikiManager extends BasicManager {
 		if (wikiCache!=null) {
 			wikiCache.update(OresHelper.createStringRepresenting(ores), wiki);
 		}
-		// do logging
-		ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_UPDATE, getClass());
+		
+		if(ThreadLocalUserActivityLogger.getLoggedIdentity() != null) {
+			// do logging only for real user
+			ThreadLocalUserActivityLogger.log(LearningResourceLoggingAction.LEARNING_RESOURCE_UPDATE, getClass());
+		}
 	}
 
 	/**
diff --git a/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewOptionsLinkController.java b/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewOptionsLinkController.java
index 9f7a30251adde7243b6f454336d7fc5bca604941..dea9b6c49f19f4d26e9ad48799b1f55f69d79c00 100644
--- a/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewOptionsLinkController.java
+++ b/src/main/java/org/olat/portfolio/ui/artefacts/view/EPArtefactViewOptionsLinkController.java
@@ -119,6 +119,9 @@ public class EPArtefactViewOptionsLinkController extends BasicController {
 			PortfolioStructure newStruct = epsEv.getPortfolioStructure();
 			showInfo("artefact.moved", newStruct.getTitle());
 			moveTreeBox.deactivate();
+		} else if (source == artefactOptionCalloutCtrl) {
+			removeAsListenerAndDispose(artefactOptionCalloutCtrl);
+			artefactOptionCalloutCtrl = null;
 		}
 		fireEvent(ureq, event);
 	}
diff --git a/src/main/java/org/olat/registration/RegistrationManager.java b/src/main/java/org/olat/registration/RegistrationManager.java
index 173b54a1584cc83136ee811ca0744e8aebbd3f3d..1eb978c9f8a376024e9f17d0b8bceb473e2d0e31 100644
--- a/src/main/java/org/olat/registration/RegistrationManager.java
+++ b/src/main/java/org/olat/registration/RegistrationManager.java
@@ -317,7 +317,9 @@ public class RegistrationManager extends BasicManager {
 	 */
 	public void deleteTemporaryKeyWithId(String keyValue) {
 		TemporaryKeyImpl tKey = loadTemporaryKeyByRegistrationKey(keyValue);
-		deleteTemporaryKey(tKey);
+		if(tKey != null) {
+			deleteTemporaryKey(tKey);
+		}
 	}
 
 	/**
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index 432ebece1240012c68a7ba9df509287485396a60..0725828f44787c2336bbcf62eb87763df1bfb39a 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -41,6 +41,7 @@ import org.olat.admin.securitygroup.gui.IdentitiesAddEvent;
 import org.olat.basesecurity.BaseSecurity;
 import org.olat.basesecurity.BaseSecurityManager;
 import org.olat.basesecurity.Constants;
+import org.olat.basesecurity.IdentityImpl;
 import org.olat.basesecurity.PolicyImpl;
 import org.olat.basesecurity.SecurityGroup;
 import org.olat.basesecurity.SecurityGroupMembershipImpl;
@@ -77,6 +78,7 @@ import org.olat.core.util.vfs.VFSItem;
 import org.olat.core.util.vfs.VFSLeaf;
 import org.olat.core.util.vfs.VFSManager;
 import org.olat.course.assessment.manager.UserCourseInformationsManager;
+import org.olat.group.BusinessGroupImpl;
 import org.olat.group.GroupLoggingAction;
 import org.olat.group.context.BGContext2Resource;
 import org.olat.group.model.BGResourceRelation;
@@ -1335,20 +1337,35 @@ public class RepositoryManager extends BasicManager {
 	//fxdiff VCRP-1,2: access control
 	public boolean isMember(Identity identity, RepositoryEntry entry) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("select count(v) from ").append(RepositoryEntry.class.getName()).append(" as v ")
-			.append(" where v.key=:repositoryEntryKey and v.key in (")
-			.append("   select vmember.key from ").append(RepositoryEntryMember.class.getName()).append(" vmember")
-			.append("   where vmember.key=:repositoryEntryKey and ")
-			.append("     (vmember.repoParticipantKey=:identityKey or vmember.repoTutorKey=:identityKey or vmember.repoOwnerKey=:identityKey")
-			.append("     or vmember.groupParticipantKey=:identityKey or vmember.groupOwnerKey=:identityKey)")
+		sb.append("select re.key, ident.key ")
+		  .append("from ").append(RepositoryEntry.class.getName()).append(" as re, ")
+		  .append(IdentityImpl.class.getName()).append(" as ident ")
+		  .append("where ident.key=:identityKey and re.key=:repositoryEntryKey ")
+		  .append(" and (exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ")
+			.append("     where ident=vmember.identity and vmember.securityGroup=re.participantGroup")
+			.append("  ) or exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ")
+			.append("     where ident=vmember.identity and vmember.securityGroup=re.tutorGroup")
+			.append("  ) or exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember ")
+			.append("     where ident=vmember.identity and vmember.securityGroup=re.ownerGroup")
+			.append("  ) or exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember, ")
+			.append("      ").append(BGResourceRelation.class.getName()).append(" as bresource, ")
+			.append("      ").append(BusinessGroupImpl.class.getName()).append(" as bgroup")
+			.append("      where bgroup.partipiciantGroup=vmember.securityGroup and re.olatResource=bresource.resource ")
+			.append("        and bgroup=bresource.group and ident=vmember.identity")
+			.append("  ) or exists (from ").append(SecurityGroupMembershipImpl.class.getName()).append(" as vmember, ")
+			.append("      ").append(BGResourceRelation.class.getName()).append(" as bresource, ")
+			.append("      ").append(BusinessGroupImpl.class.getName()).append(" as bgroup")
+			.append("      where bgroup.ownerGroup=vmember.securityGroup and re.olatResource=bresource.resource ")
+			.append("        and bgroup=bresource.group and ident=vmember.identity")
+			.append("  )")
 			.append(" )");
 
-		Number counter = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Number.class)
+		List<Object[]> counter = dbInstance.getCurrentEntityManager().createQuery(sb.toString(), Object[].class)
 				.setParameter("identityKey", identity.getKey())
 				.setParameter("repositoryEntryKey", entry.getKey())
 				.setHint("org.hibernate.cacheable", Boolean.TRUE)
-				.getSingleResult();
-		return counter.intValue() > 0;
+				.getResultList();
+		return !counter.isEmpty();
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_de.properties
index a7182192d7c3716a5cfc3bcf2a660db2ce75b773..dfec9100f8869b190918eb4132fd73c94b4e0065 100644
--- a/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_de.properties
@@ -13,6 +13,7 @@ table.header.graduate=$org.olat.group.ui.main\:table.header.graduate
 table.header.firstName=$org.olat.group.ui.main\:table.header.firstName
 table.header.lastName=$org.olat.group.ui.main\:table.header.lastName
 table.header.mail=$org.olat.group.ui.main\:table.header.mail
+table.header.login=$org.olat.group.ui.main\:table.header.login
 table.header.firstTime=$org.olat.group.ui.main\:table.header.firstTime
 table.header.lastTime=$org.olat.group.ui.main\:table.header.lastTime
 table.header.role=$org.olat.group.ui.main\:table.header.role
@@ -23,8 +24,6 @@ table.header.freePlace=$org.olat.group.ui.main\:table.header.freePlace
 table.header.tutors=$org.olat.group.ui.main\:table.header.tutors
 table.header.participants=$org.olat.group.ui.main\:table.header.participants
 table.header.waitingList=$org.olat.group.ui.main\:table.header.waitingList
-
-
-
+dialog.modal.bg.send.mail=$org.olat.group.ui.main\:dialog.modal.bg.send.mail
 dialog.modal.bg.leave.text=$org.olat.group.ui.main\:dialog.modal.bg.leave.text
 nomembers=XXX No members
\ No newline at end of file
diff --git a/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_en.properties
index 7c64cb46327a59838167135e607c36630f0772c6..c4a7b94742921c7da7a1d24f31167470da12180e 100644
--- a/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/repository/controllers/_i18n/LocalStrings_en.properties
@@ -15,6 +15,7 @@ table.header.graduate=$org.olat.group.ui.main\:table.header.graduate
 table.header.groups=$org.olat.group.ui.main\:table.header.groups
 table.header.lastName=$org.olat.group.ui.main\:table.header.lastName
 table.header.lastTime=$org.olat.group.ui.main\:table.header.lastTime
+table.header.login=$org.olat.group.ui.main\:table.header.login
 table.header.mail=$org.olat.group.ui.main\:table.header.mail
 table.header.participants=$org.olat.group.ui.main\:table.header.participants
 table.header.participantsCount=$org.olat.group.ui.main\:table.header.participantsCount
@@ -23,3 +24,4 @@ table.header.role=$org.olat.group.ui.main\:table.header.role
 table.header.tutors=$org.olat.group.ui.main\:table.header.tutors
 table.header.tutorsCount=$org.olat.group.ui.main\:table.header.tutorsCount
 table.header.waitingList=$org.olat.group.ui.main\:table.header.waitingList
+dialog.modal.bg.send.mail=$org.olat.group.ui.main\:dialog.modal.bg.send.mail
diff --git a/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java b/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
index b3d57ca5eaab9b1bdaaed42f1f0823fca0fde341..bd9f3dfac212b3b3d707da776753839770c429b8 100644
--- a/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
+++ b/src/main/java/org/olat/resource/accesscontrol/manager/ACReservationDAO.java
@@ -82,7 +82,8 @@ public class ACReservationDAO {
 	}
 	
 	public List<ResourceReservation> loadReservations(Identity identity) {
-		List<ResourceReservation> reservations = dbInstance.getCurrentEntityManager().createNamedQuery("loadReservationsByIdentity", ResourceReservation.class)
+		List<ResourceReservation> reservations = dbInstance.getCurrentEntityManager()
+				.createNamedQuery("loadReservationsByIdentity", ResourceReservation.class)
 				.setParameter("identityKey", identity.getKey())
 				.getResultList();
 		return reservations;
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index 4f070e00fdba881e4032cabf7aa786ba3ab4514c..181740063a20f6d0c45095a6adc86218f0fc01d7 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -779,8 +779,8 @@ ldap.attrib.sync.once.olatkey3=
 # Build properties
 #####
 application.name=OpenOLAT
-build.version=8.3.1
-build.identifier=openolat831-dev
+build.version=8.3.2
+build.identifier=openolat832-dev
 build.repo.revision=local-devel
 
 #####
diff --git a/src/test/java/org/olat/core/gui/components/table/SorterTest.java b/src/test/java/org/olat/core/gui/components/table/SorterTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..cec4e97198d804e72563183cc14910c51094d826
--- /dev/null
+++ b/src/test/java/org/olat/core/gui/components/table/SorterTest.java
@@ -0,0 +1,85 @@
+/**
+ * <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.core.gui.components.table;
+
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+/**
+ * 
+ * Initial date: 23.01.2013<br>
+ * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com
+ */
+public class SorterTest {
+
+	@Test
+	public void testDateAndTimeStampsSort() {
+		//use the comparator method of the default column descriptor
+		final DefaultColumnDescriptor cd = new DefaultColumnDescriptor("test", 1, "test", Locale.ENGLISH);
+		Comparator<Date> comparator = new Comparator<Date>() {
+			@Override
+			public int compare(Date o1, Date o2) {
+				return cd.compareDateAndTimestamps(o1, o2);
+			}
+		};
+		
+		//make a list of timestamps and dates
+		List<Date> dates = new ArrayList<Date>();
+		Calendar cal = Calendar.getInstance();
+		for(int i=0; i<100; i++) {
+			cal.add(Calendar.MINUTE, 2);
+			if(i % 2 == 0) {
+				Timestamp t = new Timestamp(cal.getTimeInMillis());
+				dates.add(t);
+			} else {
+				Date d = cal.getTime();
+				dates.add(d);
+			}
+		}
+		//something a little bit random
+		Collections.shuffle(dates);
+		
+		//sort
+		Collections.sort(dates, comparator);
+		
+		//check
+		Date current = null;
+		for(Date date:dates) {
+			if(current == null) {
+				current = date;
+			} else {
+				boolean before = current.before(date);
+				Assert.assertTrue(before);
+				current = date;
+			}	
+		}
+	}
+
+}
diff --git a/src/test/java/org/olat/repository/RepositoryManagerTest.java b/src/test/java/org/olat/repository/RepositoryManagerTest.java
index b0c11e1886fbcf4c368bfb184195e6c80e5f4273..859d17cc602138ac7a783a5bac4d9f3f4da2f433 100644
--- a/src/test/java/org/olat/repository/RepositoryManagerTest.java
+++ b/src/test/java/org/olat/repository/RepositoryManagerTest.java
@@ -329,6 +329,52 @@ public class RepositoryManagerTest extends OlatTestCase {
 		Assert.assertFalse(member2);
 	}
 	
+	@Test
+	public void isMember_v2() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-1-lc-" + UUID.randomUUID().toString());
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-2-lc-" + UUID.randomUUID().toString());
+		Identity id3 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-3-lc-" + UUID.randomUUID().toString());
+		Identity id4 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-4-lc-" + UUID.randomUUID().toString());
+		Identity id5 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-5-lc-" + UUID.randomUUID().toString());
+		Identity id6 = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-6-lc-" + UUID.randomUUID().toString());
+		Identity idNull = JunitTestHelper.createAndPersistIdentityAsUser("re-is-member-null-lc-" + UUID.randomUUID().toString());
+		RepositoryEntry re = JunitTestHelper.createAndPersistRepositoryEntry();
+		BusinessGroup group1 = businessGroupService.createBusinessGroup(null, "member-1-g", "tg", null, null, false, false, re);
+		BusinessGroup group2 = businessGroupService.createBusinessGroup(null, "member-2-g", "tg", null, null, false, false, re);
+		BusinessGroup group3 = businessGroupService.createBusinessGroup(null, "member-3-g", "tg", null, null, true, false, re);
+		BusinessGroup groupNull = businessGroupService.createBusinessGroup(null, "member-null-g", "tg", null, null, true, false, null);
+		securityManager.addIdentityToSecurityGroup(id1, re.getOwnerGroup());
+		securityManager.addIdentityToSecurityGroup(id2, re.getTutorGroup());
+		securityManager.addIdentityToSecurityGroup(id3, re.getParticipantGroup());
+		securityManager.addIdentityToSecurityGroup(id4, group1.getOwnerGroup());
+		securityManager.addIdentityToSecurityGroup(id5, group2.getPartipiciantGroup());
+		securityManager.addIdentityToSecurityGroup(id6, group3.getWaitingGroup());
+		securityManager.addIdentityToSecurityGroup(idNull, groupNull.getPartipiciantGroup());
+		dbInstance.commitAndCloseSession();
+
+		//id1 is owner
+		boolean member1 = repositoryManager.isMember(id1, re);
+		Assert.assertTrue(member1);
+		//id2 is tutor
+		boolean member2 = repositoryManager.isMember(id2, re);
+		Assert.assertTrue(member2);
+		//id3 is repo participant
+		boolean member3 = repositoryManager.isMember(id3, re);
+		Assert.assertTrue(member3);
+		//id4 is group coach
+		boolean member4= repositoryManager.isMember(id4, re);
+		Assert.assertTrue(member4);
+		//id5 is group participant
+		boolean member5 = repositoryManager.isMember(id5, re);
+		Assert.assertTrue(member5);
+		//id6 is waiting
+		boolean member6 = repositoryManager.isMember(id6, re);
+		Assert.assertFalse(member6);
+		//idNull is not member
+		boolean memberNull = repositoryManager.isMember(idNull, re);
+		Assert.assertFalse(memberNull);
+	}
+	
 	@Test
 	public void isOwnerOfRepositoryEntry() {
 		//create a repository entry with an owner and a participant
diff --git a/src/test/java/org/olat/test/AllTestsJunit4.java b/src/test/java/org/olat/test/AllTestsJunit4.java
index f212bb0d4046c82ee0fcbcab10932b71013a2491..b8d474d25fd137cf0a0963630b53f3f740dd92a4 100644
--- a/src/test/java/org/olat/test/AllTestsJunit4.java
+++ b/src/test/java/org/olat/test/AllTestsJunit4.java
@@ -49,6 +49,7 @@ import org.junit.runners.Suite;
 	org.olat.core.gui.components.table.MultiSelectColumnDescriptorTest.class,
 	org.olat.core.gui.components.table.TableEventTest.class,
 	org.olat.core.gui.components.table.TableMultiSelectEventTest.class,
+	org.olat.core.gui.components.table.SorterTest.class,
 	org.olat.core.commons.chiefcontrollers.ChiefControllerMessageEventTest.class,
 	org.olat.core.util.vfs.VFSManagerTest.class,
 	org.olat.core.util.filter.impl.XSSFilterTest.class,