diff --git a/pom.xml b/pom.xml
index 756fa1e91ff4129063cc75cf00c6a6665486eb06..20ea423af3b292887e3708d25dedf66f0c2e3ec0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -98,9 +98,9 @@
 	    <test.env.db.oracle.host.port>1521</test.env.db.oracle.host.port>
 	    <test.env.instance.id>myolat</test.env.instance.id>
 	    <test.env.webdriver.browser>chrome</test.env.webdriver.browser>
-	    <test.env.webdriver.firefox.version>v0.27.0</test.env.webdriver.firefox.version>
-	    <test.env.webdriver.chrome.version>86.0.4240.22</test.env.webdriver.chrome.version>
-	    <test.env.webdriver.chrome.arguments />
+	    <test.env.webdriver.firefox.version>v0.29.0</test.env.webdriver.firefox.version>
+	    <test.env.webdriver.chrome.version>88.0.4324.96</test.env.webdriver.chrome.version>
+	    <test.env.webdriver.chrome.arguments></test.env.webdriver.chrome.arguments>
 	    <skipTests>true</skipTests>
 		<skipSeleniumTests>false</skipSeleniumTests>
 
diff --git a/src/main/java/org/olat/commons/calendar/ui/ExternalLinksController.java b/src/main/java/org/olat/commons/calendar/ui/ExternalLinksController.java
index 94f6951a8e04a037f6bf2a59cf6ec21f251e7f2e..f4eda5f9c4c46b8f451954b0100b271e6560b800 100644
--- a/src/main/java/org/olat/commons/calendar/ui/ExternalLinksController.java
+++ b/src/main/java/org/olat/commons/calendar/ui/ExternalLinksController.java
@@ -124,36 +124,36 @@ public class ExternalLinksController extends FormBasicController {
 		String id = link.getId();
 		String uri = link.getLink().getURI();
 		if(!StringHelper.containsNonWhitespace(uri)) {
-			uri = "http://";
+			uri = "https://";
 		}
-		TextElement url = uifactory.addTextElement("url_" + id, null, -1, uri, layoutContainer);
+		TextElement url = uifactory.addTextElement("url_".concat(id), null, -1, uri, layoutContainer);
 		url.clearError();
 		url.setDisplaySize(60);
 		url.setMandatory(true);
 		link.setUrl(url);
 		
 		// add link description
-		TextElement name = uifactory.addTextElement("displayName_" + id, null, -1, link.getLink().getDisplayName(), layoutContainer);
+		TextElement name = uifactory.addTextElement("displayName_".concat(id), null, -1, link.getLink().getDisplayName(), layoutContainer);
 		name.clearError();
 		name.setDisplaySize(40);
 		name.setMandatory(true);
 		link.setName(name);
 		
 		// add link add action button
-		FormLink addButton = uifactory.addFormLink("add_" + id, "table.add", "table.add", layoutContainer, Link.BUTTON);
+		FormLink addButton = uifactory.addFormLink("add_".concat(id), "table.add", "table.add", layoutContainer, Link.BUTTON);
 		addButton.setUserObject(link);
 		link.setAddButton(addButton);
 
 		// add link deletion action button
-		FormLink delButton = uifactory.addFormLink("del_" + id, "table.delete", "table.delete", layoutContainer, Link.BUTTON);
+		FormLink delButton = uifactory.addFormLink("del_".concat(id), "table.delete", "table.delete", layoutContainer, Link.BUTTON);
 		delButton.setUserObject(link);
 		link.setDelButton(delButton);
 	}
 
 	@Override
 	protected boolean validateFormLogic(UserRequest ureq) {
+		boolean allOk = super.validateFormLogic(ureq);
 		
-		boolean allOk = true;
 		for(LinkWrapper link:externalLinks) {
 			link.getUrl().clearError();
 			link.getName().clearError();
@@ -182,13 +182,13 @@ public class ExternalLinksController extends FormBasicController {
 			}
 		}
 		
-		return allOk && super.validateFormLogic(ureq);
+		return allOk;
 	}
 
 	@Override
 	protected void formInnerEvent(UserRequest ureq, FormItem source, FormEvent event) {
 		if(source == newButton) {
-			String id = UUID.randomUUID().toString().replaceAll("-", "");
+			String id = UUID.randomUUID().toString().replace("-", "");
 			KalendarEventLink link = new KalendarEventLink(EXTERNAL_LINKS_PROVIDER, id, "", "", "");
 			LinkWrapper linkWrapper = new LinkWrapper(link);
 			externalLinks.add(linkWrapper);
@@ -246,7 +246,7 @@ public class ExternalLinksController extends FormBasicController {
 		//remove deleted links
 		for(Iterator<KalendarEventLink> it=links.iterator(); it.hasNext(); ) {
 			KalendarEventLink link = it.next();
-			if(EXTERNAL_LINKS_PROVIDER.equals(link.getId()) && !usedUuids.contains(link.getId())) {
+			if(EXTERNAL_LINKS_PROVIDER.equals(link.getProvider()) && !usedUuids.contains(link.getId())) {
 				it.remove();
 			}
 		}
@@ -261,10 +261,9 @@ public class ExternalLinksController extends FormBasicController {
 
 
 	private LinkWrapper createLinkWrapper() {
-		String id = UUID.randomUUID().toString().replaceAll("-", "");
+		String id = UUID.randomUUID().toString().replace("-", "");
 		KalendarEventLink newLink = new KalendarEventLink(EXTERNAL_LINKS_PROVIDER, id, "", "", "");
-		LinkWrapper newLinkWrapper = new LinkWrapper(newLink);
-		return newLinkWrapper;
+		return new LinkWrapper(newLink);
 	}
 
 	public class LinkWrapper {
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
index b1aba56d3dccc854091f179fa389495d4e101a14..ac72c676ce8d3859f2e324e5b071a7c4f239fad1 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImpl.java
@@ -293,7 +293,7 @@ public class OnlyOfficeServiceImpl implements OnlyOfficeService {
 		if (licenseEdit.intValue() <= 0) return false;
 		
 		Long accessCount = documentEditorServie.getAccessCount(OnlyOfficeEditor.TYPE, Mode.EDIT);
-		return accessCount < licenseEdit.intValue();
+		return accessCount <= licenseEdit.intValue();
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
index a838c432e4e6d128eaeff64dcb98c83c15d5d92e..13768de4941cb5395bbb7658728d2e9361243547 100644
--- a/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
+++ b/src/main/java/org/olat/core/commons/services/doceditor/onlyoffice/ui/OnlyOfficeEditorController.java
@@ -30,6 +30,7 @@ import org.olat.core.commons.services.doceditor.onlyoffice.OnlyOfficeService;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
+import org.olat.core.gui.components.Window;
 import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -65,6 +66,8 @@ public class OnlyOfficeEditorController extends BasicController {
 			final DocEditorConfigs configs, Access runAccess) {
 		super(ureq, wControl);
 		access = runAccess;
+
+		wControl.getWindowBackOffice().getWindow().addListener(this);
 		
 		if (Mode.EDIT == access.getMode() && !onlyOfficeService.isEditLicenseAvailable()) {
 			access = docEditorService.updateMode(access, Mode.VIEW);
@@ -111,11 +114,14 @@ public class OnlyOfficeEditorController extends BasicController {
 		
 		putInitialPanel(mainVC);
 	}
-
+	
 	@Override
-	protected void event(UserRequest ureq, Component source, Event event) {
-		//
+	public void event(UserRequest ureq, Component source, Event event) {
+		if(event == Window.CLOSE_WINDOW) {
+			deleteAccess();
+		}
 	}
+	
 
 	@Override
 	protected void doDispose() {
diff --git a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml
index 907b85c71e4a05f4c84ada968ce87427b87803ab..aefc59b1293951d99e23ac1023691ce660a45bc8 100644
--- a/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml
+++ b/src/main/java/org/olat/core/commons/services/scheduler/_spring/schedulerContext.xml
@@ -37,7 +37,6 @@ How to add a new job:
             <ref bean="sendNotificationsEmailTrigger" />
             <ref bean="updateStatisticsTrigger"/>
             <ref bean="searchIndexingTrigger"/>
-            <ref bean="invitationCleanupTrigger" />
             <ref bean="restTokenTrigger" />
             <ref bean="taskExecutorTrigger" />
             <ref bean="procSamplerTrigger"/>
diff --git a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
index 6c6a6ca33bd5b9cb07f10574002a3c9d72314589..971380d1ea0ad73ad7d7eeb1ca4373b859ed1bf0 100644
--- a/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
+++ b/src/main/java/org/olat/course/nodes/CheckListCourseNode.java
@@ -457,7 +457,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode {
 			}
 		}
 
-		ScoreEvaluation sceval = new ScoreEvaluation(score, new Boolean(passed));
+		ScoreEvaluation sceval = new ScoreEvaluation(score, Boolean.valueOf(passed));
 		
 		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by);
@@ -475,7 +475,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode {
 
 		CourseAssessmentService courseAssessmentService = CoreSpringFactory.getImpl(CourseAssessmentService.class);
 		ScoreEvaluation currentEval = courseAssessmentService.getAssessmentEvaluation(this, assessedUserCourseEnv);
-		ScoreEvaluation sceval = new ScoreEvaluation(new Float(score), currentEval.getPassed());
+		ScoreEvaluation sceval = new ScoreEvaluation(Float.valueOf(score), currentEval.getPassed());
 		courseAssessmentService.saveScoreEvaluation(this, identity, sceval, assessedUserCourseEnv, false, by);
 	}
 	
@@ -558,10 +558,15 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode {
 	private void updateScorePassedOnPublish(Identity assessedIdentity, Identity coachIdentity, CheckboxManager checkboxManager, ICourse course) {
 		AssessmentManager am = course.getCourseEnvironment().getAssessmentManager();
 		
-		Float currentScore = am.getNodeScore(this, assessedIdentity);
-		Boolean currentPassed = am.getNodePassed(this, assessedIdentity);
+		Float currentScore = null;
+		Boolean currentPassed = null;
+		AssessmentEntry ae = am.getAssessmentEntry(this, assessedIdentity);
+		if(ae != null) {
+			currentScore = ae.getScore() == null ? null : ae.getScore().floatValue();
+			currentPassed = ae.getPassed();
+		}
 		
-		Float updatedScore = null;
+		Float updatedScore;
 		Boolean updatedPassed = null;
 
 		ModuleConfiguration config = getModuleConfiguration();
@@ -616,7 +621,7 @@ public class CheckListCourseNode extends AbstractAccessableCourseNode {
 				|| (currentScore != null && updatedScore == null)
 				|| (currentScore != null && !currentScore.equals(updatedScore))) {
 			needUpdate = true;	
-		}	
+		}
 		
 		if(needUpdate) {
 			ScoreEvaluation scoreEval = new ScoreEvaluation(updatedScore, updatedPassed);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java b/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java
index 838335d5d8a84f3b72372874c53d11e45a44a03c..f946e509db3302ccc64d23e7ced3bb0e85792576 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java
+++ b/src/main/java/org/olat/course/nodes/cl/ui/CheckListExcelExport.java
@@ -78,6 +78,7 @@ public class CheckListExcelExport {
 	private final CheckListCourseNode courseNode;
 	private final boolean hasScore;
 	private final boolean hasPassed;
+	private final boolean hasComment;
 	private final List<UserPropertyHandler> userPropertyHandlers;
 	
 	private final UserManager userManager;
@@ -91,6 +92,7 @@ public class CheckListExcelExport {
 		AssessmentConfig assessmentConfig = courseAssessmentService.getAssessmentConfig(courseNode);
 		this.hasScore = Mode.none != assessmentConfig.getScoreMode();
 		this.hasPassed = Mode.none != assessmentConfig.getPassedMode();
+		this.hasComment = assessmentConfig.hasComment();
 		
 		userManager = CoreSpringFactory.getImpl(UserManager.class);
 		checkboxManager = CoreSpringFactory.getImpl(CheckboxManager.class);
@@ -150,6 +152,9 @@ public class CheckListExcelExport {
 		if(hasPassed) {
 			header2Row.addCell(col++, translator.translate("column.header.node.passed"), headerStyle);
 		}
+		if(hasComment) {
+			header2Row.addCell(col++, translator.translate("column.header.usercomment"), headerStyle);
+		}
 
 		ModuleConfiguration config = courseNode.getModuleConfiguration();
 		CheckboxList list = (CheckboxList)config.get(CheckListCourseNode.CONFIG_KEY_CHECKBOX);
@@ -214,6 +219,14 @@ public class CheckListExcelExport {
 				col++;
 			}
 		}
+
+		if(hasComment) {
+			if(entry != null) {
+				dataRow.addCell(col++, entry.getComment(), null);
+			} else {
+				col++;
+			}
+		}
 		
 		ModuleConfiguration config = courseNode.getModuleConfiguration();
 		CheckboxList list = (CheckboxList)config.get(CheckListCourseNode.CONFIG_KEY_CHECKBOX);
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties
index a9b49dc9f7bbc9b9b22ed43f2489fdf934c9e119..3ff4361f49d073029730351d64367c95116ba81e 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_de.properties
@@ -21,6 +21,7 @@ column.header.homepage=Homepage
 column.header.node.passed=Kursbaustein bestanden
 column.header.node.points=Kursbaustein Punkte
 column.header.points=$\:box.points
+column.header.usercomment=Kommentar f\u00FCr Benutzer
 comment.nocomment=$org.olat.course.nodes.ms\:comment.nocomment
 comment.title=$org.olat.course.nodes.ms\:comment.title
 config.checkbox.description=W\u00e4hlen Sie "$\:add.checkbox" um eine neue Checkbox zu erzeugen oder "$org.olat.core\:edit" um eine bestehende Checkbox zu ver\u00e4ndern.
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties
index 90f8e83a2f64f20e792fb58337eaf314d908b18c..cdc96b54877c3065be923e95dfb0dc83c1c8b133 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_en.properties
@@ -21,6 +21,7 @@ column.header.node.passed=Passed course element
 column.header.node.points=Score course element
 column.header.points=$\:box.points
 column.header.seqnum=Sequence number
+column.header.usercomment=Comments for users
 comment.nocomment=$org.olat.course.nodes.ms\:comment.nocomment
 comment.title=$org.olat.course.nodes.ms\:comment.title
 config.checkbox.description=Click "$\:add.checkbox" to create a new checkbox or select "$org.olat.core\:edit" to configure an existing checkbox.
diff --git a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_fr.properties
index fe675148d8a6467a0d136cd862013d01c4a4f633..80c1fc87bd23118f3d5e921d8882b8f4f0532b8a 100644
--- a/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/nodes/cl/ui/_i18n/LocalStrings_fr.properties
@@ -21,6 +21,7 @@ column.header.node.passed=\u00C9l\u00E9ment de cours r\u00E9ussi
 column.header.node.points=Points \u00E9l\u00E9ment de cours
 column.header.points=$\:box.points
 column.header.seqnum=Num\u00E9ro
+column.header.usercomment=Commentaires pour l'utilisateur
 comment.nocomment=$org.olat.course.nodes.ms\:comment.nocomment
 comment.title=$org.olat.course.nodes.ms\:comment.title
 config.checkbox.description=Clicuez "$\:add.checkbox" pour cr\u00E9er une nouvelle case \u00E0 cocher ou s\u00E9lectionnez "$org.olat.core\:edit" pour configurer une case \u00E0 cocher existante.
diff --git a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
index e592d98c3b66454cdb216e4f5f6c3de910f36171..d3d8d7246215edcb5ed6741a4bbd2da2dce65b4a 100644
--- a/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
+++ b/src/main/java/org/olat/course/nodes/gta/ui/SubmitDocumentsController.java
@@ -234,6 +234,12 @@ class SubmitDocumentsController extends FormBasicController {
 	private void updateWarnings() {
 		if(minDocs > 0 && model.getRowCount() < minDocs) {
 			String msg = translate("error.min.documents", new String[]{ Integer.toString(minDocs) });
+			if(uploadDocButton != null) {
+				uploadDocButton.setEnabled(true);
+			}
+			if(createDocButton != null) {
+				createDocButton.setEnabled(true);
+			}
 			flc.contextPut("minDocsWarning", msg);
 			flc.contextRemove("maxDocsWarning");
 		} else if(maxDocs > 0 && model.getRowCount() >= maxDocs) {
diff --git a/src/main/java/org/olat/course/run/CourseRuntimeController.java b/src/main/java/org/olat/course/run/CourseRuntimeController.java
index a9c70778a0aef95fb4acd456fc213b309191ff90..1dbc506ca73a419793cb8d8840e2dff59aecdaa8 100644
--- a/src/main/java/org/olat/course/run/CourseRuntimeController.java
+++ b/src/main/java/org/olat/course/run/CourseRuntimeController.java
@@ -481,9 +481,15 @@ public class CourseRuntimeController extends RepositoryEntryRuntimeController im
 	
 	private void setCourseClosedMessage() {
 		UserCourseEnvironment userCourseEnv = getUserCourseEnvironment();
-		if(userCourseEnv != null &&  getRepositoryEntry().getEntryStatus() == RepositoryEntryStatusEnum.closed) {
-			toolbarPanel.setMessage(translate("course.closed"));
-			toolbarPanel.setMessageCssClass("o_warning");
+		if(userCourseEnv != null) {
+			if(getRepositoryEntry().getEntryStatus() == RepositoryEntryStatusEnum.closed) {
+				toolbarPanel.setMessage(translate("course.closed"));
+				toolbarPanel.setMessageCssClass("o_warning");
+			} else if(getRepositoryEntry().getEntryStatus() == RepositoryEntryStatusEnum.deleted
+					|| getRepositoryEntry().getEntryStatus() == RepositoryEntryStatusEnum.trash) {
+				toolbarPanel.setMessage(translate("course.deleted"));
+				toolbarPanel.setMessageCssClass("o_warning");
+			}
 		} else {
 			toolbarPanel.setMessage(null);
 			toolbarPanel.setMessageComponent(null);
diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
index fd13bbb9485ab7009da7ba65786b88ed774b6352..3be482b63fee7927b84e9a2b8dafa055be57f09c 100644
--- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_de.properties
@@ -55,6 +55,7 @@ command.run=Kurs Laufzeitumgebung
 command.settings=Kursinfo \u00e4ndern
 command.wiki=Wiki
 course.closed=Dieser Kurs wurde beendet und kann nicht mehr bearbeitet oder aktualisiert werden.
+course.deleted=Dieser Kurs wurde gel\u00f6scht und kann nicht mehr bearbeitet oder aktualisiert werden.
 course.disposed.command.restart=Den Kurs beenden und neu starten
 course.disposed.message=Bitte beenden Sie diesen Kurs und starten Sie ihn neu.
 course.disposed.title=Dieser Kurs wurde ver\u00e4ndert.
diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
index 0defb69156aab597a9f7b758ad3acb14343a811d..5d0f8ecd4f7fce6e3b5d1fbf3b03014792ff5cf7 100644
--- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_en.properties
@@ -55,6 +55,7 @@ command.run=Course runtime
 command.settings=Change course info
 command.wiki=Wiki
 course.closed=This course is finished and can therefore no longer be edited or updated.
+course.deleted=This course is deleted and can therefore no longer be edited or updated.
 course.disposed.command.restart=Close course and restart
 course.disposed.message=Please close this course and restart.
 course.disposed.title=This course has been modified.
diff --git a/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties
index d954f235e95ea3d0724b87eee1cb76c9783ded9d..7dd82aaddc4a0e8445fa237a3b61cab6fcf5c3be 100644
--- a/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/course/run/_i18n/LocalStrings_fr.properties
@@ -55,6 +55,7 @@ command.run=Cours
 command.settings=Modifier la description
 command.wiki=Wiki
 course.closed=Ce cours est termin\u00E9 et n'est plus \u00E9dit\u00E9 ou actualis\u00E9.
+course.deleted=Ce cours a \u00E9t\u00E9 effac\u00E9 et n'est plus \u00E9dit\u00E9 ou actualis\u00E9.
 course.disposed.command.restart=Fermer le cours et red\u00E9marrer.
 course.disposed.message=Fermez le cours et red\u00E9marrez-le \u00E0 nouveau SVP.
 course.disposed.title=Le cours a \u00E9t\u00E9 modifi\u00E9.
diff --git a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
index bf905bc81e75759d343cae970f0d29e9cc76302b..075cc4099ead66b02a4e3b3cc29cb30172469d74 100644
--- a/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
+++ b/src/main/java/org/olat/course/run/userview/UserCourseEnvironmentImpl.java
@@ -50,7 +50,6 @@ import org.olat.group.BusinessGroup;
 import org.olat.modules.curriculum.CurriculumElement;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryEntrySecurity;
-import org.olat.repository.RepositoryEntryStatusEnum;
 import org.olat.repository.model.RepositoryEntryLifecycle;
 
 /**
@@ -80,8 +79,8 @@ public class UserCourseEnvironmentImpl implements UserCourseEnvironment {
 	
 	public UserCourseEnvironmentImpl(IdentityEnvironment identityEnvironment, CourseEnvironment courseEnvironment) {
 		this(identityEnvironment, courseEnvironment, null, null, null, null, null, null, null, null);
-		if(courseEnvironment != null) {
-			courseReadOnly = courseEnvironment.getCourseGroupManager().getCourseEntry().getEntryStatus() == RepositoryEntryStatusEnum.closed;
+		if(courseEnvironment != null && courseEnvironment.getCourseGroupManager().getCourseEntry().getEntryStatus() != null) {
+			courseReadOnly = courseEnvironment.getCourseGroupManager().getCourseEntry().getEntryStatus().decommissioned();
 		}
 	}
 
diff --git a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java
index 5b5c9caff705a1cef7f90173b6b58174fd8f86bf..66337fd5ad624df0390d50fc79892f9892d7fb54 100644
--- a/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java
+++ b/src/main/java/org/olat/ims/qti21/model/xml/AssessmentHtmlBuilder.java
@@ -342,6 +342,7 @@ public class AssessmentHtmlBuilder {
 						String parameters = content.substring(start + startScript.length(), end);
 						translateToObject(parameters);
 					}
+					scriptBuffer = new StringBuilder();
 					video = false;
 				}
 				return;
diff --git a/src/main/java/org/olat/modules/_spring/modulesContext.xml b/src/main/java/org/olat/modules/_spring/modulesContext.xml
index 7d55dd77fc2b86d1ca97a9f076b817c75b8ffbdc..5ad479379006dcf44568aa072505a53e51e9c049 100644
--- a/src/main/java/org/olat/modules/_spring/modulesContext.xml
+++ b/src/main/java/org/olat/modules/_spring/modulesContext.xml
@@ -197,37 +197,6 @@
 		</property>
 	</bean>
 	
-	<bean id="invitationCleanupTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
-		<property name="jobDetail" ref="invitationCleanupJob.${cluster.singleton.services}" />
-		<!-- adjust cron style syntax for your notification needs 
-			"0 10 0 * *"  e.g. 10 minutes after midnight
-			
-			A "Cron-Expression" is a string comprised of 6 or 7 fields separated by white space. The 6 mandatory and 1 optional fields are as follows:
-			Field Name 	  	Allowed Values 	  	Allowed Special Characters
-			Seconds 	  	0-59 	  			, - * /
-			Minutes 	  	0-59 	  			, - * /
-			Hours 	  		0-23 	  			, - * /
-			Day-of-month 	1-31 	  			, - * ? / L W C
-			Month 	  		1-12 or JAN-DEC 	, - * /
-			Day-of-Week 	1-7 or SUN-SAT 	  	, - * ? / L C #
-			Year (Optional)	empty, 1970-2099 	, - * /
-		
-			As of OLAT 6.3 it's best to let the cronjob run every two hours since users can now choose how often 
-			they will get notified. The shortest interval is set to two hours. 	    	
-		-->
-		<property name="cronExpression" value="0 2 */12 * * ?" />
-		<property name="startDelay" value="150000" />
-	</bean>
-
-	<bean id="invitationCleanupJob.enabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean" lazy-init="true">
-		<property name="jobClass" value="org.olat.modules.portfolio.manager.InvitationCleanupJob" />
-	</bean>
-	<!-- dummy bean -->
-	<bean id="invitationCleanupJob.disabled" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"  lazy-init="true">
-		<property name="jobClass" value="org.olat.core.commons.services.scheduler.DummyJob" />
-	</bean>
-	
-	
 	<!-- vitero admin. panel -->
 	<bean class="org.olat.core.extensions.action.GenericActionExtension" init-method="initExtensionPoints">
 		<property name="order" value="8228" />
diff --git a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonGuestJoinController.java b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonGuestJoinController.java
index 20cb30768aaaf36853a2324b200c70891a39b449..5e18aab9a3ab3f7d80e4e2fd3c0690f0f22ef9aa 100644
--- a/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonGuestJoinController.java
+++ b/src/main/java/org/olat/modules/bigbluebutton/ui/BigBlueButtonGuestJoinController.java
@@ -307,12 +307,21 @@ public class BigBlueButtonGuestJoinController extends FormBasicController implem
 			allOk &= false;
 		}
 		
+		if(!joinButton.isEnabled()) {
+			if(!nameEl.hasError()) {// don't overwrite the validation error of name
+				nameEl.setErrorKey("meeting.create.intro", null);
+			}
+			allOk &= false;
+		}
+		
 		return allOk;
 	}
 
 	@Override
 	protected void formOK(UserRequest ureq) {
-		doJoin(ureq);
+		if(joinButton.isEnabled()) {
+			doJoin(ureq);
+		}
 	}
 
 	@Override
diff --git a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties
index 69c22f300fa42e5fc1f3902a000c58ab7552c2e5..97850769f1fbfb88085a95baf5c9b4bf8e1405de 100644
--- a/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/lecture/ui/_i18n/LocalStrings_de.properties
@@ -74,7 +74,7 @@ closed=Erledigt
 coach.absence=Absenzen
 coach.appeals=Rekurse
 coach.cockpit=Cockpit
-coach.dispensation=Abmeldungen / Dispensen
+coach.dispensation=Abmeldungen / Dispense
 coach.lectures=Lektionen
 coach.lectures.search=Benutzersuche
 coach.report=Report
@@ -122,7 +122,7 @@ delete.lectures.title=Lektionenblock l\u00F6schen
 delete.title=Begr\u00FCndung l\u00F6schen
 detailled.list=Detaillierte Liste
 details=Details
-dispensations.title=Abmeldungen und Dispensen
+dispensations.title=Abmeldungen und Dispense
 done=Erledigt
 edit.absence.category=Absenzenbegr\u00FCndung bearbeiten
 edit.assessment.mode=Pr\u00FCfung editieren
@@ -132,7 +132,7 @@ edit.type.absence=Absenz editieren
 edit.type.dispensation=Dispens editieren
 edit.type.notice.absence=Abmeldung editieren
 effective.lectures=Effektive Lektionen
-empty.absences.list=Es wurden kein Absenzen/Dispensen gefunden, welche den Kriterien entsprechen.
+empty.absences.list=Es wurden kein Absenzen/Dispense gefunden, welche den Kriterien entsprechen.
 empty.appeals.list=Es wurden kein Rekurs gefunden, welcher den Kriterien entspricht.
 empty.lectures.list=Die Tabelle ist leer
 empty.repository.entry.lectures=Sie mussten in diesem Kurs noch keine Lektionen besuchen.
@@ -212,7 +212,7 @@ lecture.groups=Kurs / Gruppe / Curriculum
 lecture.location=Ort
 lecture.mastercoach.can.authorize.absence=Klassenlehrer d\u00FCrfen Absenzen entschuldigen
 lecture.mastercoach.can.authorize.appeal=Klassenlehrer d\u00FCrfen Rekurse bewiligen
-lecture.mastercoach.can.record.notice=Klassenlehrer d\u00FCrfen Absenzen/Abmeldung/Dispensen erfassen
+lecture.mastercoach.can.record.notice=Klassenlehrer d\u00FCrfen Absenzen/Abmeldung/Dispens erfassen
 lecture.mastercoach.can.see.absence=Klassenlehrer d\u00FCrfen Absenzen einsehen
 lecture.mastercoach.can.see.appeal=Klassenlehrer d\u00FCrfen Rekurse einsehen
 lecture.owner.can.view.all.curriculum.elements=Kursbesitzer d\u00FCrfen alle Kurse in Curriculum Elementen sehen
@@ -523,7 +523,7 @@ unauthorized.filter.label=Anzeige
 unoverride.lecture=\u00DCbergehen anhalten
 upto=bis {0}
 user.overview.appeals=Rekurse
-user.overview.dispensation=Dispensen
+user.overview.dispensation=Dispense
 user.overview.lectures=Lektionen und Absenzen
 user.profil=Benutzerprofil
 warning.choose.at.least.one.appeal=Sie m\u00FCssen mindestens einen Rekurs w\u00E4hlen.
diff --git a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
index faa4cc5c5b256667b6d47d1a52b666840f5e1266..37a4adf45ef1f3a65bf3732de8969e37dc79c903 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/BinderDAO.java
@@ -84,6 +84,8 @@ public class BinderDAO {
 	@Autowired
 	private GroupDAO groupDao;
 	@Autowired
+	private InvitationDAO invitationDao;
+	@Autowired
 	private AssignmentDAO assignmentDao;
 	@Autowired
 	private PageUserInfosDAO pageUserInfosDao;
@@ -459,8 +461,8 @@ public class BinderDAO {
 		
 		binder.getSections().clear();
 		
-		
 		Group baseGroup = binder.getBaseGroup();
+		invitationDao.deleteInvitation(baseGroup);
 		rows += groupDao.removeMemberships(baseGroup);
 		dbInstance.getCurrentEntityManager().remove(binder);
 		dbInstance.getCurrentEntityManager().remove(baseGroup);
@@ -495,22 +497,20 @@ public class BinderDAO {
 	public int detachBinderFromRepositoryEntry(RepositoryEntry entry) {
 		//remove reference to the course and the course node
 		String sb = "update pfbinder binder set binder.entry=null,binder.subIdent=null where binder.entry.key=:entryKey";
-		int rows = dbInstance.getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 			.createQuery(sb)
 			.setParameter("entryKey", entry.getKey())
 			.executeUpdate();
-		return rows;
 	}
 	
 	public int detachBinderFromRepositoryEntry(RepositoryEntry entry, PortfolioCourseNode node) {
 		//remove reference to the course and the course node
 		String sb = "update pfbinder binder set binder.entry=null,binder.subIdent=null where binder.entry.key=:entryKey and binder.subIdent=:nodeIdent";
-		int rows = dbInstance.getCurrentEntityManager()
+		return dbInstance.getCurrentEntityManager()
 			.createQuery(sb)
 			.setParameter("entryKey", entry.getKey())
 			.setParameter("nodeIdent", node.getIdent())
 			.executeUpdate();
-		return rows;
 	}
 	
 	/**
diff --git a/src/main/java/org/olat/modules/portfolio/manager/InvitationCleanupJob.java b/src/main/java/org/olat/modules/portfolio/manager/InvitationCleanupJob.java
deleted file mode 100644
index ed3b1cfb6de869edb12e576650ad2a4b54cea2a0..0000000000000000000000000000000000000000
--- a/src/main/java/org/olat/modules/portfolio/manager/InvitationCleanupJob.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * <a href="http://www.openolat.org">
- * OpenOLAT - Online Learning and Training</a><br>
- * <p>
- * Licensed under the Apache License, Version 2.0 (the "License"); <br>
- * you may not use this file except in compliance with the License.<br>
- * You may obtain a copy of the License at the
- * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
- * <p>
- * Unless required by applicable law or agreed to in writing,<br>
- * software distributed under the License is distributed on an "AS IS" BASIS, <br>
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
- * See the License for the specific language governing permissions and <br>
- * limitations under the License.
- * <p>
- * Initial code contributed and copyrighted by<br>
- * frentix GmbH, http://www.frentix.com
- * <p>
- */
-package org.olat.modules.portfolio.manager;
-
-import org.apache.logging.log4j.Logger;
-import org.olat.core.CoreSpringFactory;
-import org.olat.core.commons.services.scheduler.JobWithDB;
-import org.olat.core.logging.Tracing;
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.JobExecutionContext;
-
-/**
- * Description:<br>
- * A job to remove invitation without policies.
- * 
- * <P>
- * Initial Date:  11 nov. 2010 <br>
- * @author srosse
- */
-@DisallowConcurrentExecution
-public class InvitationCleanupJob extends JobWithDB {
-
-	private static final Logger log = Tracing.createLoggerFor(InvitationCleanupJob.class);
-
-	@Override
-	public void executeWithDB(JobExecutionContext context) {
-		try {
-			log.info("Starting invitation clean up job");
-			InvitationDAO invitationDao = CoreSpringFactory.getImpl(InvitationDAO.class);
-			invitationDao.cleanUpInvitations();
-		} catch (Exception e) {
-			// ups, something went completely wrong! We log this but continue next time
-			log.error("Error while cleaning up invitation", e);
-		}
-		// db closed by JobWithDB class		
-	}
-}
diff --git a/src/main/java/org/olat/modules/portfolio/manager/InvitationDAO.java b/src/main/java/org/olat/modules/portfolio/manager/InvitationDAO.java
index b7a3df765e71e29fdfbe29bd0a4332e7decdf4bd..cc716f4c053f87f36ae9bbfe080398599f850ad8 100644
--- a/src/main/java/org/olat/modules/portfolio/manager/InvitationDAO.java
+++ b/src/main/java/org/olat/modules/portfolio/manager/InvitationDAO.java
@@ -19,7 +19,6 @@
  */
 package org.olat.modules.portfolio.manager;
 
-import java.util.Calendar;
 import java.util.Date;
 import java.util.List;
 import java.util.Locale;
@@ -35,13 +34,11 @@ import org.olat.basesecurity.Invitation;
 import org.olat.basesecurity.OrganisationRoles;
 import org.olat.basesecurity.OrganisationService;
 import org.olat.basesecurity.manager.GroupDAO;
-import org.olat.basesecurity.manager.OrganisationDAO;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.id.User;
 import org.olat.core.id.UserConstants;
 import org.olat.modules.portfolio.model.InvitationImpl;
-import org.olat.user.UserLifecycleManager;
 import org.olat.user.UserManager;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -69,11 +66,7 @@ public class InvitationDAO {
 	@Autowired
 	private BaseSecurity securityManager;
 	@Autowired
-	private OrganisationDAO organisationDao;
-	@Autowired
 	private OrganisationService organisationService;
-	@Autowired
-	private UserLifecycleManager userLifecycleManager;
 	
 	public Invitation createInvitation() {
 		InvitationImpl invitation = new InvitationImpl();
@@ -164,10 +157,10 @@ public class InvitationDAO {
 		StringBuilder sb = new StringBuilder();
 		sb.append("select invitation.key from binvitation as invitation")
 		  .append(" inner join invitation.baseGroup as baseGroup")
-		  .append(" where invitation.token=:token ")
-		  .append("   and exists(select binder from pfbinder as binder")
-		  .append("        where binder.baseGroup.key=baseGroup.key")
-		  .append("        )");
+		  .append(" where invitation.token=:token")
+		  .append(" and exists(select binder from pfbinder as binder")
+		  .append("   where binder.baseGroup.key=baseGroup.key")
+		  .append(" )");
 
 		TypedQuery<Long> query = dbInstance.getCurrentEntityManager()
 				.createQuery(sb.toString(), Long.class)
@@ -177,7 +170,7 @@ public class InvitationDAO {
 				.setFirstResult(0)
 				.setMaxResults(1)
 				.getResultList();
-		return keys == null || keys.isEmpty() || keys.get(0) == null ? false : keys.get(0).longValue() > 0;
+		return keys != null && !keys.isEmpty() && keys.get(0) != null && keys.get(0).longValue() > 0;
 	}
 	
 	/**
@@ -198,25 +191,6 @@ public class InvitationDAO {
 	    return invitations.isEmpty() ? null : invitations.get(0);
 	}
 	
-	/**
-	 * Find an invitation by its security group
-	 * @param secGroup
-	 * @return The invitation or null if not found
-	 */
-	public Invitation findInvitation(Group group) {
-		StringBuilder sb = new StringBuilder();
-		sb.append("select invitation from binvitation as invitation ")
-		  .append(" inner join fetch invitation.baseGroup bGroup")
-		  .append(" where bGroup=:group");
-
-		List<Invitation> invitations = dbInstance.getCurrentEntityManager()
-				  .createQuery(sb.toString(), Invitation.class)
-				  .setParameter("group", group)
-				  .getResultList();
-		if(invitations.isEmpty()) return null;
-		return invitations.get(0);
-	}
-	
 	/**
 	 * 
 	 * Warning! The E-mail is used in this case as a foreign key to match
@@ -295,7 +269,7 @@ public class InvitationDAO {
 			.createQuery(sb.toString(), Number.class)
 			.setParameter("identityKey", identity.getKey())
 			.getSingleResult();
-	    return invitations == null ? false : invitations.intValue() > 0;
+	    return invitations != null && invitations.intValue() > 0;
 	}
 	
 	/**
@@ -310,46 +284,13 @@ public class InvitationDAO {
 		dbInstance.getCurrentEntityManager().remove(refInvitation);
 	}
 	
-	/**
-	 * Clean up old invitation and set to deleted temporary users
-	 */
-	public void cleanUpInvitations() {
-		Calendar cal = Calendar.getInstance();
-		cal.setTime(new Date());
-		cal.add(Calendar.HOUR, -6);
-		Date dateLimit = cal.getTime();
-
-		StringBuilder sb = new StringBuilder(512);
-		sb.append("select invitation from ").append(InvitationImpl.class.getName()).append(" as invitation ")
-		  .append(" inner join invitation.baseGroup baseGroup ")
-		  .append(" where invitation.creationDate<:dateLimit");
-		
-		List<Invitation> oldInvitations = dbInstance.getCurrentEntityManager()
-				.createQuery(sb.toString(), Invitation.class)
-				.setParameter("dateLimit", dateLimit)
-				.getResultList();
+	public int deleteInvitation(Group group) {
+		if(group == null || group.getKey() == null) return 0;
 		
-		if(oldInvitations.isEmpty()) {
-			return;
-		}
-	  
-		for(Invitation invitation:oldInvitations) {
-			List<Identity> identities = groupDao.getMembers(invitation.getBaseGroup(), GroupRoles.invitee.name());
-			//normally only one identity
-			for(Identity identity:identities) {
-				if(identity.getStatus().equals(Identity.STATUS_DELETED)) {
-					//already deleted
-				} else if(organisationDao.hasAnyRole(identity, OrganisationRoles.invitee.name())) {
-					//out of scope
-				} else {
-					//delete user
-					userLifecycleManager.deleteIdentity(identity, null);
-				}
-			}
-			Invitation invitationRef = dbInstance.getCurrentEntityManager()
-				.getReference(InvitationImpl.class, invitation.getKey());
-			dbInstance.getCurrentEntityManager().remove(invitationRef);
-			dbInstance.commit();
-		}
+		String delete = "delete from binvitation as invitation where invitation.baseGroup.key=:groupKey";
+		return dbInstance.getCurrentEntityManager()
+				.createQuery(delete)
+				.setParameter("groupKey", group.getKey())
+				.executeUpdate();
 	}
 }
diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java
index 51bcc10c34670101b8e1cb7de8b382b5e10e68bc..96020a285a3b7c947ad82d726b4ceb657aaf74cd 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/BinderListController.java
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 import java.util.stream.Collectors;
 
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.persistence.DBFactory;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.Component;
@@ -133,6 +134,8 @@ public class BinderListController extends FormBasicController
 	private ConfirmMoveBinderToTrashController moveBinderToTrashCtrl;
 	private DialogBoxController confirmRestoreBinderCtrl;
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private PortfolioV2Module portfolioModule;
 	@Autowired
@@ -736,7 +739,8 @@ public class BinderListController extends FormBasicController
 	private void doMoveBinderToTrash(BinderRow row) {
 		Binder binder = portfolioService.getBinderByKey(row.getKey());
 		binder.setBinderStatus(BinderStatus.deleted);
-		binder = portfolioService.updateBinder(binder);
+		portfolioService.updateBinder(binder);
+		dbInstance.commit();
 		showInfo("delete.binder.success");
 	}
 	
@@ -756,6 +760,7 @@ public class BinderListController extends FormBasicController
 	
 	private void doDeleteBinder(BinderRef binder) {
 		portfolioService.deleteBinder(binder);
+		dbInstance.commit();
 		showInfo("delete.binder.success");
 	}
 	
@@ -769,7 +774,7 @@ public class BinderListController extends FormBasicController
 	private void doRestore(BinderRef row) {
 		Binder binder = portfolioService.getBinderByKey(row.getKey());
 		binder.setBinderStatus(BinderStatus.open);
-		binder = portfolioService.updateBinder(binder);
+		portfolioService.updateBinder(binder);
 		showInfo("restore.binder.success");
 	}
 	
diff --git a/src/main/java/org/olat/modules/portfolio/ui/BinderMetadataEditController.java b/src/main/java/org/olat/modules/portfolio/ui/BinderMetadataEditController.java
index b83aa4cf10b441fe3604e0da6514aeadfc8348bd..aee71ac92ed76d38313ea1caadd5e7087113e4ea 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/BinderMetadataEditController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/BinderMetadataEditController.java
@@ -26,6 +26,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -79,6 +80,8 @@ public class BinderMetadataEditController extends FormBasicController {
 	private Map<String,String> categories = new HashMap<>();
 	private Map<String,Category> categoriesMap = new HashMap<>();
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private UserManager userManager;
 	@Autowired
@@ -229,6 +232,7 @@ public class BinderMetadataEditController extends FormBasicController {
 		
 		List<String> updatedCategories = categoriesEl.getValueList();
 		portfolioService.updateCategories(binder, updatedCategories);
+		dbInstance.commit();
 		
 		fireEvent(ureq, Event.DONE_EVENT);
 	}
diff --git a/src/main/java/org/olat/modules/portfolio/ui/DeletedBinderController.java b/src/main/java/org/olat/modules/portfolio/ui/DeletedBinderController.java
index 4840ab4fe5096a6a1c86b6d0ba83b321d6eba772..181963144030cdf043caa737aace66b13a47d8a8 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/DeletedBinderController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/DeletedBinderController.java
@@ -22,6 +22,7 @@ package org.olat.modules.portfolio.ui;
 import java.util.ArrayList;
 import java.util.List;
 
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.gui.UserRequest;
 import org.olat.core.gui.components.form.flexible.FormItem;
 import org.olat.core.gui.components.form.flexible.FormItemContainer;
@@ -52,6 +53,7 @@ import org.olat.modules.portfolio.model.BinderStatistics;
 import org.olat.modules.portfolio.ui.event.DeleteBinderEvent;
 import org.olat.modules.portfolio.ui.event.RestoreBinderEvent;
 import org.olat.modules.portfolio.ui.model.BinderRow;
+import org.springframework.beans.factory.annotation.Autowired;
 
 /**
  * 
@@ -66,6 +68,9 @@ public class DeletedBinderController extends BinderListController {
 	private DialogBoxController confirmRestoreBinderCtrl;
 	private ConfirmDeleteBinderController deleteBinderCtrl;
 	
+	@Autowired
+	private DB dbInstance;
+	
 	public DeletedBinderController(UserRequest ureq, WindowControl wControl, TooledStackedPanel stackPanel) {
 		super(ureq, wControl, stackPanel);
 	}
@@ -225,7 +230,8 @@ public class DeletedBinderController extends BinderListController {
 	private void doRestore(BinderRow row) {
 		Binder binder = portfolioService.getBinderByKey(row.getKey());
 		binder.setBinderStatus(BinderStatus.open);
-		binder = portfolioService.updateBinder(binder);
+		portfolioService.updateBinder(binder);
+		dbInstance.commit();
 		showInfo("restore.binder.success");
 	}
 }
\ No newline at end of file
diff --git a/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java b/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java
index 49e460f3a7ae142179f1ad4d6314278bf0b24bda..cc08533beedb71584a6ab8bc385db5be96195768 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/SectionEditController.java
@@ -31,6 +31,7 @@ import org.olat.core.gui.components.form.flexible.impl.FormLayoutContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.util.StringHelper;
 import org.olat.modules.portfolio.BinderRef;
 import org.olat.modules.portfolio.BinderSecurityCallback;
 import org.olat.modules.portfolio.PortfolioService;
@@ -95,6 +96,9 @@ public class SectionEditController extends FormBasicController {
 		titleEl = uifactory.addTextElement("title", "title", 255, title, formLayout);
 		titleEl.setElementCssClass("o_sel_pf_edit_section_title");
 		titleEl.setMandatory(true);
+		if(!StringHelper.containsNonWhitespace(title)) {
+			titleEl.setFocus(true);
+		}
 		
 		String description = section == null ? null : section.getDescription();
 		descriptionEl = uifactory.addRichTextElementForStringDataMinimalistic("summary", "page.summary", description, 8, 60, formLayout, getWindowControl());
diff --git a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
index debe917bf60f238a486f8775917b8d4c25723e77..daf0f4dbfc1b26340f11255dd1cd7c13ff92f8d3 100644
--- a/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
+++ b/src/main/java/org/olat/modules/portfolio/ui/TableOfContentController.java
@@ -27,6 +27,7 @@ import java.util.Map;
 import org.olat.NewControllerFactory;
 import org.olat.core.commons.fullWebApp.LayoutMain3ColsController;
 import org.olat.core.commons.fullWebApp.popup.BaseFullWebappPopupLayoutFactory;
+import org.olat.core.commons.persistence.DB;
 import org.olat.core.commons.services.commentAndRating.CommentAndRatingDefaultSecurityCallback;
 import org.olat.core.commons.services.commentAndRating.CommentAndRatingSecurityCallback;
 import org.olat.core.commons.services.commentAndRating.ReadOnlyCommentsSecurityCallback;
@@ -151,6 +152,8 @@ public class TableOfContentController extends BasicController implements TooledC
 	private final BinderConfiguration config;
 	private final BinderSecurityCallback secCallback;
 	
+	@Autowired
+	private DB dbInstance;
 	@Autowired
 	private PdfModule pdfModule;
 	@Autowired
@@ -955,8 +958,10 @@ public class TableOfContentController extends BasicController implements TooledC
 	}
 	
 	private void doMoveBinderToTrash() {
+		binder = portfolioService.getBinderByKey(binder.getKey());
 		binder.setBinderStatus(BinderStatus.deleted);
 		binder = portfolioService.updateBinder(binder);
+		dbInstance.commit();
 		showInfo("delete.binder.success");
 	}
 	
@@ -967,8 +972,10 @@ public class TableOfContentController extends BasicController implements TooledC
 	}
 	
 	private void doRestore() {
+		binder = portfolioService.getBinderByKey(binder.getKey());
 		binder.setBinderStatus(BinderStatus.open);
 		binder = portfolioService.updateBinder(binder);
+		dbInstance.commit();
 		showInfo("restore.binder.success");
 	}
 	
diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties
index 7d94e86f2699b2a933179d662ae8ee45425f5f26..fe14058b803c070a27aa592aa2762e3173667c06 100644
--- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_de.properties
@@ -23,7 +23,7 @@ rule.after.date=Nach Datum
 rule.before.date=Bis Datum
 rule.course.enrollment.date=Einschreibedatum
 rule.course.role=Kursrolle
-rule.group.member=Gruppenteilnehmer
+rule.group.member=Gruppenmitglieder
 rule.initial.course.launch.date=Erster Kursbesuch
 rule.lifecycle.validfrom=Beginndatum von Kurs-Durchf\u00FChrungzeitraum
 rule.lifecycle.validto=Enddatum von Kurs-Durchf\u00FChrungzeitraum
diff --git a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties
index 043b930d02a6216b63148a9f5bb1c902336cbee9..fcb2b6f661ee279a0d9aa2be1e51a3f1cdcb023d 100644
--- a/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties
+++ b/src/main/java/org/olat/modules/reminder/ui/_i18n/LocalStrings_fr.properties
@@ -23,7 +23,7 @@ rule.after.date=Fonction de la date
 rule.before.date=Jusqu'\u00E0
 rule.course.enrollment.date=Date d'inscription
 rule.course.role=R\u00F4le au sein du cours
-rule.group.member=Participant \u00E0 un groupe
+rule.group.member=Membre \u00E0 un groupe
 rule.initial.course.launch.date=Premi\u00E8re visite du cours
 rule.lifecycle.validfrom=Date de comment de la p\u00E9riode du cours
 rule.lifecycle.validto=Date de fin de la p\u00E9riode de mise en \u0153uvre
diff --git a/src/main/java/org/olat/repository/RepositoryManager.java b/src/main/java/org/olat/repository/RepositoryManager.java
index c363cc7e23f39a8b4e59653017b73aeaee836542..0fcc5567e08b1413f4343a5a0f7832044909c365 100644
--- a/src/main/java/org/olat/repository/RepositoryManager.java
+++ b/src/main/java/org/olat/repository/RepositoryManager.java
@@ -69,7 +69,6 @@ import org.olat.core.util.coordinate.CoordinatorManager;
 import org.olat.core.util.event.EventBus;
 import org.olat.core.util.event.MultiUserEvent;
 import org.olat.core.util.mail.MailPackage;
-import org.olat.core.util.resource.OresHelper;
 import org.olat.core.util.vfs.LocalFolderImpl;
 import org.olat.core.util.vfs.VFSContainer;
 import org.olat.core.util.vfs.VFSItem;
@@ -641,7 +640,7 @@ public class RepositoryManager {
 			}
 		}
 
-		boolean readOnly = re.getEntryStatus() == RepositoryEntryStatusEnum.closed;
+		boolean readOnly = re.getEntryStatus().decommissioned();
 
 		return new RepositoryEntrySecurityImpl(isEntryAdmin, isOwner,
 				isCourseParticipant, isCourseCoach,
@@ -1397,11 +1396,10 @@ public class RepositoryManager {
 		sendDeferredEvents(deferredEvents, re);
 	}
 
-	private void sendDeferredEvents(List<? extends MultiUserEvent> events, OLATResourceable ores) {
+	private void sendDeferredEvents(List<? extends MultiUserEvent> events, RepositoryEntry ores) {
 		EventBus eventBus = CoordinatorManager.getInstance().getCoordinator().getEventBus();
 		for(MultiUserEvent event:events) {
 			eventBus.fireEventToListenersOf(event, ores);
-			eventBus.fireEventToListenersOf(event, OresHelper.lookupType(RepositoryEntry.class));
 		}
 	}
 
@@ -1419,8 +1417,8 @@ public class RepositoryManager {
 				ThreadLocalUserActivityLogger.setStickyActionType(actionType);
 			}
 	
-			log.info(Tracing.M_AUDIT, "Identity(.key):" + ureqIdentity.getKey() + " removed identity '" + identity.getKey()
-					+ "' as owner from repositoryentry with key " + re.getKey());
+			log.info(Tracing.M_AUDIT, "Identity(.key):{} removed identity '{}' as owner from repositoryentry with key {}",
+					ureqIdentity.getKey(), identity.getKey(), re.getKey());
 		}
 	}
 
@@ -1609,8 +1607,8 @@ public class RepositoryManager {
 		} finally {
 			ThreadLocalUserActivityLogger.setStickyActionType(actionType);
 		}
-		log.info(Tracing.M_AUDIT, "Identity(.key):" + ureqIdentity.getKey() + " added identity '" + identity.getKey()
-				+ "' to repositoryentry with key " + re.getKey());
+		log.info(Tracing.M_AUDIT, "Identity(.key):{} added identity '{}' to repositoryentry with key {}",
+				ureqIdentity.getKey(), identity.getKey(), re.getKey());
 	}
 
 	/**
@@ -2082,7 +2080,6 @@ public class RepositoryManager {
 		if(changes.getRepoParticipant() != null) {
 			if(changes.getRepoParticipant().booleanValue()) {
 				addParticipants(ureqIdentity, ureqRoles, new IdentitiesAddEvent(changes.getMember()), re, mailing);
-				deferredEvents.add(RepositoryEntryMembershipModifiedEvent.roleParticipantAdded(changes.getMember(), re));
 			} else {
 				removeParticipant(ureqIdentity, changes.getMember(), re, mailing, true);
 				deferredEvents.add(RepositoryEntryMembershipModifiedEvent.removed(changes.getMember(), re));
diff --git a/src/main/java/org/olat/repository/model/SingleRoleRepositoryEntrySecurity.java b/src/main/java/org/olat/repository/model/SingleRoleRepositoryEntrySecurity.java
index 991fce053e27db6faeb165964483fa889c09bae4..3b78d27beba190d9c347f13fc9bdbc0728d60d78 100644
--- a/src/main/java/org/olat/repository/model/SingleRoleRepositoryEntrySecurity.java
+++ b/src/main/java/org/olat/repository/model/SingleRoleRepositoryEntrySecurity.java
@@ -58,7 +58,7 @@ public class SingleRoleRepositoryEntrySecurity implements RepositoryEntrySecurit
 			return iconCssClass;
 		}
 		
-	};
+	}
 	
 	private Role currentRole;
 	private RepositoryEntrySecurity wrappedSecurity;
diff --git a/src/main/resources/serviceconfig/olat.properties b/src/main/resources/serviceconfig/olat.properties
index deead65890da4f5bd9df16c9655e2e8345b44004..4088f089a7d74a425afa4b1a8a325dc4d457760f 100644
--- a/src/main/resources/serviceconfig/olat.properties
+++ b/src/main/resources/serviceconfig/olat.properties
@@ -1374,8 +1374,8 @@ ldap.learningResourceManagerRoleValue=
 # Build properties
 #####
 application.name=OpenOlat
-build.version=15.3.8
-build.identifier=openolat1538-dev
+build.version=15.3.9
+build.identifier=openolat1539-dev
 build.repo.revision=local-devel
 
 #####
diff --git a/src/main/webapp/static/js/openolat/iframe.js b/src/main/webapp/static/js/openolat/iframe.js
index a146933fb726a8b5ac061989e41fea4063026822..bfd7431ce048435add48042d42bc88e3314a1b25 100644
--- a/src/main/webapp/static/js/openolat/iframe.js
+++ b/src/main/webapp/static/js/openolat/iframe.js
@@ -205,23 +205,7 @@ function b_changeLinkTargets() {
 		var anchor = anchors[i];
 		if (anchor.getAttribute('href')) {
 			var target = anchor.getAttribute('target');
-			var href = anchor.getAttribute("href");
-			if ((href.indexOf("/url/") != -1 || href.indexOf("/auth/") != -1) && 
-					(
-						href.indexOf("/repo/go?rid=") != -1 
-						|| href.indexOf("/RepositoryEntry/") != -1 
-						|| href.indexOf("/BusinessGroup/") != -1 
-						|| href.indexOf("Site/") != -1
-						|| href.indexOf("/CatalogEntry/") != -1										
-						|| href.indexOf("/Portal/") != -1
-						|| href.indexOf("/CatalogAdmin/") != -1
-						|| href.indexOf("/GMCMenuTree/") != -1
-					)
-			) {
-				// absolute links to repository entries have to by opened in the parent frame
-				// /auth/repo/ is legacy format, /url/RepositoryEntry/ is new format
-				anchor.target = "_parent";
-			} else if (target != null && target != undefined && (target == '_top' || target == '_parent')) {
+			if (target != null && target != undefined && (target == '_top' || target == '_parent')) {
 				// fix broken legacy links that try to open content in top window
 				// iframe content must always stay within iframe 
 				var mainwindow = b_getMainWindow(window.parent);
diff --git a/src/test/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImplTest.java b/src/test/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImplTest.java
index 6784dbb2b78b08266fe24f27f0ded8f619778f8c..85cf1c04be820010bf038672195dd31922330a45 100644
--- a/src/test/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImplTest.java
+++ b/src/test/java/org/olat/core/commons/services/doceditor/onlyoffice/manager/OnlyOfficeServiceImplTest.java
@@ -81,12 +81,24 @@ public class OnlyOfficeServiceImplTest {
 	}
 	
 	@Test
-	public void shouldNotAllowEditIfAllLicensesInUse() {
+	public void shouldAllowEditIfAlmostAllLicensesInUse() {
+		// Because the access is created before the license check is done,
+		// the access is demanding for the last license.
 		when(onlyOfficeModuleMock.getLicenseEdit()).thenReturn(10);
 		when(documentEditorServiceMock.getAccessCount(any(), any())).thenReturn(Long.valueOf(10));
 		
 		boolean editLicenseAvailable = sut.isEditLicenseAvailable();
 		
+		assertThat(editLicenseAvailable).isTrue();
+	}
+	
+	@Test
+	public void shouldNotAllowEditIfAllLicensesInUse() {
+		when(onlyOfficeModuleMock.getLicenseEdit()).thenReturn(10);
+		when(documentEditorServiceMock.getAccessCount(any(), any())).thenReturn(Long.valueOf(11));
+		
+		boolean editLicenseAvailable = sut.isEditLicenseAvailable();
+		
 		assertThat(editLicenseAvailable).isFalse();
 	}
 
diff --git a/src/test/java/org/olat/modules/portfolio/manager/InvitationDAOTest.java b/src/test/java/org/olat/modules/portfolio/manager/InvitationDAOTest.java
index af3e5d241080675b0d676fe008352637eaa99f89..1a6c556e06a46c6c3a6531d9b5077a8bdf888801 100644
--- a/src/test/java/org/olat/modules/portfolio/manager/InvitationDAOTest.java
+++ b/src/test/java/org/olat/modules/portfolio/manager/InvitationDAOTest.java
@@ -30,6 +30,7 @@ import org.olat.basesecurity.Invitation;
 import org.olat.basesecurity.manager.GroupDAO;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
+import org.olat.test.JunitTestHelper;
 import org.olat.test.OlatTestCase;
 import org.springframework.beans.factory.annotation.Autowired;
 
@@ -63,21 +64,6 @@ public class InvitationDAOTest extends OlatTestCase {
 		Assert.assertNotNull(invitation.getToken());
 	}
 	
-	@Test
-	public void findInvitation_group() {
-		Invitation invitation = invitationDao.createAndPersistInvitation();
-		Group baseGroup = invitation.getBaseGroup();
-		Assert.assertNotNull(invitation);
-		dbInstance.commitAndCloseSession();
-		
-		Invitation reloadedInvitation = invitationDao.findInvitation(baseGroup);
-		Assert.assertNotNull(reloadedInvitation);
-		Assert.assertNotNull(reloadedInvitation.getKey());
-		Assert.assertEquals(baseGroup, reloadedInvitation.getBaseGroup());
-		Assert.assertEquals(invitation, reloadedInvitation);
-		Assert.assertEquals(invitation.getToken(), reloadedInvitation.getToken());
-	}
-	
 	@Test
 	public void findInvitation_token() {
 		Invitation invitation = invitationDao.createAndPersistInvitation();
@@ -93,12 +79,31 @@ public class InvitationDAOTest extends OlatTestCase {
 	}
 	
 	@Test
-	public void hasInvitationPolicies_testHQL() {
+	public void hasInvitationTestHQL() {
 		String token = UUID.randomUUID().toString();
 		boolean hasInvitation = invitationDao.hasInvitations(token);
 		Assert.assertFalse(hasInvitation);
 	}
 	
+	@Test
+	public void isInvitee() {
+		Invitation invitation = invitationDao.createInvitation();
+		String uuid = UUID.randomUUID().toString().replace("-", "");
+		invitation.setFirstName("Fiona");
+		invitation.setLastName("Laurence".concat(uuid));
+		invitation.setMail(uuid.concat("@frentix.com"));
+
+		Group group = groupDao.createGroup();
+		Identity id2 = invitationDao.loadOrCreateIdentityAndPersistInvitation(invitation, group, Locale.ENGLISH);
+		Identity id1 = JunitTestHelper.createAndPersistIdentityAsRndUser("Invitee-2");
+		dbInstance.commitAndCloseSession();
+		
+		boolean invitee = invitationDao.isInvitee(id2);
+		Assert.assertTrue(invitee);
+		boolean notInvitee = invitationDao.isInvitee(id1);
+		Assert.assertFalse(notInvitee);
+	}
+	
 	@Test
 	public void createAndUpdateInvitation() {
 		Invitation invitation = invitationDao.createAndPersistInvitation();
@@ -174,12 +179,16 @@ public class InvitationDAOTest extends OlatTestCase {
 		Assert.assertTrue(numOfInvitations > 0l);
 	}
 	
-	/**
-	 * Only check if the query is valid.
-	 */
 	@Test
-	public void cleanUpInvitations() {
-		invitationDao.cleanUpInvitations();
+	public void deleteInvitationByGroup() {
+		Invitation invitation = invitationDao.createAndPersistInvitation();
+		dbInstance.commit();
+		Assert.assertNotNull(invitation);
+		
+		invitationDao.deleteInvitation(invitation.getBaseGroup());
+		dbInstance.commit();
+		
+		Invitation deletedInvitation = invitationDao.findInvitation(invitation.getToken());
+		Assert.assertNull(deletedInvitation);
 	}
-
 }
diff --git a/src/test/java/org/olat/selenium/AssessmentTest.java b/src/test/java/org/olat/selenium/AssessmentTest.java
index a927df45d81601f9b5063c66129002f2d038c17b..454f083c8fb27a67a4fdbcfc3577d93409291ed8 100644
--- a/src/test/java/org/olat/selenium/AssessmentTest.java
+++ b/src/test/java/org/olat/selenium/AssessmentTest.java
@@ -597,9 +597,8 @@ public class AssessmentTest extends Deployments {
 			.stop(assessmentName)
 			.confirmStop();
 		
-		By continueBy = By.className("o_sel_assessment_continue");
-		OOGraphene.waitElementSlowly(continueBy, 20, ryomouBrowser);
-		OOGraphene.waitElementSlowly(continueBy, 20, kanuBrowser);
+		kanuAssessment.waitBackToOpenOlat();
+		ryomouAssessment.waitBackToOpenOlat();
 		kanuAssessment.backToOpenOLAT();
 		ryomouAssessment.backToOpenOLAT();
 		
@@ -1689,7 +1688,7 @@ public class AssessmentTest extends Deployments {
 			.clickToolbarBack();
 		coursePage
 			.clickTree()
-			.selectWithTitle(gtaNodeTitle);
+			.assertWithTitleSelected(gtaNodeTitle);
 		
 		//Participant log in
 		LoginPage ryomouLoginPage = LoginPage.load(ryomouBrowser, deploymentUrl);
@@ -1707,7 +1706,7 @@ public class AssessmentTest extends Deployments {
 		CoursePageFragment ryomouTestCourse = new CoursePageFragment(ryomouBrowser);
 		ryomouTestCourse
 			.clickTree()
-			.selectWithTitle(gtaNodeTitle);
+			.assertWithTitleSelected(gtaNodeTitle);
 		OOGraphene.waitAndCloseBlueMessageWindow(ryomouBrowser);
 		
 		GroupTaskPage ryomouTask = new GroupTaskPage(ryomouBrowser);
@@ -1728,7 +1727,7 @@ public class AssessmentTest extends Deployments {
 		//back to author
 		coursePage
 			.clickTree()
-			.selectWithTitle(gtaNodeTitle);
+			.assertWithTitleSelected(gtaNodeTitle);
 		GroupTaskToCoachPage participantToCoach = new GroupTaskToCoachPage(browser);
 		
 		participantToCoach
@@ -1742,7 +1741,7 @@ public class AssessmentTest extends Deployments {
 		//participant checks she passed the task
 		ryomouTestCourse
 			.clickTree()
-			.selectWithTitle(gtaNodeTitle);
+			.assertWithTitleSelected(gtaNodeTitle);
 		ryomouTask
 			.assertPassed();
 	}
diff --git a/src/test/java/org/olat/selenium/page/core/MenuTreePageFragment.java b/src/test/java/org/olat/selenium/page/core/MenuTreePageFragment.java
index 71f7d03830f63826ee17b8f0a35b63563001a0f9..ebe0bd3a6654866627c1add7138a5431c3a76cd8 100644
--- a/src/test/java/org/olat/selenium/page/core/MenuTreePageFragment.java
+++ b/src/test/java/org/olat/selenium/page/core/MenuTreePageFragment.java
@@ -65,6 +65,8 @@ public class MenuTreePageFragment {
 		OOGraphene.waitElement(linkBy, browser);
 		browser.findElement(linkBy).click();
 		OOGraphene.waitBusy(browser);
+		By activeLinkBy = By.xpath("//div[contains(@class,'o_tree')]//li[contains(@class,'active')]/div/span[contains(@class,'o_tree_link')][contains(@class,'active')]/a[span[contains(text(),'" + title + "')]]");
+		OOGraphene.waitElement(activeLinkBy, browser);
 		return this;
 	}
 
diff --git a/src/test/java/org/olat/selenium/page/course/AssessmentModePage.java b/src/test/java/org/olat/selenium/page/course/AssessmentModePage.java
index a75c6c045e7f0ea67efade3c3b5f66e0f214ab20..9ab464212be997a8da598235e79d4e6cd88486fa 100644
--- a/src/test/java/org/olat/selenium/page/course/AssessmentModePage.java
+++ b/src/test/java/org/olat/selenium/page/course/AssessmentModePage.java
@@ -164,6 +164,12 @@ public class AssessmentModePage {
 		return this;
 	}
 	
+	public AssessmentModePage waitBackToOpenOlat() {
+		By continueBy = By.xpath("//div[@class='modal-content']//a[contains(@class,'o_sel_assessment_continue')]");
+		OOGraphene.waitElementSlowly(continueBy, 20, browser);
+		return this;
+	}
+	
 	/**
 	 * After an assessment, go back to OpenOLAT.
 	 */
diff --git a/src/test/resources/arquillian.xml b/src/test/resources/arquillian.xml
index af3b32c9eea16cce433fe89879d4d4d44c4dffa5..6cd16fe3f81467614ce99471455adcc328a5457e 100644
--- a/src/test/resources/arquillian.xml
+++ b/src/test/resources/arquillian.xml
@@ -28,9 +28,9 @@
 		<property name="chromeDriverBinary">target/drone/675a673c111fdcc9678d11df0e69b334/chromedriver</property>
 		<property name="firefoxDriverBinary">target/drone/ce03addb1fc8c24900011f90fc80f3c1/geckodriver</property>
 		-->
-		<property name="firefoxDriverVersion">${webdriver.firefox.version:v0.28.0}</property>
+		<property name="firefoxDriverVersion">${webdriver.firefox.version:v0.29.0}</property>
 		<property name="firefoxUserPreferences">src/test/profile/firefox/prefs.js</property>
-		<property name="chromeDriverVersion">${webdriver.chrome.version:87.0.4280.88}</property>
+		<property name="chromeDriverVersion">${webdriver.chrome.version:88.0.4324.96}</property>
 		<property name="chromeArguments">${webdriver.chrome.arguments}</property>
 		<property name="chromeExperimentalOption">{
 			"prefs":{"credentials_enable_service": false, "profile.password_manager_enabled": false }