diff --git a/pom.xml b/pom.xml
index 31803666d7ec4278ce728496ca890fd6c1f993f1..ca31bb174d3e5e8fcd45815c372cb242cacd791c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,7 +71,7 @@
 		<jackson.version>2.10.2</jackson.version>
 		<org.mysql.version>5.1.46</org.mysql.version>
 		<org.postgresql.version>42.2.9</org.postgresql.version>
-		<org.infinispan.version>10.1.0.Final</org.infinispan.version>
+		<org.infinispan.version>10.1.1.Final</org.infinispan.version>
 		<lucene.version>7.7.0</lucene.version>
 		<version.selenium>3.141.59</version.selenium>
 		<version.drone>2.5.1</version.drone>
diff --git a/src/main/java/org/olat/_spring/mainContext.xml b/src/main/java/org/olat/_spring/mainContext.xml
index 7407d055155c7f314f1f447980b85f2deb055bc4..1a40e3a4b93f709ca8af057624cc3b4363a6c9a9 100644
--- a/src/main/java/org/olat/_spring/mainContext.xml
+++ b/src/main/java/org/olat/_spring/mainContext.xml
@@ -9,7 +9,7 @@
         http://www.springframework.org/schema/context/spring-context.xsd">
   
 	<context:property-placeholder location="classpath:serviceconfig/olat.properties, classpath:olat.local.properties" system-properties-mode="OVERRIDE"/>
-	<context:component-scan base-package="org.olat.basesecurity,org.olat.note,org.olat.social,org.olat.commons.memberlist,org.olat.commons.info" />
+	<context:component-scan base-package="org.olat.basesecurity,org.olat.note,org.olat.social,org.olat.commons.memberlist,org.olat.commons.info,org.olat.collaboration" />
 	<context:annotation-config />
 
 	<import resource="classpath:/org/olat/core/_spring/mainCorecontext.xml"/>
diff --git a/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java b/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java
index 9ae57138866463935e8689e131dedada0c8ea2fa..388d345e32de53d794754f5cb57fe1f2cc8a6c5f 100644
--- a/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java
+++ b/src/main/java/org/olat/admin/sysinfo/LargeFilesController.java
@@ -37,6 +37,7 @@ import org.olat.admin.sysinfo.model.LargeFilesTableModel;
 import org.olat.admin.sysinfo.model.LargeFilesTableModel.LargeFilesTableColumns;
 import org.olat.core.commons.persistence.SortKey;
 import org.olat.core.commons.services.taskexecutor.TaskExecutorManager;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
 import org.olat.core.commons.services.vfs.VFSFilterKeys;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSRepositoryModule;
@@ -60,8 +61,8 @@ import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTable
 import org.olat.core.gui.components.form.flexible.impl.elements.table.FlexiTableDataModelFactory;
 import org.olat.core.gui.components.form.flexible.impl.elements.table.SelectionEvent;
 import org.olat.core.gui.components.link.Link;
-import org.olat.core.gui.components.text.TextFactory;
 import org.olat.core.gui.components.util.KeyValues;
+import org.olat.core.gui.components.velocity.VelocityContainer;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.Event;
 import org.olat.core.gui.control.WindowControl;
@@ -160,7 +161,7 @@ public class LargeFilesController extends FormBasicController implements Extende
 					downloadCountMin, revisionsCountMin, minSize);
 
 			for(VFSMetadata file:files) {
-				LargeFilesTableContentRow contentRow = new LargeFilesTableContentRow(file);
+				LargeFilesTableContentRow contentRow = new LargeFilesTableContentRow(file, getLocale());
 
 				String[] path = contentRow.getPath().split("/");
 
@@ -188,7 +189,7 @@ public class LargeFilesController extends FormBasicController implements Extende
 					downloadCountMin, revisionsCountMin, minSize);
 
 			for(VFSRevision revision:revisions) {
-				LargeFilesTableContentRow contentRow = new LargeFilesTableContentRow(revision);
+				LargeFilesTableContentRow contentRow = new LargeFilesTableContentRow(revision, getLocale());
 
 				String[] path = contentRow.getPath().split("/");
 
@@ -306,6 +307,7 @@ public class LargeFilesController extends FormBasicController implements Extende
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, LargeFilesTableColumns.uuid));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, LargeFilesTableColumns.name, new LargeFilesNameCellRenderer()));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, LargeFilesTableColumns.size, new LargeFilesSizeCellRenderer(vfsRepositoryModule)));
+		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, LargeFilesTableColumns.context));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(true, LargeFilesTableColumns.path));
 		columnsModel.addFlexiColumnModel(new DefaultFlexiColumnModel(false, LargeFilesTableColumns.age, new LargeFilesAgeCellRenderer()));
 
@@ -401,9 +403,12 @@ public class LargeFilesController extends FormBasicController implements Extende
 				LargeFilesTableContentRow row = (LargeFilesTableContentRow) link.getUserObject();
 
 				CalloutSettings settings = new CalloutSettings(false);
+				VFSContextInfo contextInfo = vfsRepositoryService.getContextInfoFor(row.getPath(), getLocale());			
+				VelocityContainer pathInfoVC = createVelocityContainer("large_files_path_info");
+				pathInfoVC.contextPut("contextInfo", contextInfo);
+				pathInfoVC.contextPut("row", row);
 
-				pathInfoCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),
-						TextFactory.createTextComponentFromString("pathInfo", row.getPath(), "", true, null), link.getFormDispatchId(), "", true, "", settings);
+				pathInfoCalloutCtrl = new CloseableCalloutWindowController(ureq, getWindowControl(),pathInfoVC, link.getFormDispatchId(), "", true, "", settings);
 				listenTo(pathInfoCalloutCtrl);
 				pathInfoCalloutCtrl.activate();
 			}
diff --git a/src/main/java/org/olat/admin/sysinfo/_content/large_files_path_info.html b/src/main/java/org/olat/admin/sysinfo/_content/large_files_path_info.html
new file mode 100644
index 0000000000000000000000000000000000000000..da1fc91d28868db5768219757a8faa01c29ddb21
--- /dev/null
+++ b/src/main/java/org/olat/admin/sysinfo/_content/large_files_path_info.html
@@ -0,0 +1,7 @@
+<div class='o_nowrap'><strong>$r.translate("vfs.context.name"):</strong> $contextInfo.getContextTitle()</div>
+<div class='o_nowrap'><strong>$r.translate("vfs.context.type"):</strong> $contextInfo.getContextTypeName()</div>
+<div class='o_nowrap'><strong>$r.translate("largefiles.path"):</strong> $row.getPath() $row.getName()</div>
+#if ($contextInfo.getContextUrl())
+<div class="o_nowrap"><strong>$r.translate("vfs.context.url"):</strong> <a href='$contextInfo.getContextUrl()'>$contextInfo.getContextUrl()</a></div>	
+#end
+	
\ No newline at end of file
diff --git a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
index 0e6fed3885a9c3a063adf25d87ffd52cad26bc1d..cd7e57e480b12239ee2c38e40948feb5f09c563c 100644
--- a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_de.properties
@@ -88,6 +88,7 @@ java.threads.title=Gleichzeitige Threads
 largefiles.age=Alter
 largefiles.author=Autor
 largefiles.comment=Kommentar
+largefiles.context=Kontext
 largefiles.createdat=Erstellt am
 largefiles.creator=Ersteller
 largefiles.downloads=Downloads
@@ -252,3 +253,6 @@ table.header.trigger=Expression
 title.hibernate.statistics=Hibernate Datenbank Zugriff Statistik
 title.connection.statistics=Datenbank Connections Statistik
 usersession.title=Information \u00FCber Benutzer-Sessions
+vfs.context.name=Name
+vfs.context.type=Typ
+vfs.context.url=URL
diff --git a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_en.properties
index 95c61f2abb6e91ba6b4ff5bf29ed211c9bc7a010..6cfeb16e9848162c8dbbea180c510a2e429141cd 100644
--- a/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/admin/sysinfo/_i18n/LocalStrings_en.properties
@@ -88,6 +88,7 @@ java.threads.title=Current threads
 largefiles.age=Age
 largefiles.author=Author
 largefiles.comment=Comment
+largefiles.context=Context
 largefiles.createdat=Created
 largefiles.creator=Creator
 largefiles.downloads=Downloads
@@ -252,3 +253,7 @@ table.header.trigger=Expression
 title.connection.statistics=Database connections statistics
 title.hibernate.statistics=Hibernate database access statistics
 usersession.title=Information on user sessions
+vfs.context.name=Name
+vfs.context.type=Type
+vfs.context.url=URL
+
diff --git a/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableContentRow.java b/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableContentRow.java
index 7d7fcd18cbcb8b2c0fe1fff6674ff5cdac970f8c..684b46817d024c5f17f9ccf0e039235dbf6a5f10 100644
--- a/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableContentRow.java
+++ b/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableContentRow.java
@@ -21,10 +21,14 @@ package org.olat.admin.sysinfo.model;
 
 import java.util.Calendar;
 import java.util.Date;
+import java.util.Locale;
 
+import org.olat.core.CoreSpringFactory;
 import org.olat.core.commons.services.license.LicenseType;
 import org.olat.core.commons.services.vfs.VFSMetadata;
+import org.olat.core.commons.services.vfs.VFSRepositoryService;
 import org.olat.core.commons.services.vfs.VFSRevision;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoUnknownPathResolver;
 import org.olat.core.gui.components.form.flexible.elements.FormLink;
 import org.olat.core.id.Identity;
 import org.olat.core.util.WebappHelper;
