diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
index 06c177f9956a4dadbee8b809393bfd4fc83fb2aa..fe13e0eefbb9161bc50a5883f21cee4eb086ddf4 100644
--- a/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
+++ b/src/main/java/org/olat/collaboration/CollaborationToolsSettingsController.java
@@ -31,7 +31,6 @@ import java.util.List;
 import org.olat.commons.calendar.CalendarManager;
 import org.olat.commons.calendar.CalendarModule;
 import org.olat.commons.calendar.ui.events.CalendarGUIModifiedEvent;
-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;
@@ -275,31 +274,39 @@ public class CollaborationToolsSettingsController extends BasicController {
 }
 
 class ChoiceOfToolsForm extends FormBasicController {
-	CollaborationTools cts;
-	MultipleSelectionElement ms;
+	private CollaborationTools cts;
+	private MultipleSelectionElement ms;
 	
-	List <String>theKeys   = new ArrayList<String>();
-	List <String>theValues = new ArrayList<String>();
-
-	final String[] availableTools;
+	private final String[] toolsKeys;
+	private final String[] toolsValues;
+	private final String[] cssClasses;
+	private final String[] availableTools;
+	
+	@Autowired
+	private InstantMessagingModule imModule;
 	
 	public ChoiceOfToolsForm(UserRequest ureq, WindowControl wControl, CollaborationTools cts, final String[] availableTools) {
 		super(ureq, wControl);
 		this.cts = cts;
 		this.availableTools = availableTools;
 		
+		List<String> theKeys = new ArrayList<>();
+		List<String> theValues = new ArrayList<>();
+		List<String> theClasses = new ArrayList<>();
 		for (int i=0; i<availableTools.length; i++) {
 			String k = availableTools[i];
-			if (k.equals(CollaborationTools.TOOL_CHAT)) {
-				InstantMessagingModule imModule = CoreSpringFactory.getImpl(InstantMessagingModule.class);
-				if (!imModule.isEnabled() || !imModule.isGroupEnabled()) {
-					continue;
-				}
+			if (k.equals(CollaborationTools.TOOL_CHAT) && (!imModule.isEnabled() || !imModule.isGroupEnabled())) {
+				continue;
 			}
 			theKeys.add(""+i);
-			theValues.add(translate("collabtools.named."+availableTools[i]));
+			theValues.add(translate("collabtools.named." + availableTools[i]));
+			theClasses.add(translate("o_sel_" + availableTools[i]));
 		}
 		
+		toolsKeys = theKeys.toArray(new String[theKeys.size()]);
+		toolsValues = theValues.toArray(new String[theValues.size()]);
+		cssClasses = theClasses.toArray(new String[theClasses.size()]);
+		
 		initForm(ureq);
 	}
 	
@@ -314,10 +321,7 @@ class ChoiceOfToolsForm extends FormBasicController {
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
-		ms = uifactory.addCheckboxesVertical(
-				"selection", formLayout, 
-				theKeys.toArray(new String[theKeys.size()]),
-				theValues.toArray(new String[theValues.size()]), 1);
+		ms = uifactory.addCheckboxesVertical("selection", "selection", formLayout, toolsKeys, toolsValues, cssClasses, null, 1);
 		ms.setElementCssClass("o_sel_collab_tools");
 		for (int i=0; i<availableTools.length; i++) {
 			ms.select(""+i, cts.isToolEnabled(availableTools[i]));
diff --git a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
index e65884bd2fac448894ef4e5cc15754b43115471d..8ab6a34e59fcb34187fe853db589a67e12430158 100644
--- a/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/commons/calendar/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,4 @@
-#Sun Nov 08 13:10:17 CET 2015
+#Sun Nov 29 17:18:08 CET 2015
 cal.add.event=Ajouter rendez-vous
 cal.add.readonly=(lecture uniquement)
 cal.color.choose=Choisir la couleur
@@ -65,6 +65,8 @@ cal.form.title=D\u00E9tails du rendez-vous
 cal.fri=Vendredi
 cal.from=De
 cal.goto.event=Aller au rdv. s\u00E9lectionn\u00E9
+cal.icalfeed.aggregated.info=Utilisez le lien suivant pour l'acc\u00E8s de votre calendrier  (tous les calendriers agr\u00E9g\u00E9 inclus) \u00E0 partir d'autres applications. Vous pouvez copier le lien et le coller dans une application qui prend en charge le format iCal.
+cal.icalfeed.aggregated.title=Flux iCal des calendriers agr\u00E9g\u00E9s
 cal.icalfeed.aggregated.tooltip=$\:cal.icalfeed.aggregated.title
 cal.icalfeed.info=Veuillez utiliser l'URL suivante pour appeler ce calendrier depuis une autre application. Vous pouvez copier l'URL et l'ins\u00E9rer dans toute autre application de calendrier qui supporte le format iCal.
 cal.icalfeed.regenerate.info=Le lien iCal Feed a \u00E9t\u00E9 r\u00E9actualis\u00E9.
@@ -201,6 +203,7 @@ tab.links.extern.url=URL
 tab.links.extern.url.invalid=L'URL donn\u00E9e n'est pas valide.
 table.add=+
 table.delete=-
+table.header.aggregated.feed=Agr\u00E9g\u00E9
 table.header.color=Couleur
 table.header.name=Nom
 table.header.tools=<i class\="o_icon o_icon-lg o_icon_actions"> </i>
diff --git a/src/main/java/org/olat/core/commons/services/notifications/NotificationHelper.java b/src/main/java/org/olat/core/commons/services/notifications/NotificationHelper.java
index 074135dbf7c14af8ccaeb7d249e923f02e39db13..33db9824de996ab066c719fabd82e6dcdbadd7e1 100644
--- a/src/main/java/org/olat/core/commons/services/notifications/NotificationHelper.java
+++ b/src/main/java/org/olat/core/commons/services/notifications/NotificationHelper.java
@@ -107,12 +107,9 @@ public class NotificationHelper {
 	 * @return
 	 */
 	public static String getFormatedName(Identity ident) {
-		Translator trans;
-		User user = null;
-		String formattedName = null;
-		
+		String formattedName;
 		if (ident == null) {
-			trans = Util.createPackageTranslator(NotificationNewsController.class, I18nManager.getInstance().getLocaleOrDefault(null));
+			Translator trans = Util.createPackageTranslator(NotificationNewsController.class, I18nManager.getInstance().getLocaleOrDefault(null));
 			return trans.translate("user.unknown");
 		} else {
 			// Optimize: use from cache to not re-calculate user properties over and over again
@@ -121,10 +118,10 @@ public class NotificationHelper {
 				return formattedName;
 			}
 		}
-		trans = Util.createPackageTranslator(NotificationNewsController.class, I18nManager.getInstance().getLocaleOrDefault(
-				ident.getUser().getPreferences().getLanguage()));
-		user = ident.getUser();
 		
+		Translator trans = Util.createPackageTranslator(NotificationNewsController.class, I18nManager.getInstance().getLocaleOrDefault(
+				ident.getUser().getPreferences().getLanguage()));
+		User user = ident.getUser();
 		if (user == null) {
 			formattedName =  trans.translate("user.unknown");
 		} else {
@@ -144,7 +141,6 @@ public class NotificationHelper {
 		}
 		// put formatted name in cache, times out after 5 mins
 		userPropertiesCache.put(ident.getKey(), formattedName);
-		
 		return formattedName;
 	}
 
diff --git a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
index 283f0af80159fa6372abe7470f84d78e143d8b7c..382f490e96b254fe9d636e20f4f9748aad549be2 100644
--- a/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
+++ b/src/main/java/org/olat/core/dispatcher/ErrorFeedbackMailer.java
@@ -33,11 +33,11 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
 import org.olat.basesecurity.BaseSecurity;
-import org.olat.core.CoreSpringFactory;
 import org.olat.core.id.Identity;
 import org.olat.core.logging.LogFileParser;
 import org.olat.core.logging.OLog;
 import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
 import org.olat.core.util.WebappHelper;
 import org.olat.core.util.mail.MailBundle;
 import org.olat.core.util.mail.MailManager;
@@ -53,6 +53,25 @@ import org.olat.core.util.mail.MailManager;
 public class ErrorFeedbackMailer implements Dispatcher {
 	
 	private static final OLog log = Tracing.createLoggerFor(ErrorFeedbackMailer.class);
+	
+	private MailManager mailManager;
+	private BaseSecurity securityManager;
+
+	/**
+	 * [used by Spring]
+	 * @param mailManager
+	 */
+	public void setMailManager(MailManager mailManager) {
+		this.mailManager = mailManager;
+	}
+
+	/**
+	 * [used by spring]
+	 * @param securityManager
+	 */
+	public void setSecurityManager(BaseSecurity securityManager) {
+		this.securityManager = securityManager;
+	}
 
 	/**
 	 * send email to olat support with user submitted error informaition
@@ -64,27 +83,26 @@ public class ErrorFeedbackMailer implements Dispatcher {
 		String errorNr = request.getParameter("fx_errnum");
 		String username = request.getParameter("username");
 		try {
-			BaseSecurity im = CoreSpringFactory.getImpl(BaseSecurity.class);
-			Identity ident = im.findIdentityByName(username);
-			// if null, user may crashed befor getting a valid session, try with
-			// guest user instead
-			if (ident == null)
-				ident = im.findIdentityByName("guest");
-			Collection<String> logFileEntries = LogFileParser.getErrorToday(errorNr, false);
-			StringBuilder out = new StringBuilder(2048);
-			out.append(feedback)
-			   .append("\n------------------------------------------\n\n --- from user: ").append(username).append(" ---");
-			if (logFileEntries != null) {
-				for (Iterator<String> iter = logFileEntries.iterator(); iter.hasNext();) {
-					out.append(iter.next());
+			if(StringHelper.containsNonWhitespace(username)) {
+				Identity ident = securityManager.findIdentityByName(username);
+				Collection<String> logFileEntries = LogFileParser.getErrorToday(errorNr, false);
+				StringBuilder out = new StringBuilder(2048);
+				out.append(feedback)
+				   .append("\n------------------------------------------\n\n --- from user: ").append(username).append(" ---");
+				if (logFileEntries != null) {
+					for (Iterator<String> iter = logFileEntries.iterator(); iter.hasNext();) {
+						out.append(iter.next());
+					}
 				}
+	
+				MailBundle bundle = new MailBundle();
+				bundle.setFromId(ident);
+				bundle.setTo(WebappHelper.getMailConfig("mailError"));
+				bundle.setContent("Feedback from Error Nr.: " + errorNr, out.toString());
+				mailManager.sendExternMessage(bundle, null);
+			} else {
+				log.error("Try to send a feedback without identity");
 			}
-
-			MailBundle bundle = new MailBundle();
-			bundle.setFromId(ident);
-			bundle.setTo(WebappHelper.getMailConfig("mailError"));
-			bundle.setContent("Feedback from Error Nr.: " + errorNr, out.toString());
-			CoreSpringFactory.getImpl(MailManager.class).sendExternMessage(bundle, null);
 		} catch (Exception e) {
 			handleException(request, e);
 			return;
diff --git a/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml b/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml
index dfa21c66b9abc9802aed9d3375b0ab5b2a59ba57..51cb8590e5b7f16e1c707dd00c5e199878533a31 100644
--- a/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml
+++ b/src/main/java/org/olat/core/dispatcher/_spring/dispatcherContext.xml
@@ -68,7 +68,10 @@
 	<bean id="oauthcallback" class="org.olat.login.oauth.OAuthDispatcher" />
 	
 	<!-- send bug report dispatcher -->
-	<bean id="errorMailBean" class="org.olat.core.dispatcher.ErrorFeedbackMailer" />
+	<bean id="errorMailBean" class="org.olat.core.dispatcher.ErrorFeedbackMailer">
+		<property name="mailManager" ref="mailManager"/>
+		<property name="securityManager" ref="baseSecurityManager"/>
+	</bean>
 
 	<!--  all olat dispatchers -->
 	<bean id="dmzbean" class="org.olat.dispatcher.DMZDispatcher">
diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_de.properties
index 81f9b8556163948db9a9b8101b3be461a4b42edb..e582540cd0421e4228ec6b7e3e51e534ae7f5cfc 100644
--- a/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_de.properties
@@ -5,7 +5,7 @@ option.delivery=Layout
 mode=Anzeigemodus
 mode.standard=Standard
 mode.configured=Optimiert f\u00FCr OpenOLAT
-mode.hover=Verwenden Sie die Standardeinstellung f?r extern erstellten Inhalt.
+mode.hover=Verwenden Sie die Standardeinstellung f\u00FCr extern erstellten Inhalt.
 option.css=Layout anpassen
 option.css.none=Keine
 option.css.openolat=OpenOLAT Stylesheets
@@ -21,7 +21,7 @@ encoding.auto=Automatisch
 encoding.same=Gleich wie Inhalt
 height.auto=Automatisch
 height.label=H\u00F6he Anzeigefl\u00E4che
-inherit.label=Standardwerte übernehmen
+inherit.label=Standardwerte \u00FCbernehmen
 inherit=Aus Layouteinstellungen der Lernressource \u00FCbernehmen
 custom=Anpassen
 glossary.need.jQuery=Glossar braucht jQuery
diff --git a/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_fr.properties
index 45f14001232a13a5628de10ff9bc3b48c0baebec..50f73ea2e77c8a8e4dc4e931af9e839a5928dc50 100644
--- a/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/core/gui/control/generic/iframe/_i18n/LocalStrings_fr.properties
@@ -1,15 +1,5 @@
-#Thu Sep 03 11:24:42 CEST 2015
+#Sun Nov 29 10:58:54 CET 2015
 automatic.need.js=Automatique \u00E0 besoin de javascript
-
-
-
-
-
-
-
-
-
-
 command.download=T\u00E9l\u00E9charger fichier
 custom=Modifi\u00E9
 encoding.auto=Automatiquement
@@ -24,6 +14,7 @@ inherit=H\u00E9rit\u00E9
 inherit.label=H\u00E9ritage
 mode=Mode standard 
 mode.configured=Modifi\u00E9
+mode.hover=Utilisez de pr\u00E9f\u00E9rence le mode standard avec les contenus cr\u00E9\u00E9s avec un \u00E9diteur externe.
 mode.standard=Strict
 option.css=Librairie CSS
 option.css.none=Aucune
diff --git a/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_fr.properties
index 46ab26f59d42e7076892d9d7cbec6e56a93fd98e..287f0d35f8d7719253c7775ff82428ac3672e1cd 100644
--- a/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/core/util/i18n/devtools/_i18n/LocalStrings_fr.properties
@@ -1,17 +1,66 @@
-#Fri Nov 06 17:05:17 CET 2015
+#Sun Nov 29 20:40:57 CET 2015
 caching.enabled=Le stockage dans la m\u00E9moire cache est activ\u00E9e. Pour utiliser les outils de d\u00E9veloppeurs, la m\u00E9moire cache devrait \u00EAtre d\u00E9sactiv\u00E9e.
 coreasjar=Le framework olatcore est t\u00E9l\u00E9charg\u00E9 comme Jar, ce qui fait qu'il est impossible de le modifier.
 devtools.title=Outils de d\u00E9veloppeurs pour traductions
+devtools.warning=Le module de traduction i18n doit \u00EAtre activ\u00E9. Ajouter ou modifier les lignes suivantes dans votre fichier olat.local.properties\:<br/><br/>is.translation.server\=enabled<br/>i18n.application.src.dir\=${project.build.home.directory}/src/main/java
+menu.i18nDev=Maintenance i18n
+menu.i18nDev.alt=Maintenance i18n
 submitAddKey=Ajouter une cl\u00E9
+submitGetDupKeys=Chercher les cl\u00E9s en double
+submitGetDupVals=Chercher les valeurs en double
+submitMerge=Fusionner
+submitMove=D\u00E9placer
+submitMoveKey=D\u00E9placer la cl\u00E9
+submitMoveKeyToBundle=D\u00E9placez la cl\u00E9
+submitRemoveDeleted=Enlever les cl\u00E9s effac\u00E9es
+submitRemoveEmpty=Enlever les cl\u00E9s vides
+submitRemoveKey=Enlever la cl\u00E9
+submitRemovePackage=Enlever le package
+submitRemoveTodo=Enlever les cl\u00E9s TODO
+submitRenameKey=Renommer la cl\u00E9
+submitRenameLanguage=Renommer la langue
+submitSort=Trier alphab\u00E9tiquement
+task.add.key=Ajouter une cl\u00E9
+task.add.key.bundle=Bundle
+task.add.key.key=Cl\u00E9
+task.add.key.locale=Locale
+task.add.key.value=Valeur
 task.delete.key=Effacer cl\u00E9
 task.delete.package=Effacer paquet
 task.find.douplicates=Trouver doublons
 task.find.unreferenced.keys=Trouver cl\u00E9s non r\u00E9f\u00E9renci\u00E9es
 task.merge.package=Assembler paquets
 task.move.key=D\u00E9placer cl\u00E9
+task.move.key.key=Cl\u00E9
+task.move.key.to.bundle=D\u00E9placer la cl\u00E9
 task.move.language=D\u00E9placer langue
 task.move.package=D\u00E9placer paquet
+task.move.package.source=Source
+task.move.package.target=Cible
+task.remove.deletedKeys=Enlever les cl\u00E9s effac\u00E9es
+task.remove.deletedKeysCheck=Essai \u00E0 vide
+task.remove.emptyKeys=Enlever les cl\u00E9s vides
+task.remove.emptyKeysCheck=Essai \u00E0 vide
+task.remove.key=Enlever la cl\u00E9
+task.remove.key.bundle=Bundle
+task.remove.key.key=Cl\u00E9
+task.remove.key.locale=Locale
+task.remove.package=Enlever le package
+task.remove.package.bundle=Bundle
+task.remove.todoKeys=Enlever les cl\u00E9s TODO
+task.remove.todoKeysCheck=Essay \u00E0 vide
+task.remove.xKeys=Enelever les cl\u00E9s X
+task.remove.xKeysCheck=Essai \u00E0 vide
 task.remove.xkeys=Supprimer cl\u00E9s X
 task.rename.key=Renommer cl\u00E9
+task.rename.key.bundle=Bundle
+task.rename.key.orig=Nom de la cl\u00E9 d'origine
+task.rename.key.origBundle=Bundle d'origine
+task.rename.key.target=Nom de la cl\u00E9 cible
+task.rename.key.targetBundle=Bundle cible
 task.rename.language=Renommer langue
+task.rename.language.source=Langue source
+task.rename.language.target=Langue cible
+task.sort.check=Essai \u00E0 vide
+task.sort.keys=Trier tous les cl\u00E9s alphab\u00E9tiquement
 task.unknown.keys=Afficher/effacer les cl\u00E9s fausses
diff --git a/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java b/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java
index 03ed08d5c9eb18e14d12ec95cbaa324fa2c7c65a..47782ba9b0e7388d25f54586716ea91e18e2e8dd 100644
--- a/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java
+++ b/src/main/java/org/olat/core/util/openxml/HTMLToOpenXMLHandler.java
@@ -62,6 +62,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
 	private Table currentTable;
 	private Element currentParagraph;
 	private ListParagraph currentListParagraph;
+	private boolean pNeedNewParagraph = true;
 	
 	public HTMLToOpenXMLHandler(OpenXMLDocument document, Element paragraph) {
 		this.factory = document;
@@ -153,7 +154,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
 			}
 		} else {
 			Element currentRun = getCurrentRun();
-			String text = textBuffer.toString();
+			String text = textBuffer.toString().replace("\n", "").replace("\r", "");
 			if(text.length() > 0 && Character.isSpaceChar(text.charAt(0))) {
 				currentRun.appendChild(factory.createPreserveSpaceEl());
 			}
@@ -318,7 +319,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
 	public void startElement(String uri, String localName, String qName, Attributes attributes) {
 		String tag = localName.toLowerCase();
 		if("p".equalsIgnoreCase(tag)) {
-			getCurrentParagraph(true);
+			getCurrentParagraph(pNeedNewParagraph);
 		} else if("span".equalsIgnoreCase(tag)) {
 			flushText();
 
@@ -361,6 +362,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
 			Style[] styles = setTextPreferences(Style.italic);
 			styleStack.add(new StyleStatus(tag, true, styles));
 			appendParagraph(new Spacing(90, 0));
+			pNeedNewParagraph = false;
 		} else if("div".equals(tag)) {
 			String cl = attributes.getValue("class");
 			if(StringHelper.containsNonWhitespace(cl)) {
@@ -368,6 +370,7 @@ public class HTMLToOpenXMLHandler extends DefaultHandler {
 					Style[] styles = setTextPreferences(Style.italic);
 					styleStack.add(new StyleStatus(tag, true, styles));
 					appendParagraph(new Spacing(120, 0));
+					pNeedNewParagraph = false;
 				} else {
 					styleStack.add(new StyleStatus(tag, new Style[0]));
 				}
diff --git a/src/main/java/org/olat/course/nodes/fo/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/fo/_i18n/LocalStrings_fr.properties
index a5768004f8a4e95b6b959b82eb1d1cb65a9f0ac7..ef2de1af067c1cb6132cc98a6923b93dc8533887 100644
--- a/src/main/java/org/olat/course/nodes/fo/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/nodes/fo/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,6 @@
-#Mon Feb 08 21:03:37 CET 2010
+#Sun Nov 29 13:41:34 CET 2015
+allow.guest.post=Permettent aux utilisateurs invit\u00E9s de r\u00E9pondre sur le forum
+allow.pseudonym.post=Autoriser les messages anonymes avec pseudonyme
 command.closefo=Fermer visualisation 
 command.show=Afficher forum 
 command.showpopup=Afficher forum dans nouvelle fen\u00EAtre 
@@ -9,15 +11,13 @@ display.config.fieldsettitle=Configuration
 display.config.startPage=Avec page d'accueil?
 display.config.startPage.false=Non, d\u00E9marer contenu tout de suite svp
 display.config.startPage.true=Oui, afficher svp
-
-
-
-
 pane.tab.accessibility=Acc\u00E8s
 pane.tab.foconfig=Affichage
+pane.tab.settings=Configuration
 peekview.allItemsLink=Toutes les contributions
 preview.canModerate=Animer des contributions du forum possible
 preview.canPost=Ecriture de contributions du forum possible
 preview.canRead=Lecture de contributions du forum possible
 preview.header=Droits dans forum pour l'utilisateur simul\u00E9
+settings.title=Configuration
 warn.forumdelete=Attention\: toutes les contributions seront supprim\u00E9es.
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties
index 3fd05e86e06dc1fc80211e9b75ca3fb212579a5d..ba6819f4fe2d2c2b7889cfc27a330c230ec10609 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/nodes/gta/ui/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,4 @@
-#Thu Sep 03 11:24:42 CEST 2015
+#Sun Nov 29 19:33:12 CET 2015
 add.solution=T\u00E9l\u00E9chargez une solution
 add.task=Ajouter un devoir
 assessment.group.tool=Evaluer les groupes
@@ -7,8 +7,10 @@ assignment.deadline=Attribution jusqu'au
 before=avant
 bulk.download.title=T\u00E9l\u00E9charger tous les documents que vous avez soumis
 bulk.review=T\u00E9l\u00E9charger la critique
+bulk.revisions=T\u00E9l\u00E9charger les documents r\u00E9vis\u00E9s
 bulk.solutions=T\u00E9l\u00E9chargez les solutions
 bulk.submitted.documents=Documents soumis
+bulk.submitted.revisions=T\u00E9l\u00E9charger les documents corrig\u00E9s
 change.group=Choisir le groupe actif
 change.group.description=Vous \u00EAtes inscrits dans plusieurs groupes.
 choose.areas=Choisir des domaines d'\u00E9tudes
@@ -17,17 +19,30 @@ choosed.areas=Domaines d'\u00E9tudes
 choosed.groups=Groupes
 coach.assessment=Evaluer
 coach.close.revision.button=Terminer le processus de r\u00E9vision
+coach.corrections.closed=Le document soumis a \u00E9t\u00E9 accept\u00E9 pour \u00E9valuation
 coach.corrections.description=Vous avez re\u00E7u les corrections suivantes en retour.
+coach.corrections.rejected=Le document a \u00E9t\u00E9 retourn\u00E9 pour r\u00E9vision.
+coach.corrections.waiting=Les documents soumis sont en attente de v\u00E9rification.
 coach.document=Documents
+coach.document.open.editor=Cr\u00E9er une correction
 coach.documents.successfully.reviewed=Evaluer\!
 coach.need.revision.button=N\u00E9cessite une r\u00E9\u00E9criture
 coach.reviewed.button=Evaluer
+coach.reviewed.confirm.text=Veuillez confirmer que les documents remis ont \u00E9t\u00E9 accept\u00E9s. Le devoir est donc termin\u00E9 pour l'utilisateur, qui n'aura plus d'occasion de le r\u00E9viser.
+coach.reviewed.confirm.title=Confirmation\: accepter le document soumis
+coach.revisions.confirm.text=Veuillez confirmer la demande d'une r\u00E9vision. L'utilisateur pourra soumettre des documents suppl\u00E9mentaires.
+coach.revisions.confirm.text.warn=Ainsi, vous fermez le dossier de d\u00E9p\u00F4t. Si vous voulez continuer \u00E0 cr\u00E9er ou t\u00E9l\u00E9charger des corrections, cliquez "Annuler".
+coach.revisions.confirm.title=Confirmation\: r\u00E9vision demand\u00E9e
 coach.revisions.description=Vous avez re\u00E7u en retour des documents retravaill\u00E9s.
+coach.revisions.nofiles=La demande de r\u00E9vision a \u00E9t\u00E9 envoy\u00E9 sans document pour l'accompagner.
 coach.submit.corrections.to.revision.button=Envoyer les corrections
 coach.submitted.documents.description=Les documents suivants vous ont \u00E9t\u00E9 transmis.
+coach.submitted.nofiles=La soumission du devoir a \u00E9t\u00E9 effectu\u00E9 sans le moindre document.
 coach.task.assigned.description=Les devoirs suivants ont \u00E9t\u00E9 assign\u00E9s.
 coach.waiting.assignment=Attendre une affectation
+coach.waiting.assignment.description=Le devoir n'a pas encore \u00E9t\u00E9 attribu\u00E9. La soumission de documents et leur correction ne pourront commencer que lorsque le devoir sera assign\u00E9.
 coach.waiting.submitted.documents=Attendre les documents
+coach.waiting.submitted.documents.description=Aucun document n'a \u00E9t\u00E9 soumis. Le retour et la correction ne peuvent commencer que lorsque un devoir r\u00E9solu a \u00E9t\u00E9 soumis.
 comment=Commentaires
 condition.accessibility.title=Acc\u00E8s
 confirm.delete.solution.description=Voulez-vous vraiment effacer la solution "{0}"?
@@ -41,6 +56,7 @@ create.task=Cr\u00E9er un devoir
 days.after=jours apr\u00E8s
 document=Documents d\u00E9pos\u00E9s
 document.date=Date
+document.open.editor=R\u00E9diger une solution
 download.task=T\u00E9l\u00E9charger les devoirs
 download.task.infos={0} ({1} MB)
 edit.task=Editer le devoir
@@ -54,6 +70,7 @@ error.editor.atLeastOne=Vous devez choisir un type d'\u00E9diteur au moins.
 error.file.exists=$org.olat.core.commons.modules.bc\:cfile.already.exists
 error.file.invalid=$org.olat.core.commons.modules.bc\:cfile.name.notvalid
 error.max.documents=Vous ne pouvez pas d\u00E9poser plus de <b>{0}</b> documents, mais vous pouvez encore \u00E9diter ou \u00E9changer un fichier.
+error.missing.file=Le fichier d'un devoir est manquant.
 error.missing.group=Vous n'avez pas encore choisi un groupe.
 error.missing.score.config=Configuration de l'\u00E9valuation est manquante
 error.missing.solutions=Vous n'avez pas encore t\u00E9l\u00E9charg\u00E9 de solution.
@@ -68,6 +85,7 @@ external.editor=T\u00E9l\u00E9charger un fichier (PDF par exemple)
 file.name=Nom du document
 file.name.example=Document.html
 grading=Evaluation
+grading.enabled=Activ\u00E9 l'\u00E9valuation des documents
 group.apply.toall=Appliquer au groupe
 group.comment=Commentaire pour le groupe
 group.passed=R\u00E9ussi pour le groupe
@@ -77,6 +95,8 @@ info.title=$org.olat.course.nodes.ms\:info.title
 log.title=Historique des modifications
 mail.confirm.assignment.body=Affectation du devoir est r\u00E9ussi.
 mail.confirm.assignment.subject=Affectation
+mailto.group=Courriel au groupe
+mailto.user=Courriel au utilisateur
 max.documents=Nombre maximum de documents
 notifications.correction=Nouvelles corrections "{0}" de "{1}"
 notifications.header=Devoirs de groupe du cours "{0}"
@@ -107,6 +127,8 @@ process.revision=Remaniements
 process.solution=Solution
 process.submission=D\u00E9p\u00F4t
 relative.dates=Dates relatives
+relative.to.assignment=Affectation des devoirs
+relative.to.assignment.message={0} jours apr\u00E8s l'affectation du devoir.
 relative.to.course.launch=Premi\u00E8re visite du participant au cours
 relative.to.course.start=D\u00E9but du cours ({0})
 relative.to.enrollment=Inscription / r\u00E9servations
@@ -121,6 +143,7 @@ run.assignment.title=Affectation d'un devoir
 run.coach=Corriger
 run.coach.corrections.description=Vous avez retourner les demandes de corrections suivantes.
 run.corrections.description=Votre coach a ajout\u00E9 les documents suivants \u00E0 votre intention\:
+run.corrections.rejected=$\:coach.corrections.rejected
 run.documents.successfully.submitted=Votre/vos document(s) ont \u00E9t\u00E9 transmis avec succ\u00E8s.
 run.grading=Evaluation
 run.pick.task.description=Veuillez s'il vous pla\u00EEt choisir un devoir.
@@ -129,6 +152,7 @@ run.review.closed=Votre coach a \u00E9valu\u00E9 les documents que vous lui avez
 run.review.description=Votre coach \u00E9valu\u00E9 les documents que vous lui avez transmis. Vous serez avertis d\u00E8s qu'une version remani\u00E9e ou corrig\u00E9e sera disponible ou vous sera demand\u00E9e.
 run.review.waiting=Votre coach \u00E9value les documents que vous lui avez transmis. Vous serez avertis d\u00E8s qu'une version remani\u00E9e ou corrig\u00E9e sera disponible ou vous sera demand\u00E9e.
 run.revised.description=Vous avez transmis les documents remani\u00E9s suivants\:
+run.revised.nofiles=La r\u00E9vision a \u00E9t\u00E9 soumise sans le moindre document
 run.revision=P\u00E9riode de remaniement
 run.revision.period.description=Votre coach a ajout\u00E9 une p\u00E9riode de r\u00E9vision. Cr\u00E9er un document remani\u00E9 ou t\u00E9l\u00E9chargez-en un.
 run.run=Devoir
@@ -139,12 +163,15 @@ run.submit=D\u00E9p\u00F4t
 run.submit.button=Transmettre le devoir
 run.submit.confirm=Le d\u00E9p\u00F4t de votre devoir est d\u00E9finitif.
 run.submit.confirm.group=$\:run.submit.confirm<br/>C'est un devoir de groupe\! La s\u00E9lection effectu\u00E9e ici est valable pour tous les participants du groupe "{0}"\!
+run.submit.confirm.warning=Vous n'avez pas t\u00E9l\u00E9charger ou cr\u00E9er de document. Souhaitez toujours soumettre votre devoir? La remise du devoir est d\u00E9finitive et ne peut \u00EAtre r\u00E9voqu\u00E9e. Vous ne pourrez plus t\u00E9l\u00E9charger  de documents ensuite.
+run.submit.confirm.warning.group=$\:run.submit.confirm.warning<br/>C'ist un de vor de groupe\! Les actions effectu\u00E9es ici le sont au nom de tous les membres du groupe "{0}"\!
 run.submit.due.date=D\u00E9lai de d\u00E9p\u00F4t\: {0}
 run.submit.individual.description.all=Entrez votre solution soit en t\u00E9l\u00E9chargeant un document ou en utilisant l'\u00E9diteur int\u00E9gr\u00E9 mis \u00E0 votre disposition.
 run.submit.individual.description.editor=Ecrivez directement votre solution dans l'\u00E9diteur.
 run.submit.individual.description.upload=T\u00E9l\u00E9chargez un document termin\u00E9 en tant que solution.
 run.submit.revision.button=Soumettre les remaniements
 run.submitted.description=Vous avez rendus les solutions suivantes\:
+run.submitted.nofiles=Le devoir a \u00E9t\u00E9 soumis sans le moindre document.
 sample.solution=Solutions
 sample.solution.enabled=activ\u00E9
 sample.solution.visible.after=Visible apr\u00E8s le
@@ -177,6 +204,7 @@ table.header.uploaded.by=T\u00E9l\u00E9charger par
 task.alreadyChosen=$org.olat.course.nodes.ta\:task.chosen
 task.assigned.description=Le devoir suivant vous a \u00E9t\u00E9 affect\u00E9\:
 task.assignment=Affectation
+task.assignment.enabled=Assigner des devoirs aux participants
 task.assignment.error=Une erreur inattendue s'est produite\!
 task.assignment.type=$org.olat.course.nodes.ta\:form.task.type
 task.assignment.type.auto=$org.olat.course.nodes.ta\:form.task.type.auto
@@ -201,3 +229,9 @@ wait.for.solutions=Les solutions mod\u00E8les seront visible apr\u00E8s l'heure
 warning.group.pick.task=Ceci est un devoir de groupe\! La s\u00E9lection effectu\u00E9e ici s'applique \u00E0 tous les participants du groupe "{0}"\! Assurez-vous que votre choix \u00E0 \u00E9t\u00E9 discut\u00E9 au sein de votre groupe\! Seul un participant du groupe pour choisir un devoir.
 warning.group.submit=Ceci est un devoir de groupe\! Les documents soumis le sont pour tous les participants du groupe "{0}"\! Assurez-vous que les solutions ont \u00E9t\u00E9 discut\u00E9es au sein du groupe\! Un seul membre du groupe peut soumettre la solution d\u00E9finitive.
 warning.group.task=Ceci est un devoir de groupe\! L'affectation des devoirs, le d\u00E9p\u00F4t de la solution comme l'\u00E9valuation sont effectu\u00E9es pour tout le groupe. Discutez avec les autres membres du groupe comme vous allez ensemble choisir puis g\u00E9rer le devoir.
+warning.no.task.choosed=Il semble qu'il n'a pas \u00E9t\u00E9 possible de vous choisir un devoir en raison de changements dans la configuration de l'\u00E9l\u00E9ment de cours.
+warning.no.task.choosed.coach=Il semble qu'en raison d'un changement dans la configuration de l'\u00E9l\u00E9ment de cours, un utilisateur n'a pas pu se voir assigner un devoir.
+warning.tasks.in.process.delete.text=Voulez-vous vraiment supprimer ce devoir? Des utilisateurs l'ont d\u00E9j\u00E0 commenc\u00E9. Cela entra\u00EEnera des probl\u00E8mes pour ces utilisateurs.
+warning.tasks.in.process.delete.title=$\:warning.tasks.in.process.title
+warning.tasks.in.process.text=Il ya d\u00E9j\u00E0 des utilisateurs qui ont commenc\u00E9 les devoirs. Des modifications de la configuration du processus pourra entra\u00EEner des probl\u00E8mes pour ces utilisateurs.
+warning.tasks.in.process.title=Devoirs d\u00E9j\u00E0 commenc\u00E9s
diff --git a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_fr.properties
index d67b42f28d2d9b4d2d8af10435789305b2cc24ad..b8dcb6e12d8e8fbd56f49332fb0039762ab6fc60 100644
--- a/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/group/ui/edit/_i18n/LocalStrings_fr.properties
@@ -1,66 +1,9 @@
-#Sun Dec 14 10:43:00 CET 2014
+#Sun Nov 29 10:55:55 CET 2015
 add.member=$org.olat.group.ui.main\:add.member
 allow.leaving.group=Les participants peuvent quitter le groupe
 areachoice.no.areas.admin=Aucun domaine d'\u00E9tude trouv\u00E9. Cr\u00E9ez SVP un domaine d'\u00E9tude dans la gestion des groupes
 areachoice.no.areas.owner=Aucun domaine d'\u00E9tude trouv\u00E9. Les domaines d'\u00E9tude peuvent \u00EAtre cr\u00E9\u00E9s uniquement par les personnes autoris\u00E9es pour toute la gestion des groupes.
 assessment=$org.olat.group.ui.main\:assessment
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
 chkBox.open=Publier ce groupe \u00E0 la r\u00E9servation
 chkBox.open.downloadList=Les utilisateurs peuvent t\u00E9l\u00E9charger la liste des membres
 chkBox.open.owners=Tous voient les coaches
@@ -96,16 +39,7 @@ group.edit.tab.members=Membres
 group.edit.tab.resources=Cours
 group.edit.tab.rights=Autorisations
 group.edit.title=Editer le groupe <i>{0}</i> 
-
-
-
-
-
-
-
-
-
-
+group.id.help=Cherchez cette Id. dans la recherche avanc\u00E9e.
 home=$org.olat.group.ui.main\:home
 import.member=$org.olat.group.ui.main\:import.member
 mail.member=$org.olat.group.ui.main\:mail.member
diff --git a/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_fr.properties
index bbb8769c5965cac841530f4ac9c00bf2f39a755a..e866e9c86eaeeb1775fd6a28127c35c8fae6475f 100644
--- a/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/group/ui/wizard/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,4 @@
-#Fri Nov 06 17:06:35 CET 2015
+#Sun Nov 29 10:56:31 CET 2015
 action.general=Action
 backLink=Retour
 bgcopywizard.copyform.areas=Configuration domaines d'\u00E9tude
@@ -34,6 +34,7 @@ copy.wizard.bgstep=Copier\: "{0}"
 create.form.error.emptylist=Indiquez au moins le nom d'un groupe, svp
 create.form.error.numberOrNull=Seulement des chiffres, svp (ou laisser vide)
 create.form.title.max=Nombre pr\u00E9vu <br>de participants
+email.other.groups={0} et {1} autres groupes
 email.select.receiver.description=But
 email.select.receiver.participant=Participant
 email.select.receiver.title=But
diff --git a/src/main/java/org/olat/ims/qti/editor/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/ims/qti/editor/_i18n/LocalStrings_fr.properties
index 5439555a3c4bcf1e5398e97fc016810aa9302fbe..84284934874101dcdd1847d84819c3ee1a47ca6c 100644
--- a/src/main/java/org/olat/ims/qti/editor/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/ims/qti/editor/_i18n/LocalStrings_fr.properties
@@ -1,4 +1,4 @@
-#Sun Nov 08 13:00:33 CET 2015
+#Sun Nov 29 17:14:42 CET 2015
 add_answer=Ajouter nouvelle r\u00E9ponse
 add_blank=Ajouter nouveau trou
 add_text=Ajouter nouveau fragment de texte
@@ -54,7 +54,9 @@ fieldset.legend.preview=Aper\u00E7u
 fieldset.legend.question=Question
 fieldset.legend.sectionsettings=R\u00E9glages
 form.assessment.order_type=Ordres des sections
+form.assessment.order_type.hover=D\u00E9terminer l'ordre dans lequel les sections choisies doivent \u00EAtre affich\u00E9es \u00E0 l'utilisateur.
 form.assessment.selection_pre=Nombre de sections dans cette \u00E9valuation
+form.assessment.selection_pre.hover=Indiquez si toutes les sections ou une s\u00E9lection al\u00E9atoire seulement sera \u00E0 affich\u00E9e \u00E0 l'utilisateur.
 form.chngmsg.info=Vous avez modifi\u00E9 une ressource r\u00E9f\u00E9renc\u00E9e par d'autres auteurs. \u00C9crivez un message qui sera envoy\u00E9 avec l'historique des modifications \u00E9tabli automatiquement. Vous devez envoyer ce message afin de rendre effectives vos modifications.
 form.chngmsg.infolabel=Information
 form.chngmsg.informlearners=Les apprenants peuvent voir l'historique des modifications.
@@ -81,6 +83,7 @@ form.imd.type=Type
 form.metadata.cutvalue=Nombre de points n\u00E9cessaire pour "r\u00E9ussi"
 form.metadata.duration=Limite de temps
 form.metadata.globalfeedbackNsolution=Placer les Feedback / Solutions pour tout le test
+form.metadata.globalfeedbackNsolution.hover=D\u00E9terminer si l'\u00E9valuation et la solution seront pr\u00E9sent\u00E9s \u00E0 l'utilisateur.
 form.metadata.minutes=Min
 form.metadata.objectives=Description
 form.metadata.seconds=Sec
diff --git a/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java b/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
index 71fe27d81280a1ad21ae665b9de534cb491bb937..4c9ed78bc6643109a5387306c7d43dd6d0c03ddf 100644
--- a/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
+++ b/src/main/java/org/olat/modules/fo/ForumNotificationsHandler.java
@@ -99,7 +99,11 @@ public class ForumNotificationsHandler extends LogDelegator implements Notificat
 					
 					String name;
 					if(modifier != null) {
-						name = NotificationHelper.getFormatedName(modifier);
+						if(modifier.equals(creator) && StringHelper.containsNonWhitespace(mInfo.getPseudonym())) {
+							name = mInfo.getPseudonym();
+						} else {
+							name = NotificationHelper.getFormatedName(modifier);
+						}
 					} else if(StringHelper.containsNonWhitespace(mInfo.getPseudonym())) {
 						name = mInfo.getPseudonym();
 					} else if(mInfo.isGuest()) {
diff --git a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_de.properties
index fc699e16b5f3f53bd1c0712f328f8b043dd9596e..a79ebeaee7aeaa9e1bbc876065f046a3f401b8d6 100644
--- a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_de.properties
@@ -9,6 +9,7 @@ anonymous.group.default=Default for group forum
 anonymous.posting=Erlaubt anonymous posting using a pseudonym
 anonymous.poster=Gastbeitrag
 guest=Gast
+guest.suffix=(Gast)
 archive.forum=Forum archivieren
 archive.forum.dialog=Wollen Sie dieses Forum wirklich in Ihrem pers\u00F6nlichen Ordner im Unterordner "private/archive" archivieren?
 archive.forum.successfully=Das Forum wurde in Ihrem pers\u00F6nlichen Ordner im Unterordner "private/archive" archiviert.
@@ -74,6 +75,7 @@ msg.title=Titel
 msg.title.re=Re\:
 msg.update=Editieren
 msg.upload=Datei anh\u00E4ngen
+natural.sort=Verschaltet
 no=Nein
 notifications.entry=Nachricht "{0}" von {1} erstellt
 notifications.entry.modified=Nachricht "{0}" von {1} ver\u00E4ndert
diff --git a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_en.properties
index 106b346c3db07bce35ca1ecb343f73083b73d77a..0f5f5d943e2790d71acb0c00d8faad3753708d6d 100644
--- a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_en.properties
@@ -29,6 +29,8 @@ filter.header.allUsers=All contributions
 filter.header.title=Search for persons
 filter.results.title=Contributions by
 forum.emtpy=No posts published in this forum.
+guest=Guest
+guest.suffix=(Guest)
 header.cannoteditmessage=Post cannot be edited
 header.cannotsavemessage=Post cannot be saved
 header.editmsg=Edit post
@@ -76,6 +78,7 @@ msg.title=Title
 msg.title.re=Re\:
 msg.update=Edit
 msg.upload=Attach file
+natural.sort=Thread
 no=No
 notifications.entry=Message "{0}" created by {1}
 notifications.entry.modified=Message "{0}" modified by {1}
diff --git a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_fr.properties
index 2af4fad9ee700a94b997b2a6dc8f3ec67fdc886d..78d9b6685819b0360770e045c6df29a35e96ecf5 100644
--- a/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/modules/fo/_i18n/LocalStrings_fr.properties
@@ -1,5 +1,13 @@
-#Mon Oct 22 15:53:49 CEST 2012
+#Sun Nov 29 11:12:42 CET 2015
+admin.menu.title=Forum
+admin.menu.title.alt=Configuration de la fonction forum
 admin.title=Configuration des forums
+anonymous.course.default=D\u00E9faut pour forums des cours
+anonymous.default.disabled=Pseudonyme d\u00E9sactiv\u00E9
+anonymous.default.enabled=Pseudonyme activ\u00E9
+anonymous.group.default=D\u00E9faut pour les forums des groupes
+anonymous.poster=Message d'un invit\u00E9
+anonymous.posting=Permettre aux utilisateurs invit\u00E9s les contributions aux forums
 archive.forum=Archiver le forum
 archive.forum.dialog=Etes-vous s\u00FBr de vouloir archiver ce forum dans votre dossier personnel sous private?
 archive.forum.successfully=Ce forum a \u00E9t\u00E9 archiv\u00E9 dans votre dossier personnel sous private.
@@ -15,11 +23,14 @@ close.thread=Terminer discussion
 delete.att.ok=Les fichiers ont \u00E9t\u00E9 supprim\u00E9s.
 deleteok=La contribution a \u00E9t\u00E9 supprim\u00E9e.
 error.field.not.empty=Ce champ ne peut pas \u00EAtre vide. 
+error.pseudonym=Trop de similitude avec le nom d'un utilisateur pr\u00E9-existant
 filter=Filtre personne
 filter.header.allUsers=Contributions de toutes les personnes
 filter.header.title=Recherche de personnes
 filter.results.title=Contributions de
 forum.emtpy=Ce forum ne contient pas  de contributions.
+guest=Invit\u00E9
+guest.suffix=(Invit\u00E9)
 header.cannoteditmessage=Impossible d'\u00E9diter la contribution
 header.cannotsavemessage=Impossible de sauvegarder la contribution
 header.editmsg=Editer contribution
@@ -62,11 +73,12 @@ msg.reply=R\u00E9pondre
 msg.save=Enregistrer
 msg.save.impossible=Retour vers l'aper\u00E7u
 msg.split=S\u00E9parer la contribution avec r\u00E9ponses
-msg.sticky=Mettre priorit\u00E9s au sujet (sticky)
+msg.sticky=En faire un sujet prioritaire (sticky)
 msg.title=Titre
 msg.title.re=Re\:
 msg.update=Editer
 msg.upload=Attacher fichier
+natural.sort=Sujet de discussion
 no=Non
 notifications.entry=Message "{0}" \u00E9tabli par {1}
 notifications.entry.modified=Message "{0}" de {1} a \u00E9t\u00E9 modifi\u00E9
@@ -74,11 +86,13 @@ notifications.header=Il y a des nouveaux messages dans un des forums que vous av
 notifications.header.course=Forum dans le cours "{0}"
 notifications.header.group=Forum dans groupe  "{0}"
 open.thread=Ouvrir discussion
+pseudonym.suffix=(Pseudonyme)
 reallydeleteAtt=Voulez-vous vraiment supprimer ce(s) fichier(s)?
 reallydeleteleaf=Voulez-vous vraiment supprimer la contribution <i>{0}</i>?
 reallydeletenode1=Voulez-vous vraiment supprimer la contribution <i>{0}</i> avec sa r\u00E9ponse? 
 reallydeletenodeN=Voulez-vous vraiment supprimer la contribution <i>{0}</i> avec l'ensemble de ses <b>{1}</b> r\u00E9ponses?
 reallysplitthread=Voulez-vous vraiment s\u00E9parer la contribution avec les r\u00E9ponses?
+remove.sticky=Enlever la priorit\u00E9 du sujet (sticky)
 show.thread=Afficher discussion
 table.choose=D\u00E9placer ici
 table.closed=Termin\u00E9
@@ -105,6 +119,7 @@ table.user.lastname=Nom
 table.user.replies=R\u00E9ponses
 table.user.threads=Sujets
 table.userfriendlyname=Auteur
+use.pseudonym=R\u00E9diger par
 use.pseudonym.label=Utiliser un pseudonyme
 viewswitch.flatview=tous (plat)
 viewswitch.marked=marqu\u00E9e
diff --git a/src/main/java/org/olat/modules/fo/archiver/formatters/ForumOpenXMLFormatter.java b/src/main/java/org/olat/modules/fo/archiver/formatters/ForumOpenXMLFormatter.java
index c756944a8aa04d427b94f42335c63bb42510a50c..d89aff44d36a62b68bf8f218b76a8bfbaa7b61a0 100644
--- a/src/main/java/org/olat/modules/fo/archiver/formatters/ForumOpenXMLFormatter.java
+++ b/src/main/java/org/olat/modules/fo/archiver/formatters/ForumOpenXMLFormatter.java
@@ -98,23 +98,30 @@ public class ForumOpenXMLFormatter extends ForumFormatter {
 		MessageNode m = (MessageNode) node;
 		
 		StringBuilder creatorAndDate = new StringBuilder();
+		Identity creator = m.getCreator();
 		if(StringHelper.containsNonWhitespace(m.getPseudonym())) {
 			creatorAndDate.append(m.getPseudonym())
-			  .append(" ")
-			  .append(translator.translate("pseudonym.suffix"));
+			  .append(" ");
+			if(m.isGuest()) {
+				creatorAndDate.append(translator.translate("guest.suffix"));
+			} else {
+				creatorAndDate.append(translator.translate("pseudonym.suffix"));
+			}
 		} else if(m.isGuest()) {
 			creatorAndDate.append(translator.translate("guest"));
-		} else {
-			creatorAndDate.append(m.getCreator().getUser().getProperty(UserConstants.FIRSTNAME, null));
+		} else if(creator != null) {
+			creatorAndDate.append(creator.getUser().getProperty(UserConstants.FIRSTNAME, null));
 			creatorAndDate.append(" ");
-			creatorAndDate.append(m.getCreator().getUser().getProperty(UserConstants.LASTNAME, null));
+			creatorAndDate.append(creator.getUser().getProperty(UserConstants.LASTNAME, null));
+		} else {
+			creatorAndDate.append("???");
 		}
 		creatorAndDate.append(" ");
 		creatorAndDate.append(formatter.formatDateAndTime(m.getCreationDate()));
 
 		if (isTopThread) {
 			document.appendHeading1(m.getTitle(), creatorAndDate.toString());
-			this.isTopThread = false;
+			isTopThread = false;
 		} else {
 			document.appendHeading2(m.getTitle(), creatorAndDate.toString());
 		}
@@ -122,16 +129,29 @@ public class ForumOpenXMLFormatter extends ForumFormatter {
 		Identity modifier = m.getModifier();
 		if (modifier != null) {
 			StringBuilder modSb = new StringBuilder();
-			modSb.append(translator.translate("msg.modified")).append(": ")
-			     .append(modifier.getUser().getProperty(UserConstants.FIRSTNAME, null))
-			     .append(" ")
-			     .append(modifier.getUser().getProperty(UserConstants.LASTNAME,  null))
-			     .append(" ")
-			     .append(formatter.formatDateAndTime(m.getModifiedDate()));
+			if(modifier.equals(creator) && StringHelper.containsNonWhitespace(m.getPseudonym())) {
+				modSb.append(m.getPseudonym())
+				  .append(" ");
+				if(m.isGuest()) {
+					modSb.append(translator.translate("guest.suffix"));
+				} else {
+					modSb.append(translator.translate("pseudonym.suffix"));
+				}
+			} else {
+				modSb.append(translator.translate("msg.modified")).append(": ")
+				     .append(modifier.getUser().getProperty(UserConstants.FIRSTNAME, null))
+				     .append(" ")
+				     .append(modifier.getUser().getProperty(UserConstants.LASTNAME,  null))
+				     .append(" ")
+				     .append(formatter.formatDateAndTime(m.getModifiedDate()));
+			}
 			document.appendSubtitle(modSb.toString());
 		}
 		
 		String body = m.getBody();
+		if(body != null) {
+			body = body.replace("<p>&nbsp;", "<p>");
+		}
 		document.appendHtmlText(body, new Spacing(180, 0));
 		
 		// message attachments
diff --git a/src/main/java/org/olat/modules/fo/manager/ForumManager.java b/src/main/java/org/olat/modules/fo/manager/ForumManager.java
index 56ac4e6215d81dd3a3d2e4b73363f04b13f7dcf4..854a129a27d7a6d9db399667f6a9d321f2fadb08 100644
--- a/src/main/java/org/olat/modules/fo/manager/ForumManager.java
+++ b/src/main/java/org/olat/modules/fo/manager/ForumManager.java
@@ -170,20 +170,7 @@ public class ForumManager {
 	 */
 	public List<Message> getMessagesByForum(Forum forum){
 		if (forum == null) return new ArrayList<Message>(0); // fxdiff: while indexing it can somehow occur, that forum is null!
-		return getMessagesByForumID(forum.getKey(),  0, -1, null, true);
-	}
-	
-	/**
-	 * 
-	 * @param forum_id
-	 * @param start
-	 * @param limit
-	 * @param orderBy
-	 * @param asc
-	 * @return
-	 */
-	public List<Message> getMessagesByForumID(Long forum_id, int firstResult, int maxResults, Message.OrderBy orderBy, boolean asc) {
-		return getMessagesByForumID(forum_id, firstResult, maxResults, false, orderBy, asc);
+		return getMessagesByForumID(forum.getKey(),  0, -1, false, null, true);
 	}
 	
 	/**
@@ -199,7 +186,7 @@ public class ForumManager {
 	private List<Message> getMessagesByForumID(Long forumKey, int firstResult, int maxResults, boolean onlyThreads, Message.OrderBy orderBy, boolean asc) {
 		StringBuilder query = new StringBuilder();
 		query.append("select msg from fomessage as msg")
-		     .append(" inner join fetch msg.creator as creator")
+		     .append(" left join fetch msg.creator as creator")
 		     .append(" where msg.forum.key=:forumKey ");
 		if(onlyThreads) {
 			query.append(" and msg.parent is null");
@@ -218,6 +205,18 @@ public class ForumManager {
 		return dbQuery.getResultList();
 	}
 	
+	public List<Message> getMessageChildren(Message parentMessage) {
+		StringBuilder query = new StringBuilder();
+		query.append("select msg from fomessage as msg")
+		     .append(" inner join msg.parent as parentMsg")
+		     .append(" where parentMsg.key=:parentKey");
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(query.toString(), Message.class)
+				.setParameter("parentKey", parentMessage.getKey())
+				.getResultList();
+		
+	}
+	
 	private int countMessagesByForumID(Long forumKey, boolean onlyThreads) {
 		StringBuilder query = new StringBuilder();
 		query.append("select count(msg) from fomessage as msg")
@@ -274,13 +273,15 @@ public class ForumManager {
 		  .append(" ) as numOfMessages")
 		  .append(" , (select max(replies.lastModified) from fomessage as replies")
 		  .append("  where replies.threadtop.key=msg.key and replies.forum.key=:forumKey")
-		  .append(" ) as lastModified")
-		  .append(" , (select count(read.key) from foreadmessage as read, fomessage as posts")
-		  .append("  where (posts.threadtop.key=msg.key or posts.key=msg.key) and read.message.key=posts.key and read.identity.key=:identityKey")
-		  .append(" ) as numOfReadMessages");
+		  .append(" ) as lastModified");
+
 		if(identity != null) {
-			sb.append(" ,(select count(mark.key) from ").append(MarkImpl.class.getName()).append(" as mark ")
-			  .append("   where mark.creator.key=:identityKey and mark.resId=:forumKey and msg.key = cast(mark.resSubPath as long) and mark.resName='Forum'")
+			sb.append(" , (select count(read.key) from foreadmessage as read, fomessage as posts")
+			  .append("  where (posts.threadtop.key=msg.key or posts.key=msg.key) and read.message.key=posts.key and read.identity.key=:identityKey")
+			  .append(" ) as numOfReadMessages")
+			  .append(" ,(select count(mark.key) from ").append(MarkImpl.class.getName()).append(" as mark, fomessage as mposts ")
+			  .append("   where mark.creator.key=:identityKey and mark.resId=:forumKey and (mposts.threadtop.key=msg.key or mposts.key=msg.key)")
+			  .append("    and mposts.key=cast(mark.resSubPath as long) and mark.resName='Forum'")
 			  .append(" ) as marks");
 		}
 		
@@ -290,10 +291,11 @@ public class ForumManager {
 
 		TypedQuery<Object[]> objectsQuery = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Object[].class)
-				.setParameter("forumKey", forum.getKey())
-				.setParameter("identityKey", identity.getKey());
+				.setParameter("forumKey", forum.getKey());
+		if(identity != null) {
+			objectsQuery.setParameter("identityKey", identity.getKey());
+		}
 
-		
 		List<Object[]> objects = objectsQuery.getResultList();
 		List<ForumThread> threadList = new ArrayList<>(objects.size());
 		for(Object[] object:objects) {
@@ -304,11 +306,11 @@ public class ForumManager {
 			String creator = userManager.getUserDisplayName(msg.getCreator());
 			ForumThread thread = new ForumThread(msg, creator, lastModifed, numOfMessages);
 
-			Number readMessages = (Number)object[3];
-			int numOfReadMessages = readMessages == null ? 0 : readMessages.intValue();
-			thread.setNewMessages(numOfMessages - numOfReadMessages);
-			
 			if(identity != null) {
+				Number readMessages = (Number)object[3];
+				int numOfReadMessages = readMessages == null ? 0 : readMessages.intValue();
+				thread.setNewMessages(numOfMessages - numOfReadMessages);
+
 				Number numOfMarkedMessagesLong = (Number)object[4];
 				int numOfMarkedMessages = numOfMarkedMessagesLong == null ? 0 : numOfMarkedMessagesLong.intValue();
 				thread.setMarkedMessages(numOfMarkedMessages);
@@ -389,6 +391,14 @@ public class ForumManager {
 				.getResultList();
 	}
 	
+	/**
+	 * Return the messages of a user written under it's own name
+	 * (not under a pseudonym).
+	 * 
+	 * @param forum
+	 * @param user
+	 * @return
+	 */
 	public List<MessageLight> getLightMessagesByUser(Forum forum, IdentityRef user) {
 		StringBuilder query = new StringBuilder();
 		query.append("select msg from folightmessage as msg")
@@ -404,6 +414,15 @@ public class ForumManager {
 				.getResultList();
 	}
 	
+	/**
+	 * Return the messages of a specified user under a specific
+	 * pseudonym.
+	 * 
+	 * @param forum
+	 * @param user
+	 * @param pseudonym
+	 * @return
+	 */
 	public List<MessageLight> getLightMessagesByUserUnderPseudo(Forum forum, IdentityRef user, String pseudonym) {
 		StringBuilder query = new StringBuilder();
 		query.append("select msg from folightmessage as msg")
@@ -821,31 +840,23 @@ public class ForumManager {
 		} else {	
 			//it only make sense to split a thread if the current message is not a threadtop message.	
 			List<Message> threadList = getThread(msg.getThreadtop().getKey());
-			List<Message> subthreadList = new ArrayList<Message>();
-			subthreadList.add(msg);
+			List<Message> subthreadList = new ArrayList<>();
 			getSubthread(msg, threadList, subthreadList);
 
-			Iterator<Message> messageIterator = subthreadList.iterator();
-			Message firstMessage = null;
-			if (messageIterator.hasNext()) {
-				firstMessage = messageIterator.next();
-				firstMessage = getMessageById(firstMessage.getKey());
-				firstMessage.setParent(null);
-				firstMessage.setThreadtop(null);
-				updateMessage(firstMessage, false);
-				newTopMessage = firstMessage;
-			}
-			while (firstMessage != null && messageIterator.hasNext()) {
-				Message message = messageIterator.next();
-				message = getMessageById(firstMessage.getKey());
-				message.setThreadtop(firstMessage);
-				updateMessage(message, false);
+			newTopMessage = getMessageById(msg.getKey());
+			newTopMessage.setParent(null);
+			newTopMessage.setThreadtop(null);
+			newTopMessage = dbInstance.getCurrentEntityManager().merge(newTopMessage);
+
+			for(Message message : subthreadList) {
+				message.setThreadtop(newTopMessage);
+				message = dbInstance.getCurrentEntityManager().merge(message);
 			}
 
 			dbInstance.commit();// before sending async event
 			ForumChangedEvent event = new ForumChangedEvent(ForumChangedEvent.SPLIT, newTopMessage.getKey(), null, null);
 			CoordinatorManager.getInstance().getCoordinator().getEventBus()
-				.fireEventToListenersOf(event, firstMessage.getForum());
+				.fireEventToListenersOf(event, newTopMessage.getForum());
 		}		
 		return newTopMessage;
 	}
@@ -858,31 +869,34 @@ public class ForumManager {
 	 * @return the moved message
 	 */
 	public Message moveMessage(Message msg, Message topMsg) {
-		List<Message> oldThreadList = getThread(msg.getThreadtop().getKey());
-		List<Message> subThreadList = new ArrayList<Message>();
-		getSubthread(msg, oldThreadList, subThreadList);
-		// one has to set a new parent for all childs of the moved message
+		// one has to set a new parent for all children of the moved message
 		// first message of sublist has to get the parent from the moved message
-		for (Message childMessage : subThreadList) {
-			childMessage = getMessageById(childMessage.getKey());
-			childMessage.setParent(msg.getParent());
-			updateMessage(childMessage, false);
+		List<Message> children = getMessageChildren(msg);
+		for (Message child : children) {
+			child.setParent(msg.getParent());
+			dbInstance.getCurrentEntityManager().merge(child);
 		}
 		
-		// now move the message to the choosen thread
+		// now move the message to the chosen thread
+		Message targetThread = topMsg.getThreadtop();
+		if(targetThread == null) {
+			targetThread = topMsg;
+		}
+
 		final Message oldMessage = getMessageById(msg.getKey());
 		Message message = createMessage(oldMessage.getForum(), oldMessage.getCreator(), oldMessage.isGuest());
+		((MessageImpl)message).setCreationDate(oldMessage.getCreationDate());
+		message.setLastModified(oldMessage.getLastModified());
 		message.setModifier(oldMessage.getModifier());
-		message.setLastModified(oldMessage.getLastModified()); // OLAT-6295
 		message.setTitle(oldMessage.getTitle());
 		message.setBody(oldMessage.getBody());
 		message.setPseudonym(oldMessage.getPseudonym());
-		message.setThreadtop(topMsg);
+		message.setThreadtop(targetThread);
 		message.setParent(topMsg);
 		Status status = Status.getStatus(oldMessage.getStatusCode());
 		status.setMoved(true);
 		message.setStatusCode(Status.getStatusCode(status));
-		saveMessage(message);
+		message = saveMessage(message);
 		
 		//move marks
 		OLATResourceable ores = OresHelper.createOLATResourceableInstance(Forum.class, msg.getForum().getKey());
diff --git a/src/main/java/org/olat/modules/fo/ui/ForumController.java b/src/main/java/org/olat/modules/fo/ui/ForumController.java
index 67d9b37c25e5c197475bb61f4174ceb4f2a9d3bd..e32bc7198a3ed57c56d57977fdcee568c6db7026 100644
--- a/src/main/java/org/olat/modules/fo/ui/ForumController.java
+++ b/src/main/java/org/olat/modules/fo/ui/ForumController.java
@@ -49,6 +49,7 @@ import org.olat.modules.fo.Forum;
 import org.olat.modules.fo.ForumCallback;
 import org.olat.modules.fo.ForumChangedEvent;
 import org.olat.modules.fo.Message;
+import org.olat.modules.fo.Status;
 import org.olat.modules.fo.manager.ForumManager;
 import org.olat.modules.fo.ui.events.SelectMessageEvent;
 import org.olat.modules.fo.ui.events.SelectUserEvent;
@@ -159,18 +160,19 @@ public class ForumController extends BasicController implements GenericEventList
 					if (message != null) {
 						doThreadList(ureq);
 						Message thread = message.getThreadtop() == null ? message : message.getThreadtop();
-
-						String subType = null;
-						if(entries.size() > 1) {
-							subType = entries.get(1).getOLATResourceable().getResourceableTypeName();
-						}
-						
-						if("Marked".equalsIgnoreCase(subType)) {
-							doMarkedView(ureq, thread, message);
-						} else if("New".equalsIgnoreCase(subType)) {
-							doMarkedView(ureq, thread, message);
-						} else {
-							doThreadView(ureq, thread, message);
+						if(focallback.mayEditMessageAsModerator() || !Status.getStatus(thread.getStatusCode()).isHidden()) {
+							String subType = null;
+							if(entries.size() > 1) {
+								subType = entries.get(1).getOLATResourceable().getResourceableTypeName();
+							}
+							
+							if("Marked".equalsIgnoreCase(subType)) {
+								doMarkedView(ureq, thread, message);
+							} else if("New".equalsIgnoreCase(subType)) {
+								doMarkedView(ureq, thread, message);
+							} else {
+								doThreadView(ureq, thread, message);
+							}
 						}
 					}
 				}
diff --git a/src/main/java/org/olat/modules/fo/ui/ForumMessageDataModel.java b/src/main/java/org/olat/modules/fo/ui/ForumMessageDataModel.java
index f6f68b135859c13ff1c627394572936e5c23d571..7f52c6737eb5cae7994a603266c95f628fc4ff2b 100644
--- a/src/main/java/org/olat/modules/fo/ui/ForumMessageDataModel.java
+++ b/src/main/java/org/olat/modules/fo/ui/ForumMessageDataModel.java
@@ -51,8 +51,12 @@ public class ForumMessageDataModel extends DefaultFlexiTableDataModel<MessageLig
 	@Override
 	public void sort(SortKey orderBy) {
 		if(orderBy != null) {
-			List<MessageLightView> views = new ForumMessageDataModelSort(orderBy, this, null).sort();
-			super.setObjects(views);
+			if("natural".equals(orderBy.getKey())) {
+				System.out.println();
+			} else {
+				List<MessageLightView> views = new ForumMessageDataModelSort(orderBy, this, null).sort();
+				super.setObjects(views);
+			}
 		}
 	}
 	
diff --git a/src/main/java/org/olat/modules/fo/ui/ForumMessageListController.java b/src/main/java/org/olat/modules/fo/ui/ForumMessageListController.java
index 61bbadcd4ebb4ea6cfaa371d47b2a9da6a07bc94..8db009683174983741358aacb618c224b2e84eb1 100644
--- a/src/main/java/org/olat/modules/fo/ui/ForumMessageListController.java
+++ b/src/main/java/org/olat/modules/fo/ui/ForumMessageListController.java
@@ -33,6 +33,8 @@ import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
 import org.olat.core.gui.components.form.flexible.elements.FlexiTableElement;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSort;
+import org.olat.core.gui.components.form.flexible.elements.FlexiTableSortOptions;
 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.elements.table.DefaultFlexiColumnModel;
@@ -164,12 +166,17 @@ public class ForumMessageListController extends FormBasicController implements F
 
 	@Override
 	protected void initForm(FormItemContainer formLayout, Controller listener, UserRequest ureq) {
+		List<FlexiTableSort> sorts = new ArrayList<>();
+		sorts.add(new FlexiTableSort(translate("natural.sort"), "natural"));
+		
 		FlexiTableColumnModel columnsModel = FlexiTableDataModelFactory.createFlexiTableColumnModel();
 		if(withType) {
 			columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ForumMessageCols.type, new StatusTypeCellRenderer()));
+			sorts.add(new FlexiTableSort(translate(ForumMessageCols.type.i18nHeaderKey()), ForumMessageCols.type.name()));
 		}
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ForumMessageCols.thread,
 				"select", new StaticFlexiCellRenderer("select", new IndentCellRenderer())));
+		sorts.add(new FlexiTableSort(translate(ForumMessageCols.thread.i18nHeaderKey()), ForumMessageCols.thread.name()));
 		
 		int colPos = USER_PROPS_OFFSET;
 		for (UserPropertyHandler userPropertyHandler : userPropertyHandlers) {
@@ -185,15 +192,23 @@ public class ForumMessageListController extends FormBasicController implements F
 			} else {
 				col = new DefaultFlexiColumnModel(visible, userPropertyHandler.i18nColumnDescriptorLabelKey(), colPos, true, propName);
 			}
+
+			sorts.add(new FlexiTableSort(translate(userPropertyHandler.i18nColumnDescriptorLabelKey()), propName));
 			columnsModel.addFlexiColumnModel(col);
 			colPos++;
 		}
 
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(ForumMessageCols.lastModified));
+		sorts.add(new FlexiTableSort(translate(ForumMessageCols.lastModified.i18nHeaderKey()), ForumMessageCols.lastModified.name()));
 
 		dataModel = new ForumMessageDataModel(columnsModel, getTranslator());
 		tableEl = uifactory.addTableElement(getWindowControl(), "messages", dataModel, getTranslator(), formLayout);
 		tableEl.setRowCssDelegate(this);
+		
+		FlexiTableSortOptions sortOptions = new FlexiTableSortOptions();
+		sortOptions.setFromColumnModel(false);
+		sortOptions.setSorts(sorts);
+		tableEl.setSortSettings(sortOptions);
 	}
 	
 	@Override
diff --git a/src/main/java/org/olat/modules/fo/ui/IndentCellRenderer.java b/src/main/java/org/olat/modules/fo/ui/IndentCellRenderer.java
index 4578b8f352cc5fefa424ec0eee066d0349c75738..a4bceb094b94d49b522a560258f15c9cf691bc6c 100644
--- a/src/main/java/org/olat/modules/fo/ui/IndentCellRenderer.java
+++ b/src/main/java/org/olat/modules/fo/ui/IndentCellRenderer.java
@@ -43,7 +43,7 @@ public class IndentCellRenderer implements FlexiCellRenderer {
 			FlexiTableComponent source, URLBuilder ubu, Translator translator) {
 		
 		SortKey[] keys = source.getFlexiTableElement().getOrderBy();
-		if(keys != null && keys.length > 0 && keys[0] != null) {
+		if(keys != null && keys.length > 0 && keys[0] != null && !"natural".equals(keys[0].getKey())) {
 			if(cellValue instanceof String) {
 				target.append((String)cellValue);
 			}
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
index 74f853c2f7e19ddedd29fb9945684e0b1b344f38..79edbd2479750f21fc530e7a7c764793cdca6063 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageEditController.java
@@ -370,11 +370,7 @@ public class MessageEditController extends FormBasicController {
 		// set values from form to message
 		message.setTitle(titleEl.getValue());
 		String body = bodyEl.getValue();
-		
-		String tinyBlanc = "<p>&nbsp;";
-		if(body.startsWith(tinyBlanc)) {
-			body = "<p>" + body.substring(tinyBlanc.length(), body.length());
-		}
+		body = body.replace("<p>&nbsp;", "<p>");
 
 		message.setBody(body.trim());
 		if(usePseudonymEl != null && (usePseudonymEl.isAtLeastSelected(1) || guestOnly)) {
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageListController.java b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
index 31d7b4e9e06af2370db6404d8738b8649b8e7225..31f377a30d8e9fea658734c787a04dafbedf8a77 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageListController.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageListController.java
@@ -377,7 +377,7 @@ public class MessageListController extends BasicController implements GenericEve
 
 		MessageView view = new MessageView(message, userPropertyHandlers, getLocale());
 		view.setNumOfChildren(0);
-		addMessageToCurrentMessagesAndVC(ureq, message, view, backupViews.size(), marks, stats, artefactStats, rms);
+		addMessageToCurrentMessagesAndVC(ureq, message, view, marks, stats, artefactStats, rms);
 		return view;
 	}
 	
@@ -432,10 +432,9 @@ public class MessageListController extends BasicController implements GenericEve
 			}
 		}
 		
-		int msgNum = 0;
 		//append ui things
 		for (MessageLight msg: messages) {
-			addMessageToCurrentMessagesAndVC(ureq, msg, keyToViews.get(msg.getKey()), msgNum++, marks, stats, artefactStats, rms);
+			addMessageToCurrentMessagesAndVC(ureq, msg, keyToViews.get(msg.getKey()), marks, stats, artefactStats, rms);
 		}
 		
 		mainVC.contextPut("messages", views);
@@ -473,7 +472,7 @@ public class MessageListController extends BasicController implements GenericEve
 		}
 	}
 	
-	private void addMessageToCurrentMessagesAndVC(UserRequest ureq, MessageLight m, MessageView messageView, int msgCount,
+	private void addMessageToCurrentMessagesAndVC(UserRequest ureq, MessageLight m, MessageView messageView,
 			Map<String,Mark> marks, Map<String,MarkResourceStat> stats, Map<String,Long> artefactStats,
 			Set<Long> readSet) {
 		
@@ -491,17 +490,21 @@ public class MessageListController extends BasicController implements GenericEve
 		// add some data now
 		messageView.setFormattedCreationDate(formatter.formatDateAndTime(m.getCreationDate()));
 		messageView.setFormattedLastModified(formatter.formatDateAndTime(m.getLastModified()));
-		
+
+		Identity creator = m.getCreator();
 		Identity modifier = m.getModifier();
 		if (modifier != null) {
 			messageView.setModified(true);
-			messageView.setModifierFirstName(modifier.getUser().getProperty(UserConstants.FIRSTNAME, getLocale()));
-			messageView.setModifierLastName(modifier.getUser().getProperty(UserConstants.LASTNAME, getLocale()));
+			if(modifier.equals(creator) && StringHelper.containsNonWhitespace(m.getPseudonym())) {
+				messageView.setModifierPseudonym(m.getPseudonym());
+			} else {
+				messageView.setModifierFirstName(modifier.getUser().getProperty(UserConstants.FIRSTNAME, getLocale()));
+				messageView.setModifierLastName(modifier.getUser().getProperty(UserConstants.LASTNAME, getLocale()));
+			}
 		} else {
 			messageView.setModified(false);
 		}
 		
-		Identity creator = m.getCreator();
 		boolean userIsMsgCreator = false;
 		//keeps the first 15 chars
 		if(creator != null) {
@@ -536,52 +539,51 @@ public class MessageListController extends BasicController implements GenericEve
 		}
 		messageView.setClosed(isThreadClosed);
 		
-		if(!guestOnly && !m.isGuest() && !StringHelper.containsNonWhitespace(m.getPseudonym())) {
+		if(!guestOnly && !m.isGuest() && creator != null && !StringHelper.containsNonWhitespace(m.getPseudonym())) {
 			// add portrait to map for later disposal and key for rendering in velocity
-			DisplayPortraitController portrait = new DisplayPortraitController(ureq, getWindowControl(), m.getCreator(), true, true, false, true);
+			DisplayPortraitController portrait = new DisplayPortraitController(ureq, getWindowControl(), creator, true, true, false, true);
 			messageView.setPortrait(portrait);
 			mainVC.put("portrait_".concat(keyString), portrait.getInitialComponent());
 		  
 			// Add link with username that is clickable
 			String creatorFullName = StringHelper.escapeHtml(UserManager.getInstance().getUserDisplayName(creator));
-			Link visitingCardLink = LinkFactory.createCustomLink("vc_"+msgCount, "vc_"+msgCount, creatorFullName, Link.LINK_CUSTOM_CSS + Link.NONTRANSLATED, mainVC, this);
+			Link visitingCardLink = LinkFactory.createCustomLink("vc_".concat(keyString), "vc", creatorFullName, Link.LINK_CUSTOM_CSS + Link.NONTRANSLATED, mainVC, this);
 			visitingCardLink.setUserObject(messageView);
-			
 			LinkPopupSettings settings = new LinkPopupSettings(800, 600, "_blank");
 			visitingCardLink.setPopup(settings);
 		}
 
 		if(!isThreadClosed) {
 			if((numOfChildren == 0 && userIsMsgCreator) || foCallback.mayDeleteMessageAsModerator()) {
-				Link deleteLink = LinkFactory.createCustomLink("dl_"+msgCount, "dl_"+msgCount, "msg.delete", Link.BUTTON_SMALL, mainVC, this);
+				Link deleteLink = LinkFactory.createCustomLink("dl_".concat(keyString), "dl", "msg.delete", Link.BUTTON_SMALL, mainVC, this);
 				deleteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_delete_item");
 				deleteLink.setUserObject(messageView);
 			}
 			
 			if((numOfChildren == 0 && userIsMsgCreator) || foCallback.mayEditMessageAsModerator()) {
-				Link editLink = LinkFactory.createCustomLink("ed_"+msgCount, "ed_"+msgCount, "msg.update", Link.BUTTON_SMALL, mainVC, this);
+				Link editLink = LinkFactory.createCustomLink("ed_".concat(keyString), "ed", "msg.update", Link.BUTTON_SMALL, mainVC, this);
 				editLink.setIconLeftCSS("o_icon o_icon-fw o_icon_edit");
 				editLink.setUserObject(messageView);
 			}
 			
 			if(foCallback.mayReplyMessage()) {
-				Link quoteLink = LinkFactory.createCustomLink("qt_"+msgCount, "qt_"+msgCount, "msg.quote", Link.BUTTON_SMALL, mainVC, this);
+				Link quoteLink = LinkFactory.createCustomLink("qt_".concat(keyString), "qt", "msg.quote", Link.BUTTON_SMALL, mainVC, this);
 				quoteLink.setElementCssClass("o_sel_forum_reply_quoted");
 				quoteLink.setIconLeftCSS("o_icon o_icon-fw o_icon_reply_with_quote");
 				quoteLink.setUserObject(messageView);
 				
-				Link replyLink = LinkFactory.createCustomLink("rp_"+msgCount, "rp_"+msgCount, "msg.reply", Link.BUTTON_SMALL, mainVC, this);
+				Link replyLink = LinkFactory.createCustomLink("rp_".concat(keyString), "rp", "msg.reply", Link.BUTTON_SMALL, mainVC, this);
 				replyLink.setElementCssClass("o_sel_forum_reply");
 				replyLink.setIconLeftCSS("o_icon o_icon-fw o_icon_reply");
 				replyLink.setUserObject(messageView);
 			}
 			
 			if(foCallback.mayEditMessageAsModerator() && !threadTop) {
-				Link splitLink = LinkFactory.createCustomLink("split_"+msgCount, "split_"+msgCount, "msg.split", Link.LINK, mainVC, this);
+				Link splitLink = LinkFactory.createCustomLink("split_".concat(keyString), "split", "msg.split", Link.LINK, mainVC, this);
 				splitLink.setIconLeftCSS("o_icon o_icon-fw o_icon_split");
 				splitLink.setUserObject(messageView);
 				
-				Link moveLink = LinkFactory.createCustomLink("move_"+msgCount, "move_"+msgCount, "msg.move", Link.LINK, mainVC, this);
+				Link moveLink = LinkFactory.createCustomLink("move_".concat(keyString), "move", "msg.move", Link.LINK, mainVC, this);
 				moveLink.setIconLeftCSS("o_icon o_icon-fw o_icon_move");
 				moveLink.setUserObject(messageView);
 			}
@@ -594,7 +596,7 @@ public class MessageListController extends BasicController implements GenericEve
 					getWindowControl().getBusinessControl().getAsString() + "[Message:" + m.getKey() + "]"
 					: currentMark.getBusinessPath();
 			Controller markCtrl = markingService.getMarkController(ureq, getWindowControl(), currentMark, stat, forumOres, keyString, businessPath);
-			mainVC.put("mark_" + msgCount, markCtrl.getInitialComponent());
+			mainVC.put("mark_".concat(keyString), markCtrl.getInitialComponent());
 		}
 		
 		if(userIsMsgCreator && !StringHelper.containsNonWhitespace(m.getPseudonym())) {
@@ -658,22 +660,22 @@ public class MessageListController extends BasicController implements GenericEve
 			String command = link.getCommand();
 			Object uobject = link.getUserObject();
 
-			if (command.startsWith("qt_")) {
+			if (command.startsWith("qt")) {
 				doReply(ureq, (MessageView)uobject, true);
-			} else if (command.startsWith("rp_")) {
+			} else if (command.startsWith("rp")) {
 				doReply(ureq, (MessageView)uobject, false);
-			} else if (command.startsWith("dl_")) {
+			} else if (command.startsWith("dl")) {
 				doConfirmDeleteMessage(ureq, (MessageView)uobject);
-			} else if (command.startsWith("ed_")) {
+			} else if (command.startsWith("ed")) {
 				doEditMessage(ureq, (MessageView)uobject);
-			}	else if (command.startsWith("split_")) {
+			}	else if (command.startsWith("split")) {
 				doConfirmSplit(ureq, (MessageView)uobject);
-			} else if (command.startsWith("move_")) {
+			} else if (command.startsWith("move")) {
 				doMoveMessage(ureq, (MessageView)uobject);
 			}
 		} else if(mainVC == source) {
 			String cmd = event.getCommand();
-			if (cmd.startsWith("attachment_")) {
+			if (cmd.startsWith("attachment")) {
 				doDeliverAttachment(ureq, cmd);
 			}
 		}
@@ -1148,6 +1150,7 @@ public class MessageListController extends BasicController implements GenericEve
 			Message parentMessage = forumManager.getMessageById(parentMessageKey);
 			message = forumManager.moveMessage(message, parentMessage);
 			markRead(message);
+			DBFactory.getInstance().commit();//commit before sending event
 			
 			ThreadLocalUserActivityLogger.log(ForumLoggingAction.FORUM_MESSAGE_MOVE, getClass(), LoggingResourceable.wrap(message));
 			Long threadKey = parentMessage.getThreadtop() == null ? parentMessage.getKey() : parentMessage.getThreadtop().getKey();
diff --git a/src/main/java/org/olat/modules/fo/ui/MessageView.java b/src/main/java/org/olat/modules/fo/ui/MessageView.java
index 1c2ee21dcc7f220fb858ac7ff2963319a7191a15..55d307d386996a8aac7135b65498f98d50f8e9c6 100644
--- a/src/main/java/org/olat/modules/fo/ui/MessageView.java
+++ b/src/main/java/org/olat/modules/fo/ui/MessageView.java
@@ -45,6 +45,7 @@ public class MessageView extends MessageLightView {
 	private boolean modified;
 	private String modifierFirstName;
 	private String modifierLastName;
+	private String modifierPseudonym;
 	
 	private String creatorFirstname;
 	private String creatorLastname;
@@ -152,6 +153,14 @@ public class MessageView extends MessageLightView {
 		this.modifierLastName = modifierLastName;
 	}
 
+	public String getModifierPseudonym() {
+		return modifierPseudonym;
+	}
+
+	public void setModifierPseudonym(String modifierPseudonym) {
+		this.modifierPseudonym = modifierPseudonym;
+	}
+
 	public boolean isAuthor() {
 		return author;
 	}
diff --git a/src/main/java/org/olat/modules/fo/ui/StatusTypeCellRenderer.java b/src/main/java/org/olat/modules/fo/ui/StatusTypeCellRenderer.java
index a64d6e8f1c056d1822e9b5b9c52e9f17bd9d51c4..972a40f153714038b1e831f03b870137524033b4 100644
--- a/src/main/java/org/olat/modules/fo/ui/StatusTypeCellRenderer.java
+++ b/src/main/java/org/olat/modules/fo/ui/StatusTypeCellRenderer.java
@@ -43,17 +43,18 @@ public class StatusTypeCellRenderer implements FlexiCellRenderer {
 			int status = ((Number)cellValue).intValue();
 			
 			Status messageStatus = Status.getStatus(status);
-			boolean isSticky = messageStatus.isSticky(); 
-			boolean isClosed = messageStatus.isClosed(); 
+			boolean isSticky = messageStatus.isSticky();
+			boolean isClosed = messageStatus.isClosed();
 
 			target.append("<i class='o_icon o_forum_");
-
 			if(isSticky && isClosed) {
 				target.append("status_sticky_closed");
-			} else if (isSticky) {
+			} else if(isSticky) {
 				target.append("status_sticky");
-			} else if (isClosed) {
+			} else if(isClosed) {
 				target.append("status_closed");
+			} else if(messageStatus.isHidden()) {
+				target.append("status_hidden");
 			} else {
 				target.append("status_thread");
 			}
diff --git a/src/main/java/org/olat/modules/fo/ui/ThreadListController.java b/src/main/java/org/olat/modules/fo/ui/ThreadListController.java
index 2c8b95211ba71ce73187769ef11ed87e479dffa1..1d0575a6a57228ddb6424ac4271e921518bf0de0 100644
--- a/src/main/java/org/olat/modules/fo/ui/ThreadListController.java
+++ b/src/main/java/org/olat/modules/fo/ui/ThreadListController.java
@@ -19,6 +19,7 @@
  */
 package org.olat.modules.fo.ui;
 
+import java.util.Iterator;
 import java.util.List;
 
 import org.olat.basesecurity.BaseSecurityModule;
@@ -52,6 +53,7 @@ import org.olat.modules.fo.Forum;
 import org.olat.modules.fo.ForumCallback;
 import org.olat.modules.fo.Message;
 import org.olat.modules.fo.MessageRef;
+import org.olat.modules.fo.Status;
 import org.olat.modules.fo.archiver.formatters.ForumDownloadResource;
 import org.olat.modules.fo.manager.ForumManager;
 import org.olat.modules.fo.model.ForumThread;
@@ -153,6 +155,14 @@ public class ThreadListController extends FormBasicController {
 	public void loadModel() {
 		Identity identity = guestOnly ? null : getIdentity();
 		List<ForumThread> threads = forumManager.getForumThreads(forum, identity);
+		if(!foCallback.mayEditMessageAsModerator()) {
+			for(Iterator<ForumThread> threadIt=threads.iterator(); threadIt.hasNext(); ) {
+				if(Status.getStatus(threadIt.next().getStatusCode()).isHidden()) {
+					threadIt.remove();
+				}
+			}	
+		}
+		
 		threadTableModel.setObjects(threads);
 		threadTableModel.sort(new SortKey(ThreadListCols.thread.name(), true));
 		threadTable.reloadData();
diff --git a/src/main/java/org/olat/modules/fo/ui/_content/threadview.html b/src/main/java/org/olat/modules/fo/ui/_content/threadview.html
index 8a2a270fe74a0791f5ccfc215a2dfc2b57449a8a..4e3246fb2f519b66b8b8cb993184a2db4d96e380 100644
--- a/src/main/java/org/olat/modules/fo/ui/_content/threadview.html
+++ b/src/main/java/org/olat/modules/fo/ui/_content/threadview.html
@@ -65,14 +65,13 @@
 	#end
 	
 #foreach ($message in $messages)
-	#set( $count = $velocityCount - 1)
 	<div #if($threadMode) style="margin-left: ${message.depth}em" #end class="o_forum_message o_block_large_bottom #if($message.newMessage) o_forum_message_new #end #if($message.key == $goToMessageId) o_forum_message_highlight #end" id="o_forum_message_${message.key}">
 		<div class="o_forum_message_header clearfix">
 			#if($r.available("eportfolio_${message.key}"))
 				<div class="o_ep_collect">$r.render("eportfolio_${message.key}")</div>
 			#end
-			#if($r.available("mark_${count}"))
-				<div class="o_mark">$r.render("mark_${count}")</div>
+			#if($r.available("mark_${message.key}"))
+				<div class="o_mark">$r.render("mark_${message.key}")</div>
 			#end
 			#if(!$guestOnly)
 				#if($message.guest || ($message.pseudonym && !${message.pseudonym.isEmpty()}))
@@ -93,8 +92,8 @@
 					$r.escapeHtml($message.pseudonym)
 				#elseif($message.guest)
 					$r.translate("anonymous.poster")
-				#elseif($r.available("vc_${count}"))
-					$r.render("vc_${count}")
+				#elseif($r.available("vc_${message.key}"))
+					$r.render("vc_${message.key}")
 				#else							
 					$r.escapeHtml($message.creatorFirstname) $r.escapeHtml($message.creatorLastname)
 				#end
@@ -106,7 +105,13 @@
 			#if($message.modified || $message.moved)
 			<div class="o_modified">
 				#if($message.modified)
-		   			$r.translate("msg.modified"): $r.escapeHtml($message.modifierFirstName) $r.escapeHtml($message.modifierLastName) $message.formattedLastModified
+					$r.translate("msg.modified"):
+					#if($message.modifierPseudonym && !${message.modifierPseudonym.isEmpty()})
+						$r.escapeHtml($message.modifierPseudonym)
+					#else
+		   				$r.escapeHtml($message.modifierFirstName) $r.escapeHtml($message.modifierLastName)
+		   			#end
+		   			$message.formattedLastModified
 		   		#end
 		   		#if($message.moved)
 		   			$r.translate("msg.moved")
@@ -120,34 +125,34 @@
 		</div>
 
 		<div class="o_forum_message_actions o_button_group">
-			#if($r.available("open_in_thread_${count}"))
-				$r.render("open_in_thread_${count}")
+			#if($r.available("open_in_thread_${message.key}"))
+				$r.render("open_in_thread_${message.key}")
 			#end
 
-			#if ($r.available("dl_${count}") || $r.available("ed_${count}"))
+			#if ($r.available("dl_${message.key}") || $r.available("ed_${message.key}"))
 			<div class="btn-group">
-				#if($r.available("dl_${count}"))
-					$r.render("dl_${count}")
+				#if($r.available("dl_${message.key}"))
+					$r.render("dl_${message.key}")
 				#end
-				#if ($r.available("ed_${count}"))
-					$r.render("ed_${count}")
+				#if ($r.available("ed_${message.key}"))
+					$r.render("ed_${message.key}")
 				#end
 			</div>
 			#end
 			
-			#if ($r.available("rp_${count}"))
-			<div class="btn-group">$r.render("qt_${count}") $r.render("rp_${count}")</div>
+			#if ($r.available("rp_${message.key}"))
+			<div class="btn-group">$r.render("qt_${message.key}") $r.render("rp_${message.key}")</div>
 			#end
 			
-			#if($r.available("split_${count}"))
+			#if($r.available("split_${message.key}"))
 			<div class="btn-group">
 				<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
 					<i class="o_icon o_icon-fw o_icon_actions"></i>
 					<span class="caret"></span>
 				</button>
 				<ul class="dropdown-menu dropdown-menu-right">
-					<li>$r.render("split_${count}")</li>
-					<li>$r.render("move_${count}")</li>
+					<li>$r.render("split_${message.key}")</li>
+					<li>$r.render("move_${message.key}")</li>
 				</ul>
 			</div>
 			#end
diff --git a/src/main/java/org/olat/repository/ui/author/AuthorListController.java b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
index 0410c3efdc20f08cf2089e5d02b088138ab0150d..43f3afe425478ed40cad1701389358430ba07d5a 100644
--- a/src/main/java/org/olat/repository/ui/author/AuthorListController.java
+++ b/src/main/java/org/olat/repository/ui/author/AuthorListController.java
@@ -557,13 +557,19 @@ public class AuthorListController extends FormBasicController implements Activat
 		removeAsListenerAndDispose(toolsCtrl);
 		removeAsListenerAndDispose(toolsCalloutCtrl);
 
-		toolsCtrl = new ToolsController(ureq, getWindowControl(), row);
-		listenTo(toolsCtrl);
-
-		toolsCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),
-				toolsCtrl.getInitialComponent(), link.getFormDispatchId(), "", true, "");
-		listenTo(toolsCalloutCtrl);
-		toolsCalloutCtrl.activate();
+		RepositoryEntry entry = repositoryService.loadByKey(row.getKey());
+		if(entry == null) {
+			tableEl.reloadData();
+			showWarning("repositoryentry.not.existing");
+		} else {
+			toolsCtrl = new ToolsController(ureq, getWindowControl(), row, entry);
+			listenTo(toolsCtrl);
+	
+			toolsCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),
+					toolsCtrl.getInitialComponent(), link.getFormDispatchId(), "", true, "");
+			listenTo(toolsCalloutCtrl);
+			toolsCalloutCtrl.activate();
+		}
 	}
 	
 	private void doImport(UserRequest ureq) {
@@ -916,19 +922,18 @@ public class AuthorListController extends FormBasicController implements Activat
 	private class ToolsController extends BasicController {
 		
 		private final AuthoringEntryRow row;
-		private final RepositoryEntry entry;
+
 		private final VelocityContainer mainVC;
 		
 		private boolean isOwner;
 		private boolean isOlatAdmin;
 		private boolean isAuthor;
 		
-		public ToolsController(UserRequest ureq, WindowControl wControl, AuthoringEntryRow row) {
+		public ToolsController(UserRequest ureq, WindowControl wControl, AuthoringEntryRow row, RepositoryEntry entry) {
 			super(ureq, wControl);
 			setTranslator(AuthorListController.this.getTranslator());
 			this.row = row;
-			this.entry = repositoryService.loadByKey(row.getKey());
-
+			
 			Identity identity = getIdentity();
 			Roles roles = ureq.getUserSession().getRoles();
 			isOlatAdmin = roles.isOLATAdmin();
diff --git a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties
index 97a6907acda80945c3400e2ff36f595a9892aedc..5e0cb75ccb1e4385d7bdce0e564461de6e9124d3 100644
--- a/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/shibboleth/_i18n/LocalStrings_fr.properties
@@ -1,8 +1,14 @@
-#Sun Nov 08 13:11:57 CET 2015
+#Sun Nov 29 17:24:38 CET 2015
+admin.ac.attribute=Activ\u00E9 le contr\u00F4le d'acc\u00E8s par attribut
 admin.ac.attribute.1=Attribut Shibboleth 1
 admin.ac.attribute.2=Attribut Shibboleth 2
+admin.ac.url=Lien direct pour l'acc\u00E8s SSO
+admin.ac.value.1=Valeur permise pour l'attribut 1
+admin.ac.value.2=Valeur permise pour l'attribut 2
+admin.description=La configuration de base de Shibboleth doit \u00EAtre faite dans le fichier de configuration OpenOLAT. En utilisant le formulaire ci-dessous, vous pouvez activer l'acc\u00E8s des utilisateurs bas\u00E9 sur leurs attributs Shibboleth. Un maximum de deux attributs avec chacun leurs propres valeurs permises peut \u00EAtre configur\u00E9. Une personne est consid\u00E9r\u00E9e comme autoris\u00E9e si 1) la personne peut \u00EAtre authentifier avec succ\u00E8s par l'IDP et 2) l'une des valeurs des deux attributs sp\u00E9cifi\u00E9s dans la liste correspond \u00E0 celles de l'utilisateur.
 admin.menu.shibboleth=Shibboleth
 admin.menu.shibboleth.desc=Configuration du module Shibboleth
+admin.title=Autorisation Shibboleth
 authentication.provider.description=\u00CAtes-vous membre d'une institution qui utilise Shibboleth pour l'authentification?
 authentication.provider.linkText=Se connecter avec un compte Shibboleth
 eduPersonAffiliation=Affiliation
@@ -18,6 +24,7 @@ employeeNumber=Num\u00E9ro personnel
 error.insufficieant.attributes=Attributs Shibboleth n\u00E9cessaires\:Shib-SwissEP-UniqueID, Shib-InetOrgPerson-givenName, Shib-Person-surname, Shib-InetOrgPerson-mail, Shib-SwissEP-HomeOrganization
 error.shibboleth.generic=Erreur Shibboleth. Reconnectez-vous, s.v.p.\!
 error.shibboleth.head=OLAT - Online Learning And Training - Error
+error.shibboleth.not.authorized=Vous n'\u00EAtes pas autoris\u00E9 \u00E0 vous connecter \u00E0 OpenOLAT.
 error.unqueid.notfound=Avez-vous un droit d'acc\u00E8s \u00E0 OLAT? Si oui, veuillez r\u00E9essayer de vous connecter, s.v.p..
 givenName=Nom de famille
 idp.support.email=Veuillez vous adresser \u00E0 votre soutien IdP\:
diff --git a/src/test/java/org/olat/modules/fo/ForumManagerTest.java b/src/test/java/org/olat/modules/fo/ForumManagerTest.java
index 302935dc930c88dfa9700757f10a09f4f4eeb0d7..1d9a09babb2ffa041d87b84d1ebf27eac43ad17c 100644
--- a/src/test/java/org/olat/modules/fo/ForumManagerTest.java
+++ b/src/test/java/org/olat/modules/fo/ForumManagerTest.java
@@ -30,6 +30,7 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 import java.util.UUID;
 
 import org.junit.Assert;
@@ -40,6 +41,7 @@ import org.olat.core.id.Identity;
 import org.olat.modules.fo.manager.ForumManager;
 import org.olat.modules.fo.model.ForumThread;
 import org.olat.modules.fo.model.ForumUserStatistics;
+import org.olat.modules.fo.ui.MessagePeekview;
 import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.olat.user.UserManager;
@@ -442,6 +444,182 @@ public class ForumManagerTest extends OlatTestCase {
 		Assert.assertEquals(thread1.getKey(), messageUnderPseudo.getThreadtop().getKey());
 	}
 	
+	@Test
+	public void getMessageById() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Forum forum = forumManager.addAForum();
+		dbInstance.commit();
+		
+		Message message = forumManager.createMessage(forum, id, false);
+		message.setTitle("Get message by id");
+		message.setBody("Get message by id");
+		forumManager.addTopMessage(message);
+		dbInstance.commit();
+		
+		//load the message by id
+		Message loadedMessage = forumManager.getMessageById(message.getKey());
+		dbInstance.commitAndCloseSession();
+		
+		Assert.assertNotNull(loadedMessage);
+		Assert.assertEquals(message.getKey(), loadedMessage.getKey());
+		Assert.assertEquals(message.getTitle(), loadedMessage.getTitle());
+		Assert.assertEquals(message.getBody(), loadedMessage.getBody());
+		Assert.assertNotNull(loadedMessage.getCreator());
+		Assert.assertEquals(id, loadedMessage.getCreator());
+		Assert.assertFalse(loadedMessage.isGuest());
+		Assert.assertNull(loadedMessage.getThreadtop());
+	}
+	
+	@Test
+	public void getPeekviewMessages() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Identity id2 =  JunitTestHelper.createAndPersistIdentityAsRndUser("fo-2");
+		Forum forum = forumManager.addAForum();
+		dbInstance.commit();
+		
+		Message thread1 = forumManager.createMessage(forum, id1, false);
+		thread1.setTitle("Get peekview messages");
+		thread1.setBody("Get peekview messages");
+		forumManager.addTopMessage(thread1);
+		dbInstance.commit();
+		
+		Message reply = forumManager.createMessage(forum, id2, false);
+		reply.setTitle("Re: Get peekview messages");
+		reply.setBody("Get peekview messages");
+		forumManager.replyToMessage(reply, thread1);
+		dbInstance.commitAndCloseSession();
+		
+		Message replyPseudo = forumManager.createMessage(forum, id2, false);
+		replyPseudo.setTitle("Re: Get peekview messages with pseudo");
+		replyPseudo.setBody("Get peekview messages and other usefull stuff we need");
+		String pseudo = "Id pseudo " + UUID.randomUUID();
+		replyPseudo.setPseudonym(pseudo);
+		forumManager.replyToMessage(replyPseudo, thread1);
+		dbInstance.commitAndCloseSession();
+		
+		//load the peekview
+		List<MessagePeekview> peekViews = forumManager.getPeekviewMessages(forum, 2);
+		Assert.assertNotNull(peekViews);
+		Assert.assertEquals(2, peekViews.size());
+		
+		int found = 0;
+		for(MessagePeekview peekView:peekViews) {
+			if(peekView.getKey().equals(thread1.getKey())
+					|| peekView.getKey().equals(reply.getKey())
+					|| peekView.getKey().equals(replyPseudo.getKey())) {
+				found++;
+			}
+		}
+		Assert.assertEquals(2, found);
+	}
+	
+	@Test
+	public void getPseudonym() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Identity id2 =  JunitTestHelper.createAndPersistIdentityAsRndUser("fo-2");
+		Forum forum = forumManager.addAForum();
+		dbInstance.commit();
+		
+		Message thread1 = forumManager.createMessage(forum, id1, false);
+		thread1.setTitle("Get pseudonym");
+		thread1.setBody("Get pseudonym");
+		forumManager.addTopMessage(thread1);
+		dbInstance.commit();
+	
+		Message replyPseudo = forumManager.createMessage(forum, id2, false);
+		replyPseudo.setTitle("Re: Get pseudonym");
+		replyPseudo.setBody("Get pseudonym in forum and other usefull stuff we need");
+		String pseudo = "Id pseudo " + UUID.randomUUID();
+		replyPseudo.setPseudonym(pseudo);
+		forumManager.replyToMessage(replyPseudo, thread1);
+		dbInstance.commitAndCloseSession();
+		
+		// get pseudonym of id 2
+		String alias2 = forumManager.getPseudonym(forum, id2);
+		Assert.assertEquals(pseudo, alias2);
+		
+		// get pseudonym of id 1
+		String alias1 = forumManager.getPseudonym(forum, id1);
+		Assert.assertNull(alias1);
+	}
+	
+	@Test
+	public void readMessages() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-2");
+		Forum forum = forumManager.addAForum();
+		dbInstance.commit();
+		
+		Message thread1 = forumManager.createMessage(forum, id1, false);
+		thread1.setTitle("Read messages workflow");
+		thread1.setBody("Read messages workflow");
+		forumManager.addTopMessage(thread1);
+		dbInstance.commit();
+	
+		Message replyPseudo = forumManager.createMessage(forum, id1, false);
+		replyPseudo.setTitle("Re: Read messages workflow");
+		replyPseudo.setBody("Read messages workflow and other usefull stuff we need");
+		String pseudo = "Id pseudo " + UUID.randomUUID();
+		replyPseudo.setPseudonym(pseudo);
+		forumManager.replyToMessage(replyPseudo, thread1);
+		dbInstance.commitAndCloseSession();
+
+		Message reply = forumManager.createMessage(forum, id2, false);
+		reply.setTitle("Re: Read messages workflow");
+		reply.setBody("Read messages workflow and other usefull stuff we need");
+		forumManager.replyToMessage(reply, thread1);
+		dbInstance.commitAndCloseSession();
+		
+		//mark thread1 as read
+		forumManager.markAsRead(id1, forum, thread1);
+		dbInstance.commitAndCloseSession();
+		
+		//load read set and check for id1
+		Set<Long> readSet = forumManager.getReadSet(id1, forum);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(readSet);
+		Assert.assertEquals(1, readSet.size());
+		Assert.assertTrue(readSet.contains(thread1.getKey()));
+		
+		//mark thread1 as read
+		forumManager.markAsRead(id2, forum, reply);
+		forumManager.markAsRead(id2, forum, replyPseudo);
+		dbInstance.commitAndCloseSession();
+		
+		//load read set and check for id2
+		Set<Long> readSet2 = forumManager.getReadSet(id2, forum);
+		dbInstance.commitAndCloseSession();
+		Assert.assertNotNull(readSet2);
+		Assert.assertEquals(2, readSet2.size());
+		Assert.assertTrue(readSet2.contains(reply.getKey()));
+		Assert.assertTrue(readSet2.contains(replyPseudo.getKey()));
+	}
+	
+	@Test
+	public void updateMessage() {
+		Identity id = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Forum fo = forumManager.addAForum();
+		dbInstance.commit();
+
+		Message topMessage = forumManager.createMessage(fo, id, false);
+		topMessage.setTitle("Message counter");
+		topMessage.setBody("Message counter");
+		forumManager.addTopMessage(topMessage);
+		dbInstance.commit();
+		
+		//update message
+		topMessage.setBody("Message counter and other stuff");
+		Message updatedMessage = forumManager.updateMessage(topMessage, true);
+		Assert.assertNotNull(updatedMessage);
+		Assert.assertEquals(topMessage.getKey(), updatedMessage.getKey());
+		Assert.assertEquals("Message counter", updatedMessage.getTitle());
+		Assert.assertEquals("Message counter and other stuff", updatedMessage.getBody());
+		Assert.assertNotNull(updatedMessage.getNumOfCharacters());
+		Assert.assertEquals(27, updatedMessage.getNumOfCharacters().intValue());
+		Assert.assertNotNull(updatedMessage.getNumOfWords());
+		Assert.assertEquals(5, updatedMessage.getNumOfWords().intValue());
+	}
+	
 	@Test
 	public void countMessagesByForumID() {
 		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
@@ -533,6 +711,261 @@ public class ForumManagerTest extends OlatTestCase {
 		Assert.assertEquals(2, olderLastMessages.size());
 	}
 	
+	@Test
+	public void moveMessage() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-2");
+		Identity guest3 =  securityManager.getAndUpdateAnonymousUserForLanguage(Locale.ENGLISH);
+		Forum fo = forumManager.addAForum();
+		dbInstance.commit();
+		
+		// thread
+		// -> message
+		// -> -> message to move
+		// -> -> -> message child 1
+		// -> -> -> -> message child 1.1
+		// -> -> -> message child 2
+		// -> -> message staying
+
+		Message topMessage = forumManager.createMessage(fo, id1, false);
+		topMessage.setTitle("Thread move message");
+		topMessage.setBody("Thread move message");
+		forumManager.addTopMessage(topMessage);
+		dbInstance.commit();
+
+		Message message = forumManager.createMessage(fo, id2, false);
+		message.setTitle("Re: Thread move message");
+		message.setBody("Thread move message");
+		forumManager.replyToMessage(message, topMessage);
+		dbInstance.commit();
+		
+		Message messageToMove = forumManager.createMessage(fo, id2, false);
+		messageToMove.setTitle("Message to move");
+		messageToMove.setBody("Thread move message");
+		forumManager.replyToMessage(messageToMove, message);
+		dbInstance.commit();
+		
+		Message messageToMove_1 = forumManager.createMessage(fo, id2, false);
+		messageToMove_1.setTitle("Re: Message to move 1");
+		messageToMove_1.setBody("Thread move message");
+		forumManager.replyToMessage(messageToMove_1, messageToMove);
+		dbInstance.commit();
+		
+		Message messageToMove_1_1 = forumManager.createMessage(fo, guest3, true);
+		messageToMove_1_1.setTitle("Re: Message to move 1");
+		messageToMove_1_1.setBody("Thread move message");
+		forumManager.replyToMessage(messageToMove_1_1, messageToMove_1);
+		dbInstance.commit();
+		
+		Message messageToMove_2 = forumManager.createMessage(fo, id2, false);
+		messageToMove_2.setTitle("Re: Message to move 2");
+		messageToMove_2.setBody("Thread move message");
+		forumManager.replyToMessage(messageToMove_2, messageToMove);
+		dbInstance.commit();
+		
+		Message messageToStay = forumManager.createMessage(fo, id2, false);
+		messageToStay.setTitle("Message to stay");
+		messageToStay.setBody("Thread move message");
+		forumManager.replyToMessage(messageToStay, message);
+		dbInstance.commit();
+			
+		Message targetThread = forumManager.createMessage(fo, id2, false);
+		targetThread.setTitle("Target thread");
+		targetThread.setBody("Target thread");
+		forumManager.addTopMessage(targetThread);
+		dbInstance.commit();
+		
+		Message targetMessage = forumManager.createMessage(fo, id2, false);
+		targetMessage.setTitle("Message to stay");
+		targetMessage.setBody("Thread move message");
+		forumManager.replyToMessage(targetMessage, targetThread);
+		dbInstance.commit();
+		
+		//move the message
+		Message movedMessage = forumManager.moveMessage(messageToMove, targetMessage);
+		dbInstance.commitAndCloseSession();
+		
+		//check target thread
+		List<Message> targetMessages = forumManager.getThread(targetThread.getKey());
+		Assert.assertEquals(3, targetMessages.size());
+		Assert.assertTrue(targetMessages.contains(targetThread));
+		Assert.assertTrue(targetMessages.contains(targetMessage));
+		Assert.assertTrue(targetMessages.contains(movedMessage));
+		
+		//check thread and parent of the target thread
+		Message reloadedTargetThread = forumManager.getMessageById(targetThread.getKey());
+		Assert.assertNull(reloadedTargetThread.getThreadtop());
+		Assert.assertNull(reloadedTargetThread.getParent());
+
+		Message reloadedTargetMessage = forumManager.getMessageById(targetMessage.getKey());
+		Assert.assertEquals(targetThread, reloadedTargetMessage.getThreadtop());
+		Assert.assertEquals(targetThread, reloadedTargetMessage.getParent());
+
+		Message reloadedMovedMessage = forumManager.getMessageById(movedMessage.getKey());
+		Assert.assertEquals(targetThread, reloadedMovedMessage.getThreadtop());
+		Assert.assertEquals(targetMessage, reloadedMovedMessage.getParent());
+		
+		//check original thread
+		List<Message> originMessages = forumManager.getThread(topMessage.getKey());
+		Assert.assertEquals(6, originMessages.size());
+		Assert.assertTrue(originMessages.contains(topMessage));
+		Assert.assertTrue(originMessages.contains(message));
+		Assert.assertTrue(originMessages.contains(messageToStay));
+		Assert.assertTrue(originMessages.contains(messageToMove_1));
+		Assert.assertTrue(originMessages.contains(messageToMove_1_1));
+		Assert.assertTrue(originMessages.contains(messageToMove_2));
+		Assert.assertFalse(originMessages.contains(movedMessage));
+		Assert.assertFalse(originMessages.contains(messageToMove));
+		
+		// thread
+		// -> message
+		// -> -> message child 1
+		// -> -> -> message child 1.1
+		// -> -> message child 2
+		// -> -> message staying
+		
+		//check thread and parent of the target thread
+		Message reloadedTopMessage = forumManager.getMessageById(topMessage.getKey());
+		Assert.assertNull(reloadedTopMessage.getThreadtop());
+		Assert.assertNull(reloadedTopMessage.getParent());
+		
+		Message reloadedMessage = forumManager.getMessageById(message.getKey());
+		Assert.assertEquals(topMessage, reloadedMessage.getThreadtop());
+		Assert.assertEquals(topMessage, reloadedMessage.getParent());
+
+		Message reloadedMessageToMove_1 = forumManager.getMessageById(messageToMove_1.getKey());
+		Assert.assertEquals(topMessage, reloadedMessageToMove_1.getThreadtop());
+		Assert.assertEquals(message, reloadedMessageToMove_1.getParent());
+		
+		Message reloadedMessageToMove_1_1 = forumManager.getMessageById(messageToMove_1_1.getKey());
+		Assert.assertEquals(topMessage, reloadedMessageToMove_1_1.getThreadtop());
+		Assert.assertEquals(messageToMove_1, reloadedMessageToMove_1_1.getParent());
+		
+		Message reloadedMessageToMove_2 = forumManager.getMessageById(messageToMove_1.getKey());
+		Assert.assertEquals(topMessage, reloadedMessageToMove_2.getThreadtop());
+		Assert.assertEquals(message, reloadedMessageToMove_2.getParent());
+		
+		Message reloadedMessageToStay = forumManager.getMessageById(messageToStay.getKey());
+		Assert.assertEquals(topMessage, reloadedMessageToStay.getThreadtop());
+		Assert.assertEquals(message, reloadedMessageToStay.getParent());
+	}
+	
+	@Test
+	public void splitMessage() {
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-1");
+		Identity id2 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-2");
+		Identity guest3 =  securityManager.getAndUpdateAnonymousUserForLanguage(Locale.ENGLISH);
+		Forum fo = forumManager.addAForum();
+		dbInstance.commit();
+		
+		// thread
+		// -> message
+		// -> -> message to split
+		// -> -> -> message child 1
+		// -> -> -> -> message child 1.1
+		// -> -> -> message child 2
+		// -> -> message staying
+
+		Message topMessage = forumManager.createMessage(fo, id1, false);
+		topMessage.setTitle("Thread split message");
+		topMessage.setBody("Thread split message");
+		forumManager.addTopMessage(topMessage);
+		dbInstance.commit();
+
+		Message message = forumManager.createMessage(fo, id2, false);
+		message.setTitle("Re: Thread split message");
+		message.setBody("Thread split message");
+		forumManager.replyToMessage(message, topMessage);
+		dbInstance.commit();
+		
+		Message messageToSplit = forumManager.createMessage(fo, id2, false);
+		messageToSplit.setTitle("Message to split");
+		messageToSplit.setBody("Thread split message");
+		forumManager.replyToMessage(messageToSplit, message);
+		dbInstance.commit();
+		
+		Message messageToSplit_1 = forumManager.createMessage(fo, id2, false);
+		messageToSplit_1.setTitle("Re: Message to split 1");
+		messageToSplit_1.setBody("Thread split message");
+		forumManager.replyToMessage(messageToSplit_1, messageToSplit);
+		dbInstance.commit();
+		
+		Message messageToSplit_1_1 = forumManager.createMessage(fo, guest3, true);
+		messageToSplit_1_1.setTitle("Re: Re: Message to split 1");
+		messageToSplit_1_1.setBody("Thread split message");
+		forumManager.replyToMessage(messageToSplit_1_1, messageToSplit_1);
+		dbInstance.commit();
+		
+		Message messageToSplit_2 = forumManager.createMessage(fo, id2, false);
+		messageToSplit_2.setTitle("Re: Message to split 2");
+		messageToSplit_2.setBody("Thread split message");
+		forumManager.replyToMessage(messageToSplit_2, messageToSplit);
+		dbInstance.commit();
+		
+		Message messageToStay = forumManager.createMessage(fo, id2, false);
+		messageToStay.setTitle("Message to stay");
+		messageToStay.setBody("Thread split message");
+		forumManager.replyToMessage(messageToStay, message);
+		dbInstance.commit();
+		
+		//move the message
+		Message splitedMessage = forumManager.splitThread(messageToSplit);
+		dbInstance.commitAndCloseSession();
+		
+		//check the original thread
+		// thread
+		// -> message
+		// -> -> message staying
+		List<Message> originalMessages = forumManager.getThread(topMessage.getKey());
+		Assert.assertEquals(3, originalMessages.size());
+		Assert.assertTrue(originalMessages.contains(topMessage));
+		Assert.assertTrue(originalMessages.contains(message));
+		Assert.assertTrue(originalMessages.contains(messageToStay));
+		
+		//check thread and parent of the target thread
+		Message reloadedTopMessage = forumManager.getMessageById(topMessage.getKey());
+		Assert.assertNull(reloadedTopMessage.getThreadtop());
+		Assert.assertNull(reloadedTopMessage.getParent());
+
+		Message reloadedMessage = forumManager.getMessageById(message.getKey());
+		Assert.assertEquals(topMessage, reloadedMessage.getThreadtop());
+		Assert.assertEquals(topMessage, reloadedMessage.getParent());
+
+		Message reloadedMessageToStay = forumManager.getMessageById(messageToStay.getKey());
+		Assert.assertEquals(topMessage, reloadedMessageToStay.getThreadtop());
+		Assert.assertEquals(message, reloadedMessageToStay.getParent());
+		
+		//check original thread
+		// message to split
+		// -> message child 1
+		// -> -> message child 1.1
+		// -> message child 2
+		List<Message> splitedMessages = forumManager.getThread(splitedMessage.getKey());
+		Assert.assertEquals(4, splitedMessages.size());
+		Assert.assertTrue(splitedMessages.contains(splitedMessage));
+		Assert.assertTrue(splitedMessages.contains(messageToSplit_1));
+		Assert.assertTrue(splitedMessages.contains(messageToSplit_1_1));
+		Assert.assertTrue(splitedMessages.contains(messageToSplit_2));
+
+		//check thread and parent of the splited thread
+		
+		Message reloadedmessageToSplit = forumManager.getMessageById(messageToSplit.getKey());
+		Assert.assertNull(reloadedmessageToSplit.getThreadtop());
+		Assert.assertNull(reloadedmessageToSplit.getParent());
+
+		Message reloadedMessageToSplit_1 = forumManager.getMessageById(messageToSplit_1.getKey());
+		Assert.assertEquals(messageToSplit, reloadedMessageToSplit_1.getThreadtop());
+		Assert.assertEquals(messageToSplit, reloadedMessageToSplit_1.getParent());
+		
+		Message reloadedMessageToSplit_1_1 = forumManager.getMessageById(messageToSplit_1_1.getKey());
+		Assert.assertEquals(messageToSplit, reloadedMessageToSplit_1_1.getThreadtop());
+		Assert.assertEquals(messageToSplit_1, reloadedMessageToSplit_1_1.getParent());
+		
+		Message reloadedMessageToSplit_2 = forumManager.getMessageById(messageToSplit_1.getKey());
+		Assert.assertEquals(messageToSplit, reloadedMessageToSplit_2.getThreadtop());
+		Assert.assertEquals(messageToSplit, reloadedMessageToSplit_2.getParent());
+	}
+	
 	@Test
 	public void deleteMessageTree() {
 		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("fo-5");
diff --git a/src/test/java/org/olat/selenium/CourseTest.java b/src/test/java/org/olat/selenium/CourseTest.java
index 38041c268daa79a453c969c256d220fbf2cbb03c..db823a6002d84c772f50f2ff96748f6a2f4faa84 100644
--- a/src/test/java/org/olat/selenium/CourseTest.java
+++ b/src/test/java/org/olat/selenium/CourseTest.java
@@ -1146,7 +1146,7 @@ public class CourseTest {
 	 */
 	@Test
 	@RunAsClient
-	public void concurrentForum(@InitialPage LoginPage loginPage,
+	public void forum_concurrent(@InitialPage LoginPage loginPage,
 			@Drone @Participant WebDriver kanuBrowser,
 			@Drone @Student WebDriver reiBrowser)
 	throws IOException, URISyntaxException {
diff --git a/src/test/java/org/olat/selenium/page/group/GroupPage.java b/src/test/java/org/olat/selenium/page/group/GroupPage.java
index d4036a2252b7e311f29fab92a45855d41ba145f8..ac12929975fc864782b565811ee3e4da942fc081 100644
--- a/src/test/java/org/olat/selenium/page/group/GroupPage.java
+++ b/src/test/java/org/olat/selenium/page/group/GroupPage.java
@@ -51,6 +51,34 @@ public class GroupPage {
 	private static final By bookingConfigBy = By.className("o_sel_accesscontrol_create");
 	private static final By memberMenuItem = By.cssSelector("li.o_sel_group_members a");
 	
+	private static final Tool calendarTool = new Tool(
+			By.cssSelector("li.o_sel_group_calendar a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasCalendar input[type='checkbox']"));
+	private static final Tool chatTool = new Tool(
+			By.cssSelector("li.o_sel_group_chat a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasChat input[type='checkbox']"));
+	private static final Tool contactTool = new Tool(
+			By.cssSelector("li.o_sel_group_contact a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasContactForm input[type='checkbox']"));
+	private static final Tool membersTool = new Tool(
+			By.cssSelector("li.o_sel_group_members a"), null);
+	private static final Tool newsTool = new Tool(
+			By.cssSelector("li.o_sel_group_news a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasNews input[type='checkbox']"));
+	private static final Tool folderTool = new Tool(
+			By.cssSelector("li.o_sel_group_folder a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasFolder input[type='checkbox']"));
+	private static final Tool forumTool = new Tool(
+			By.cssSelector("li.o_sel_group_forum a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasForum input[type='checkbox']"));
+	private static final Tool wikiTool = new Tool(
+			By.cssSelector("li.o_sel_group_wiki a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasWiki input[type='checkbox']"));
+	private static final Tool portfolioTool = new Tool(
+			By.cssSelector("li.o_sel_group_portfolio a"),
+			By.cssSelector(".o_sel_collab_tools label.o_sel_hasPortfolio input[type='checkbox']"));
+
+	
 	private WebDriver browser;
 	
 	public GroupPage() {
@@ -94,51 +122,50 @@ public class GroupPage {
 	}
 	
 	public IMPage openChat() {
-		openMenuItem("o_sel_group_chat");
+		openMenuItem(chatTool);
 		return new IMPage(browser);
 	}
 	
 	public CalendarPage openCalendar() {
-		openMenuItem("o_sel_group_calendar");
+		openMenuItem(calendarTool);
 		return new CalendarPage(browser);
 	}
 	
 	public ContactPage openContact() {
-		openMenuItem("o_sel_group_contact");
+		openMenuItem(contactTool);
 		return new ContactPage(browser);
 	}
 	
 	public GroupPage openMembers() {
-		return openMenuItem("o_sel_group_members");
+		return openMenuItem(membersTool);
 	}
 	
 	public GroupPage openNews() {
-		return openMenuItem("o_sel_group_news");
+		return openMenuItem(newsTool);
 	}
 	
 	public FolderPage openFolder() {
-		openMenuItem("o_sel_group_folder");
+		openMenuItem(folderTool);
 		return new FolderPage(browser);
 	}
 	
 	public ForumPage openForum() {
-		openMenuItem("o_sel_group_forum");
+		openMenuItem(forumTool);
 		return ForumPage.getGroupForumPage(browser);
 	}
 	
 	public WikiPage openWiki() {
-		openMenuItem("o_sel_group_wiki");
+		openMenuItem(wikiTool);
 		return WikiPage.getGroupWiki(browser);
 	}
 	
 	public PortfolioPage openPortfolio() {
-		openMenuItem("o_sel_group_portfolio");
+		openMenuItem(portfolioTool);
 		return new PortfolioPage(browser);
 	}
 	
-	private GroupPage openMenuItem(String cssClass) {
-		By newsBy = By.cssSelector("li." + cssClass + " a");
-		browser.findElement(newsBy).click();
+	private GroupPage openMenuItem(Tool tool) {
+		browser.findElement(tool.getMenuItemBy()).click();
 		OOGraphene.waitBusy(browser);
 		return this;
 	}
@@ -201,13 +228,22 @@ public class GroupPage {
 	}
 	
 	public GroupPage enableTools() {
-		By checkToolsBy = By.cssSelector(".o_sel_collab_tools input[type='checkbox']");
-		List<WebElement> checkTools = browser.findElements(checkToolsBy);
-		Assert.assertFalse(checkTools.isEmpty());
-		for(WebElement checkTool:checkTools) {
-			checkTool.click();
-			OOGraphene.waitBusy(browser);
-		}
+		return enableTool(calendarTool)
+				.enableTool(chatTool)
+				.enableTool(contactTool)
+				.enableTool(newsTool)
+				.enableTool(folderTool)
+				.enableTool(forumTool)
+				.enableTool(wikiTool)
+				.enableTool(portfolioTool);
+	}
+	
+	private GroupPage enableTool(Tool tool) {
+		By checkToolsBy = tool.getCheckboxBy();
+		WebElement checkToolEl = browser.findElement(checkToolsBy);
+		checkToolEl.click();
+		OOGraphene.waitBusy(browser);
+		OOGraphene.waitElement(tool.getMenuItemBy(), 2, browser);
 		return this;
 	}
 	
@@ -316,4 +352,22 @@ public class GroupPage {
 		List<WebElement> elements = browser.findElements(longBy);
 		return elements.size() > 0;
 	}
+	
+	private static class Tool {
+		private final By menuItemBy;
+		private final By checkboxBy;
+		
+		public Tool(By menuItemBy, By checkboxBy) {
+			this.menuItemBy = menuItemBy;
+			this.checkboxBy = checkboxBy;
+		}
+
+		public By getMenuItemBy() {
+			return menuItemBy;
+		}
+
+		public By getCheckboxBy() {
+			return checkboxBy;
+		}
+	}
 }