@@ -42,6 +46,7 @@ public class LargeFilesTableContentRow {
 	private final Long size;
 	private FormLink pathInfo;
 	private final String path;
+	private final String context;
 	private final Identity author;
 	private final boolean revision;
 	private final String fileType;
@@ -65,12 +70,14 @@ public class LargeFilesTableContentRow {
 	private final long revisionNr;
 	private final String revisionComment;
 
-	public LargeFilesTableContentRow(VFSMetadata metadata) {
+	public LargeFilesTableContentRow(VFSMetadata metadata, Locale locale) {
 		key = metadata.getKey();
 		name = metadata.getFilename();
 		size = metadata.getFileSize();
 		author = metadata.getAuthor();
 		path = metadata.getRelativePath();
+		VFSRepositoryService vfsRepositoryService = CoreSpringFactory.getImpl(VFSRepositoryService.class);
+		context = vfsRepositoryService.getContextTypeFor(path, locale);		
 		fileType = WebappHelper.getMimeType(metadata.getFilename()) != null ? WebappHelper.getMimeType(metadata.getFilename()).split("/")[1] : "Unknown";
 		fileCategory = WebappHelper.getMimeType(metadata.getFilename()) != null ? WebappHelper.getMimeType(metadata.getFilename()).split("/")[0] : "Unknown";
 		revision = false;
@@ -94,12 +101,14 @@ public class LargeFilesTableContentRow {
 		revisionComment = metadata.getRevisionComment();
 	}
 
-	public LargeFilesTableContentRow(VFSRevision rev) {
+	public LargeFilesTableContentRow(VFSRevision rev, Locale locale) {
 		key = rev.getMetadata().getKey();
 		name = rev.getFilename();
 		size = rev.getSize();
 		author = rev.getAuthor();
 		path = rev.getMetadata().getRelativePath();
+		VFSRepositoryService vfsRepositoryService = CoreSpringFactory.getImpl(VFSRepositoryService.class);
+		context = vfsRepositoryService.getContextTypeFor(path, locale);		
 		revision = true;
 		fileType = WebappHelper.getMimeType(rev.getFilename()) != null ? WebappHelper.getMimeType(rev.getFilename()).split("/")[1] : "Unknown";
 		fileCategory = WebappHelper.getMimeType(rev.getFilename()) != null ? WebappHelper.getMimeType(rev.getFilename()).split("/")[0] : "Unknown";
@@ -172,6 +181,13 @@ public class LargeFilesTableContentRow {
 		return path;
 	}
 
+	public String getContext() {
+		if (context == null || context.equals(VFSContextInfoUnknownPathResolver.UNKNOWN_TYPE)) {
+			return path;
+		}
+		return context;
+	}
+
 	public Boolean isRevision() {
 		return revision;
 	}
diff --git a/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableModel.java b/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableModel.java
index eb5c1d2d6703d4189095bb4a569f0132b347920e..943c83a61313d1ed4fa96d92ed5652d4cb6a5d92 100644
--- a/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableModel.java
+++ b/src/main/java/org/olat/admin/sysinfo/model/LargeFilesTableModel.java
@@ -69,6 +69,7 @@ implements SortableFlexiTableDataModel<LargeFilesTableContentRow> {
 		case name: return row.getName();
 		case size: return row.getSize();
 		case path: return row.getPathInfo();
+		case context: return row.getContext();
 		case author: return row.getAuthor() != null ? row.getAuthor().getUser().getFirstName() + " " + row.getAuthor().getUser().getLastName() : null;
 		case revision: return row.isRevision();
 		case fileCategory: return row.getFileCategory();
@@ -115,6 +116,7 @@ implements SortableFlexiTableDataModel<LargeFilesTableContentRow> {
 		name("largefiles.name"),
 		size("largefiles.size"),
 		path("largefiles.path"),
+		context("largefiles.context"),
 		author("largefiles.author"),
 		revision("largefiles.revision"),
 		fileType("largefiles.filetype"),
diff --git a/src/main/java/org/olat/collaboration/CollaborationToolsFolderVFSContextInfoResolver.java b/src/main/java/org/olat/collaboration/CollaborationToolsFolderVFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..878ddffd3efce42c19145b9eefbdff1dba578919
--- /dev/null
+++ b/src/main/java/org/olat/collaboration/CollaborationToolsFolderVFSContextInfoResolver.java
@@ -0,0 +1,114 @@
+/**
+ * <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.collaboration;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.VFSContextInfoResolver;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoImpl;
+import org.olat.core.id.context.BusinessControlFactory;
+import org.olat.core.id.context.ContextEntry;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.group.BusinessGroup;
+import org.olat.group.BusinessGroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+/**
+ *  
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+@Order(value=300)
+public class CollaborationToolsFolderVFSContextInfoResolver implements VFSContextInfoResolver {
+	private static final Logger log = Tracing.createLoggerFor(CollaborationToolsFolderVFSContextInfoResolver.class);
+	
+	@Autowired
+	private BusinessGroupService bgService;
+
+
+	@Override
+	public String resolveContextTypeName(String vfsMetadataRelativePath, Locale locale) {
+		if (vfsMetadataRelativePath == null) {
+			return null;
+		}
+		String type = null;
+		// Is either a transcoding or the master video
+		if (vfsMetadataRelativePath.startsWith("cts")) {
+			if (vfsMetadataRelativePath.startsWith("cts/folders")) {
+				type = Util.createPackageTranslator(CollaborationToolsFolderVFSContextInfoResolver.class, locale).translate("vfs.context.cts.folders");
+			} else if (vfsMetadataRelativePath.startsWith("cts/wikis")) {
+				type = Util.createPackageTranslator(CollaborationToolsFolderVFSContextInfoResolver.class, locale).translate("vfs.context.cts.wikis");
+			}
+		}		
+		return type;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String vfsMetadataRelativePath, Locale locale) {
+		String type = resolveContextTypeName(vfsMetadataRelativePath, locale);
+		if (type == null) {
+			return null;
+		}
+		
+		// Try finding detail infos. Path looks something like this cts/[tooltype]/BusinessGroup/[groupid]/...
+		String name = "Unknown";
+		String url = null;
+				
+		String[] path = vfsMetadataRelativePath.split("/");		
+		if (path.length < 4) {
+			return null; // no idea
+		}
+		String keyString = path[3];	
+		// lookup group resource
+		if (StringHelper.isLong(keyString)) {
+
+			BusinessGroup businessGroup = bgService.loadBusinessGroup(Long.valueOf(keyString));
+			
+			if (businessGroup == null) {
+				log.warn("No group found for id::" + keyString + " for path::" + vfsMetadataRelativePath);
+			} else {
+				name = businessGroup.getName();
+				BusinessControlFactory bcf = BusinessControlFactory.getInstance();
+				List<ContextEntry> entries = bcf.createCEListFromString("[BusinessGroup:" + businessGroup.getKey() + "]");					
+				if (path[1].equals("folders")) {
+					entries.addAll(bcf.createCEListFromString("[toolfolder:0]"));					
+					// TODO: add other path elements to subdirectory
+				} else if (path[1].equals("wikis")) {
+					entries.addAll(bcf.createCEListFromString("[wiki:0]"));					
+				}
+				url = bcf.getAsURIString(entries, true);
+			}
+		} else {
+			log.warn("Can not parse group id for path::{}", vfsMetadataRelativePath);
+		}
+		return new VFSContextInfoImpl(type, name, url);	
+	}
+
+}
diff --git a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties
index d77c2b366231cc3bc5abc1f7fc85e21022cfeca5..fbdd32ab0629c30b7cfee9ab6e3de25b7e598952 100644
--- a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_de.properties
@@ -22,3 +22,5 @@ folder.access.title=Ordner Schreibberechtigung konfigurieren
 news.access=Informationen Schreibberechtigung
 news.content=Information an Mitglieder
 selection=Auswahl
+vfs.context.cts.folders=Gruppen-Ordner
+vfs.context.cts.wikis=Gruppen-Wiki
\ No newline at end of file
diff --git a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties
index f20d59f6f3dc57f7530a66173796104e9610a3be..98095422dd12a084de2858b16228d4a4e4edc7a3 100644
--- a/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/collaboration/_i18n/LocalStrings_en.properties
@@ -22,3 +22,5 @@ folder.access.title=Configure folder write permission
 news.access=News write permission
 news.content=Information for members
 selection=Selection
+vfs.context.cts.folders=Group folder
+vfs.context.cts.wikis=Group wiki
\ No newline at end of file
diff --git a/src/main/java/org/olat/core/commons/fullWebApp/_content/main_3cols.html b/src/main/java/org/olat/core/commons/fullWebApp/_content/main_3cols.html
index e68357d1e819ce09ad6006b17df0a89d3036eaaa..968b6814c05cc91415396dd3b1b7454d62e933d2 100644
--- a/src/main/java/org/olat/core/commons/fullWebApp/_content/main_3cols.html
+++ b/src/main/java/org/olat/core/commons/fullWebApp/_content/main_3cols.html
@@ -56,7 +56,7 @@ jQuery().ready(function() {
 		if (!menuState.open) {
 			jQuery('#o_main_left_content').show();
 			var l = jQuery('#o_main_left');
-			l.transition({'x': '0', 'left': '0'}, duration, function() {
+			l.transition({'x': 0, 'y': 0, 'left': 0}, duration, function() {
 				menuState.open = true;
 			});
 		} 
@@ -66,7 +66,7 @@ jQuery().ready(function() {
 		if (!menuState.docked && menuState.open) {
 			var l = jQuery('#o_main_left');
 			jQuery('#o_main_left_content').hide();
-			l.transition({'x': '-' + l.css('width'), 'left': '5px'}, duration, function() {
+			l.transition({'x': '-' + l.css('width'), 'y': 0, 'left': '5px'}, duration, function() {
 				menuState.open = false;
 			});			
 		} 
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfo.java b/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfo.java
new file mode 100644
index 0000000000000000000000000000000000000000..d2003faa67ae755032fdab093808f142bfb902e0
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfo.java
@@ -0,0 +1,54 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs;
+
+/**
+ * Describes the context of a VFS item for display purposes. The
+ * context info is localized for the current user.
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+public interface VFSContextInfo {
+
+	/**
+	 * The type of the context / file, e.g. "Home folder"
+	 * 
+	 * @return
+	 */
+	public String getContextTypeName();
+
+	/**
+	 * The specific name, e.g. course element
+	 * 
+	 * @return
+	 */
+	public String getContextTitle();
+
+	/**
+	 * The URL to open this context within OpenOlat or NULL if not applicable
+	 * 
+	 * @return
+	 */
+	public String getContextUrl();
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfoResolver.java b/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..b41933ece68707a0005fc6936ec1eaeed79e2e1d
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSContextInfoResolver.java
@@ -0,0 +1,55 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs;
+
+import java.util.Locale;
+
+/**
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+public interface VFSContextInfoResolver {
+
+	/**
+	 * Resolve the localized type name for a give file path. This method is "light
+	 * weight" without any db access, resolving is done by applying some regexp on
+	 * the path.
+	 * 
+	 * @param VFSMetadataRelativePath the relative file path
+	 * @param locale                  The user locale
+	 * @return The localized type name or NULL if not resolvable by this resolver
+	 */
+	public String resolveContextTypeName(String VFSMetadataRelativePath, Locale locale);
+
+	
+	/**
+	 * Resolve the localized context info for a give file path. This method will do
+	 * db queries to build the context info.
+	 * 
+	 * @param VFSMetadataRelativePath the relative file path
+	 * @param locale The user locale
+	 * @return The localized context info or NULL if not resolvable by this resolver
+	 */
+	public VFSContextInfo resolveContextInfo(String VFSMetadataRelativePath, Locale locale);
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
index 889c0278cdfc07679bc620c4c925eee6b9d9877a..d3c1c590f4a19cf46ed5f4b277d1a029c08ccfaa 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/VFSRepositoryService.java
@@ -23,6 +23,7 @@ import java.io.File;
 import java.io.InputStream;
 import java.util.Date;
 import java.util.List;
+import java.util.Locale;
 
 import org.olat.core.commons.services.license.License;
 import org.olat.core.commons.services.vfs.model.VFSFileStatistics;
@@ -45,6 +46,29 @@ public interface VFSRepositoryService {
 	
 	public VFSMetadata getMetadataFor(File file);
 	
+	/**
+	 * Resolve the context type for the given metadata. This method is "light
+	 * weight" and does not trigger database queries
+	 * 
+	 * @param relativePath The vfs metadada relative path for which the context is
+	 *                     resolved
+	 * @param locale       The users locale
+	 * @return A localized string or "Unknown" if not resolved
+	 */
+	public String getContextTypeFor(String relativePath, Locale locale);
+
+	/**
+	 * Resolve and build the detailed context information for the given metadata.
+	 * This methods is "heavy weight" and might user multiple database queries to
+	 * lookup all information. Use this only to lookup individual items.
+	 * 
+	 * @param relativePath The vfs metadada relative path for which the context is
+	 *                     resolved
+	 * @param locale       The users locale
+	 * @return The resolved and localized context or the VFSContextInfoUnknown
+	 */
+	public VFSContextInfo getContextInfoFor(String relativePath, Locale locale);
+	
 	public VFSMetadata getMetadata(VFSMetadataRef ref);
 	
 	public VFSMetadata getMetadataByUUID(String uuid);
diff --git a/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoImpl.java b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoImpl.java
new file mode 100644
index 0000000000000000000000000000000000000000..01f831d34d3777a8f4bfa51573278988d058ba60
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoImpl.java
@@ -0,0 +1,56 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.impl;
+
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+
+/**
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSContextInfoImpl implements VFSContextInfo {
+	private String contextTypeName;
+	private String contextTitle;
+	private String contextUrl;
+
+	public VFSContextInfoImpl(String contextTypeName, String contextTitle, String contextUrl) {
+		this.contextTypeName = contextTypeName;
+		this.contextTitle = contextTitle;
+		this.contextUrl = contextUrl;
+	}
+
+	@Override
+	public String getContextTypeName() {
+		return contextTypeName;
+	}
+
+	@Override
+	public String getContextTitle() {
+		return contextTitle;
+	}
+
+	@Override
+	public String getContextUrl() {
+		return contextUrl;
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknown.java b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknown.java
new file mode 100644
index 0000000000000000000000000000000000000000..09eec69e281c9373140224254c817c256bca85d3
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknown.java
@@ -0,0 +1,34 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.impl;
+
+/**
+ * Default context resolver for contexts that are not yet implemented
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+public class VFSContextInfoUnknown extends VFSContextInfoImpl {
+	
+	public VFSContextInfoUnknown(String reason) {
+		super("Unknown", reason, null);
+	}
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknownPathResolver.java b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknownPathResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..c7cafc09e6e8fb9876534442b5133662850cd5c8
--- /dev/null
+++ b/src/main/java/org/olat/core/commons/services/vfs/impl/VFSContextInfoUnknownPathResolver.java
@@ -0,0 +1,55 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.core.commons.services.vfs.impl;
+
+import java.util.Locale;
+
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.VFSContextInfoResolver;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * Don't remove this, is used as default resolver when no other resolver matches
+ *  
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Component
+@Order(Ordered.LOWEST_PRECEDENCE)
+public class VFSContextInfoUnknownPathResolver implements VFSContextInfoResolver {
+	public static final String UNKNOWN_TYPE = "Unknown";		
+	public static final String UNKNOWN_CONTEXT = "Unknown Context";		
+
+
+	@Override
+	public String resolveContextTypeName(String VFSMetadataRelativePath, Locale locale) {
+		return UNKNOWN_TYPE;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String VFSMetadataRelativePath, Locale locale) {
+		return new VFSContextInfoUnknown(UNKNOWN_CONTEXT);	
+	}
+
+}
diff --git a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
index 20706f2a363a476a2d9a99c1d3b4b2600723fd3d..d6ff01b2a498c6ed37808b053dda13c71819b3c8 100644
--- a/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
+++ b/src/main/java/org/olat/core/commons/services/vfs/manager/VFSRepositoryServiceImpl.java
@@ -41,6 +41,7 @@ import java.util.HashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 import java.util.UUID;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -61,6 +62,8 @@ import org.olat.core.commons.services.license.LicenseType;
 import org.olat.core.commons.services.thumbnail.CannotGenerateThumbnailException;
 import org.olat.core.commons.services.thumbnail.FinalSize;
 import org.olat.core.commons.services.thumbnail.ThumbnailService;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.VFSContextInfoResolver;
 import org.olat.core.commons.services.vfs.VFSFilterKeys;
 import org.olat.core.commons.services.vfs.VFSMetadata;
 import org.olat.core.commons.services.vfs.VFSMetadataRef;
@@ -70,6 +73,8 @@ import org.olat.core.commons.services.vfs.VFSRevision;
 import org.olat.core.commons.services.vfs.VFSRevisionRef;
 import org.olat.core.commons.services.vfs.VFSThumbnailMetadata;
 import org.olat.core.commons.services.vfs.VFSVersionModule;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoUnknown;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoUnknownPathResolver;
 import org.olat.core.commons.services.vfs.manager.MetaInfoReader.Thumbnail;
 import org.olat.core.commons.services.vfs.model.VFSFileStatistics;
 import org.olat.core.commons.services.vfs.model.VFSMetadataImpl;
@@ -141,6 +146,8 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 	private CoordinatorManager coordinatorManager;
 	@Autowired
 	private BaseSecurity securityManager;
+	// Autowired liste by setVfsContextInfoResolver() method
+	private List<VFSContextInfoResolver> vfsContextInfoResolver;
 	
 	@Override
 	public void afterPropertiesSet() throws Exception {
@@ -285,6 +292,34 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 		return metadata;
 	}
 	
+	@Override
+	public String getContextTypeFor(String relativePath, Locale locale) {
+		if (relativePath == null) {
+			return "No path";
+		}
+		for (VFSContextInfoResolver resolver : vfsContextInfoResolver) {
+			String contextType = resolver.resolveContextTypeName(relativePath, locale);
+			if (contextType != null) {
+				return contextType;
+			}
+		}
+		return VFSContextInfoUnknownPathResolver.UNKNOWN_TYPE;
+	}
+	
+	@Override
+	public VFSContextInfo getContextInfoFor(String relativePath, Locale locale) {
+		if (relativePath == null) {
+			new VFSContextInfoUnknown("No Relative Path");	
+		}
+		for (VFSContextInfoResolver resolver : vfsContextInfoResolver) {
+			VFSContextInfo contextInfo = resolver.resolveContextInfo(relativePath, locale);
+			if (contextInfo != null) {
+				return contextInfo;
+			}
+		}
+		return new VFSContextInfoUnknown(VFSContextInfoUnknownPathResolver.UNKNOWN_CONTEXT);				
+	}
+	
 	@Override
 	public VFSItem getItemFor(VFSMetadata metadata) {
 		if(metadata == null) return null;
@@ -1540,4 +1575,15 @@ public class VFSRepositoryServiceImpl implements VFSRepositoryService, GenericEv
 	public VFSThumbnailStatistics getThumbnailStats() {
 		return statsDao.getThumbnailStats();
 	}
+	
+	
+	/**
+	 * Set list of context info resolver. Used to autowire resolvers from various implementers
+	 * @param vfsContextInfoResolver
+	 */
+	@Autowired
+	public void setVfsContextInfoResolvers(List<VFSContextInfoResolver> vfsContextInfoResolver) {
+		this.vfsContextInfoResolver = vfsContextInfoResolver;
+	}
+	
 }
diff --git a/src/main/java/org/olat/course/CourseVFSContextInfoResolver.java b/src/main/java/org/olat/course/CourseVFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..8bdd820e5b27d6f0a89a961f4384351ffe01e820
--- /dev/null
+++ b/src/main/java/org/olat/course/CourseVFSContextInfoResolver.java
@@ -0,0 +1,116 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.course;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoImpl;
+import org.olat.core.helpers.Settings;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryVFSContextInfoResolver;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+/**
+ * 
+ * A specialized version of the repository entry resolver that catches the
+ * course resources. Since courses are special, they are not located in the
+ * standard repository directory but have their own. 
+ * <br />
+ * The class inheritence is not necessary, it just shows that this belongs to
+ * the repository.
+ * 
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+@Order(value=100)
+public class CourseVFSContextInfoResolver extends RepositoryEntryVFSContextInfoResolver {
+	private static final Logger log = Tracing.createLoggerFor(CourseVFSContextInfoResolver.class);
+
+	@Override
+	public String resolveContextTypeName(String vfsMetadataRelativePath, Locale locale) {
+		if (vfsMetadataRelativePath == null) {
+			return null;
+		}
+		String type = null;
+		// Is either a transcoding or the master video
+		if (vfsMetadataRelativePath.startsWith(PersistingCourseImpl.COURSE_ROOT_DIR_NAME)) {
+			if (vfsMetadataRelativePath.contains(PersistingCourseImpl.COURSEFOLDER)) {
+				type = Util.createPackageTranslator(CourseVFSContextInfoResolver.class, locale).translate("vfs.context.coursefolder");
+			} else if (vfsMetadataRelativePath.contains("foldernodes")) {
+				type = Util.createPackageTranslator(CourseVFSContextInfoResolver.class, locale).translate("vfs.context.foldernodes");
+			}		
+		}		
+		return type;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String vfsMetadataRelativePath, Locale locale) {
+		String type = resolveContextTypeName(vfsMetadataRelativePath, locale);
+		if (type == null) {
+			return null;
+		}
+		
+		// Try finding detail infos
+		String name = "Unknown";
+		String url = null;
+				
+		String[] path = vfsMetadataRelativePath.split("/");		
+		String keyString = path[1];						
+		if (StringHelper.isLong(keyString)) {
+			List<RepositoryEntry> repoEntries = repositoryService.searchByIdAndRefs(keyString);
+			if (repoEntries.size() != 1) {
+				log.warn("No olat resource resource found for id::{} for path::{}", keyString, vfsMetadataRelativePath);
+			} else {
+				RepositoryEntry re = repoEntries.get(0);
+				if (re == null) {
+					log.warn("No repository entry found for key::{} for path::{}", keyString, vfsMetadataRelativePath);
+				} else {
+					name = re.getDisplayname();
+					url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + re.getKey();					
+					
+					if (path.length >= 4 && PersistingCourseImpl.COURSEFOLDER.equals(path[2])) {
+						// Add direct path to course folder
+						// TODO: add other path elements to subdirectory
+						url += "/path%3D~~/0";
+					} else if (path.length >= 4 && "foldernodes".equals(path[2])) {
+						// Add course node jump in if available
+						url += "/CourseNode" + path[3];
+					}
+				}
+			}
+		} else {
+			log.warn("Can not parse repo entry id for path::{}", vfsMetadataRelativePath);
+		}
+		
+		return new VFSContextInfoImpl(type, name, url);	
+	}
+
+}
diff --git a/src/main/java/org/olat/course/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/course/_i18n/LocalStrings_de.properties
index 21005030ac3e81e323790ec81c8cf3add44074ac..798b99d915b555ad9bc49a2a224ebf072a5637db 100644
--- a/src/main/java/org/olat/course/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/course/_i18n/LocalStrings_de.properties
@@ -12,3 +12,5 @@ course.times.loaded=Aufrufe
 course.title=Titel
 current.active.user=Aktiv
 error.helpcourse.not.configured=In diesem System steht keine Hilfe zur Verf\u00FCgung.
+vfs.context.coursefolder=Kurs Ablageordner
+vfs.context.foldernodes=Kursbaustein Daten
\ No newline at end of file
diff --git a/src/main/java/org/olat/course/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/course/_i18n/LocalStrings_en.properties
index 42e18705d2209d6660e770ee6de70b5f78773e6a..4bab508f42523d28ae1b31589b1d93694ef42523 100644
--- a/src/main/java/org/olat/course/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/course/_i18n/LocalStrings_en.properties
@@ -12,3 +12,5 @@ course.times.loaded=Calls
 course.title=Title
 current.active.user=Active
 error.helpcourse.not.configured=This system does not provide any help feature.
+vfs.context.coursefolder=Course folder
+vfs.context.foldernodes=Course element data
diff --git a/src/main/java/org/olat/home/PersonalFolderVFSContextInfoResolver.java b/src/main/java/org/olat/home/PersonalFolderVFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..7d45b7d61a136f3240dc6cac6a1846624188e8c1
--- /dev/null
+++ b/src/main/java/org/olat/home/PersonalFolderVFSContextInfoResolver.java
@@ -0,0 +1,92 @@
+/**
+ * <a href="http://www.openolat.org">
+ * OpenOLAT - Online Learning and Training</a><br>
+ * <p>
+ * Licensed under the Apache License, Version 2.0 (the "License"); <br>
+ * you may not use this file except in compliance with the License.<br>
+ * You may obtain a copy of the License at the
+ * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a>
+ * <p>
+ * Unless required by applicable law or agreed to in writing,<br>
+ * software distributed under the License is distributed on an "AS IS" BASIS, <br>
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br>
+ * See the License for the specific language governing permissions and <br>
+ * limitations under the License.
+ * <p>
+ * Initial code contributed and copyrighted by<br>
+ * frentix GmbH, http://www.frentix.com
+ * <p>
+ */
+package org.olat.home;
+
+import java.util.Locale;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.basesecurity.BaseSecurityManager;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.VFSContextInfoResolver;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoImpl;
+import org.olat.core.helpers.Settings;
+import org.olat.core.id.Identity;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.Util;
+import org.olat.user.UserManager;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ *  
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Component
+@Order(value=400)
+public class PersonalFolderVFSContextInfoResolver implements VFSContextInfoResolver {
+	private static final Logger log = Tracing.createLoggerFor(PersonalFolderVFSContextInfoResolver.class);
+
+	@Autowired
+	private BaseSecurityManager baseSecurityMgr;
+
+	@Override
+	public String resolveContextTypeName(String vfsMetadataRelativePath, Locale locale) {
+		if (vfsMetadataRelativePath == null) {
+			return null;
+		}
+		String type = null;
+		// Is either a transcoding or the master video
+		if (vfsMetadataRelativePath.startsWith("homes")) {
+			type = Util.createPackageTranslator(PersonalFolderVFSContextInfoResolver.class, locale).translate("vfs.context.homes");
+		}		
+		return type;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String vfsMetadataRelativePath, Locale locale) {
+		String type = resolveContextTypeName(vfsMetadataRelativePath, locale);
+		if (type == null) {
+			return null;
+		}
+		
+		// Try finding detail infos
+		String name = "Unknown";
+		String url = null;
+				
+		String[] path = vfsMetadataRelativePath.split("/");		
+		String keyString = path[1];						
+		Identity identity = baseSecurityMgr.findIdentityByName(keyString);
+		if (identity == null) {
+			log.warn("No identity found for id::{} for path::{}", keyString, vfsMetadataRelativePath);
+		} else {
+			name = UserManager.getInstance().getUserDisplayName(identity); 
+			url = Settings.getServerContextPathURI() + "/auth/HomeSite/" + identity.getKey() + "/userfolder/0";
+			// TODO: add other path elements to subdirectory
+
+		}
+		
+		return new VFSContextInfoImpl(type, name, url);	
+	}
+
+}
diff --git a/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties
index c5515fa8ee83cc648285a395315aaaeef1537b21..2ba24380fb79074588174006a0076aca9406ffe2 100644
--- a/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/home/_i18n/LocalStrings_de.properties
@@ -59,3 +59,5 @@ warn.session.was.killed=Sie hatten OpenOlat bereits in einem anderen Browser off
 welcome.header=Willkommen bei OpenOlat
 welcome.intro=<\!-- -->
 welcome.rss=Lesen Sie Ihre pers\u00F6nlichen News als RSS-Feed
+vfs.context.homes=$\:menu.bc
+
diff --git a/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties
index 4251c1857e5793c1e747eb20934c24326ca08b8f..a8e9c582aee7e088dbaa12e412edff33ece20fbb 100644
--- a/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/home/_i18n/LocalStrings_en.properties
@@ -59,3 +59,4 @@ warn.session.was.killed=You are using OpenOlat in another browser. You cannot lo
 welcome.header=Welcome to OpenOlat
 welcome.intro=<\!-- -->
 welcome.rss=Read your personal news as RSS Feed
+vfs.context.homes=$\:menu.bc
diff --git a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
index 461ce4e571e3ddc334c168f972d73a09230ed170..1bfa7136caa93a573f4c4c104a062249844ef8b3 100644
--- a/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
+++ b/src/main/java/org/olat/ims/qti21/model/xml/interactions/FIBAssessmentItemBuilder.java
@@ -499,6 +499,11 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder {
 		this.scoreEvaluation = scoreEvaluation;
 	}
 	
+	/**
+	 * This method only applies to score per answer.
+	 * 
+	 * @return true if some variant hasn't the same score as the main response.
+	 */
 	public boolean alternativesWithSpecificScore() {
 		for(Map.Entry<String, AbstractEntry> entry:responseIdentifierToTextEntry.entrySet()) {
 			AbstractEntry e = entry.getValue();
@@ -508,7 +513,7 @@ public class FIBAssessmentItemBuilder extends AssessmentItemBuilder {
 				if(textEntry.getAlternatives() != null && !textEntry.getAlternatives().isEmpty()) {
 					for(TextEntryAlternative alternative:textEntry.getAlternatives()) {
 						double altScore = alternative.getScore();
-						if(altScore >= 0.0d && score != null && score.doubleValue() != altScore) {
+						if(score != null && score.doubleValue() != altScore) {
 							return true;
 						}
 					}
diff --git a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBScoreController.java b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBScoreController.java
index 48d06b47d9c7f3e4806e388fb96982534a3391eb..e7497eeedc0e8f85e329436ee59f0a59a989fbd4 100644
--- a/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBScoreController.java
+++ b/src/main/java/org/olat/ims/qti21/ui/editor/interactions/FIBScoreController.java
@@ -285,7 +285,7 @@ public class FIBScoreController extends AssessmentItemRefEditorController implem
 	
 	private FIBAlternativeWrapper createAlternativeWrapper(TextEntryAlternative alternative) {
 		String altPointElId = "points_" + counter++;
-		String altScoreStr = alternative.getScore() == -1.0d ? "" : Double.toString(alternative.getScore());
+		String altScoreStr = Double.toString(alternative.getScore());
 		TextElement altPointEl = uifactory.addTextElement(altPointElId, null, 5, altScoreStr, scoreCont);
 		altPointEl.setDisplaySize(5);
 		altPointEl.setEnabled(!restrictedEdit && !readOnly);
@@ -321,23 +321,25 @@ public class FIBScoreController extends AssessmentItemRefEditorController implem
 	}
 	
 	private void updateScoresUI() {
-		boolean perAnswer = assessmentModeEl.isSelected(1) || assessmentModeEl.isSelected(2);
-		scoreCont.setVisible(perAnswer);
-		scoreCont.contextPut("withAlternatives", Boolean.valueOf(assessmentModeEl.isSelected(2)));
-		if(perAnswer) {
+		boolean perAnswer = assessmentModeEl.isSelected(1);
+		boolean perAnswerAndVariants = assessmentModeEl.isSelected(2);
+		scoreCont.setVisible(perAnswer || perAnswerAndVariants);
+		scoreCont.contextPut("withAlternatives", Boolean.valueOf(perAnswerAndVariants));
+		if(perAnswer || perAnswerAndVariants) {
 			for(FIBEntryWrapper wrapper:wrappers) {
 				AbstractEntry entry = wrapper.getEntry();
 				Double points = entry.getScore();
 				if(points != null && points.doubleValue() == -1.0d) {//replace the all answers score
 					wrapper.getEntry().setScore(1.0d);
 					wrapper.getPointsEl().setValue("1.0");
+					points = Double.valueOf(1.0d);
 				}
 				
 				if(entry instanceof TextEntry && wrapper.getAlternatives() != null && !wrapper.getAlternatives().isEmpty()) {
 					for(FIBAlternativeWrapper alternativeWrapper:wrapper.getAlternatives()) {
 						TextEntryAlternative alternative = alternativeWrapper.getAlternative();
 						if(StringHelper.containsNonWhitespace(alternativeWrapper.getPointsEl().getValue())) {
-							if(points != null && points.doubleValue() >= 0.0d && alternative.getScore() == 1.0d) {
+							if(points != null && (alternative.getScore() == 1.0d || alternative.getScore() == -1.0d)) {
 								alternative.setScore(points.doubleValue());
 								alternativeWrapper.getPointsEl().setValue(points.toString());
 							}
diff --git a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
index f28262382cda2bd3d187315253ddb2cfad972fd3..c10e0cc35bebe8ec86b75322271484922d78f0c7 100644
--- a/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
+++ b/src/main/java/org/olat/ims/qti21/ui/statistics/QTI21StatisticResourceResult.java
@@ -33,6 +33,9 @@ import org.olat.core.gui.components.tree.TreeModel;
 import org.olat.core.gui.components.tree.TreeNode;
 import org.olat.core.gui.control.Controller;
 import org.olat.core.gui.control.WindowControl;
+import org.olat.core.gui.control.generic.messages.MessageUIFactory;
+import org.olat.core.gui.translator.Translator;
+import org.olat.core.util.Util;
 import org.olat.course.nodes.CourseNodeConfiguration;
 import org.olat.course.nodes.CourseNodeFactory;
 import org.olat.course.nodes.QTICourseNode;
@@ -47,6 +50,7 @@ import org.olat.ims.qti21.QTI21StatisticsManager;
 import org.olat.ims.qti21.model.QTI21QuestionType;
 import org.olat.ims.qti21.model.QTI21StatisticSearchParams;
 import org.olat.ims.qti21.model.xml.QtiNodesExtractor;
+import org.olat.ims.qti21.ui.AssessmentTestDisplayController;
 import org.olat.repository.RepositoryEntry;
 
 import uk.ac.ed.ph.jqtiplus.node.item.AssessmentItem;
@@ -359,6 +363,12 @@ public class QTI21StatisticResourceResult implements StatisticResourceResult {
 	private Controller createAssessmentItemController(UserRequest ureq, WindowControl wControl,
 			AssessmentItemRef assessmentItemRef, String sectionTitle, boolean printMode) {
 		ResolvedAssessmentItem resolvedAssessmentItem = resolvedAssessmentTest.getResolvedAssessmentItem(assessmentItemRef);
+		if(resolvedAssessmentItem == null || resolvedAssessmentItem.getItemLookup() == null) {
+			Translator translator = Util.createPackageTranslator(AssessmentTestDisplayController.class, ureq.getLocale());
+			String text = translator.translate("error.assessment.item.missing");
+			Controller errorCtrl = MessageUIFactory.createErrorMessage(ureq, wControl, "", text);
+			return TitledWrapperHelper.getWrapper(ureq, wControl, errorCtrl, courseNode, "o_icon_error");
+		}
 		
 		Controller ctrl = new QTI21AssessmentItemStatisticsController(ureq, wControl,
 				assessmentItemRef, resolvedAssessmentItem, sectionTitle, this, withFilter, printMode);
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypeVO.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypeVO.java
index 9e73c82f7eb27ec292f05c34a3a45bce1d271024..4e57b733aa0d5335765247dc42aefa2e6fdd2c82 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypeVO.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypeVO.java
@@ -21,6 +21,7 @@ package org.olat.modules.curriculum.restapi;
 
 import javax.xml.bind.annotation.XmlAccessType;
 import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
 import javax.xml.bind.annotation.XmlRootElement;
 
 import org.olat.modules.curriculum.CurriculumElementType;
@@ -57,7 +58,18 @@ public class CurriculumElementTypeVO {
 			 "copy(all)",
 			 "delete(all)"})
 	private String managedFlagsString;
+	@Schema(required = false, description = "Enable or disable the calendars aggregation", allowableValues = { 
+			"enabled",
+			"disabled",
+			"inherited"})
+	@XmlAttribute(name="calendars", required=false)
 	private String calendars;
+	@Schema(required = false, description = "Enable or disable the lecture block overview and aggregation", allowableValues = { 
+			"enabled",
+			"disabled",
+			"inherited"})
+	@XmlAttribute(name="lectures", required=false)
+	private String lectures;
 	
 	public CurriculumElementTypeVO() {
 		//
@@ -73,6 +85,7 @@ public class CurriculumElementTypeVO {
 		vo.setExternalId(type.getExternalId());
 		vo.setManagedFlagsString(CurriculumElementTypeManagedFlag.toString(type.getManagedFlags()));
 		vo.setCalendars(type.getCalendars().name());
+		vo.setLectures(type.getLectures().name());
 		return vo;
 	}
 
@@ -138,5 +151,13 @@ public class CurriculumElementTypeVO {
 
 	public void setCalendars(String calendars) {
 		this.calendars = calendars;
-	}	
+	}
+
+	public String getLectures() {
+		return lectures;
+	}
+
+	public void setLectures(String lectures) {
+		this.lectures = lectures;
+	}
 }
diff --git a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypesWebService.java b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypesWebService.java
index 2b102c65c198ba773919df7b10da6ff16559b050..ea98c3116f3fd5395fee3b4718fa74929a9092e6 100644
--- a/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypesWebService.java
+++ b/src/main/java/org/olat/modules/curriculum/restapi/CurriculumElementTypesWebService.java
@@ -20,7 +20,6 @@
 package org.olat.modules.curriculum.restapi;
 
 import java.util.ArrayList;
-
 import java.util.List;
 import java.util.Set;
 
@@ -41,6 +40,7 @@ import org.olat.modules.curriculum.CurriculumCalendars;
 import org.olat.modules.curriculum.CurriculumElementType;
 import org.olat.modules.curriculum.CurriculumElementTypeManagedFlag;
 import org.olat.modules.curriculum.CurriculumElementTypeToType;
+import org.olat.modules.curriculum.CurriculumLectures;
 import org.olat.modules.curriculum.CurriculumService;
 import org.olat.modules.curriculum.model.CurriculumElementTypeRefImpl;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -237,6 +237,12 @@ public class CurriculumElementTypesWebService {
 		} else {
 			elementType.setCalendars(CurriculumCalendars.disabled);
 		}
+		if(StringHelper.containsNonWhitespace(elementTypeVo.getLectures())) {
+			elementType.setLectures(CurriculumLectures.valueOf(elementTypeVo.getLectures()));
+		} else {
+			elementType.setLectures(CurriculumLectures.disabled);
+		}
+		
 		elementType.setManagedFlags(CurriculumElementTypeManagedFlag.toEnum(elementTypeVo.getManagedFlagsString()));
 		return curriculumService.updateCurriculumElementType(elementType);
 	}
diff --git a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java
index c3b70ae17115de14fc95c2d16ab21803a76d4c38..3e9feb4cd630b96435c73956dc67964c121afc5c 100644
--- a/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java
+++ b/src/main/java/org/olat/modules/lecture/ui/TeacherRollCallController.java
@@ -596,7 +596,7 @@ public class TeacherRollCallController extends FormBasicController {
 			check.select(onKeys[0], true);
 		}
 		row.setRollCall(rollCall);
-		if(authorizedAbsenceEnabled) {
+		if(authorizedAbsenceEnabled && row.getAuthorizedAbsence() != null) {
 			if(rollCall.getAbsenceAuthorized() != null && rollCall.getAbsenceAuthorized().booleanValue()) {
 				row.getAuthorizedAbsence().select(onKeys[0], true);
 			} else {
diff --git a/src/main/java/org/olat/modules/quality/analysis/MultiTrendSeries.java b/src/main/java/org/olat/modules/quality/analysis/MultiTrendSeries.java
index 72c970e671df2ce12d615e07b4d811e058e53ad9..6b56fca37e022dca20c5bcf9c11c61824a722091 100644
--- a/src/main/java/org/olat/modules/quality/analysis/MultiTrendSeries.java
+++ b/src/main/java/org/olat/modules/quality/analysis/MultiTrendSeries.java
@@ -43,9 +43,11 @@ public class MultiTrendSeries<V> {
 		this.temporalKeys = Collections.emptyList();
 	}
 	
-	public MultiTrendSeries(TemporalGroupBy temporalGroupBy, TemporalKey min, TemporalKey max) {
+	public MultiTrendSeries(TemporalGroupBy temporalGroupBy, TemporalMinMaxKeys minMaxKeys) {
 		this.temporalGroupBy = temporalGroupBy;
 		this.temporalKeys = new ArrayList<>();
+		TemporalKey min = minMaxKeys.getMinKey();
+		TemporalKey max = minMaxKeys.getMaxKey();
 		if (!TemporalKey.none().equals(min) && !TemporalKey.none().equals(max)) {
 			generateTemporalKeys(temporalKeys, min, max);
 		}
@@ -92,6 +94,35 @@ public class MultiTrendSeries<V> {
 		}
 		return series;
 	}
-	
+
+	public static class TemporalMinMaxKeys {
+		
+		private static final TemporalMinMaxKeys NONES = new TemporalMinMaxKeys(TemporalKey.none(), TemporalKey.none());
+		
+		private final TemporalKey minKey;
+		private final TemporalKey maxKey;
+		
+		public static TemporalMinMaxKeys nones() {
+			return NONES;
+		}
+		
+		public static TemporalMinMaxKeys of(TemporalKey minKey, TemporalKey maxKey) {
+			return new TemporalMinMaxKeys(minKey, maxKey);
+		}
+		
+		private TemporalMinMaxKeys(TemporalKey minKey, TemporalKey maxKey) {
+			this.minKey = minKey;
+			this.maxKey = maxKey;
+		}
+
+		public TemporalKey getMinKey() {
+			return minKey;
+		}
+
+		public TemporalKey getMaxKey() {
+			return maxKey;
+		}
+		
+	}
 
 }
diff --git a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
index 8faba390c22f4295590f4c84e8110de3bde59c33..6ba36341c40608720eab5e697d7b84f6931e1fe3 100644
--- a/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
+++ b/src/main/java/org/olat/modules/quality/analysis/manager/StatisticsCalculator.java
@@ -42,6 +42,7 @@ import org.olat.modules.quality.analysis.GroupedStatistics;
 import org.olat.modules.quality.analysis.HeatMapStatistic;
 import org.olat.modules.quality.analysis.MultiKey;
 import org.olat.modules.quality.analysis.MultiTrendSeries;
+import org.olat.modules.quality.analysis.MultiTrendSeries.TemporalMinMaxKeys;
 import org.olat.modules.quality.analysis.RawGroupedStatistic;
 import org.olat.modules.quality.analysis.TemporalGroupBy;
 import org.olat.modules.quality.analysis.TemporalKey;
@@ -236,18 +237,10 @@ public class StatisticsCalculator {
 
 
 	MultiTrendSeries<String> getTrendsByIdentifiers(GroupedStatistics<GroupedStatistic> statistics, TemporalGroupBy temporalGroupBy) {
-		Set<TemporalKey> temporalKeys = new HashSet<>();
-		for (GroupedStatisticKeys groupedStatistic : statistics.getStatistics()) {
-			temporalKeys.add(groupedStatistic.getTemporalKey());
-		}
-		List<TemporalKey> sortedTemporalKeys = new ArrayList<>(temporalKeys);
-		Collections.sort(sortedTemporalKeys);
-		TemporalKey minKey = sortedTemporalKeys.get(0);
-		TemporalKey maxKey = sortedTemporalKeys.get(sortedTemporalKeys.size() - 1);
-		
+		TemporalMinMaxKeys minMaxKeys = getTemporalMinMax(statistics);
 		Set<String> identifiers = statistics.getIdentifiers();
 		
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(temporalGroupBy, minKey, maxKey);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(temporalGroupBy, minMaxKeys);
 		for (String identifier: identifiers) {
 			GroupedStatistic lastStatistic = null;
 			for (TemporalKey temporalKey: multiTrendSeries.getTemporalKeys()) {
@@ -266,18 +259,10 @@ public class StatisticsCalculator {
 	}
 	
 	MultiTrendSeries<MultiKey> getTrendsByMultiKey(GroupedStatistics<GroupedStatistic> statistics, TemporalGroupBy temporalGroupBy) {
-		Set<TemporalKey> temporalKeys = new HashSet<>();
-		for (GroupedStatisticKeys groupedStatistic : statistics.getStatistics()) {
-			temporalKeys.add(groupedStatistic.getTemporalKey());
-		}
-		List<TemporalKey> sortedTemporalKeys = new ArrayList<>(temporalKeys);
-		Collections.sort(sortedTemporalKeys);
-		TemporalKey minKey = sortedTemporalKeys.get(0);
-		TemporalKey maxKey = sortedTemporalKeys.get(sortedTemporalKeys.size() - 1);
-		
+		TemporalMinMaxKeys minMaxKeys = getTemporalMinMax(statistics);
 		Set<MultiKey> multiKeys = statistics.getMultiKeys();
 		
-		MultiTrendSeries<MultiKey> multiTrendSeries = new MultiTrendSeries<>(temporalGroupBy, minKey, maxKey);
+		MultiTrendSeries<MultiKey> multiTrendSeries = new MultiTrendSeries<>(temporalGroupBy, minMaxKeys);
 		for (MultiKey multiKey: multiKeys) {
 			GroupedStatistic lastStatistic = null;
 			for (TemporalKey temporalKey: multiTrendSeries.getTemporalKeys()) {
@@ -295,6 +280,21 @@ public class StatisticsCalculator {
 		return multiTrendSeries;
 	}
 	
+	private TemporalMinMaxKeys getTemporalMinMax(GroupedStatistics<GroupedStatistic> statistics) {
+		if (statistics.getStatistics().isEmpty()) return TemporalMinMaxKeys.nones();
+		
+		Set<TemporalKey> temporalKeys = new HashSet<>();
+		for (GroupedStatisticKeys groupedStatistic : statistics.getStatistics()) {
+			temporalKeys.add(groupedStatistic.getTemporalKey());
+		}
+		List<TemporalKey> sortedTemporalKeys = new ArrayList<>(temporalKeys);
+		Collections.sort(sortedTemporalKeys);
+		TemporalKey minKey = sortedTemporalKeys.get(0);
+		TemporalKey maxKey = sortedTemporalKeys.get(sortedTemporalKeys.size() - 1);
+		
+		return TemporalMinMaxKeys.of(minKey, maxKey);
+	}
+	
 	Double getAvgDiffAbsolute(GroupedStatistic prev, GroupedStatistic current) {
 		if (prev == null || prev.getAvg() == null || current == null || current.getAvg() == null) return null;
 		
diff --git a/src/main/java/org/olat/modules/video/manager/VideoVFSContextInfoResolver.java b/src/main/java/org/olat/modules/video/manager/VideoVFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..4a64f6ff86914adc5d9c68b52dcb02fe3d49b3a2
--- /dev/null
+++ b/src/main/java/org/olat/modules/video/manager/VideoVFSContextInfoResolver.java
@@ -0,0 +1,103 @@
+/**
+ * <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.video.manager;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoImpl;
+import org.olat.core.helpers.Settings;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.olat.modules.video.ui.VideoDisplayController;
+import org.olat.repository.RepositoryEntry;
+import org.olat.repository.RepositoryEntryVFSContextInfoResolver;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Service;
+
+/**
+ * A specialized version of the repository entry resolver that catches also the
+ * transcoded video resources. This resolver has a higher order value to be
+ * executed before the default repository resolver.
+ * <br />
+ * The class inheritence is not necessary, it just shows that this belongs to the repository
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Service
+@Order(value=200)
+public class VideoVFSContextInfoResolver extends RepositoryEntryVFSContextInfoResolver {
+	private static final Logger log = Tracing.createLoggerFor(VideoVFSContextInfoResolver.class);
+
+	@Override
+	public String resolveContextTypeName(String vfsMetadataRelativePath, Locale locale) {
+		if (vfsMetadataRelativePath == null) {
+			return null;
+		}
+		String type = null;
+		// Is either a transcoding or the master video
+		if (vfsMetadataRelativePath.startsWith("transcodedVideos")) {
+			type = Util.createPackageTranslator(VideoDisplayController.class, locale).translate("admin.menu.transcoding.title");
+		} else if (vfsMetadataRelativePath.startsWith("repository") && vfsMetadataRelativePath.endsWith("master")) {
+			type = Util.createPackageTranslator(VideoDisplayController.class, locale).translate("quality.master");
+		}			
+		return type;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String vfsMetadataRelativePath, Locale locale) {
+		String type = resolveContextTypeName(vfsMetadataRelativePath, locale);
+		if (type == null) {
+			return null;
+		}
+		
+		// Try finding detail infos
+		String name = "Unknown";
+		String url = null;
+				
+		String[] path = vfsMetadataRelativePath.split("/");		
+		String keyString = path[1];				
+		if (StringHelper.isLong(keyString)) {
+			List<RepositoryEntry> repoEntries = repositoryService.searchByIdAndRefs(keyString);
+			if (repoEntries.size() != 1) {
+				log.warn("No olat resource resource found for id::" + keyString + " for path::" + vfsMetadataRelativePath);
+			} else {
+				RepositoryEntry re = repoEntries.get(0);
+				if (re == null) {
+					log.warn("No repository entry found for key::" + keyString + " for path::" + vfsMetadataRelativePath);
+				} else {
+					name = re.getDisplayname();
+					url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + re.getKey();
+				}
+			}
+		} else {
+			log.warn("Can not parse repo entry id for path::{}", vfsMetadataRelativePath);
+		}
+		
+		return new VFSContextInfoImpl(type, name, url);	
+	}
+
+}
diff --git a/src/main/java/org/olat/repository/RepositoryEntryVFSContextInfoResolver.java b/src/main/java/org/olat/repository/RepositoryEntryVFSContextInfoResolver.java
new file mode 100644
index 0000000000000000000000000000000000000000..b4357c356c3760d0280444439ccef332550d4468
--- /dev/null
+++ b/src/main/java/org/olat/repository/RepositoryEntryVFSContextInfoResolver.java
@@ -0,0 +1,98 @@
+/**
+ * <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.repository;
+
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.logging.log4j.Logger;
+import org.olat.core.commons.services.vfs.VFSContextInfo;
+import org.olat.core.commons.services.vfs.VFSContextInfoResolver;
+import org.olat.core.commons.services.vfs.impl.VFSContextInfoImpl;
+import org.olat.core.helpers.Settings;
+import org.olat.core.logging.Tracing;
+import org.olat.core.util.StringHelper;
+import org.olat.core.util.Util;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+
+/**
+ * A generic repository resolver that catches everything that has not been
+ * resolved by a more specific resolver with the higher order
+ * 
+ * Initial date: 16 Jan 2020<br>
+ * 
+ * @author gnaegi, gnaegi@frentix.com, http://www.frentix.com
+ *
+ */
+@Component
+@Order(value=10000)
+public class RepositoryEntryVFSContextInfoResolver implements VFSContextInfoResolver {
+	private static final Logger log = Tracing.createLoggerFor(RepositoryEntryVFSContextInfoResolver.class);
+
+	@Autowired
+	protected RepositoryService repositoryService;
+
+	@Override
+	public String resolveContextTypeName(String vfsMetadataRelativePath, Locale locale) {
+		if (vfsMetadataRelativePath == null) {
+			return null;
+		}
+		String type = null;
+		// Catch all repo entry path
+		if (vfsMetadataRelativePath.startsWith("repository")){
+			type = Util.createPackageTranslator(RepositoryEntryVFSContextInfoResolver.class, locale).translate("vfs.context.repositoryentry");
+		}			
+		return type;	
+	}
+
+	@Override
+	public VFSContextInfo resolveContextInfo(String vfsMetadataRelativePath, Locale locale) {
+		String type = resolveContextTypeName(vfsMetadataRelativePath, locale);
+		if (type == null) {
+			return null;
+		}
+		
+		// Try finding detail infos
+		String name = "Unknown";
+		String url = null;
+				
+		String[] path = vfsMetadataRelativePath.split("/");		
+		String keyString = path[1];				
+		if (StringHelper.isLong(keyString)) {
+
+			List<RepositoryEntry> repoEntries = repositoryService.searchByIdAndRefs(keyString);
+			if (repoEntries.size() != 1) {
+				log.warn("No olat resource resource found for id::" + keyString + " for path::" + vfsMetadataRelativePath);
+			} else {
+				RepositoryEntry re = repoEntries.get(0);
+				name = re.getDisplayname();
+				url = Settings.getServerContextPathURI() + "/url/RepositoryEntry/" + re.getKey();
+				type = Util.createPackageTranslator(RepositoryEntryVFSContextInfoResolver.class, locale).translate(re.getOlatResource().getResourceableTypeName());
+			}
+		} else {
+			log.warn("Can not parse repo entry id for path::{}", vfsMetadataRelativePath);
+		}
+		
+		return new VFSContextInfoImpl(type, name, url);	
+	}
+
+}
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
index a638e30795a7a99d3541ba133b44a65ca1756c97..3d882a3eca3989399fc4c63db3abb694b4e0fb06 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_de.properties
@@ -761,3 +761,4 @@ wizardsteptitledescription=Beschreibung eintragen
 wizardsteptitleproperties=Einstellungen vornehmen 
 wizardsteptitleupload=Datei hochladen
 year=Jahr
+vfs.context.repositoryentry=Lernressource
diff --git a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
index b3239642cde26d7429c8717a271cf54f6362efc9..22dbde6c45563dad5a17db10177a6f9bf54c6339 100644
--- a/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
+++ b/src/main/java/org/olat/repository/_i18n/LocalStrings_en.properties
@@ -756,3 +756,5 @@ wizardsteptitledescription=Indicate description
 wizardsteptitleproperties=Set properties
 wizardsteptitleupload=Upload file
 year=Year
+vfs.context.repositoryentry=Learning resource
+
diff --git a/src/test/java/org/olat/modules/quality/analysis/MultiTrendSeriesTest.java b/src/test/java/org/olat/modules/quality/analysis/MultiTrendSeriesTest.java
index e2456593e67aed6ed47d685e4f367ba36ca33e23..2b8ffba2de913b7134a4d14f5049c9bd0fb65340 100644
--- a/src/test/java/org/olat/modules/quality/analysis/MultiTrendSeriesTest.java
+++ b/src/test/java/org/olat/modules/quality/analysis/MultiTrendSeriesTest.java
@@ -24,6 +24,7 @@ import static org.assertj.core.api.Assertions.assertThat;
 import java.util.List;
 
 import org.junit.Test;
+import org.olat.modules.quality.analysis.MultiTrendSeries.TemporalMinMaxKeys;
 import org.olat.modules.quality.analysis.model.TrendImpl;
 
 /**
@@ -40,16 +41,18 @@ public class MultiTrendSeriesTest {
 		TemporalKey tk2001 = TemporalKey.of(2001);
 		TemporalKey tk2002 = TemporalKey.of(2002);
 		TemporalKey tk2003 = TemporalKey.of(2003);
+		TemporalMinMaxKeys minMaxKeys = TemporalMinMaxKeys.of(tk2000, tk2003);
 
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, tk2000, tk2003);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, minMaxKeys);
 		
 		assertThat(multiTrendSeries.getTemporalKeys()).containsExactly(tk2000, tk2001, tk2002, tk2003);
 	}
 	@Test
 	public void shouldGenerateTemporalKeysIfMinEqualsMax() {
 		TemporalKey tk2000 = TemporalKey.of(2000);
+		TemporalMinMaxKeys minMaxKeys = TemporalMinMaxKeys.of(tk2000, tk2000);
 
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, tk2000, tk2000);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, minMaxKeys);
 		
 		assertThat(multiTrendSeries.getTemporalKeys()).containsExactly(tk2000);
 	}
@@ -59,8 +62,9 @@ public class MultiTrendSeriesTest {
 		String identifier = "1";
 		TemporalKey tk2000 = TemporalKey.of(2000);
 		TemporalKey tk2003 = TemporalKey.of(2003);
+		TemporalMinMaxKeys minMaxKeys = TemporalMinMaxKeys.of(tk2000, tk2003);
 
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, tk2000, tk2003);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, minMaxKeys);
 		multiTrendSeries.put(identifier, tk2000, null);
 		
 		List<Trend> trendList = multiTrendSeries.getSeries(identifier).toList();
@@ -72,9 +76,10 @@ public class MultiTrendSeriesTest {
 		String identifier = "1";
 		TemporalKey tk2000 = TemporalKey.of(2000);
 		TemporalKey tk2003 = TemporalKey.of(2003);
+		TemporalMinMaxKeys minMaxKeys = TemporalMinMaxKeys.of(tk2000, tk2003);
 		Trend trend = new TrendImpl(null, null, null, null);
 
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, tk2000, tk2003);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, minMaxKeys);
 		multiTrendSeries.put(identifier, tk2003, trend);
 		
 		List<Trend> trendList = multiTrendSeries.getSeries(identifier).toList();
@@ -86,8 +91,9 @@ public class MultiTrendSeriesTest {
 		String identifier = "1";
 		TemporalKey tk2000 = TemporalKey.of(2000);
 		TemporalKey tk2003 = TemporalKey.of(2003);
+		TemporalMinMaxKeys minMaxKeys = TemporalMinMaxKeys.of(tk2000, tk2003);
 
-		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, tk2000, tk2003);
+		MultiTrendSeries<String> multiTrendSeries = new MultiTrendSeries<>(TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR, minMaxKeys);
 		
 		List<Trend> trendList = multiTrendSeries.getSeries(identifier).toList();
 		assertThat(trendList).containsExactly(null, null, null, null);
diff --git a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
index d97883d2066ad506dd75bd0c7325ad4b5138ca99..c266b18559b8c90c9a3f023eaf2295006b726dd0 100644
--- a/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
+++ b/src/test/java/org/olat/modules/quality/analysis/manager/StatisticsCalculatorTest.java
@@ -326,6 +326,24 @@ public class StatisticsCalculatorTest {
 		assertThat(trend3.getDirection()).isEqualTo(DIRECTION.UP);
 	}
 	
+	@Test
+	public void shouldCalculateTrendsByMultiKeyWithoutData() {
+		GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>();
+		
+		MultiTrendSeries<MultiKey> multiTrendSeries = sut.getTrendsByMultiKey(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR);
+		
+		assertThat(multiTrendSeries.getTemporalKeys()).hasSize(0);
+	}
+	
+	@Test
+	public void shouldCalculateTrendssByIdentifiersWithoutData() {
+		GroupedStatistics<GroupedStatistic> statistics = new GroupedStatistics<>();
+		
+		MultiTrendSeries<String> multiTrendSeries = sut.getTrendsByIdentifiers(statistics, TemporalGroupBy.DATA_COLLECTION_DEADLINE_YEAR);
+		
+		assertThat(multiTrendSeries.getTemporalKeys()).hasSize(0);
+	}
+	
 	@Test
 	public void shouldReduceIdentifier() {
 		// Rubric 1
diff --git a/src/test/java/org/olat/restapi/CurriculumElementTypesWebServiceTest.java b/src/test/java/org/olat/restapi/CurriculumElementTypesWebServiceTest.java
index f68a3295de70fee720767c6e5f6de92f1b319173..06aa424232b76fe2e44f615607f9668e60882d1b 100644
--- a/src/test/java/org/olat/restapi/CurriculumElementTypesWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/CurriculumElementTypesWebServiceTest.java
@@ -40,6 +40,7 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -135,7 +136,7 @@ public class CurriculumElementTypesWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		CurriculumElementTypeVO savedVo = conn.parse(response, CurriculumElementTypeVO.class);
diff --git a/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java b/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
index 4dbd9b3d39232f13c0478f5f2a5d5e4f7430bcd7..c3a1d19bd4718aa7c6fa71828cd2c04fbb88b5be 100644
--- a/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/CurriculumElementsWebServiceTest.java
@@ -40,6 +40,7 @@ import org.apache.http.client.methods.HttpHead;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -241,7 +242,7 @@ public class CurriculumElementsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		CurriculumElementVO savedVo = conn.parse(response, CurriculumElementVO.class);
diff --git a/src/test/java/org/olat/restapi/CurriculumsWebServiceTest.java b/src/test/java/org/olat/restapi/CurriculumsWebServiceTest.java
index 0337bdf09a9832b5fa8bb6e2e4c9829f47bcdca2..513c22cf1b9359fe2a9318e97da7cb39db0cfcdd 100644
--- a/src/test/java/org/olat/restapi/CurriculumsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/CurriculumsWebServiceTest.java
@@ -39,6 +39,7 @@ import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
 import org.apache.logging.log4j.Logger;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -157,7 +158,7 @@ public class CurriculumsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		CurriculumVO savedVo = conn.parse(response, CurriculumVO.class);
diff --git a/src/test/java/org/olat/restapi/IdentityToIdentityRelationsWebServiceTest.java b/src/test/java/org/olat/restapi/IdentityToIdentityRelationsWebServiceTest.java
index 6fd345f9fe213ce6b60fc3e82a39e9aab7b8a05c..447e763cb9e30f2e1dd27f7e8fbd675d30d3076e 100644
--- a/src/test/java/org/olat/restapi/IdentityToIdentityRelationsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/IdentityToIdentityRelationsWebServiceTest.java
@@ -37,6 +37,7 @@ import org.apache.http.client.methods.HttpDelete;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -149,7 +150,7 @@ public class IdentityToIdentityRelationsWebServiceTest extends OlatRestTestCase
 		conn.addJsonEntity(method, relationVo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		IdentityToIdentityRelationVO savedRelationVo = conn.parse(response, IdentityToIdentityRelationVO.class);
@@ -187,7 +188,7 @@ public class IdentityToIdentityRelationsWebServiceTest extends OlatRestTestCase
 		conn.addJsonEntity(method, relationVo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		IdentityToIdentityRelationVO savedRelationVo = conn.parse(response, IdentityToIdentityRelationVO.class);
diff --git a/src/test/java/org/olat/restapi/OrganisationTypesWebServiceTest.java b/src/test/java/org/olat/restapi/OrganisationTypesWebServiceTest.java
index 26a9a587bfe6c20c10ecb38c60376ad09800b64a..1d94def04f56c6da3c70b0316131d0a5d724ae8c 100644
--- a/src/test/java/org/olat/restapi/OrganisationTypesWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/OrganisationTypesWebServiceTest.java
@@ -39,6 +39,7 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -134,7 +135,7 @@ public class OrganisationTypesWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationTypeVO savedVo = conn.parse(response, OrganisationTypeVO.class);
diff --git a/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java b/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
index 8bd51dae2de97b1000b3fa4c879494b0645a8e44..ca10c465dfda730dac70ff5eb3c202c359c9684d 100644
--- a/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/OrganisationsWebServiceTest.java
@@ -19,8 +19,8 @@
  */
 package org.olat.restapi;
 
-import static org.junit.Assert.assertTrue;
 import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 import java.io.InputStream;
@@ -38,6 +38,8 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
+import org.apache.logging.log4j.Logger;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -52,7 +54,6 @@ import org.olat.basesecurity.model.OrganisationRefImpl;
 import org.olat.core.commons.persistence.DB;
 import org.olat.core.id.Identity;
 import org.olat.core.id.Organisation;
-import org.apache.logging.log4j.Logger;
 import org.olat.core.logging.Tracing;
 import org.olat.repository.RepositoryEntry;
 import org.olat.repository.RepositoryService;
@@ -154,7 +155,7 @@ public class OrganisationsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationVO savedVo = conn.parse(response, OrganisationVO.class);
@@ -214,7 +215,7 @@ public class OrganisationsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationVO savedVo = conn.parse(response, OrganisationVO.class);
@@ -310,7 +311,7 @@ public class OrganisationsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationVO savedVo = conn.parse(response, OrganisationVO.class);
@@ -357,7 +358,7 @@ public class OrganisationsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, organisationVo2);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationVO savedVo = conn.parse(response, OrganisationVO.class);
@@ -428,7 +429,7 @@ public class OrganisationsWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		OrganisationVO savedVo = conn.parse(response, OrganisationVO.class);
diff --git a/src/test/java/org/olat/restapi/RelationRolesWebServiceTest.java b/src/test/java/org/olat/restapi/RelationRolesWebServiceTest.java
index 4348cae0623903795bdb6504127c1dee8d3fcac1..8b350228fb8fcef8e63ecc395c9a2f54633a8cc3 100644
--- a/src/test/java/org/olat/restapi/RelationRolesWebServiceTest.java
+++ b/src/test/java/org/olat/restapi/RelationRolesWebServiceTest.java
@@ -40,6 +40,7 @@ import org.apache.http.client.methods.HttpGet;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.methods.HttpPut;
 import org.apache.http.util.EntityUtils;
+import org.hamcrest.MatcherAssert;
 import org.hamcrest.Matchers;
 import org.junit.Assert;
 import org.junit.Test;
@@ -237,7 +238,7 @@ public class RelationRolesWebServiceTest extends OlatRestTestCase {
 		conn.addJsonEntity(method, vo);
 		
 		HttpResponse response = conn.execute(method);
-		Assert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
+		MatcherAssert.assertThat(response.getStatusLine().getStatusCode(), Matchers.either(Matchers.is(200)).or(Matchers.is(201)));
 		
 		// checked VO
 		RelationRoleVO savedVo = conn.parse(response, RelationRoleVO.class);